Compare commits

...

163 Commits

Author SHA1 Message Date
Oliver Smith
622148bbf6 Bump version: 1.7.0.1-fc0c → 1.7.1
Change-Id: Ia9d48cb2b878946df5809bac53c2bd2905903a58
2021-09-06 17:07:36 +02:00
Oliver Smith
55701c111b debian/control: remove dh-systemd build-depend
Related: OS#5223
Change-Id: I769bf61a2f3a97d55c65999436d2cb079c9170a0
2021-09-06 17:07:26 +02:00
Oliver Smith
a71826878e gtphub: remove llist_first, llist_last macros
Use list_first_entry_or_null instead of llist_first, which has been
present in libosmocore since the 0.10.0 release.

Use llist_last_entry instead of llist_last (also present since
libosmocore 0.10.0). This macro does not have a check for an empty
list, however the only user is already checking for an empty list
before using the macro.

This solves a build error, as llist_last was defined in libosmocore
Icf455bf6ba9d60bd311af17c9e80febaa42cacc9 (should probably be reverted
for backwards compatibility with previous osmo-sgsn versions?):

gtphub.c:68:0: error: "llist_last" redefined [-Werror]
 #define llist_last(head, type, entry) \

In file included from /build/deps/install/stow/libosmocore/include/osmocom/core/timer.h:46:0,
                 from /build/deps/install/stow/osmo-ggsn/include/gtp.h:17,
                 from gtphub.c:32:
/build/deps/install/stow/libosmocore/include/osmocom/core/linuxlist.h:245:0: note: this is the location of the previous definition
 #define llist_last(head) (head)->prev

Change-Id: Ia0496c24386cd13b1e9e604aa2d425d3fa28d352
2021-09-06 17:07:05 +02:00
Pau Espin Pedrol
80adb30e93 Bump version: 1.6.0.157-b05c1-dirty → 1.7.0
Change-Id: Ifa861bb0109f433b103a75d5140425bf19c66943
2021-02-23 19:39:45 +00:00
Harald Welte
ebd39830cb main: change initialization order
We must have initialized e.g. the NS protocol stack before calling
handle_options(), as that might want to dumpy the VTY XML, and it
can obviously only dump those nodes that are registered at that
point.

Change-Id: Icd1b8fb3f466cdace67ff0d4f7c85183d8266c41
2021-02-23 16:43:37 +01:00
Harald Welte
b05c1d0ce4 manuals: generate vty reference xml at build time
Move 'doc' subdir further down to "make sure" the osmo-bsc binary is built
before the docs

Rremove sgsn_vty_reference from the source tree.

In manuals//Makefile.am use the new BUILT_REFERENCE_XML feature recently added
to osmo-gsm-manuals, and add a build target to generate the XML using the new
osmo-sgsn --vty-ref-xml cmdline switch.

Change-Id: Ied75fdd13283aa592350994fb4febce06c213d3a
Depends: I613d692328050a036d05b49a436ab495fc2087ba
2021-02-23 15:52:54 +01:00
Harald Welte
999a776b70 main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
Change-Id: I893fc869d5900eff8395bfded0c2fa3883c5a1e7
Depends: Ie2022a7f9e167e5ceacf15350c037dd43768ff40
Related: SYS#5359
2021-02-23 15:52:54 +01:00
Pau Espin Pedrol
11ccc4305d Fix nsei+bvci not updated on rx UL SNDCP data
msgid2mmctx() was already being called for signalling messages in
gsm0408_gprs_rcvmsg_gb() before calling gprs_gb_recv_pdu(), but it was
not called in sndcp_llunitdata_ind().

Let's move msgid2mmctx() inside gprs_gb_recv_pdu() since we want to
always update the nsei+bvci, regardless of message containing data or
control content.

This commit fixes the scenario where an MS changes to a new cell (PCU)
and then continues transmitting UL data. Prior to this patch, the SGSN
kept sending DL content to the old cell (PCU nsei+bvci) instead of the
new one even after the MS transmitted Ul content fro mthe new cell.

Related: SYS#4909
Change-Id: I2c14e1d65575f54212924f7c5f0a2f4c1b76ec81
2021-02-16 13:59:07 +01:00
Oliver Smith
901ed14c89 gbproxy: remove (moved to own repository)
New repository:
https://git.osmocom.org/osmo-gbproxy/

Related: OS#4992
Change-Id: I37f7cebaf2a06bd93627a452f5df44edcfc0f87a
2021-02-08 11:52:53 +00:00
Pau Espin Pedrol
4be5ab3707 sndcp: Fix struct bit fields on big endian
Change-Id: I30014bf84e7a69fa3d85d542d03e41d56506beb7
2021-02-04 12:49:40 +01:00
Pau Espin Pedrol
c999c223ae .gitignore: Ignore new autofoo tmp files
Change-Id: I20b03d40214fe1822aab8df01e3c79404a795f01
2021-02-04 12:48:17 +01:00
Philipp Maier
2ce050ba46 sgsn_rim: Add routing for (GERAN) BSSGP RIM messages
The SGSN currently does not forward BSSGP RIM messages.

Related: SYS#5103
Depends: libosmocore Icd667f41d5735de56cd9fb257670337c679dd258
Change-Id: I6fde8ab8955660b48000ca1b650cfc7c7b2e24ba
2021-01-28 23:20:31 +01:00
Alexander Couzens
43e5f8a2c6 follow libosmocore/gprs_ns2 API changes (gprs_ns2_dynamic_create_nse)
The call gprs_ns2_dynamic_create_nse has been removed because it
was a workaround for the old/dropped vty api.

Depends-on: Ie924ead6da17657f3da334068c8ada82c8845495 (libosmocore)
Change-Id: Ie636cfd18d6d43da0e42f2c2de68dfa5c571d55c
2021-01-28 21:19:59 +00:00
Alexander Couzens
caf73b803c sgsn: migrate to the new gprs_ns2_vty configuration
Change the whole vty configuration for NS to be more flexible
and support more setups. Old configurations are invalid.

API change which must be synchronized with libosmocore

For further information see:
https://osmocom.org/projects/libosmocore/wiki/Network_service_(NS)

Depends-on: I8c3f2afecc74b78f7f914f7dce166cbcb63444eb (libosmocore)
Change-Id: Ie9306ab4d4738c2c57a69987086e22771b30657e
2021-01-28 21:19:59 +00:00
Alexander Couzens
0018d3e0ec gbproxy: follow gprs_ns2 API vty changes
The gprs_ns2_vty2 has been renamed to gprs_ns2_vty. The old
vty has been complete dropped.

API change which must be synchronized with libosmocore.

Depends-on: I8c3f2afecc74b78f7f914f7dce166cbcb63444eb (libosmocore)
Change-Id: If5bd6b86e130772e6c93d640b0c637985416136d
2021-01-28 21:19:59 +00:00
Daniel Willmann
f955d078ed manuals/gbproxy: Move pooling to separate chapter
Change-Id: Ie2ad652c8261ce56cb2ed1a6f16a81486ccdf063
Related: SYS#5115, SYS#5005
2021-01-28 20:57:16 +01:00
Daniel Willmann
93ccc3cf5d manuals/gbproxy: MSC -> SGSN for pooling chapter
Mostly just change the chapter so it makes sense for gbproxy. Some todos
are still left

Change-Id: I905835c2be7be43fe376fbc9d743107948c7e6d4
Related: SYS#5115, SYS#5005
2021-01-28 20:57:16 +01:00
Daniel Willmann
10e0fcaae2 manuals/gbproxy: Add osmo-bsc MSC pooling chapter from Neels as a base
Related: SYS#5115, SYS#5005
Change-Id: I930f5df847ea6f40d0ee0c75dd25b6dd20e00839
2021-01-28 20:57:16 +01:00
Daniel Willmann
592eb140f0 manuals/gbproxy: Update configuration chapter
Change-Id: I01f8d47f9fa384a2528ddf2e6c936ff28d11409e
Related: SYS#5115, SYS#5005
2021-01-28 20:57:16 +01:00
Daniel Willmann
c7b6aabac1 Rename OsmoGbPROXY -> *Proxy
Change-Id: I7542ac1d5242f1784146de2df7cecaf70fe93c6c
Related: SYS#5115, SYS#5005
2021-01-28 20:57:16 +01:00
Daniel Willmann
873c8a55e7 manual/gbproxy: Update overview chapter
* Remove mention of features that are no longer supported
* Update the data model

Related: SYS#5115, SYS#5005
Change-Id: Icb9095f4002f2a0a4562fccecae109075cb93c7b
2021-01-28 20:57:16 +01:00
Harald Welte
e0876bda26 gbproxy: Avoid depending on any of the SGSN code
The last remaining functin of the SGSN code base we used was
gprs_gb_parse_tlli().

Let's simply copy this function over and become  self-contained.

This would allow migrating osmo-gbproxy to a separate repository.

Change-Id: I6f3f86581b47ad71a3d97f07611a2e2709876d69
2021-01-28 19:14:32 +01:00
Alexander Couzens
21afdf9a32 follow libosmocore/gprs_ns2 API changes of GPRS enums
All gprs_ns2 enums have now GPRS_NS2 as prefix.

API change which must be synchronized with libosmocore

Depends-on: I548ff12f7277cbb7e1a630a3dc02b738ce89be72 (libosmocore)
Change-Id: I1af704cdd62ddaff4304479b837dc185b80d7dd6
2021-01-27 21:07:01 +01:00
Daniel Willmann
c09cb29d78 gbproxy: Fix radio status routing by TMSI
If a radio status message contains a TMSI it should be routed as if it
was a TLLI. Convert the TMSI to (foreign) TLLI so NRI-routing works.

Both foreign and local TLLIs are routed the same.

Fixes: OS#4954
Change-Id: Ifd64f02fa16b44f8e2e19eb8ba973f50a829ead5
2021-01-22 12:42:14 +01:00
Daniel Willmann
6ad4040f55 gbproxy: Improve log messages in gbproxy_select_sgsn
Change-Id: Id7bc755b90c35ed7c8cfa8408073e2866d639f2d
Related: OS#4954
2021-01-22 12:36:13 +01:00
Daniel Willmann
45bf92feb4 gbproxy: Print the correct message type for dummy paging/paging reject
Change-Id: I5337abb27587fa2e8320b5bfc3765c9de5c57f6c
2021-01-19 11:37:55 +01:00
Daniel Willmann
d367b8bc78 gbproxy: Use IMSI cache for PTP paging and implement DUMMY_PAGING_PS
Some code was missing to support PAGING_REJECT and DUMMY_PAGING_PS over both PTP
and signalling. This commit adds the missing pieces, notably:

* Use and route according to the IMSI cache for paging on PTP
* Ensure DUMMY_PAGING_PS is broadcast if no routing area is included

Change-Id: I7243e0d4470cb62fa6db36d26002ccd6542b5147
Related: OS#4951, OS#4472
2021-01-19 09:59:01 +01:00
Harald Welte
5037b6817f gb_proxy: Don't use orphan log subsystem DPCU
DPCU is defined in debug.h, but never registered as log subsystem,
so we shall not use it.  Also remove other similar "orphan" log
subsystems from debug.h

Change-Id: I8be54ee49e10d4004128352613923c4700063aa3
2021-01-18 20:32:25 +00:00
Daniel Willmann
d245c0e542 gbproxy: Add VTY commands to query the TLLI/IMSI cache
OsmoGbProxy# show gbproxy tlli-cache
TLLI cache timeout 10s
 TLLI c2200024 -> NSE(02001/BSS) valid 10s
TLLI cache contains 1 entries

OsmoGbProxy# show gbproxy imsi-cache
IMSI cache timeout 10s
 IMSI 262420000001000 -> NSE(00102/SGSN): valid 5s
 IMSI 262420000000000 -> NSE(00101/SGSN): valid 3s
IMSI cache contains 2 entries

Change-Id: I03f1050573de9b241eb4fa82460c434155c15c6a
Related: OS#4951, OS#4472
2021-01-18 18:47:41 +01:00
Daniel Willmann
4380f94cf2 gbproxy: Define and use help string for gbproxy
Change-Id: Ic9336c83147903e5af6622179f9394130f969a77
2021-01-18 18:46:32 +01:00
Daniel Willmann
0d170d61aa gbproxy: Fix VTY cmd name
Change-Id: I5bb5f7cf93779a7a07965f2f35fdb59a7a2b731b
2021-01-18 18:46:32 +01:00
Daniel Willmann
fb5ccb468a gbproxy: Remove unused variable assignment
Change-Id: I79684e0b27211d756912a63be5cae890ea44be82
2021-01-17 13:51:57 +01:00
Daniel Willmann
b96d5a6ead gbproxy: Move helper function to a more logical place
Change-Id: I3b39991fe2441334aaa9dda6c33c0b7b4484e455
2021-01-17 13:51:57 +01:00
Daniel Willmann
6ff8d21fed gbproxy: Use C-style comments
Change-Id: Ia3d27ef79a3370147395e7441149fd1231a760d5
2021-01-17 13:51:57 +01:00
Daniel Willmann
5b1122f717 gbproxy: Use IMSI cache to handle PAGING_PS_REJECT
Change-Id: I7d91d9ecfba757dc81edcf05efb7a2158348099d
Related: OS#4472, OS#4951
2021-01-17 13:51:57 +01:00
Daniel Willmann
914484d561 gbproxy: Implement IMSI cache
When SGSN pooling is enabled we need to route some responses based on
IMSI back to the correct SGSN, e.g. PAGING_PS_REJECT.

The IMSI cache keeps track of this IMSI <-> NSE(SGSN) mapping.

Change-Id: If0a8d6cc1d63f2fb2c395cc5d4373a915bc2cb87
Related: OS#4951, OS#4472
2021-01-17 13:51:57 +01:00
Oliver Smith
b6343a72d8 contrib/jenkins: don't build osmo-gsm-manuals
Related: OS#4912
Change-Id: I3fc43b1afb7cdfd2b78c062e36ccf2491700f988
2021-01-14 14:58:41 +00:00
Daniel Willmann
ef0c2a4b85 gbproxy: Increase TLLI cache timeout to 10s
The range of SUSPEND/RESUME timers T3/T4 is up to 10s so we should keep
the cache entries valid for this time.

Fixes: OS#4895
Change-Id: I9e88e49981098831f3255938deb868f4503f650f
Related: SYS#5235
2021-01-13 18:21:48 +01:00
Daniel Willmann
02b24c5a44 gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME
When routing a SUSPEND/RESUME we need to keep track of where it came
from so we can send the (N)ACK back to the correct BSS. Use the TLLI
which is present in both messages to cache and retrieve the correct BSS.

A timer runs every two seconds and expires entries that are older than
the timeout (hardcoded to 5 seconds for now).

Related: SYS#4865, OS#4472
Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568
2021-01-11 15:09:05 +01:00
Alexander Couzens
cd7c7a74b7 configure.ac: define a c standard instead of using the compilers default
Change-Id: I9867adbed211db0a7b42ac3557f56c3042a67936
2021-01-08 02:32:33 +00:00
Daniel Willmann
ddb3fbb0f2 Fix gbproxy_sgsn_by_tlli wraparound
Change-Id: I74ecb655f4d433f7ac14d00d934d237325aab606
Related: SYS#4865, OS#4472
2021-01-05 18:29:39 +01:00
Vadim Yanitskiy
e245677cdd gb_proxy_peer: fix NULL pointer dereference in gbproxy_sgsn_alloc()
LOGPSGSN_CAT() dereferences sgsn->nse in order to get NSEI.

Change-Id: I1c592dd6f0da5f167290f38de3b30a1a04c4313d
Fixes: CID#215868
2021-01-05 15:26:30 +01:00
Vadim Yanitskiy
1c33e4af05 gb_proxy_peer: sgsn can never be NULL in gbproxy_sgsn_by_nri()
Redundant check makes Coverity think that sgsn can be NULL...

Change-Id: Iffdeb18e0a5575a2a09129eed9b8a41c3340dcbf
Fixes: CID#215870
2021-01-05 14:38:05 +01:00
Daniel Willmann
3844da98f8 gbproxy: Add VTY command to override the node selection function
This is mainly useful when testing SGSN pooling

Change-Id: I2894320413dbd0b9aec9a9bc9b88ce7cdeed206b
Related: SYS#5115, OS#4472
2021-01-04 18:33:52 +01:00
Daniel Willmann
dee0bcc8e9 gbproxy: Add config option to name an SGSN
This is useful for logging and configuration to identify an SGSN by name

Change-Id: I2a3410dd9bebb242957e13a63ed70e447204203c
Related: SYS#5115, OS#4472
2021-01-04 18:33:52 +01:00
Alexander Couzens
51730f7a8c gbproxy: use ns2 vty2
The new gprs_ns2 vty2 support ip-sns and reorganize the
network service configuration

Depends: I163279cf57e84198dc8c53e1c109f5a9474670e9 (libosmocore)
Change-Id: I2a18dcf035f1fc7304a0c7c7c83b5e8e15429d2b
2021-01-04 16:27:41 +00:00
Alexander Couzens
f23e2db752 sgsn: Use the new NS2 api
The new NS2 api supports NSE with multiple NS-VC and contains a NS-VC
fsm. FR/GRE support is not working.
The configuration is compatible except for FR/GRE.

Relates: OS#4629
Depends-on: Iaad7b53d44338e5dd81dc2202f23bdcb715af804 (libosmocore)
Depends-on: I6cef42749555e577d5573f2ed8b8bce4cf842a98 (libosmocore)
Change-Id: I92a3bcaf166b091a22d74c7c1586964d33d7cc9d
2021-01-04 16:06:13 +00:00
Harald Welte
8a33528854 gbproxy: Fix build on Deiban 8
[  258s]   CC       gb_proxy.o
[  258s] gb_proxy.c: In function 'gbproxy_select_sgsn_bvc':
[  258s] gb_proxy.c:293:2: error: 'for' loop initial declarations are only allowed in C99 or C11 mode
[  258s]   for (int i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
[  258s]   ^
[  258s] gb_proxy.c:293:2: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your
code

Change-Id: I717410b11f1ee38d49e9ca5af593cb59a244ae0a
2020-12-30 12:13:56 +01:00
Daniel Willmann
00c1f91ed7 gbproxy: Add comments to sgsn functions
Change-Id: I8c96308045112f25292b0e57c306d8486a2524cc
2020-12-29 16:41:43 +01:00
Daniel Willmann
8d382c5337 gbproxy: Add SGSN pooling support
Change-Id: I58b9f55065f6bd43450e4b07cffe7ba132b1fd9b
Related: OS#4472
2020-12-29 16:41:29 +01:00
Daniel Willmann
ef3c9af0f9 gbproxy: Add SGSN NRI configuration
In order to support SGSN pooling we need to configure the various NRI
parameters such as the bitlen, NULL NRI, and which NRIs are assigned to
which SGSN.

Related: OS#4890, OS#4472
Change-Id: Id67592aa7712e5e04e7264b2fb8f26d57eb7e69e
2020-12-29 16:38:49 +01:00
Harald Welte
5a21f07dff gbproxy: Add "show gbproxy cell ..." VTY command
This allows the user to inspect CELL related gb-proxy state.

Change-Id: Iad1e8bbc358df9a3b3392404a70445a169dfebd5
2020-12-22 19:33:34 +00:00
Daniel Willmann
ea0b5d0df6 gbproxy: Fix confusing log message in gbprox_relay2nse
This function is now used to transmit messages in both directions,
BSS->SGSN and SGSN->BSS.
Print the actual direction in the logs

Change-Id: I31682156dfe88f7ca121a711968e625caed8bd5e
Related: OS#4472
2020-12-22 12:32:16 +01:00
Daniel Willmann
3054213e87 osmo-gbproxy: Initialize all hash_maps
Change-Id: I9578af77a7b2f61b57c918a703768ca20221c294
Related: OS#4472
2020-12-21 18:44:08 +01:00
Alexander Couzens
3326ba7d4c sgsn: check for NULL of gprs_subscr_get_or_create()
gprs_subscr_get_or_create() can return NULL if no memory can
be allocated. Detected by the compiler on Ubuntu s390x.

Signed-off-by: Steve Langasek <steve.langasek@ubuntu.com>
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>

Change-Id: I86b3652d46bdd581fe6cbab16b52395a0daaa082
2020-12-15 11:57:16 +01:00
Harald Welte
b6b2f14197 gbproxy: rename vty command "show gbproxy ..." to "show gbproxy bvc ..."
we have other objects to show, and the orthogoanl way to do this is
to rename the existing one.

Change-Id: I7836a37533a2de81720acedda712d61f429df12c
2020-12-14 12:21:17 +01:00
Harald Welte
959f77e34b gbproxy: Improve VTY state introspection
* allow to print not only BSS-side BVCs, but also SGSN-side
* differentiate between SIG and PTP BVC
* print the actual BVC FSM state name instead of just UNBLOCKED/nothing

Change-Id: I8e09a9dc296b15094d191b0451d04457c815d116
2020-12-12 19:12:52 +01:00
Harald Welte
9e917647ae gbproxy: Implement scaling of BVC flow control in SGSN pool
When there are multiple SGSNs inside a pool, we need to decide
how much of the per-BVC capacity advertised by the BSS in its
BVC-FLOW-CONTROL we should announce to each of the pool members.

A conservative approach would be to advertise 1/num_sgsn, but
there may also be use case where over-provisioning (announcing more
than an equal share of the capacity) is useful.

Hence, let's introduce "pool bvc-flow-control-ratio <1-100>" in order
to allow the administrator to decide.

Related: OS#4891
Change-Id: Ibe5addf657e7237499ca0205bacfe999ecd1e771
2020-12-12 19:12:18 +01:00
Harald Welte
784c59f87e gbproxy: Add FSM related VTY commands
Change-Id: Id84ce52722d705eb25a12ee6f108ad3107a9f8d2
2020-12-12 17:33:49 +01:00
Harald Welte
1aa0ae9db1 gbproxy: Fix segfault when receiving PAGING for unknown destination
The 'nse' variable had been used both as the input argument of the
SGSN-side NSE, as well as a loop iteration variable.  Let's separate
this clearly.

Closes: OS#4904
Change-Id: I375a219cd72eb11a9a0cb7d55a3efb7b83b771ac
2020-12-12 16:16:57 +01:00
Harald Welte
cab8588242 gbproxy: (Re)allocate SGSN-side PTP BVC even if CELL already exists
After a SGSN-side RESET of the SIG-BVC, all PTP BVC on the SGSN side
are gone.  However, the CELLs and the BSS side BVCs continue to exist
(as there may be other SGSNs).

So if a PTP-BVC RESET from the BSS side arrives in such a situation,
and we can find a matching CELL, we still need to check if we need
to create any SGSN-side PTP BVCs instead of simply being happy with
the CELLs already existing.

Change-Id: I1d1562e421082fa4399c73ac31290e4c95718e49
Closes: OS#4903
2020-12-12 15:18:05 +01:00
Harald Welte
4b4c997dc5 gbproxy: Copy RA-ID from BSS side BVC to CELL and SGSN-side BVC
Change-Id: I18669f269c4a959fcfa51885aafb719b662a7f8a
Related: OS#4894
2020-12-12 15:17:33 +01:00
Daniel Willmann
c4c1db9e78 gbproxy: Fix bvci check in gbprox_rx_ptp_from_*
The check for bvci in _rx_ptp_from_* was always false.

Change-Id: I16a0284ba3201c146c307db6997a416589d7e693
Related: OS#4472
2020-12-10 18:11:47 +01:00
Harald Welte
61ff273365 gbproxy: Implement handling of BVC Flow Control
We must locally terminate + acknowledge any inbound BSSGP-FC-BVC,
and ourselves trigger the transmission of BSSGP-FC-BVC to each
SGSN in the pool.

Related: OS#4891
Depends: libosmcoore.git Ie59be6761177c43456898be9148727f15861a622
Change-Id: Ib6495e5de4bfcf748a98e08743d1a8f2565f8b69
2020-12-10 18:09:21 +01:00
Harald Welte
bf69833b6d gbproxy: Don't create an extra msgb copy for SGSN DL SIG
That copy may have made sense while we were doing patching/buffering,
but we're not doing any of that anymore.

Related: OS#4472
Change-Id: I207a869ffac8bf60104f80f9ed58faf0021e5e95
2020-12-10 18:08:58 +01:00
Harald Welte
7cb76a4321 gbproxy: Introduce new DOBJ log category; log object allocation/release
Related: OS#4472
Change-Id: I43bcbcda8667d193e7a17fd8e8e9109597b01484
2020-12-10 18:06:34 +01:00
Harald Welte
c91f53ca0a gbproxy: Use "(nsei << 16) | bvci" as rate_ctr_group index
As we now have gbproxy_bvc on both the SGSN and the BSS side
with the same BVCI, using the BVCI alone will no longer render
unique indexes.

Related: OS#4472
Change-Id: I13f3c9e69562a56ad7d3742fdeb2ba48f134fdaa
2020-12-10 18:06:06 +01:00
Harald Welte
5687ae65fa gbproxy major rewrite for SGSN pool support
Rewrite of a large part of osmo-gbproxy in order to prepare
for SGSN pool support.  The amount of changes are of such fundamental
nature that it doesn't make sense to try to split this into hundreds
of individual changesets.

Related: OS#4472
Change-Id: Ie0746f17927a9509c3806cc80dc1a31d25df7937
2020-12-10 18:05:52 +01:00
Daniel Willmann
7c86a1efce mm_state_gb_fsm: Handle implicit detach from mm_standby
Change-Id: I63d04a2dcdc17b4df6616c515641c435d919c787
Related: OS#2737
2020-12-10 15:25:51 +00:00
Harald Welte
453a51d1a1 migrate to DLBSSGP as log sub-system for BSSGP
Change-Id: I69ee10b6fad1da2053cf6f3ae99d3ecf62a144ce
Depends: libosmocore.git Change-Id I506190aae9217c0956e4b5764d1a0c0772268e93
2020-12-10 15:42:15 +01:00
Harald Welte
a54ed46bac gbproxy: Log FSM timeouts
Change-Id: I5c48e42083ab6f8622808457ca3f017adf35cdff
2020-12-07 18:30:01 +01:00
Harald Welte
052d855449 gb_proxy: Use osmo_tlv_prot_parse() to validate mandatory IEs
We recently introduced code to libosmocore which allows us to validate
the mandatory IE presence (and length) in a generic way.  Let's use it.

Change-Id: I0ea3f5f9566d9bf5a8429c3ee748e3e90cda6cd7
Depends: libosmocore.git I7e4226463f3c935134b5c2c737696fbfd1dd5815
2020-12-07 18:22:20 +01:00
Harald Welte
11ad5713f2 gbproxy: use gbprox_relay2peer() whenever possible
gbprox_relay2peer() is a small wrapper around gbprox_relay2nse(),
but as it manages the transmit error counter, we should use it whenever
possible.

Change-Id: I85ab49ca0a25dd7c54b88c4fdc8838843e6d2209
2020-12-07 18:22:20 +01:00
Harald Welte
d651edcce0 gb_proxy: Introduce more validation / constraint checks
* ensure the BSSGP PDU header length before reading pdu_type field
* ensure we never process uplink PDUs in downlink and vice-versa
* ensure we never proceses PTP PDUs on SIGNALING BVCI and vice-versa

Change-Id: I6e40aed0283f1a0860ab273606605f7fb28717cf
Depends: libosmocore.git I7e4226463f3c935134b5c2c737696fbfd1dd5815
2020-12-07 18:22:20 +01:00
Harald Welte
56f5e74d7d gbproxy: Delete gbproxy_test
The test is actually performing invalid operations such as
sending empty NS packets without even a BSSGP header - and assumes
that gbproxy should route those.

Given that we have a much more comprehensive tset suite in
GBProxy_Tests.ttcn in osmo-ttch3-hacks.git, it makes sense to remove
the testsuite.  It may contain many more wrong assumptions, or
assumptions that no longer hold true with the "gbproxy 2020".

Change-Id: I053aebab6bf5d0ee955f2221bf27925b36140cf3
2020-12-07 18:22:20 +01:00
Harald Welte
4bf53ef19a gb_proxy: cosmetic: Use function rather than open-coding is_sgsn
Change-Id: Id41d74ebd41e5084377a986f4a1acd53cae12bc1
2020-12-05 17:50:50 +01:00
Harald Welte
91bb720449 gbproxy: Remove patching, TLLI-tracking and SGSN2 support
Those features were introduced a long time ago for one specific use
case at one specific user, and they are not needed anymore.  They
complicate the code base significantly and are hard to maintain with
all the upcoming modifications regarding SGSN pool supoprt.

Change-Id: Id9cc2e1c63486491ac5bb68876088a615075fde6
2020-12-05 14:05:36 +01:00
Harald Welte
993d3f4d9a gbproxy: convert nse->bvcs from llist_head to hashtable
For the common lookup-by-bvci, this should reduce the computational
complexity significantly.

Depends: libosmocore.git I8ef73a62fe9846ce45058eb21cf999dd3eed5741
Change-Id: Ic8e9279fd61a3c514fc3203429f36a468f0e81d3
2020-12-05 13:55:06 +01:00
Harald Welte
78db244b42 gbproxy: convert bss_nses from llist_head to hashtable
For the common lookup-by-nsei, this should reduce the computational
complexity significantly.

Depends: libosmocore.git I8ef73a62fe9846ce45058eb21cf999dd3eed5741
Change-Id: Idbb6a362332bb6e3ce22102e7409ae80d0980f44
2020-12-05 13:49:37 +01:00
Harald Welte
0e1b791c81 gbproxy: Rename gbproxy_cfg.nses to gbproxy_cfg.bss_nses
We will soon also have a list of sgsn-side NSEs, and we need to
differentiate those.

Change-Id: If5accec0c70c01b88927ea07beba6f6488bd9d5a
Related: OS#4472
2020-12-05 12:08:10 +01:00
Harald Welte
8cd74407ab gb_proxy: Rename gbproxy_peer to gbproxy_bvc
I cannot really read the code while it contains its historical weird
naming.  A "peer" used to be a strange amalgamation of NSE + BVC,
while in reality we can have any number of BVC on top of each NSE.

We recently started to split the peer into a gbproxy_nse_peer + gbproxy_peer.
This takes it one step further and renames gbproxy_peer to gbproxy_bvc,
as that's really what it is.

Change-Id: Iae01067282a6401f6af4cab731202872d2cdb080
2020-12-05 12:06:42 +01:00
Harald Welte
6c4c6f08ae gb_proxy: Use TLVP_PRES_LEN instead of TLVP_PRESENT
With TLVP_PRESENT we only check if a tiven TLV/IE is present,
but don't verify that it's length matches our expectation.  This can
lead to out-of-bounds reads, so let's always use TLVP_PRES_LEN.

Change-Id: I1519cff0f6b2fe77f9a91eee17e0055d9df1bce6
2020-12-05 11:44:39 +01:00
Harald Welte
fb7f8c5f07 gbproxy: Send BVC-STATUS if BSS sends us BVC-RESET without mandatory IEs
Change-Id: I198ca70f5e0947735f76d32cd9d3eed159349a94
2020-12-05 11:44:38 +01:00
Daniel Willmann
9a2fc908df gbproxy: Delete gbproxy_nse in delete-gbproxy-peer VTY command
The gbproxy_nse is created when the signalling BVC is resetted. When
we delete all bvcs of an nsei we need to remove it as well.

Change-Id: I997b29fef93188565f81bd403bc68840473958c3
Related: SYS#5002
2020-12-04 17:49:19 +01:00
Daniel Willmann
e794c1f00b gbproxy: Allow gbproxy_nse_free(NULL)
Calling free() with a null-pointer is usually supported and does
nothing. Change gbproxy_{peer,nse}_free() to reflect that behaviour.

Change-Id: Ia32084f81ca8f8cb9ddea3adabd4b44fd766f1c7
2020-12-04 17:49:19 +01:00
Daniel Willmann
bd356a6d84 gbproxy: Add newline to log message
Change-Id: I91a076872b5d744a237f6d325857b95362455e8d
2020-12-04 01:31:05 +01:00
Daniel Willmann
e8c8ec9683 gbproxy: Add BVC log filters
Since gbproxy doesn't use bssgp_rcvmsg from libosmocore we need to
implement our own filtering.

Change-Id: I4d1b57b89990945d307f27a58a7f630be0253d5b
Related: SYS#5232
2020-12-04 01:31:05 +01:00
Harald Welte
55253716d2 gbproxy: Cosmetics: use longer lines
Change-Id: I9426bf4be2faa0da7848cb102b20cc539948b3f5
2020-12-02 23:06:37 +01:00
Harald Welte
1239cf457e gb_proxy: Slightly restructure processing of BSS-originated BVC-RESET
* explicit else clause rather than implicit
* don't continue processing if mandatory BVCI missing from message

Change-Id: I038576b91ae1ece149149d8663de7b8495d24e06
2020-12-02 23:03:22 +01:00
Harald Welte
ac44d6b2a2 gbproxy: Move BSS-side BVC-RESET processing to its own function
The switch clause was getting a bit too long/nested, let's add
a separate gbprox_rx_bvc_reset_from_bss() function.

Change-Id: If262566e275cca96035045d1194ce102c0942eb6
2020-12-02 23:01:47 +01:00
Harald Welte
c8d98ac8f9 gb_proxy: Broadcast SGSN-INVOKE-TRACE and OVERLOAD
Both BSSGP messages appear from the SGSN in downlink on BVCI=0.

We must send a copy of this message to each of the BSS side NSEs.

Change-Id: Ia19791b143989eb1490f461d88b9edbd8e3b82be
Closes: OS#4875
2020-12-02 22:45:42 +01:00
Daniel Willmann
6626bbc215 gbproxy: Add todos encountered while going through the code
Change-Id: I8c3a788f008d3cb2d067d974c2b1b9ca45185d8d
2020-12-02 22:42:48 +01:00
Daniel Willmann
103a7ec033 gbproxy: Change generic LOG messages so BVCI/NSEI fmt is consistent
We actually need to alter our compiler flags to avoid -Werror=trigraphs
creating trouble:

gb_proxy.c: In function ‘block_unblock_peer’:
gb_proxy.c:875:37: error: trigraph ??) ignored, use -trigraphs to enable [-Werror=trigraphs]
  875 |   LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",
      |

Fixes: SYS#5233
Change-Id: I93296353dd964602699480faae1248096e331c6a
2020-12-02 22:42:42 +01:00
Daniel Willmann
6e8ed2784e gbproxy: Use LOG macros for NSE/BVC
Change-Id: If445f18bc8390c338b5aeb9085951ea392e68b3a
Related: SYS#5233
2020-12-02 17:47:49 +01:00
Daniel Willmann
7418797027 gbproxy: Add logging macros for NSE and BVC
Change-Id: Ibb2bcf3344bdc750869223b4c4861b4bbc6f417c
Related: SYS#5233
2020-12-02 17:17:17 +01:00
Harald Welte
d97ff681c3 gb_proxy: More precise + readable log messages
* use string representations instead of magic numbers whenever possible
* make text actually describe the specific case, rather than copy+paste
* proper order (foobar indication) not (indication ..... foobar)

Change-Id: I232038da26a9963763c5fc9051b87c9182b27d94
2020-12-01 11:56:57 +00:00
Pau Espin Pedrol
83142beca2 gmm: Introduce comment to ease addition of Network feature support IE later
Change-Id: I131cba3de3c80c61d5549e7c31b4eacaaeddb040
2020-12-01 11:47:58 +00:00
Pau Espin Pedrol
8c3d7fd263 gmm: fix build without define PTMSI_ALLOC
Change-Id: Idcac01c4634af81ef884dc2b1b20dec3f8d12236
2020-12-01 11:47:58 +00:00
Daniel Willmann
9e583c8d89 gbproxy: Separate function to move gbproxy_peer to different nse
Change-Id: I0a8b1e4b78384ea99d50109f050ca501b18ba5d9
Related: SYS#5226
2020-11-30 18:30:35 +01:00
Daniel Willmann
5937dfd39f gbproxy: Only send paging to each matching NSE once
Fixes: SYS#5226
Change-Id: Ia33e7816b354266b9d2659ef96b798db60c134f3
2020-11-30 18:30:35 +01:00
Daniel Willmann
cafa3881ad gbproxy: Ensure BVC0 is reset before handling PtP BVCs
Change-Id: I9c67f973f7bca00e8eb22a024ef2282c007dd84b
Related: SYS#5226
2020-11-30 18:30:35 +01:00
Daniel Willmann
447ad441e6 gbproxy: Add NSE peer that can have multiple gbproxy_peers
We want this level of indirection to support multiple BVCs per NSE. The
current code assumes that an NSE only has one BVC which breaks messages
on the signalling BVC which should only be sent once to an NSE
regardless of the number of BVCs it contains.

Change-Id: I97cc6c8f8c0f1b91577ab8f679c4ae217cc88076
Related: SYS#5226
2020-11-30 18:30:35 +01:00
Daniel Willmann
f7a1aed0e6 gbproxy: Remove test testing NSVCI change
This was overlooked in commit 82182d which already removed lots of
NS-specific code in gbproxy_test.c

From that commit message:
"""
Since NS2 has a different abstraction we mock up the prim send/recv
functions and don't test NS like the old tests did.
"""

Change-Id: Ic1d7e646e633c9fa62812f5005ed10c0108a06f2
Related: SYS#5226
2020-11-30 18:26:38 +01:00
Harald Welte
eb4233e505 gb_proxy_peer: Add some FIXMEs regarding invalid assumptions
Change-Id: Ibf3d4a3bd58e706dfa44e8cc9ff4823a7759dea5
2020-11-27 23:15:18 +01:00
Harald Welte
2636e89ff0 gbproxy: Pass TLLI as LSP towards NS to facilitate load sharing
Change-Id: I6aef26c126b330a393fc2be5f558b6d5f1d9f7f4
2020-11-27 23:15:18 +01:00
Pau Espin Pedrol
bcd7709452 sgsn: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Change-Id: I65f70a53b6982bff9ea4bd6ff786d8a2f8181eac
Fixes: OS#4865
2020-11-25 18:28:55 +01:00
Pau Espin Pedrol
7ffc6603e2 gtphub: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Change-Id: I1cab4a716cf2fda6353f698888edbcec6228d78b
Fixes: OS#4865
2020-11-25 18:22:21 +01:00
Pau Espin Pedrol
826eaa327b gbproxy: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Change-Id: I97559b29328101c7cf340aaf1052c0c406634065
Fixes: OS#4865
2020-11-25 18:22:12 +01:00
Harald Welte
952fbf20c9 gprs_gb_parse: Add function to determine TLLI from encoded BSSGP
This will be needed to use the TLLI as link selector parameter
in osmo-gbproxy in an upcoming patch.

Depends: libosmocore.git I397b32a6e6ea3e9d218446138cceafa9b27685dd
Change-Id: Ia6d5300e63ad23987cbdca824db620305bd583d7
2020-11-24 11:33:16 +01:00
Harald Welte
8553f5532a gbproxy: Implement paging to entire BSS area
When we receive a PAGING for PS or CS with destination to the entire
BSS area, we need to iterate over all peers and send one copy of the
paging to each of them.

Change-Id: Iecf244238500a354d5a5b40c76f0c0bb8f8c2511
2020-11-24 11:33:16 +01:00
Harald Welte
3375fa4d64 gbproxy: Properly implement paging to LAC/RAC
There may very well be many PCUs connected within the same RAC or LAC.

This means we'll need to iterate the list of peers and dispatch it to
each matching peer.

Change-Id: I2c44959661fb53730586f4347cbfbbcece065e13
2020-11-24 11:33:12 +01:00
Harald Welte
e1ba4239b4 Use osmo_fd_*_{disable,enable}
Change-Id: Ia207cd2ee68d657ee88cb0152a5b1faa4161c967
Depends: libosmocore.git Idb89ba7bc7c129a6304a76900d17f47daf54d17d
2020-11-11 20:15:09 +00:00
Daniel Willmann
638cddd8f1 osmo-gbproxy: Implement nsvc-state ctrl command
Change-Id: I0beb572103803f3ee4ecb28d9bf2e3139e0f8aa4
2020-11-11 20:11:50 +00:00
Daniel Willmann
58937ce333 configure.ac: Require python3 for ext_tests
The python scripts already use #!/usr/bin/env python3 so it was pure
coincidence that the tests are working.

Change-Id: I96ac31e7862fe102e5baee0c2e25458ff0451a50
2020-11-09 10:54:14 +00:00
Daniel Willmann
02f2c34f8a osmo-gbproxy: Free msgb in ns2 prim callback
Commit cce88282388f in libosmocore changed the msg ownership model - the
callback that the user registers is now responsible for freeing the msg.

Change-Id: Iee940aba7d94afefb5957dbe5f0b04dcf951b31c
Related: SYS#4998
2020-11-09 10:54:09 +00:00
Daniel Willmann
62fa6198ae Let libosmocore handle VTY parent node tracking
* is_config_node is deprecated, so don't set it
* go_parent_cb is only used if we want to do special stuff upon exiting
  a node, in osmo-sgsn and gtphub only osmo_ss7_vty_go_parent() needs to
  be called

Change-Id: I2008dd9026922d29ee703c59e70d3fecced0ee18
2020-11-06 22:21:21 +01:00
Daniel Willmann
c42331f359 gbproxy: Get the peer if paging by BVCI on SIG_BVC
Currently the code reports routing the message to a BVCI but never even
tries to get the peer for it.

Change-Id: Ic72f0f03e5886ab76404915fc60a2796e6881a7a
Related: SYS#4998
2020-11-06 22:21:21 +01:00
Daniel Willmann
15c9da226b gbproxy: Add todo for BVC RESET logic
When we receive a signalling BVC RESET from the SGSN we want to reset
the signalling BVCs for every peer.

Change-Id: I98c1a53d0e4b9a988e9ddec97ce0c67ded6f6326
Related: SYS#4998
2020-11-06 22:21:16 +01:00
Daniel Willmann
8bca8de5cb gbproxy: Whitespace fixes
Change-Id: Id70c15050b6314fdcd452e89e358d657e1f86e57
2020-11-06 18:45:05 +01:00
Alexander Couzens
82182d09c7 Port gbproxy to NS2
Since NS2 has a different abstraction we mock up the prim send/recv
functions and don't test NS like the old tests did.

Related: SYS#4998
Change-Id: Iecfd0408a35a11638d254c1db3c1d477b1a11524
2020-11-06 18:45:05 +01:00
Pau Espin Pedrol
08395b3369 process_ms_ctx_status: Fix crash deleting PDP Ctx if GTP side was already released
sgsn_delete_pdp_ctx() should never be called without checking if the GTP
side is available, since it may happen that it has already been released
by the time the mmctx tells us the pdp ctx is gone on the MS side.

Fixes: OS#4817
Change-Id: Ie618874545172ec98355174a2ee041fc4a8bec16
2020-10-23 13:25:13 +02:00
Pau Espin Pedrol
25998ddcc5 process_ms_ctx_status: refactor to avoid code duplication
Change-Id: I1d1a1284c1563b3a5598e79d8ffd544288de4d62
2020-10-23 13:23:18 +02:00
Pau Espin Pedrol
60581ae7c9 sgsn_delete_pdp_ctx: Add documentation and assert assumptions
This function is only expected to be called if the GTP side of the PDP
ctx is still alive, since it will tear down the GTP side and then finish
the pending MS side if needed.

The asserts are added to ease debugging since it was noted that a few
callers were using this function without properly checking the status of
the pdp ctx.

Related: OS#4817
Change-Id: I4248e2e9846fec5ae2c8557384da2deb86668c50
2020-10-23 13:04:48 +02:00
Keith
c70e8388c7 VTY: Add gtp state-dir command
The SGSN initialises GTP with gtp_statedir of "./" which may
not be the desired path for writing the gsn_restart file.
When starting from systemd for example, we might write
to the system root.

This patch allows override via the config file.

Closes: OS#4820
Change-Id: Ib3ffb7fd6ea1d9b0286111d8c2cba9da5394ca58
2020-10-20 13:21:37 +00:00
Pau Espin Pedrol
5ce54ba1e6 Fix crash rx DeactPdpReq while waiting for DeactPdpAck after gtp side is freed
Scenario:
1- For an unknwon reason, sgsn sends DeletePdpCtxReq on GTP towards GGSN.
2- GGSN answers with Error Indication to that pdp ctx which calls
   gtp_freepdp()
3- gtp_freepdp() calls libgtp callback cb_delete_context() before freeing the
   pointer, in osmo-sgsn callback points to cb_delete_context(), which
   removes pctx->ggsn and tries to drop the pdp on the NS side by sending a
   DeactPdpReq.
4- While waiting for DeactPdpAck, the MS/PCU sends a DeactPdpReq, and
   code was unconditionalyl trying to release the gtp side without checking
   if it was alreay released, using pctx->ggsn==NULL and crashing.

This is basically the same logic already in place in regular path
gsm48_rx_gsm_deact_pdp_ack.

Related: OS#4817
Change-Id: I02587a3dc812823d893fc00b904142b75fd190b9
2020-10-19 15:06:55 +00:00
Pau Espin Pedrol
ff5b59a821 Log error if pdp ctx is freed while holding an active timer
Change-Id: Iae520be36377b27a12441defa722fd41a3cdba0a
2020-10-19 15:06:55 +00:00
Harald Welte
be2330fde4 Use osmo_fd_setup() whenever applicable
Change-Id: I68d14b1c19dd8f1764fdf65afe1a957278255e40
2020-10-19 10:50:45 +00:00
Pau Espin Pedrol
8d2d7db818 contrib/jenkins: Enable parallel make in make distcheck
Change-Id: I423c4b1d854fa6ec7df504353ce666766ba0c787
Related: OS#4421
2020-10-12 19:34:04 +02:00
Alexander Couzens
92ef0c8675 gtphub: fix compilation with gcc 10.2.0
gtphub.c:2915:2: error: ‘snprintf’ argument 4 may overlap destination object ‘buf’ [-Werror=restrict]
 2915 |  snprintf(pos, len, " port %s", portbuf);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Be better safe and use the stack instead of byte counting in the buffer.

Change-Id: Ied9665ce6bd2633797bbc3a2171e911ada357a22
2020-10-03 20:37:15 +02:00
Alexander Couzens
68d9c5a468 gtphub_test: fix compilation error on gcc 10.2.0
Ensure dump && hex can't be zero.

gtphub_test.c: In function ‘_reply_is.constprop’:
gtphub_test.c:535:3: error: ‘%s’ directive argument is null [-Werror=format-overflow=]

Change-Id: Id27bf46855a228935fe706584f9b27cf3facf623
2020-10-02 20:44:34 +00:00
Philipp Maier
ef6205ba00 gprs_sndcp: fix use after free
When compression is turned on, an extra buffer "expnd" is allocated in
the context of msg. This means that when msg is freed, expnd is freed as
well and there is no need for freein it explcicitly, which, when it is
done after freeng msg, causes talloc to abort.

Change-Id: I8959b75e241ffabf9fa34c4cf014721584372b26
2020-10-02 17:38:12 +02:00
Daniel Willmann
86336af2a3 gbproxy-usermanual: Explain BSSGP/BVC handling
Related: SYS#5005
Change-Id: I383fcd3864a94177f13909c6b8c15648900d3201
2020-09-25 09:54:26 +02:00
Keith
6d92f148aa Fix Radio Priority in MM Attach and PDP Context Activation
3GPP TS 24.008 Section 10.5.7.2 Radio Priority states that the Radio Priority IE is
3 bits as follows:

--------------------------------------------
0 0 1   priority level 1 (highest)
0 1 0   priority level 2
0 1 1   priority level 3
1 0 0   priority level 4 (lowest)

All other values are interpreted as priority
 level 4 by this version of the protocol.
--------------------------------------------

However at least the MediaTek MT6753 and MT6592 have been
observed to interpret a value of 0 0 0 in an undetermined way
resulting in lack of access to RACH in the cell.

Fixes: OS#4506
Change-Id: I810cd541eb5764ee3f2c238bcd3a10836228d0b5
2020-09-21 00:18:48 +02:00
Alexander Couzens
27a0bf70e7 gmm: on invalid RA id reject the MS with an implicit detach
As long the SGSN doesn't support PS handover treat unknown RA as invalid
and do an implicit detach.

Fixes ttcn3 crash when an RAU happen within an Attach Request

Change-Id: I6a0b335d51f58c26349f7e0a62b2107d7d351d07
2020-09-20 09:52:24 +00:00
Alexander Couzens
d3c3ddeb51 gprs_llc: _bssgp_tx_dl_ud: ensure the LLME is valid before using it
In rare cases the LLME is NULL even when the mmctx is valid.
Ensure not accessing a NULL pointer.

Change-Id: Id9fdfb0d88264671546f8dfc4655032ff27bf43e
2020-09-18 18:32:04 +02:00
Pau Espin Pedrol
e6c5b4a970 Change default SCTP conn NULL->127.0.0.1 to localhost->localhost
"127.0.0.1" is changed to "localhost" to let local NSS decide whether to
use IPv4 or IPv6. In newish systems, IPv6 ::1 will be selected since
IPv6 takes precedence over IPv4.

Similarly, the default source addr needs to be changed from NULL to "localhost"
since for some yet unknwon reason, getaddrinfo(AF_UNSPEC, NULL) returns
first IPv4 "0.0.0.0" and later "::", which is inconsistent with
getaddrinfo("localhost") result, resulting in src=IPv4(0.0.0.0) and
dst=IPv6(::1), which is incompatible and will fail. In any case, since
the default remote address is a local one and it's the client side,
there's no real logical change since the kernel would anyway should have
taken a local address anyway.

Change-Id: I2f599e1aa449d44136ef20ba5f516ca9b61f3223
2020-08-21 18:07:11 +02:00
Pau Espin Pedrol
aae7daff81 Support setting rt-prio and cpu-affinity mask through VTY
Change-Id: I1af1b154d14de6d6d6fba08f15f167f4b2ed9aa2
Depends: libosmocore.git Change-Id If76a4bd2cc7b3c7adf5d84790a944d78be70e10a
Depends: osmo-gsm-masnuals.git Change-Id Icd75769ef630c3fa985fc5e2154d5521689cdd3c
Related: SYS#4986
2020-08-18 13:50:00 +02:00
Pau Espin Pedrol
b32936d823 doc: Update VTY reference xml file
Change-Id: I787bbc254ef10766fe8d480ffd93a16d9926a50e
2020-08-18 13:46:17 +02:00
Pau Espin Pedrol
d5dc143001 configure.ac: Fix trailing whitespace
Change-Id: I5abdce5daef43dad772bf52576b47c0867d65c98
2020-08-18 13:45:09 +02:00
Vadim Yanitskiy
65a5a0a27b debian/control: change maintainer to the Osmocom team / mailing list
Change-Id: Ic6956c4d5cc9913c06b9e293dc5bb156f6510285
2020-08-13 16:09:03 +07:00
Harald Welte
9d16b14345 Send a BVC-RESET to all persistent Gb interfaces at start-up
3GPP TS 48.018 Section 8.4:

> After any failure affecting the NSE, the party (BSS or SGSN) where
> the failure resided shall reset the signalling BVC. After sending or
> receiving a BVC-RESET PDU for the signalling BVC, the BSS shall stop all
> traffic and initiate the BVC-RESET procedure for all BVCs corresponding
> to PTP functional entities of the underlying network service entity. The
> BSS must complete the BVC-RESET procedure for signalling BVC before
> starting PTP BVC-RESET procedures.

TODO: We should not just trigger a single outbound BVC-RESET message,
but we should re-transmit them until we get a response.   This would
likely entail adding FSMs to libosmogb, which we will leave for a later
point - it's anticipated that the NS + BSSGP code is undergoing quite
some changes in the coming months anyway, so leave it for then.

Change-Id: I0b46035b40709c38bb9ab9493c11031a577e3ee0
Closes: OS#4629
Depends: libosmocore.git I353adc1aa72377f7d4b3336d2ff47791fb73d62c
2020-07-27 14:43:36 +00:00
Alexander Couzens
dd930a25ad gtphub: rename sgsn's oww osmo_sockaddr into sgsn_sockaddr
The osmo_ prefix should be only used for official struct/apis of libosmocore.
This commit was done via `sed -i 's/osmo_sockaddr/sgsn_sockaddr/g'`.

In prepartion of introducing a different api of osmo_sockaddr to
libosmocore.

Change-Id: Ibb1ddce9ff1ffe7494de5cdb8ea1843c45fe4566
2020-07-18 21:43:49 +00:00
Pau Espin Pedrol
b3e10aa8eb sgsn_libgtp: Avoid ps-paging MS on GMM Suspended state
The MS notifies movement to GMM SUSPEND state because it is for instance
handling a call and cannot use PDCH anymore. Once it releases the TCH it
will ASAP move to either dedicated mode or trigger RAU, which means it
will get out of SUSPEND state. So it doesn't make sense to try paging
the MS when in that state.

This change makes test TC_suspend_nopaging pass.

Related: OS#4616
Change-Id: Ia245899eb9f16c7f839785def4ceb721a1c3a11b
2020-06-26 12:20:57 +02:00
Pau Espin Pedrol
36ecddb705 gprs_gmm_fsm.c: Add missing license header
The file was created by myself on September 2019,
31c4657c97.

Change-Id: I94299b9ccf760ad13429e149067f06ed60d37de3
2020-06-26 12:07:12 +02:00
Harald Welte
90dedcb2e7 *.spec.in: Use %config(noreplace) to retain current config file
Change-Id: I4e7f0a44d5e2d132b24ca0f38dc6f520b59112da
2020-06-22 15:20:33 +02:00
Pau Espin Pedrol
cfd307b4e8 sgsn_libgtp: Improve ps-paging logging
Change-Id: I0c3d48d54295824c3ba5b0fa9e3c035983556326
2020-06-18 11:39:13 +00:00
Neels Hofmeyr
b26a5a82db use new osmo_mobile_identity API everywhere
Depends: If4f7be606e54cfa1c59084cf169785b1cbda5cf5 (libosmocore)
Change-Id: I4cacb10bac419633ca0c14f244f9903f7f517b49
2020-06-18 11:23:35 +00:00
Neels Hofmeyr
7369d449f1 gbproxy_test.c: fix mobile identity test data
Fix the final nibble of all IMSI BCD digits to 0xf, since it is a filler digit.

The encoded IMSI has an even amount of digits (14) and must contain a 0xf
filler nibble at the end. The test data looked correct due to repeated '1'
digits.

wrong hex: 11 12 13 14 15 16 17 18
correct:   11 12 13 14 15 16 17 f8
order:     1T 32 54 76 98 ba dc Xe  T = type, X = filler, 1..e = 14 digits

This error was found when applying the new osmo_mobile_identity API.

Change-Id: Ia006a3da6779ad1984f642e8ea29790a4daeb8b9
2020-06-18 11:23:35 +00:00
Harald Welte
5e1a486a72 Treat RAU as implicit RESUME if GMM is suspended
We so far only resumed from suspend upon receiving an explicit BSSGP
RESUME message from the BSS.  The latter is only possible in
BSC-colocated PCU, where the BSC can trigger the message when releasing
the dedicated channel.  In BTS-colocated PCUs, this is not possible,
and we have to rely on the MS resuming by RAU.

See 3GPP TS 23.060 section 16.2.1.1.1 clause 6:

The MS shall resume GPRS services by sending a Routeing Area Update Request message to the SGSN:
* if the BSS did not successfully request the SGSN to resume GPRS services,
* if the RR Channel Release message was not received before the MS left dedicated mode,
* if the MS locally determines that the conditions for the GPRS suspension have disappeared

Without this patch, the GMM state would forever be stuck in SUSPEND,
which in turn causes the SGSN to page the MS all the time.

Change-Id: I3c09187a27483d95fa0070bbb467f94a2ea3978f
Related: OS4616
2020-06-17 21:09:03 +00:00
Harald Welte
627e285fd0 Fix memory leak when SNDCP de-fragmentation is used
As msgb ownership is not passed along, we need to free the message
buffer memory we allocate in defrag_segments() after calling
sgsn_rx_sndcp_ud_ind().

Change-Id: I1185b1aa99bb167d616eb469e5445e4ed5ad949d
Closes: OS#4603
2020-06-08 20:46:53 +02:00
Oliver Smith
5e0b829884 Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
Change-Id: I15d4c9ca2c7ed0467b44f57bbaa1a2177feff154
2020-05-22 13:45:48 +02:00
Oliver Smith
bd6d677179 contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to @VERSION@, make it build
with CentOS 8 etc.

Related: OS#4550
Change-Id: I824b67f2d590ac2aa9f2e4fa4387a5283cf22521
2020-05-19 16:49:33 +02:00
Oliver Smith
482bb07301 contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: Ia18f44f1b6dc259c3d0474b88b33f4657d96fd7a
2020-05-14 11:52:28 +02:00
Neels Hofmeyr
b63e19d7d2 gsup: send RAT type on LU
At 36c3, osmo-hlr was run with a patch that records the RAN type of attached
subscribers. Even though this is not in osmo-hlr master, it is nice information
to send along.

Change-Id: I5dbe610738aed7ea1edf6b33543b1c03818cc274
2020-05-12 13:52:24 +02:00
Neels Hofmeyr
c6548bbaab fix nullpointer: in gsm48_rx_gmm_ra_upd_req()
This caused frequent crashes at 36c3. The "proper" fix is probably elsewhere
(lynxis mentions an unfinished patch), but at least this prevented some crashes
during active operation.

Once this is merged, we can (re)enable SGSN_Tests_Iu.TC_geran_attach_iu_rau,
which tests exactly for this scenario:  A Subscriber / MM context that is so
far attached via GERAN, but now receives a RAU via UTRAN/Iu.

Closes: OS#4339
Change-Id: Ifde15dc4151d84748f0e67b32c9c260cb2d9d8fc
2020-05-10 22:33:27 +00:00
Pau Espin Pedrol
b2ebc59f30 Use OSMO_FD_* instead of deprecated BSC_FD_*
New define is available since libosmocore 1.1.0, and we already require
1.2.0, so no need to update dependenices.
Let's change it to avoid people re-using old BSC_FD_* symbols when
copy-pasting somewhere else.

Change-Id: Iaebd049e383b02204a12f39cc6c932a53d25fd72
2020-05-09 19:21:15 +02:00
Harald Welte
9d550cb369 gtphub_test: Fix compilation with gcc-10
/usr/bin/ld: ../../src/gtphub/gtphub.o:/home/laforge/projects/git/osmo-sgsn/src/gtphub/gtphub.c:50: multiple definition of `osmo_gtphub_ctx'; gtphub_test.o:/home/laforge/projects/git/osmo-sgsn/tests/gtphub/gtphub_test.c:57: first defined here
collect2: error: ld returned 1 exit status

See also https://alioth-lists.debian.net/pipermail/debian-mobcom-maintainers/Week-of-Mon-20200413/000653.html

Change-Id: I19c1eef6649d2747f0b624f5292d7ae47c4ca839
2020-04-20 19:47:19 +02:00
Eric
e6b2883f10 configure.ac: fix libtool issue with clang and sanitizer
As pointed out at https://github.com/libexpat/libexpat/issues/312
libtool does not play nice with clang sanitizer builds at all.
For those builds LD shoud be set to clang too (and LDFLAGS needs the
sanitizer flags as well), because the clang compiler driver knows how
linking to the sanitizer libs works, but then at a later stage libtool
fails to actually produce the shared libraries and the build fails. This
is fixed by this patch.

Addtionally LD_LIBRARY_PATH has no effect on conftest runs during
configure time, so the rpath needs to be set to the asan library path to
ensure the configure run does not fail due to a missing asan library,
i.e.:

SANS='-fsanitize=memory -fsanitize-recover=all -shared-libsan'
export CC=clang-10
ASANPATH=$(dirname `$CC -print-file-name=libclang_rt.asan-x86_64.so`)
export LDFLAGS="-Wl,-rpath,$ASANPATH $SANS $LDFLAGS"

Change-Id: I7402b019c191304f639806a3c29e6bb698b398ed
2020-04-11 01:04:28 +02:00
Eric
6528e8c1cb tests: dlopen does not imply availability of dlsym..
Check for both.

Change-Id: If41a20bf499f791432f5f207e40688e97fb6e9f7
2020-04-11 01:04:08 +02:00
Neels Hofmeyr
6e4cd085b5 manual: explain IuPS, add SCCP/M3UA section from common chapters
Add 'cs7' default configuration, link to the
osmo-gsm-manuals/common/cs7-config.adoc chapter to fully explain the 'cs7'
client configuration.

Related: OS#2767
Depends: Ia2508d4c7b0fef9cdc57e7e122799a480e340bf7 (osmo-gsm-manuals)
Change-Id: If0f7c8fc4b94eb40b62570cf90999d5074dc00ee
2020-03-23 20:06:12 +01:00
Alexander Couzens
91a8bbd5db gprs_gmm_fsm.c: Implement RAT change between 2g and 3g
Related: OS#2737
Change-Id: I3fc614da6ba137e871ee0fe86ca22b6a4a354dd2
2020-02-04 10:21:12 +01:00
Daniel Willmann
d999e54aa2 gprs_gmm: Check for RAT change and ensure this only happens for RAU/ATT
Change-Id: I38cb31907eddeade5350cdb648df179408d908d2
Related: OS#3727
2020-02-04 09:27:20 +01:00
Pau Espin Pedrol
394aa533e9 Bump version: 1.5.0.91-5997-dirty → 1.6.0
Change-Id: I99e6950db3f54c6291dd259bed9b5c46cc26c465
2020-01-03 19:17:56 +01:00
84 changed files with 1315 additions and 22702 deletions

4
.gitignore vendored
View File

@@ -14,6 +14,7 @@ bscconfig.h.in
*.pyc
*.gcda
*.gcno
*~
#configure
aclocal.m4
@@ -40,7 +41,6 @@ ltmain.sh
# apps and app data
src/sgsn/osmo-sgsn
src/gbproxy/osmo-gbproxy
src/gtphub/osmo-gtphub
src/libcommon/gsup_test_client
@@ -69,3 +69,5 @@ doc/manuals/generated/
doc/manuals/osmomsc-usermanual.xml
doc/manuals/common
doc/manuals/build
contrib/osmo-sgsn.spec

View File

@@ -9,15 +9,21 @@ AM_CPPFLAGS = \
$(NULL)
SUBDIRS = \
doc \
include \
src \
contrib \
tests \
doc \
$(NULL)
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = git-version-gen osmoappdesc.py .version
EXTRA_DIST = \
.version \
contrib/osmo-sgsn.spec.in \
debian \
git-version-gen \
osmoappdesc.py \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)

View File

@@ -1,4 +1 @@
#component what description / commit summary line
osmo-sgsn libgtp We dropped libgtp gtp_retranstimeout timer code which became a
no-op in osmo-ggsn.git c94837c6a401bf0f80791b619a9b4cfbe9160afd,
which means next osmo-sgsn release will require libgtp > 1.4.0.

View File

@@ -22,6 +22,11 @@ AC_PROG_CC
AC_PROG_INSTALL
LT_INIT
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
AS_CASE(["$LD"],[*clang*],
[AS_CASE(["${host_os}"],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
@@ -34,34 +39,40 @@ m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
])
dnl use a defined standard across all builds and don't depend on compiler default
CFLAGS="$CFLAGS -std=gnu11"
dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.4.0)
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.3.0)
# Enable/disable 3G aka IuPS + IuCS support?
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
if test "x$osmo_ac_iu" = "xyes" ; then
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.4.0)
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.4.0)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.7.0)
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
fi
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
AC_SUBST(osmo_ac_iu)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.4.0)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.7.0)
PKG_CHECK_MODULES(LIBCARES, libcares)
dnl checks for header files
@@ -110,8 +121,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
CFLAGS="$saved_CFLAGS"
AC_SUBST(SYMBOL_VISIBILITY)
CPPFLAGS="$CPPFLAGS -Wall"
CFLAGS="$CFLAGS -Wall"
CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs"
CFLAGS="$CFLAGS -Wall -Wno-trigraphs"
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
@@ -164,9 +175,9 @@ AC_ARG_ENABLE([external_tests],
[Include the VTY/CTRL tests in make check [default=no]]),
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
if test "x$enable_ext_tests" = "xyes" ; then
AC_CHECK_PROG(PYTHON2_AVAIL,python2,yes)
if test "x$PYTHON2_AVAIL" != "xyes" ; then
AC_MSG_ERROR([Please install python2 to run the VTY/CTRL tests.])
AC_CHECK_PROG(PYTHON3_AVAIL,python3,yes)
if test "x$PYTHON3_AVAIL" != "xyes" ; then
AC_MSG_ERROR([Please install python3 to run the VTY/CTRL tests.])
fi
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
@@ -248,12 +259,10 @@ AC_OUTPUT(
src/Makefile
src/gprs/Makefile
src/sgsn/Makefile
src/gbproxy/Makefile
src/gtphub/Makefile
tests/Makefile
tests/atlocal
tests/gprs/Makefile
tests/gbproxy/Makefile
tests/sgsn/Makefile
tests/gtphub/Makefile
tests/xid/Makefile
@@ -265,4 +274,5 @@ AC_OUTPUT(
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-sgsn.spec
Makefile)

View File

@@ -1,58 +0,0 @@
#!/usr/bin/env python
"""
demonstrate a unblock bug on the GB Proxy..
"""
bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
bts_ns_unblock = "\x06"
ns_unblock_ack = "\x07"
bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
import socket
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socket.bind(("0.0.0.0", 0))
socket.setblocking(1)
import sys
port = int(sys.argv[1])
print "Sending data to port: %d" % port
def send_and_receive(packet):
socket.sendto(packet, ("127.0.0.1", port))
try:
data, addr = socket.recvfrom(4096)
except socket.error, e:
print "ERROR", e
import sys
sys.exit(0)
return data
#send stuff once
to_send = [
(bts_ns_reset, ns_reset_ack, "reset ack"),
(bts_ns_unblock, ns_unblock_ack, "unblock ack"),
(bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
]
for (out, inp, type) in to_send:
res = send_and_receive(out)
if res != inp:
print "Failed to get the %s" % type
sys.exit(-1)
import time
time.sleep(3)
res = send_and_receive(bts_bvc_reset_8167)
print "Sent all messages... check wireshark for the last response"

View File

@@ -50,7 +50,6 @@ fi
# Additional configure options and depends
CONFIG=""
if [ "$WITH_MANUALS" = "1" ]; then
osmo-build-dep.sh osmo-gsm-manuals
CONFIG="--enable-manuals"
fi
@@ -70,12 +69,12 @@ LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
LD_LIBRARY_PATH="$inst/lib" \
DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \
$MAKE distcheck \
$MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE maintainer-clean
$MAKE $PARALLEL_MAKE maintainer-clean
osmo-clean-workspace.sh

118
contrib/osmo-sgsn.spec.in Normal file
View File

@@ -0,0 +1,118 @@
#
# spec file for package osmo-sgsn
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
## Disable LTO for now since it breaks compilation of the tests
## https://osmocom.org/issues/4116
%define _lto_cflags %{nil}
%define with_iu 1
Name: osmo-sgsn
Version: @VERSION@
Release: 0
Summary: Osmocom's SGSN for 2G and 3G packet-switched mobile networks
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Productivity/Telephony/Servers
URL: https://osmocom.org/projects/osmosgsn
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: pkgconfig
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcares)
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
BuildRequires: pkgconfig(libgtp) >= 1.7.0
BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.3.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
BuildRequires: pkgconfig(libosmogb) >= 1.5.0
BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
%{?systemd_requires}
%if %{with_iu}
BuildRequires: pkgconfig(libasn1c)
BuildRequires: pkgconfig(libosmo-ranap) >= 0.7.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0
%endif
%description
OsmoSGSN is Osmocom's Serving GPRS Support Node for 2G and 3G
packet-switched mobile networks.
%package -n osmo-gtphub
Summary: Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs
Group: Productivity/Telephony/Servers
%description -n osmo-gtphub
Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
%if %{with_iu}
--enable-iu \
%endif
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
%if 0%{?suse_version}
%preun %service_del_preun %{name}.service
%postun %service_del_postun %{name}.service
%pre %service_add_pre %{name}.service
%post %service_add_post %{name}.service
%preun -n osmo-gtphub %service_del_preun osmo-gtphub.service
%postun -n osmo-gtphub %service_del_postun osmo-gtphub.service
%pre -n osmo-gtphub %service_add_pre osmo-gtphub.service
%post -n osmo-gtphub %service_add_post osmo-gtphub.service
%endif
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
%doc AUTHORS README
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-sgsn
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
%{_bindir}/osmo-sgsn
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-sgsn.cfg
%{_unitdir}/%{name}.service
%files -n osmo-gtphub
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-gtphub
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub.cfg
%{_bindir}/osmo-gtphub
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
%{_unitdir}/osmo-gtphub.service
%changelog

View File

@@ -1,11 +1,9 @@
EXTRA_DIST = \
osmo-gbproxy.service \
osmo-gtphub.service \
osmo-sgsn.service
if HAVE_SYSTEMD
SYSTEMD_SERVICES = \
osmo-gbproxy.service \
osmo-gtphub.service \
osmo-sgsn.service

View File

@@ -1,12 +0,0 @@
[Unit]
Description=Osmocom Gb proxy
[Service]
Type=simple
ExecStart=/usr/bin/osmo-gbproxy -c /etc/osmocom/osmo-gbproxy.cfg
Restart=always
RestartSec=2
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target

295
debian/changelog vendored
View File

@@ -1,3 +1,298 @@
osmo-sgsn (1.7.1) unstable; urgency=medium
* gtphub: remove llist_first, llist_last macros
* debian/control: remove dh-systemd build-depend
-- Oliver Smith <osmith@sysmocom.de> Mon, 06 Sep 2021 17:07:35 +0200
osmo-sgsn (1.7.0) unstable; urgency=medium
[ Daniel Willmann ]
* gprs_gmm: Check for RAT change and ensure this only happens for RAU/ATT
* gbproxy-usermanual: Explain BSSGP/BVC handling
* gbproxy: Whitespace fixes
* gbproxy: Add todo for BVC RESET logic
* gbproxy: Get the peer if paging by BVCI on SIG_BVC
* Let libosmocore handle VTY parent node tracking
* osmo-gbproxy: Free msgb in ns2 prim callback
* configure.ac: Require python3 for ext_tests
* osmo-gbproxy: Implement nsvc-state ctrl command
* gbproxy: Remove test testing NSVCI change
* gbproxy: Add NSE peer that can have multiple gbproxy_peers
* gbproxy: Ensure BVC0 is reset before handling PtP BVCs
* gbproxy: Only send paging to each matching NSE once
* gbproxy: Separate function to move gbproxy_peer to different nse
* gbproxy: Add logging macros for NSE and BVC
* gbproxy: Use LOG macros for NSE/BVC
* gbproxy: Change generic LOG messages so BVCI/NSEI fmt is consistent
* gbproxy: Add todos encountered while going through the code
* gbproxy: Add BVC log filters
* gbproxy: Add newline to log message
* gbproxy: Allow gbproxy_nse_free(NULL)
* gbproxy: Delete gbproxy_nse in delete-gbproxy-peer VTY command
* mm_state_gb_fsm: Handle implicit detach from mm_standby
* gbproxy: Fix bvci check in gbprox_rx_ptp_from_*
* osmo-gbproxy: Initialize all hash_maps
* gbproxy: Fix confusing log message in gbprox_relay2nse
* gbproxy: Add SGSN NRI configuration
* gbproxy: Add SGSN pooling support
* gbproxy: Add comments to sgsn functions
* gbproxy: Add config option to name an SGSN
* gbproxy: Add VTY command to override the node selection function
* Fix gbproxy_sgsn_by_tlli wraparound
* gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME
* gbproxy: Increase TLLI cache timeout to 10s
* gbproxy: Implement IMSI cache
* gbproxy: Use IMSI cache to handle PAGING_PS_REJECT
* gbproxy: Use C-style comments
* gbproxy: Move helper function to a more logical place
* gbproxy: Remove unused variable assignment
* gbproxy: Fix VTY cmd name
* gbproxy: Define and use help string for gbproxy
* gbproxy: Add VTY commands to query the TLLI/IMSI cache
* gbproxy: Use IMSI cache for PTP paging and implement DUMMY_PAGING_PS
* gbproxy: Print the correct message type for dummy paging/paging reject
* gbproxy: Improve log messages in gbproxy_select_sgsn
* gbproxy: Fix radio status routing by TMSI
* manual/gbproxy: Update overview chapter
* Rename OsmoGbPROXY -> *Proxy
* manuals/gbproxy: Update configuration chapter
* manuals/gbproxy: Add osmo-bsc MSC pooling chapter from Neels as a base
* manuals/gbproxy: MSC -> SGSN for pooling chapter
* manuals/gbproxy: Move pooling to separate chapter
[ Alexander Couzens ]
* gprs_gmm_fsm.c: Implement RAT change between 2g and 3g
* gtphub: rename sgsn's oww osmo_sockaddr into sgsn_sockaddr
* gprs_llc: _bssgp_tx_dl_ud: ensure the LLME is valid before using it
* gmm: on invalid RA id reject the MS with an implicit detach
* gtphub_test: fix compilation error on gcc 10.2.0
* gtphub: fix compilation with gcc 10.2.0
* Port gbproxy to NS2
* sgsn: check for NULL of gprs_subscr_get_or_create()
* sgsn: Use the new NS2 api
* gbproxy: use ns2 vty2
* configure.ac: define a c standard instead of using the compilers default
* follow libosmocore/gprs_ns2 API changes of GPRS enums
* gbproxy: follow gprs_ns2 API vty changes
* sgsn: migrate to the new gprs_ns2_vty configuration
* follow libosmocore/gprs_ns2 API changes (gprs_ns2_dynamic_create_nse)
[ Neels Hofmeyr ]
* manual: explain IuPS, add SCCP/M3UA section from common chapters
* fix nullpointer: in gsm48_rx_gmm_ra_upd_req()
* gsup: send RAT type on LU
* gbproxy_test.c: fix mobile identity test data
* use new osmo_mobile_identity API everywhere
[ Eric ]
* tests: dlopen does not imply availability of dlsym..
* configure.ac: fix libtool issue with clang and sanitizer
[ Harald Welte ]
* gtphub_test: Fix compilation with gcc-10
* Fix memory leak when SNDCP de-fragmentation is used
* Treat RAU as implicit RESUME if GMM is suspended
* *.spec.in: Use %config(noreplace) to retain current config file
* Send a BVC-RESET to all persistent Gb interfaces at start-up
* Use osmo_fd_setup() whenever applicable
* Use osmo_fd_*_{disable,enable}
* gbproxy: Properly implement paging to LAC/RAC
* gbproxy: Implement paging to entire BSS area
* gprs_gb_parse: Add function to determine TLLI from encoded BSSGP
* gbproxy: Pass TLLI as LSP towards NS to facilitate load sharing
* gb_proxy_peer: Add some FIXMEs regarding invalid assumptions
* gb_proxy: More precise + readable log messages
* gb_proxy: Broadcast SGSN-INVOKE-TRACE and OVERLOAD
* gbproxy: Move BSS-side BVC-RESET processing to its own function
* gb_proxy: Slightly restructure processing of BSS-originated BVC-RESET
* gbproxy: Cosmetics: use longer lines
* gbproxy: Send BVC-STATUS if BSS sends us BVC-RESET without mandatory IEs
* gb_proxy: Use TLVP_PRES_LEN instead of TLVP_PRESENT
* gb_proxy: Rename gbproxy_peer to gbproxy_bvc
* gbproxy: Rename gbproxy_cfg.nses to gbproxy_cfg.bss_nses
* gbproxy: convert bss_nses from llist_head to hashtable
* gbproxy: convert nse->bvcs from llist_head to hashtable
* gbproxy: Remove patching, TLLI-tracking and SGSN2 support
* gb_proxy: cosmetic: Use function rather than open-coding is_sgsn
* gbproxy: Delete gbproxy_test
* gb_proxy: Introduce more validation / constraint checks
* gbproxy: use gbprox_relay2peer() whenever possible
* gb_proxy: Use osmo_tlv_prot_parse() to validate mandatory IEs
* gbproxy: Log FSM timeouts
* migrate to DLBSSGP as log sub-system for BSSGP
* gbproxy major rewrite for SGSN pool support
* gbproxy: Use "(nsei << 16) | bvci" as rate_ctr_group index
* gbproxy: Introduce new DOBJ log category; log object allocation/release
* gbproxy: Don't create an extra msgb copy for SGSN DL SIG
* gbproxy: Implement handling of BVC Flow Control
* gbproxy: Copy RA-ID from BSS side BVC to CELL and SGSN-side BVC
* gbproxy: (Re)allocate SGSN-side PTP BVC even if CELL already exists
* gbproxy: Fix segfault when receiving PAGING for unknown destination
* gbproxy: Add FSM related VTY commands
* gbproxy: Implement scaling of BVC flow control in SGSN pool
* gbproxy: Improve VTY state introspection
* gbproxy: rename vty command "show gbproxy ..." to "show gbproxy bvc ..."
* gbproxy: Add "show gbproxy cell ..." VTY command
* gbproxy: Fix build on Deiban 8
* gb_proxy: Don't use orphan log subsystem DPCU
* gbproxy: Avoid depending on any of the SGSN code
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
* manuals: generate vty reference xml at build time
[ Pau Espin Pedrol ]
* Use OSMO_FD_* instead of deprecated BSC_FD_*
* sgsn_libgtp: Improve ps-paging logging
* gprs_gmm_fsm.c: Add missing license header
* sgsn_libgtp: Avoid ps-paging MS on GMM Suspended state
* configure.ac: Fix trailing whitespace
* doc: Update VTY reference xml file
* Support setting rt-prio and cpu-affinity mask through VTY
* Change default SCTP conn NULL->127.0.0.1 to localhost->localhost
* contrib/jenkins: Enable parallel make in make distcheck
* Log error if pdp ctx is freed while holding an active timer
* Fix crash rx DeactPdpReq while waiting for DeactPdpAck after gtp side is freed
* sgsn_delete_pdp_ctx: Add documentation and assert assumptions
* process_ms_ctx_status: refactor to avoid code duplication
* process_ms_ctx_status: Fix crash deleting PDP Ctx if GTP side was already released
* gbproxy: generate coredump and exit upon SIGABRT received
* gtphub: generate coredump and exit upon SIGABRT received
* sgsn: generate coredump and exit upon SIGABRT received
* gmm: fix build without define PTMSI_ALLOC
* gmm: Introduce comment to ease addition of Network feature support IE later
* .gitignore: Ignore new autofoo tmp files
* sndcp: Fix struct bit fields on big endian
* Fix nsei+bvci not updated on rx UL SNDCP data
[ Oliver Smith ]
* contrib: import RPM spec
* contrib: integrate RPM spec
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
* contrib/jenkins: don't build osmo-gsm-manuals
* gbproxy: remove (moved to own repository)
[ Vadim Yanitskiy ]
* debian/control: change maintainer to the Osmocom team / mailing list
* gb_proxy_peer: sgsn can never be NULL in gbproxy_sgsn_by_nri()
* gb_proxy_peer: fix NULL pointer dereference in gbproxy_sgsn_alloc()
[ Keith ]
* Fix Radio Priority in MM Attach and PDP Context Activation
* VTY: Add gtp state-dir command
[ Philipp Maier ]
* gprs_sndcp: fix use after free
* sgsn_rim: Add routing for (GERAN) BSSGP RIM messages
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 20:29:33 +0100
osmo-sgsn (1.6.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* gprs_gmm: Introduce macros to access msgb's associated IU UE ctx
* gprs_llc.h: Improve documentation of some structs
* gprs_gmm.c: Improve doc on nullable parameters
* gprs_gmm.c: Drop unneeded brackets
* Introduce define TLLI_UNASSIGNED
* gprs_sgsn.c: Warn upon llme free unexpected scenarios
* gprs_gmm: Clarify comment during TLLI assignment
* gprs_sgsn.c: Remove recently introduced assert
* gprs_gmm: Introduce assert to guard against unexpected condition
* gprs_gmm.c: Use correct function to set MM_IDLE state during cleanup
* gprs_sgsn.h: Flag MM_CTX_T_GERAN_Iu as not supported
* gprs_gmm.c: Flag mmctx_set_(p)mm_state() functions static
* sgsn: use sccp_simple_client API to setup ss7 id 0 instead of 1
* gprs_gmm.c: Fix typo in log message
* gprs_gmm.c: Call mmctx_set_(p)mm_state only on related ran_type
* Introduce and use log macros when no mm ctx available
* gprs_gmm: Avoid spaces in fsm events and enum strings
* tests: Verify that timers can be set over VTY
* Replace own timer infra with libosmocore osmo_tdef
* tests: Introduce vty-transcript-test tests
* gprs_gmm.c: Use osmo_rai_name() in log line
* examples: Add osmo-sgsn_custom-sccp.cfg
* vty: Introduce cs7-instance-iu
* gprs_gmm.c: Print value_string of reject cause
* gprs_gmm.c: Add spec document to function documentation
* gtp: make echo_interval unsigned
* gtp: cb_delete_context(): Clarify why pdp->lib is set to NULL
* Introduce log helper LOGGGSN and log category DGTP
* sgsn: gtp: Drop related pdp contexts on echo timeout against GGSN
* Move lots of Iu/ranap specific code into its own file
* Move llc->MM/SM Gb specific glue code to its own file
* Split enum gprs_pmm_state into Iu and Gb counterparts
* Merge common allocation steps for Gb and Iu ctx
* gprs_gmm.c: Replace inet_ntoa with inet_ntop
* sgsn_cdr.c: Fix ip addr string buffer size
* sgsn_vty: Fix mmctx rate_ctr output indentation
* sgsn_vty: Print correct Iu mmctx id in 'show mm-context'
* Introduce FSM mm_state_gb_fsm
* Introduce FSM mm_state_iu_fsm
* vty: Print MM state and RAN type in show mm-context
* src/gprs/Makefile.am: Move build of shared .c files to an internal lib
* Move out gbproxy to its own subdir
* Move out gtphub to its own subdir
* Move out sgsn to its own subdir
* gmm: Move code handling GMM Attach Complete to its own function
* gmm: Move code handling GMM Routing Area Update Complete to its own function
* gmm: Move code handling GMM PTMSI Realloc Complete to its own function
* enum gprs_gmm_state: Fix spec reference
* Implement GMM State using osmocom FSM
* Split out GPRS SM layer into its own file
* sgsn: Reject PdpActReq if no GTP pdp ctx exists
* Introduce TODO-RELEASE file
* sgsn_libgtp.c: Drop use of deprecated libgtp APIs gtp_retrans*()
* gmm: Fix assertion hit during RA UPD REQ before completting gmm attach
* Improve logging in gprs_llc.c code
* gprs_llc.c: Use enum instead of hardcoded value
* gprs_gmm.c: Send XID reset with received TLLI
[ Alexander Couzens ]
* gprs/gprs_gmm: implement T3314. Timeout to reset MM state READY->STANDBY
* gprs_gmm: only update gb/iu cell information when Iu/Gb present
* gprs_gmm: clarify comment of Iu follow-on request
* gprs_gmm: gsm48_rx_gmm_att_req(): refactor duplicated code
* sgsn_pdp_ctx_terminate: check llme before accessing
* gprs_ranap: send CommonId after receiving Security Mode Complete
* mm_gb_fsm: unassign the llme when entering MM_IDLE
* gprs_ranap: refactor REQUIRE_MM define
* sgsn: when receiving data PDU notify the Gb GMM fsm
* Avoid compiling unneeded files when building without Iu
* gprs_ranap: release Iu UE Context when exiting PMM Connected
* Iu: implement a user inactivity timer
* gprs_ranap: on Iu release, stop the attach fsm if running
* gprs_mm_state_gb_fsm: ensure T3350 is not running when entering IDLE
* gprs_ranap: add missing rc = 0
* gprs_sgsn: always allocate Gb/Iu mm fsm
* sgsn: MM Gb Fsm: fix event handling for implicit detach
* ranap: add non-spec X1001
* gprs_gmm: release Iu connection on RAU failures
* sgsn_mm_ctx_alloc(): check for unallocated fsms
* sgsn_libgtp: refactor ps paging into gprs_gb
* sgsn: Gb: implementing PS Paging when MS is MM_STANDBY
[ Vadim Yanitskiy ]
* gprs_mm_state_iu_fsm.c: fix: assign timer_cb to mm_state_iu_fsm
[ Max ]
* Use libosmocore constant for IMSI length in ACL entry
[ Harald Welte ]
* LLC: Don't use hard-coded N201-U / N201-I values in XID
* Initial OsmoGbPROXY user manual
* check for osmo_fsm_register() error return values
* check for osmo_ss7_init() error return value
* manual: Fix copy+paste error
* exit(2) on unsupported positional arguments on command line
[ Oliver Smith ]
* gitignore: fix paths to binaries
* doc: add OsmoGbProxy VTY reference
* regen_doc.sh: support gbproxy, run without docker
* osmoappdesc.py, tests: switch to python 3
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 19:17:56 +0100
osmo-sgsn (1.5.0) unstable; urgency=medium
[ Max ]

37
debian/control vendored
View File

@@ -1,10 +1,9 @@
Source: osmo-sgsn
Section: net
Priority: extra
Maintainer: Alexander Couzens <lynxis@fe80.eu>
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>=9),
dh-autoreconf,
dh-systemd (>= 1.5),
autotools-dev,
autoconf,
automake,
@@ -12,16 +11,16 @@ Build-Depends: debhelper (>=9),
pkg-config,
libtalloc-dev,
libc-ares-dev,
libgtp-dev (>= 1.4.0),
libosmocore-dev (>= 1.2.0),
libosmo-abis-dev (>= 0.6.0),
libosmo-netif-dev (>= 0.4.0),
libosmo-gsup-client-dev (>= 1.0.0),
libgtp-dev (>= 1.7.0),
libosmocore-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.1.0),
libosmo-netif-dev (>= 1.1.0),
libosmo-gsup-client-dev (>= 1.3.0),
libasn1c-dev (>= 0.9.30),
libosmo-ranap-dev (>= 0.4.0),
libosmo-sigtran-dev (>= 1.0.0),
libosmo-sccp-dev (>= 1.0.0),
osmo-gsm-manuals-dev
libosmo-ranap-dev (>= 0.7.0),
libosmo-sigtran-dev (>= 1.4.0),
libosmo-sccp-dev (>= 1.4.0),
osmo-gsm-manuals-dev (>= 1.1.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
@@ -53,22 +52,6 @@ Priority: extra
Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for Osmocom GTP Hub
Package: osmo-gbproxy
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends}
Recommends: osmo-sgsn
Description: Osmocom GPRS Gb Interface Proxy
The purpose of the Gb proxy is to aggregate the Gb links of multiple
BSS's and present them in one Gb link to the SGSN.
Package: osmo-gbproxy-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmo-gbproxy (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for Osmocom GPRS Gb Interface Proxy
Package: osmo-sgsn-doc
Architecture: all
Section: doc

12
debian/copyright vendored
View File

@@ -19,13 +19,10 @@ Files: .gitignore
contrib/ipa.py
contrib/jenkins.sh
contrib/soap.py
contrib/systemd/osmo-gbproxy.service
contrib/systemd/osmo-sgsn.service
contrib/twisted_ipa.py
doc/Makefile.am
doc/examples/Makefile.am
doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg
doc/examples/osmo-gbproxy/osmo-gbproxy.cfg
doc/examples/osmo-gtphub/gtphub-example.txt
doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
doc/examples/osmo-gtphub/osmo-gtphub.cfg
@@ -51,8 +48,6 @@ Files: .gitignore
src/gprs/osmo_sgsn.cfg
tests/Makefile.am
tests/atlocal.in
tests/gbproxy/Makefile.am
tests/gbproxy/gbproxy_test.ok
tests/gprs/Makefile.am
tests/gprs/gprs_test.c
tests/gprs/gprs_test.ok
@@ -86,12 +81,6 @@ Files: include/osmocom/sgsn/a_reset.h
src/gprs/gprs_gb_parse.c
src/gprs/gprs_utils.c
src/gprs/sgsn_ares.c
src/gbproxy/gb_proxy.c
src/gbproxy/gb_proxy_main.c
src/gbproxy/gb_proxy_patch.c
src/gbproxy/gb_proxy_peer.c
src/gbproxy/gb_proxy_tlli.c
src/gbproxy/gb_proxy_vty.c
src/gtphub/gtphub.c
src/gtphub/gtphub_main.c
src/gtphub/gtphub_vty.c
@@ -142,7 +131,6 @@ License: AGPL-3.0+
Files: src/gtphub/gtphub_ares.c
src/gtphub/gtphub_sock.c
tests/gbproxy/gbproxy_test.c
Copyright: 2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
2013 sysmocom s.f.m.c. GmbH
2014 Holger Hans Peter Freyther

View File

@@ -1,151 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: osmo-gbproxy
# Required-Start: $network $local_fs
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Osmocom GBproxy
# Description: A tool to proxy the GPRS Gb interface.
### END INIT INFO
# Author: Harald Welte <laforge@gnumonks.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
NAME=osmo-gbproxy # Introduce the short server's name here
DESC="Osmocom GBProxy" # Introduce a short description here
DAEMON=/usr/bin/osmo-gbproxy # Introduce the server's location here
SCRIPTNAME=/etc/init.d/osmocom-gbproxy
CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
# Exit if the package is not installed
[ -x $DAEMON ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
DAEMON_ARGS="-D -c $CONFIG_FILE"
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

View File

@@ -1,5 +0,0 @@
etc/osmocom/osmo-gbproxy.cfg
lib/systemd/system/osmo-gbproxy.service
usr/bin/osmo-gbproxy
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg usr/share/doc/osmo-gbproxy/examples
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy.cfg usr/share/doc/osmo-gbproxy/examples

1
debian/rules vendored
View File

@@ -58,7 +58,6 @@ override_dh_auto_configure:
override_dh_strip:
dh_strip -posmo-sgsn --dbg-package=osmo-sgsn-dbg
dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
dh_strip -posmo-gbproxy --dbg-package=osmo-gbproxy-dbg
# Print test results in case of a failure
override_dh_auto_test:

View File

@@ -1,7 +1,7 @@
OSMOCONF_FILES = \
osmo-gtphub/osmo-gtphub.cfg \
osmo-sgsn/osmo-sgsn.cfg \
osmo-gbproxy/osmo-gbproxy.cfg
$(NULL)
osmoconfdir = $(sysconfdir)/osmocom
osmoconf_DATA = $(OSMOCONF_FILES)

View File

@@ -1,44 +0,0 @@
!
! OsmoGbProxy (UNKNOWN) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
ns
nse 666 nsvci 666
nse 666 remote-role sgsn
! nse 666 encapsulation framerelay-gre
! nse 666 remote-ip 172.16.1.70
! nse 666 fr-dlci 666
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-port 23000
! encapsulation framerelay-gre enabled 1
gbproxy
sgsn nsei 666
core-mobile-country-code 666
core-mobile-network-code 6
core-access-point-name none match-imsi ^666066|^66607
tlli-list max-length 200

View File

@@ -1,26 +0,0 @@
!
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
!!
!
line vty
no login
!
gbproxy
sgsn nsei 101
ns
nse 101 nsvci 101
nse 101 remote-role sgsn
nse 101 encapsulation udp
nse 101 remote-ip 192.168.100.239
nse 101 remote-port 7777
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation framerelay-gre enabled 0
encapsulation framerelay-gre local-ip 0.0.0.0
encapsulation udp local-ip 127.0.0.100
encapsulation udp local-port 23000

View File

@@ -21,9 +21,9 @@ ns
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 127.0.0.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
bind udp local
listen 127.0.0.1 23000
accept-ipaccess
!
bssgp
!

View File

@@ -23,9 +23,9 @@ ns
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 127.0.0.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
bind udp local
listen 127.0.0.1 23000
accept-ipaccess
!
bssgp
!

View File

@@ -31,9 +31,9 @@ ns
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 127.0.0.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
bind udp local
listen 127.0.0.1 23000
accept-ipaccess
!
bssgp
!

View File

@@ -1,21 +1,23 @@
EXTRA_DIST = osmosgsn-usermanual.adoc \
osmosgsn-usermanual-docinfo.xml \
osmosgsn-vty-reference.xml \
osmogbproxy-usermanual.adoc \
osmogbproxy-usermanual-docinfo.xml \
regen_doc.sh \
chapters \
vty \
osmogbproxy-vty-reference.xml \
vty-osmogbproxy \
$(NULL)
if BUILD_MANUALS
ASCIIDOC = osmosgsn-usermanual.adoc osmogbproxy-usermanual.adoc
ASCIIDOC = osmosgsn-usermanual.adoc
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
VTY_REFERENCE = osmosgsn-vty-reference.xml osmogbproxy-vty-reference.xml
VTY_REFERENCE = osmosgsn-vty-reference.xml
BUILT_REFERENCE_XML = $(builddir)/vty/sgsn_vty_reference.xml
$(builddir)/vty/sgsn_vty_reference.xml: $(top_builddir)/src/sgsn/osmo-sgsn
mkdir -p $(builddir)/vty
$(top_builddir)/src/sgsn/osmo-sgsn --vty-ref-xml > $@
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-sgsn

View File

@@ -356,3 +356,23 @@ sgsn
sgsn
encryption GEA0
----
=== Configure SCCP/M3UA to accept _IuPS_ links
OsmoSGSN acts as client to contact an STP instance and establish an SCCP/M3UA
link.
An example configuration of OsmoSGSN's SCCP link:
----
cs7 instance 0
point-code 0.23.4
asp asp-clnt-OsmoSGSN 2905 0 m3ua
remote-ip 127.0.0.1
sctp-role client
as as-clnt-OsmoSGSN m3ua
asp asp-clnt-OsmoSGSN
routing-key 0 0.23.4
----
This configuration is explained in detail in <<cs7_config>>.

View File

@@ -1,6 +0,0 @@
== Configuring OsmoGbPROXY
TBD. Unfortunately this chapter of the manual still needs to be written.
Osmocom has very limited funding and support resources; Feel free to help
us completing this documentation by contributing with code, documentation
or by supporting the developers financially.

View File

@@ -1,29 +0,0 @@
[[control]]
== Control interface
The actual protocol is described in <<common-control-if>>, the variables
common to all programs using it are described in <<ctrl_common_vars>>. Here we
describe variables specific to OsmoGbPROXY.
.Variables available over control interface
[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
|===
|Name|Access|Trap|Value|Comment
|nsvc-state|RO|No|"<nsei>,<nsvci>,<local-alive>,<local-blocked>,<remote-role>,<remote-alive>,<remote-blocked>"|See <<nsvc_state>> for details.
|gbproxy-state|RO|No|"<nsei>,<bvci>,<mcc>,<mnc>,<lac>,<rac>,<blocked>"|See <<gbproxy_state>> for details.
|number-of-peers|RO|No|"<num-of-bss>"|Count of concurrent BSS(BTS) peers.
|===
[[nsvc_state]]
=== nsvc-state
Return the list of active NS-VCs (NS Virtual Circuits), including information
on the key parameters, such as NSEI, NSVCI and the local + remote ALIVE
and BLOCKED state.
[[gbproxy_state]]
=== gbproxy-state
Return the list of active Peers, including information on the key
parameters, such as NSEI, BVCI, and the MCC-MNC-LAC-RAC of the attached
BSS, as well as the overall state (BLOCKED or UNBLOCKED).

View File

@@ -1,127 +0,0 @@
[[chapter_overview]]
== Overview
=== About OsmoGbPROXY
OsmoGbPROXY is the Osmocom proxy for the 3GPP Gb interface. The Gb
interface is defined by 3GPP as the protocol between the BSS and the
SGSN inside the 2G/2.5G/2.75G packet switched network domain.
As Osmocom implements a BTS-colocated PCU, there are potentially many
Gb interface connections between all those many PCUs in the network
and the SGSN. This can be cumbersome to configure/maintain at the
SGSN sine.
OsmoGbPROXY aggregates many PCU-facing Gb connections into one Gb
connection to the SGSN. This is achieved by
* maintaining sepaate NS-VCs on the PCU side and on the SGSN side
* more or less transparently routing BSSGP peer-to-peer Virtual Circuits
(BVCs) through the proxy
* having some special handling for the signaling BVC (BVCI=0) which is
shared among all the PCUs connected to the proxy
=== Data Model
==== gbproxy_config
This contains the parsed configuration of the OsmoGbPROXY.
==== gproxy_peer
A "peer" is any remote NS-entity that the proxy interacts with. A peer
includes information about:
* the [unique] NSEI of the peer
* the [unique] BVCI of the peer
* the Routeing Area (RA) of the peer
==== gbproxy_tlli_state
One of the (unique) TLLI of any of the subscribers/UEs attached to any of
the BTSs/PCUs served by the proxy.
==== gbproxy_link_info
One of the [unique] subscribers/connections that are served through this
proxy. The information includes
* the TLLI on BSS side
* the TLLI on SGSN side (may be different due to P-TMSI rewriting)
* the NSEI of the SGSN for this link
* a timestamp when we last conversed with this subscriber
* state related to IMSI acquisition
** a temporary queue of stored messages (until IMSI acquisition succeeds)
** N(U) rewriting state (inserting IDENTTIY REQ changes LLC sequence numbers)
==== gbproxy_match
A single matching rule against which IMSIs are matched. The matching rule
is expressed as regular expression. There can be one such matching rule for
each
* routing between two different SGSNs, see below
* patching of messages (e.g. APN, PLMN)
=== Advanced Features
==== PLMN patching
This feature permits to modify the PLMN inside any BSSGP messages
containing the Routing Area ID (RAID).
The configured core-mcc and core-mnc will be used towards the SGSN,
irrespective of which MCC/MNC the PCU is using/reporting on Gb.
==== APN patching
This will transparently re-write the APN name inside SM ACTIVATE PDP
REQUEST messages on the way from the MS to the SGSN. The patching is
performed based on matching on the IMSI of the subscriber.
The configured core-apn will be used towards the SGSN, irrespective
of which APN the MS is requesting in its Layer3 signaling.
APN patching can only be performed if no GPRS encryption is enabled in
the network!
APN patching is useful in case a valid APN cannot reliably be
provisioned via other means, such as via the SIM Card, OTA-DM or via
CAMEL rewriting in the SGSN.
==== P-TMSI patching
This feature transparently rewrite the P-TMSI between MS and SGSN. This
is required when using the Secondary SGSN support, as both SGSNs could
allocate overlapping TMSIs and we must make sure they're unique across
both SGSNs.
P-TMSI patching is required by (and hence automatically enablede if
secondary SGSN support is enabled.
P-TMSI patching can only be performed if no GPRS encryption is enabled in
the network!
==== IMSI Acquisition
This is a special feature where the proxy will by itself inject GMM IDENTITY
REQUEST messages for the IMSI into the downlink BSSGP traffic in order
to establish the IMSI of subscribers for which it is not otherwise known
IMSI acquisition is automatically enabled if secondary SGSN support is
enabled.
==== Secondary SGSN Support
This allows the proxy to connect not only to one SGSN, but to two
different SGSNs. IMSI matching rules are applied to determine which of
the SGSNs is to be used for traffic of this subscriber.
One possible use case of this feature is to have a "local break-out" for
subscribers who are native to this network (and hence save
latencies/overhead of back-hauling all related traffic via the
SGSN+GGSN) while at the same time maintaining the classic behavior for
inbound roaming subscribers, where the roaming agreements mandate that
data traffic is brought back to the GGSN in the HPLMN via the SGSN of
the VPLMN.

View File

@@ -1,39 +0,0 @@
== Running OsmoGbPROXY
The OsmoGbPROXY executable (`osmo-gbproxy`) offers the following command-line
options:
=== SYNOPSIS
*osmo-gbproxy* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-e 'LOGLEVEL'] [-T]
=== OPTIONS
*-h, --help*::
Print a short help message about the supported options
*-V, --version*::
Print the compile-time version number of the program
*-d, --debug 'DBGMASK','DBGLEVELS'*::
Set the log subsystems and levels for logging to stderr. This
has mostly been superseded by VTY-based logging configuration,
see <<logging>> for further information.
*-D, --daemonize*::
Fork the process as a daemon into background.
*-c, --config-file 'CONFIGFILE'*::
Specify the file and path name of the configuration file to be
used. If none is specified, use `osmo_sgsn.cfg` in the current
working directory.
*-s, --disable-color*::
Disable colors for logging to stderr. This has mostly been
deprecated by VTY based logging configuration, see <<logging>>
for more information.
*-e, --log-level 'LOGLEVEL'*::
Set the global log level for logging to stderr. This has mostly
been deprecated by VTY based logging configuration, see
<<logging>> for more information.
*-T, --timestamp*::
Enable prefixing each log line on stderr with a timestamp. This
has mostly been deprecated by VTY based logging configuration, see
<<logging>> for more information.

View File

@@ -1,46 +0,0 @@
<revhistory>
<revision>
<revnumber>1</revnumber>
<date>March 21, 2019</date>
<authorinitials>HW</authorinitials>
<revremark>
Initial version.
</revremark>
</revision>
</revhistory>
<authorgroup>
<author>
<firstname>Harald</firstname>
<surname>Welte</surname>
<email>hwelte@sysmocom.de</email>
<authorinitials>HW</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2013-2019</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="https://git.osmocom.org/osmo-sgsn/doc/">
https://git.osmocom.org/osmo-sgsn/doc/
</ulink>
</para>
</legalnotice>

View File

@@ -1,34 +0,0 @@
:gfdl-enabled:
OsmoGbPROXY User Manual
=======================
Harald Welte <hwelte@sysmocom.de>
include::./common/chapters/preface.adoc[]
include::{srcdir}/chapters/gbproxy-overview.adoc[]
include::{srcdir}/chapters/gbproxy-running.adoc[]
include::{srcdir}/chapters/gbproxy-control.adoc[]
include::./common/chapters/vty.adoc[]
include::./common/chapters/logging.adoc[]
include::{srcdir}/chapters/gbproxy-configuration.adoc[]
include::./common/chapters/gb.adoc[]
include::./common/chapters/control_if.adoc[]
//include::{srcdir}/chapters/counters.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
ex:ts=2:sw=42sts=2:et
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
<!ENTITY sections-vty SYSTEM "generated/docbook_osmogbproxy-vty-reference.xml" >
]>
<book>
<info>
<revhistory>
<revision>
<revnumber>v1</revnumber>
<date>2nd December 2019</date>
<authorinitials>hw</authorinitials>
<revremark>Initial</revremark>
</revision>
</revhistory>
<title>OsmoGbProxy VTY Reference</title>
<copyright>
<year>2019</year>
</copyright>
<legalnotice>
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
</para>
</legalnotice>
</info>
<!-- Main chapters-->
&chapter-vty;
</book>

View File

@@ -19,6 +19,8 @@ include::./common/chapters/logging.adoc[]
include::{srcdir}/chapters/configuration.adoc[]
include::./common/chapters/cs7-config.adoc[]
include::./common/chapters/gb.adoc[]
include::./common/chapters/control_if.adoc[]

View File

@@ -61,12 +61,6 @@ interact_vty \
4245 \
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
interact_vty \
"update_vty_reference" \
"vty-osmogbproxy/gbproxy_vty_reference.xml" \
4246 \
osmo-gbproxy -c "../examples/osmo-gbproxy/osmo-gbproxy.cfg"
interact_vty \
"update_counters" \
"chapters/counters_generated.adoc" \

View File

@@ -1,5 +0,0 @@
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
<node id='config-gbproxy'>
<description>Configure the Gb proxy</description>
</node>
</vtydoc>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@ noinst_HEADERS = \
common.h \
crc24.h \
debug.h \
gb_proxy.h \
gprs_gb.h \
gprs_gb_parse.h \
gprs_gmm.h \
@@ -24,6 +23,7 @@ noinst_HEADERS = \
gprs_utils.h \
gtphub.h \
sgsn.h \
sgsn_rim.h \
signal.h \
slhc.h \
v42bis.h \

View File

@@ -8,38 +8,26 @@
/* Debug Areas of the code */
enum {
DRLL,
DCC,
DMM,
DRR,
DRSL,
DNM,
DMNCC,
DPAG,
DMEAS,
DSCCP,
DMSC,
DHO,
DDB,
DREF,
DGPRS,
DNS,
DBSSGP,
DLLC,
DSNDCP,
DSLHC,
DNAT,
DCTRL,
DFILTER,
DGTPHUB,
DRANAP,
DSUA,
DV42BIS,
DPCU,
DVLR,
DIUCS,
DSIGTRAN,
DGTP,
DOBJ,
DRIM,
Debug_LastEntry,
};

View File

@@ -1,334 +0,0 @@
#ifndef _GB_PROXY_H
#define _GB_PROXY_H
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/vty/command.h>
#include <sys/types.h>
#include <regex.h>
#include <stdbool.h>
#define GBPROXY_INIT_VU_GEN_TX 256
struct rate_ctr_group;
struct gprs_gb_parse_context;
struct tlv_parsed;
enum gbproxy_global_ctr {
GBPROX_GLOB_CTR_INV_BVCI,
GBPROX_GLOB_CTR_INV_LAI,
GBPROX_GLOB_CTR_INV_RAI,
GBPROX_GLOB_CTR_INV_NSEI,
GBPROX_GLOB_CTR_PROTO_ERR_BSS,
GBPROX_GLOB_CTR_PROTO_ERR_SGSN,
GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS,
GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN,
GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
GBPROX_GLOB_CTR_TX_ERR_SGSN,
GBPROX_GLOB_CTR_OTHER_ERR,
GBPROX_GLOB_CTR_PATCH_PEER_ERR,
};
enum gbproxy_peer_ctr {
GBPROX_PEER_CTR_BLOCKED,
GBPROX_PEER_CTR_UNBLOCKED,
GBPROX_PEER_CTR_DROPPED,
GBPROX_PEER_CTR_INV_NSEI,
GBPROX_PEER_CTR_TX_ERR,
GBPROX_PEER_CTR_RAID_PATCHED_BSS,
GBPROX_PEER_CTR_RAID_PATCHED_SGSN,
GBPROX_PEER_CTR_APN_PATCHED,
GBPROX_PEER_CTR_TLLI_PATCHED_BSS,
GBPROX_PEER_CTR_TLLI_PATCHED_SGSN,
GBPROX_PEER_CTR_PTMSI_PATCHED_BSS,
GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN,
GBPROX_PEER_CTR_PATCH_CRYPT_ERR,
GBPROX_PEER_CTR_PATCH_ERR,
GBPROX_PEER_CTR_ATTACH_REQS,
GBPROX_PEER_CTR_ATTACH_REJS,
GBPROX_PEER_CTR_ATTACH_ACKS,
GBPROX_PEER_CTR_ATTACH_COMPLS,
GBPROX_PEER_CTR_RA_UPD_REQS,
GBPROX_PEER_CTR_RA_UPD_REJS,
GBPROX_PEER_CTR_RA_UPD_ACKS,
GBPROX_PEER_CTR_RA_UPD_COMPLS,
GBPROX_PEER_CTR_GMM_STATUS_BSS,
GBPROX_PEER_CTR_GMM_STATUS_SGSN,
GBPROX_PEER_CTR_DETACH_REQS,
GBPROX_PEER_CTR_DETACH_ACKS,
GBPROX_PEER_CTR_PDP_ACT_REQS,
GBPROX_PEER_CTR_PDP_ACT_REJS,
GBPROX_PEER_CTR_PDP_ACT_ACKS,
GBPROX_PEER_CTR_PDP_DEACT_REQS,
GBPROX_PEER_CTR_PDP_DEACT_ACKS,
GBPROX_PEER_CTR_TLLI_UNKNOWN,
GBPROX_PEER_CTR_TLLI_CACHE_SIZE,
GBPROX_PEER_CTR_LAST,
};
enum gbproxy_keep_mode {
GBPROX_KEEP_NEVER, /* don't ever keep TLLI/IMSI state of de-registered subscribers */
GBPROX_KEEP_REATTACH, /* keep if re-attach has been requested by SGSN */
GBPROX_KEEP_IDENTIFIED, /* keep if we had resolved an IMSI */
GBPROX_KEEP_ALWAYS, /* always keep */
};
enum gbproxy_match_id {
GBPROX_MATCH_PATCHING, /* match rule on whether or not we should patch */
GBPROX_MATCH_ROUTING, /* match rule on whether or not we should route (2-SGSN) */
GBPROX_MATCH_LAST
};
struct gbproxy_match {
bool enable; /* is this match enabled? */
char *re_str; /* regular expression (for IMSI) in string format */
regex_t re_comp; /* compiled regular expression (for IMSI) */
};
/* global gb-proxy configuration */
struct gbproxy_config {
/* parsed from config file */
uint16_t nsip_sgsn_nsei;
/* NS instance of libosmogb */
struct gprs_ns_inst *nsi;
/* Linked list of all Gb peers (except SGSN) */
struct llist_head bts_peers;
/* Counter */
struct rate_ctr_group *ctrg;
/* MCC/MNC to be patched into RA-ID on the way from BSS to SGSN? */
struct osmo_plmn_id core_plmn;
/* APN to be patched into PDP CTX ACT REQ on the way from BSS to SGSN */
uint8_t* core_apn;
size_t core_apn_size;
/* Frequency (sec) at which timer to clean stale links is fired (0 disabled) */
unsigned int clean_stale_timer_freq;
/* If !0, Max age to consider a struct gbproxy_link_info as stale */
int tlli_max_age;
/* If !0, Max len of gbproxy_peer->list (list of struct gbproxy_link_info) */
int tlli_max_len;
/* If !0, Max len of gbproxy_link_info->stored_msgs (list of msgb) */
uint32_t stored_msgs_max_len;
/* Should the P-TMSI be patched on the fly (required for 2-SGSN config) */
bool patch_ptmsi;
/* Should the IMSI be acquired by the proxy (required for 2-SGSN config) */
bool acquire_imsi;
/* Should we route subscribers to two different SGSNs? */
bool route_to_sgsn2;
/* NSEI of the second SGSN */
uint16_t nsip_sgsn2_nsei;
/* should we keep a cache of per-subscriber state even after de-registration? */
enum gbproxy_keep_mode keep_link_infos;
/* IMSI checking/matching for 2-SGSN routing and patching */
struct gbproxy_match matches[GBPROX_MATCH_LAST];
};
struct gbproxy_patch_state {
struct osmo_plmn_id local_plmn;
/* List of TLLIs for which patching is enabled */
struct llist_head logical_links;
int logical_link_count;
};
/* one peer at NS level that we interact with (BSS/PCU) */
struct gbproxy_peer {
/* linked to gbproxy_config.bts_peers */
struct llist_head list;
/* point back to the config */
struct gbproxy_config *cfg;
/* NSEI of the peer entity */
uint16_t nsei;
/* BVCI used for Point-to-Point to this peer */
uint16_t bvci;
bool blocked;
/* Routeing Area that this peer is part of (raw 04.08 encoding) */
uint8_t ra[6];
/* Counter */
struct rate_ctr_group *ctrg;
/* State related to on-the-fly patching of certain messages */
struct gbproxy_patch_state patch_state;
/* Fired periodically to clean up stale links from list */
struct osmo_timer_list clean_stale_timer;
};
struct gbproxy_tlli_state {
/* currently active TLLI */
uint32_t current;
/* newly-assigned TLLI (e.g. during P-TMSI allocation procedure) */
uint32_t assigned;
/* has the BSS side validated (confirmed) the new TLLI? */
bool bss_validated;
/* has the SGSN side validated (confirmed) the new TLLI? */
bool net_validated;
/* NOTE: once both are validated, we set current = assigned and assigned = 0 */
/* The P-TMSI for this subscriber */
uint32_t ptmsi;
};
/* One TLLI (= UE, = Subscriber) served via this proxy */
struct gbproxy_link_info {
/* link to gbproxy_peer.patch_state.logical_links */
struct llist_head list;
/* TLLI on the BSS/PCU side */
struct gbproxy_tlli_state tlli;
/* TLLI on the SGSN side (can be different in case of P-TMSI patching) */
struct gbproxy_tlli_state sgsn_tlli;
/* NSEI of the SGSN serving this link */
uint32_t sgsn_nsei;
/* timestamp when we last had any contact with this UE */
time_t timestamp;
/* IMSI of the subscriber (if/once known) */
uint8_t *imsi;
size_t imsi_len;
/* is the IMSI acquisition still pending? */
bool imsi_acq_pending;
/* queue of stored UL messages (until IMSI acquisition completes and we can
* determine which of the SGSNs we should route this to */
struct llist_head stored_msgs;
uint32_t stored_msgs_len;
/* generated N(U) we use (required due to IMSI acquisition */
unsigned vu_gen_tx_bss;
/* is this subscriber deregistered (TLLI invalidated)? */
bool is_deregistered;
/* does this link match either the (2-SGSN) routing or the patching rule? */
bool is_matching[GBPROX_MATCH_LAST];
};
/* gb_proxy_vty .c */
int gbproxy_vty_init(void);
int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
/* gb_proxy_ctrl.c */
int gb_ctrl_cmds_install(void);
/* gb_proxy.c */
int gbproxy_init_config(struct gbproxy_config *cfg);
/* Main input function for Gb proxy */
int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t nsvci);
int gbprox_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data);
/* Reset all persistent NS-VC's */
int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi);
void gbprox_reset(struct gbproxy_config *cfg);
/* TLLI info handling */
void gbproxy_delete_link_infos(struct gbproxy_peer *peer);
struct gbproxy_link_info *gbproxy_update_link_state_ul(
struct gbproxy_peer *peer, time_t now,
struct gprs_gb_parse_context *parse_ctx);
struct gbproxy_link_info *gbproxy_update_link_state_dl(
struct gbproxy_peer *peer, time_t now,
struct gprs_gb_parse_context *parse_ctx);
int gbproxy_update_link_state_after(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
time_t now, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now);
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info);
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info);
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
struct gbproxy_link_info *link_info);
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
const uint8_t *imsi, size_t imsi_len);
void gbproxy_detach_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info);
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer);
struct gbproxy_link_info *gbproxy_link_info_by_tlli(
struct gbproxy_peer *peer, uint32_t tlli);
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len);
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
struct gbproxy_peer *peer, uint32_t tlli);
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli, uint32_t sgsn_nsei);
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
struct gbproxy_peer *peer,
uint32_t ptmsi);
int gbproxy_imsi_matches(
struct gbproxy_config *cfg,
enum gbproxy_match_id match_id,
struct gbproxy_link_info *link_info);
uint32_t gbproxy_map_tlli(
uint32_t other_tlli, struct gbproxy_link_info *link_info, int to_bss);
/* needed by gb_proxy_tlli.h */
uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi);
uint32_t gbproxy_make_sgsn_tlli(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
uint32_t bss_tlli);
void gbproxy_reset_link(struct gbproxy_link_info *link_info);
int gbproxy_check_imsi(
struct gbproxy_match *match, const uint8_t *imsi, size_t imsi_len);
/* Message patching */
void gbproxy_patch_bssgp(
struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
int *len_change, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_patch_llc(
struct msgb *msg, uint8_t *llc, size_t llc_len,
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
int *len_change, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_set_patch_filter(
struct gbproxy_match *match, const char *filter, const char **err_msg);
void gbproxy_clear_patch_filter(struct gbproxy_match *match);
/* Peer handling */
struct gbproxy_peer *gbproxy_peer_by_bvci(
struct gbproxy_config *cfg, uint16_t bvci);
struct gbproxy_peer *gbproxy_peer_by_nsei(
struct gbproxy_config *cfg, uint16_t nsei);
struct gbproxy_peer *gbproxy_peer_by_rai(
struct gbproxy_config *cfg, const uint8_t *ra);
struct gbproxy_peer *gbproxy_peer_by_lai(
struct gbproxy_config *cfg, const uint8_t *la);
struct gbproxy_peer *gbproxy_peer_by_lac(
struct gbproxy_config *cfg, const uint8_t *la);
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(
struct gbproxy_config *cfg, struct tlv_parsed *tp);
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);
void gbproxy_peer_free(struct gbproxy_peer *peer);
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);
#endif

View File

@@ -8,7 +8,13 @@
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable);
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx);
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg);
/* page a MS in its routing area */
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
/* called by the bssgp layer to send NS PDUs */
int gprs_gb_send_cb(void *ctx, struct msgb *msg);
/* called by the ns layer */
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);

View File

@@ -51,6 +51,8 @@ int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
struct gprs_gb_parse_context *parse_ctx);
int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli);
const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
const char *default_msg_name);

View File

@@ -1,6 +1,8 @@
#pragma once
#include <osmocom/core/fsm.h>
#include <osmocom/sgsn/gprs_sgsn.h>
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
enum gmm_fsm_states {
@@ -23,6 +25,12 @@ enum gmm_fsm_events {
E_GMM_SUSPEND,
E_GMM_RESUME,
E_GMM_CLEANUP,
E_GMM_RAT_CHANGE,
};
struct gmm_rat_change_data {
enum sgsn_ran_type new_ran_type;
struct gprs_llc_llme *llme;
};
static inline bool gmm_fsm_is_registered(struct osmo_fsm_inst *fi)

View File

@@ -35,14 +35,14 @@
/* TODO move to osmocom/core/socket.c ? */
#include <netdb.h> /* for IPPROTO_* etc */
struct osmo_sockaddr {
struct sgsn_sockaddr {
struct sockaddr_storage a;
socklen_t l;
};
/* TODO move to osmocom/core/socket.c ? */
/*! \brief Initialize a sockaddr
* \param[out] addr Valid osmo_sockaddr pointer to write result to
* \param[out] addr Valid sgsn_sockaddr pointer to write result to
* \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
@@ -53,16 +53,16 @@ struct osmo_sockaddr {
* Copy the first result from a getaddrinfo() call with the given parameters to
* *addr and *addr_len. On error, do not change *addr and return nonzero.
*/
int osmo_sockaddr_init(struct osmo_sockaddr *addr,
int sgsn_sockaddr_init(struct sgsn_sockaddr *addr,
uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port);
/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to
* osmo_sockaddr_init(). */
static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
* sgsn_sockaddr_init(). */
static inline int sgsn_sockaddr_init_udp(struct sgsn_sockaddr *addr,
const char *host, uint16_t port)
{
return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
return sgsn_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
host, port);
}
@@ -71,25 +71,25 @@ static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
* \param[in] addr_str_len Size of buffer addr_str points at.
* \param[out] port_str Valid pointer to a buffer of length port_str_len.
* \param[in] port_str_len Size of buffer port_str points at.
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
* \param[in] flags flags as passed to getnameinfo().
* \returns 0 on success, an error code on error.
*
* Return the IPv4 or IPv6 address string and the port (a.k.a. service) string
* representations of the given struct osmo_sockaddr in two caller provided
* representations of the given struct sgsn_sockaddr in two caller provided
* char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric
* address and port. Either one of addr_str or port_str may be NULL, in which
* case nothing is returned there.
*
* See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */
int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
* See also sgsn_sockaddr_to_str() (less flexible, but much more convenient). */
int sgsn_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
char *port_str, size_t port_str_len,
const struct osmo_sockaddr *addr,
const struct sgsn_sockaddr *addr,
int flags);
/*! \brief concatenate the parts returned by osmo_sockaddr_to_strs().
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
/*! \brief concatenate the parts returned by sgsn_sockaddr_to_strs().
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
* \param[in] buf A buffer to use for string operations.
* \param[in] buf_len Length of the buffer.
* \returns Address string (in buffer).
@@ -98,33 +98,33 @@ int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
* the form "<ip-addr> port <port>". The returned string is valid until the
* next invocation of this function.
*/
const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
const char *sgsn_sockaddr_to_strb(const struct sgsn_sockaddr *addr,
char *buf, size_t buf_len);
/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer.
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
/*! \brief conveniently return sgsn_sockaddr_to_strb() in a static buffer.
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
* \returns Address string in static buffer.
*
* See osmo_sockaddr_to_strb().
* See sgsn_sockaddr_to_strb().
*
* Note: only one osmo_sockaddr_to_str() call will work per print/log
* statement. For two or more, use osmo_sockaddr_to_strb() with a separate
* Note: only one sgsn_sockaddr_to_str() call will work per print/log
* statement. For two or more, use sgsn_sockaddr_to_strb() with a separate
* buffer each.
*/
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr);
const char *sgsn_sockaddr_to_str(const struct sgsn_sockaddr *addr);
/*! \brief compare two osmo_sockaddr.
/*! \brief compare two sgsn_sockaddr.
* \param[in] a The first address to compare.
* \param[in] b The other address to compare.
* \returns 0 if equal, otherwise -1 or 1.
*/
int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
const struct osmo_sockaddr *b);
int sgsn_sockaddr_cmp(const struct sgsn_sockaddr *a,
const struct sgsn_sockaddr *b);
/*! \brief Overwrite *dst with *src.
* Like memcpy(), but copy only the valid bytes. */
void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
const struct osmo_sockaddr *src);
void sgsn_sockaddr_copy(struct sgsn_sockaddr *dst,
const struct sgsn_sockaddr *src);
/* general */
@@ -179,7 +179,7 @@ int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b);
/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number
* from sa is also returned. */
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
const struct osmo_sockaddr *sa);
const struct sgsn_sockaddr *sa);
/* expiry */
@@ -389,7 +389,7 @@ struct gtphub_peer_port {
struct gtphub_peer_addr *peer_addr;
uint16_t port;
unsigned int ref_count; /* references from other peers' seq_maps */
struct osmo_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
struct sgsn_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
int last_restart_count; /* 0..255 = valid, all else means unknown */
struct rate_ctr_group *counters_io;
@@ -496,13 +496,13 @@ int gtphub_tunnel_complete(struct gtphub_tunnel *tun);
int gtphub_handle_buf(struct gtphub *hub,
unsigned int side_idx,
unsigned int port_idx,
const struct osmo_sockaddr *from_addr,
const struct sgsn_sockaddr *from_addr,
uint8_t *buf,
size_t received,
time_t now,
uint8_t **reply_buf,
struct osmo_fd **to_ofd,
struct osmo_sockaddr *to_addr);
struct sgsn_sockaddr *to_addr);
struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
struct gtphub_bind *bind,
@@ -510,7 +510,7 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
uint16_t port);
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr);
const struct sgsn_sockaddr *addr);
void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
struct gsn_addr *resolved_addr,
@@ -519,5 +519,5 @@ void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
const char *gtphub_port_str(struct gtphub_peer_port *port);
int gtphub_write(const struct osmo_fd *to,
const struct osmo_sockaddr *to_addr,
const struct sgsn_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len);

View File

@@ -3,8 +3,9 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/gsm/oap_client.h>
#include <osmocom/gsupclient/gsup_client.h>
@@ -69,7 +70,7 @@ struct sgsn_config {
struct sockaddr_in gtp_listenaddr;
/* misc */
struct gprs_ns_inst *nsi;
struct gprs_ns2_inst *nsi;
enum sgsn_auth_policy auth_policy;
enum gprs_ciph_algo cipher;
@@ -157,7 +158,7 @@ char *sgsn_gtp_ntoa(struct ul16_t *ul);
/* sgsn.c */
/* Main input function for Gb proxy */
int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *nsvc, uint16_t ns_bvci);
/* sgsn_libgtp.c */
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,

View File

@@ -0,0 +1,3 @@
#pragma once
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);

View File

@@ -16,19 +16,16 @@
app_configs = {
"gbproxy": ["doc/examples/osmo-gbproxy/osmo-gbproxy.cfg",
"doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg"],
"sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
"gtphub": ["doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg"]
}
apps = [(4246, "src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
apps = [(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
(4253, "src/gtphub/osmo-gtphub", "OsmoGTPhub", "gtphub")
]
vty_command = ["./src/sgsn/osmo-sgsn", "-c",
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
vty_app = apps[1]
vty_app = apps[0]

View File

@@ -1,6 +1,5 @@
SUBDIRS = \
gprs \
sgsn \
gbproxy \
gtphub \
$(NULL)

View File

@@ -1,46 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
-fno-strict-aliasing \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOGB_CFLAGS) \
$(LIBOSMOGSUPCLIENT_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(LIBGTP_CFLAGS) \
$(NULL)
bin_PROGRAMS = \
osmo-gbproxy \
$(NULL)
osmo_gbproxy_SOURCES = \
gb_proxy.c \
gb_proxy_main.c \
gb_proxy_vty.c \
gb_proxy_ctrl.c \
gb_proxy_patch.c \
gb_proxy_tlli.c \
gb_proxy_peer.c \
$(NULL)
osmo_gbproxy_LDADD = \
$(top_builddir)/src/gprs/gprs_gb_parse.o \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
$(top_builddir)/src/gprs/crc24.o \
$(top_builddir)/src/gprs/gprs_utils.o \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBGTP_LIBS) \
-lrt \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +0,0 @@
/* Control Interface Implementation for the Gb-proxy */
/*
* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Daniel Willmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/talloc.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/debug.h>
extern vector ctrl_node_vec;
static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gprs_ns_inst *nsi = cfg->nsi;
struct gprs_nsvc *nsvc;
cmd->reply = talloc_strdup(cmd, "");
llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
if (nsvc == nsi->unknown_nsvc)
continue;
cmd->reply = gprs_nsvc_state_append(cmd->reply, nsvc);
}
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(nsvc_state, "nsvc-state");
static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gbproxy_peer *peer;
cmd->reply = talloc_strdup(cmd, "");
llist_for_each_entry(peer, &cfg->bts_peers, list) {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, peer->ra);
cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
peer->nsei, peer->bvci,
raid.mcc, raid.mnc,
raid.lac, raid.rac,
peer->blocked ? "BLOCKED" : "UNBLOCKED");
}
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(gbproxy_state, "gbproxy-state");
static int get_num_peers(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
cmd->reply = talloc_strdup(cmd, "");
cmd->reply = talloc_asprintf_append(cmd->reply, "%u", llist_count(&cfg->bts_peers));
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(num_peers, "number-of-peers");
int gb_ctrl_cmds_install(void)
{
int rc = 0;
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_nsvc_state);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_gbproxy_state);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_num_peers);
return rc;
}

View File

@@ -1,398 +0,0 @@
/* NS-over-IP proxy */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/ctrl/control_vty.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/misc.h>
#include "../../bscconfig.h"
#define _GNU_SOURCE
#include <getopt.h>
void *tall_sgsn_ctx;
const char *openbsc_copyright =
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
#define CONFIG_FILE_DEFAULT "osmo-gbproxy.cfg"
#define CONFIG_FILE_LEGACY "osmo_gbproxy.cfg"
static char *config_file = NULL;
struct gbproxy_config *gbcfg;
static int daemonize = 0;
/* Pointer to the SGSN peer */
extern struct gbprox_peer *gbprox_peer_sgsn;
/* call-back function for the NS protocol */
static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
struct msgb *msg, uint16_t bvci)
{
int rc = 0;
switch (event) {
case GPRS_NS_EVT_UNIT_DATA:
rc = gbprox_rcvmsg(gbcfg, msg, nsvc->nsei, bvci, nsvc->nsvci);
break;
default:
LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
if (msg)
msgb_free(msg);
rc = -EIO;
break;
}
return rc;
}
static void signal_handler(int signal)
{
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
case SIGINT:
case SIGTERM:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
sleep(1);
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_sgsn_ctx, stderr);
break;
case SIGUSR2:
talloc_report_full(tall_vty_ctx, stderr);
break;
default:
break;
}
}
static void print_usage()
{
printf("Usage: bsc_hack\n");
}
static void print_help()
{
printf(" Some useful help...\n");
printf(" -h --help this text\n");
printf(" -d option --debug=DNS:DGPRS,0:0 enable debugging\n");
printf(" -D --daemonize Fork the process into a background daemon\n");
printf(" -c --config-file filename The config file to use [%s]\n", CONFIG_FILE_DEFAULT);
printf(" -s --disable-color\n");
printf(" -T --timestamp Prefix every log line with a timestamp\n");
printf(" -V --version. Print the version.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
static struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "debug", 1, 0, 'd' },
{ "daemonize", 0, 0, 'D' },
{ "config-file", 1, 0, 'c' },
{ "disable-color", 0, 0, 's' },
{ "timestamp", 0, 0, 'T' },
{ "version", 0, 0, 'V' },
{ "log-level", 1, 0, 'e' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "hd:Dc:sTVe:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_usage();
print_help();
exit(0);
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
case 'd':
log_parse_category_mask(osmo_stderr_target, optarg);
break;
case 'D':
daemonize = 1;
break;
case 'c':
config_file = optarg;
break;
case 'T':
log_set_print_timestamp(osmo_stderr_target, 1);
break;
case 'e':
log_set_log_level(osmo_stderr_target, atoi(optarg));
break;
case 'V':
print_version(1);
exit(0);
break;
default:
break;
}
}
if (argc > optind) {
fprintf(stderr, "Unsupported positional arguments on command line\n");
exit(2);
}
}
int gbproxy_vty_is_config_node(struct vty *vty, int node)
{
switch (node) {
/* add items that are not config */
case CONFIG_NODE:
return 0;
default:
return 1;
}
}
int gbproxy_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case GBPROXY_NODE:
default:
if (gbproxy_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;
else
vty->node = ENABLE_NODE;
vty->index = NULL;
}
return vty->node;
}
static struct vty_app_info vty_info = {
.name = "OsmoGbProxy",
.version = PACKAGE_VERSION,
.go_parent_cb = gbproxy_vty_go_parent,
.is_config_node = gbproxy_vty_is_config_node,
};
/* default categories */
static struct log_info_cat gprs_categories[] = {
[DGPRS] = {
.name = "DGPRS",
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DNS] = {
.name = "DNS",
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_INFO,
},
[DBSSGP] = {
.name = "DBSSGP",
.description = "GPRS BSS Gateway Protocol (BSSGP)",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
static const struct log_info gprs_log_info = {
.filter_fn = gprs_log_filter_fn,
.cat = gprs_categories,
.num_cat = ARRAY_SIZE(gprs_categories),
};
static bool file_exists(const char *path)
{
struct stat sb;
return stat(path, &sb) ? false : true;
}
int main(int argc, char **argv)
{
int rc;
struct ctrl_handle *ctrl;
tall_sgsn_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
msgb_talloc_ctx_init(tall_sgsn_ctx, 0);
vty_info.tall_ctx = tall_sgsn_ctx;
signal(SIGINT, &signal_handler);
signal(SIGTERM, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
osmo_init_ignore_signals();
osmo_init_logging2(tall_sgsn_ctx, &gprs_log_info);
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds();
gbproxy_vty_init();
handle_options(argc, argv);
/* Backwards compatibility: for years, the default config file name was
* osmo_gbproxy.cfg. All other Osmocom programs use osmo-*.cfg with a
* dash. To be able to use the new config file name without breaking
* previous setups that might rely on the legacy default config file
* name, we need to look for the old config file if no -c option was
* passed AND no file exists with the new default file name. */
if (!config_file) {
/* No -c option was passed */
if (file_exists(CONFIG_FILE_LEGACY)
&& !file_exists(CONFIG_FILE_DEFAULT))
config_file = CONFIG_FILE_LEGACY;
else
config_file = CONFIG_FILE_DEFAULT;
}
rate_ctr_init(tall_sgsn_ctx);
osmo_stats_init(tall_sgsn_ctx);
bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_sgsn_ctx);
if (!bssgp_nsi) {
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
gbcfg = talloc_zero(tall_sgsn_ctx, struct gbproxy_config);
if (!gbcfg) {
LOGP(DGPRS, LOGL_FATAL, "Unable to allocate config\n");
exit(1);
}
gbproxy_init_config(gbcfg);
gbcfg->nsi = bssgp_nsi;
gprs_ns_vty_init(bssgp_nsi);
gprs_ns_set_log_ss(DNS);
bssgp_set_log_ss(DBSSGP);
osmo_signal_register_handler(SS_L_NS, &gbprox_signal, gbcfg);
rc = gbproxy_parse_config(config_file, gbcfg);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file '%s'\n", config_file);
exit(2);
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
if (rc < 0)
exit(1);
/* Start control interface after getting config for
* ctrl_vty_get_bind_addr() */
ctrl = ctrl_interface_setup_dynip(gbcfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_GBPROXY, NULL);
if (!ctrl) {
LOGP(DGPRS, LOGL_FATAL, "Failed to create CTRL interface.\n");
exit(1);
}
if (gb_ctrl_cmds_install() != 0) {
LOGP(DGPRS, LOGL_FATAL, "Failed to install CTRL commands.\n");
exit(1);
}
if (!gprs_nsvc_by_nsei(gbcfg->nsi, gbcfg->nsip_sgsn_nsei)) {
LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u "
"without creating that NSEI before\n",
gbcfg->nsip_sgsn_nsei);
exit(2);
}
rc = gprs_ns_nsip_listen(bssgp_nsi);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
exit(2);
}
rc = gprs_ns_frgre_listen(bssgp_nsi);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
"socket. Do you have CAP_NET_RAW?\n");
exit(2);
}
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
perror("Error during daemonize");
exit(1);
}
}
/* Reset all the persistent NS-VCs that we've read from the config */
gbprox_reset_persistent_nsvcs(bssgp_nsi);
while (1) {
rc = osmo_select_main(0);
if (rc < 0)
exit(3);
}
exit(0);
}

View File

@@ -1,465 +0,0 @@
/* Gb-proxy message patching */
/* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gprs_gb_parse.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/apn.h>
extern void *tall_sgsn_ctx;
/* patch RA identifier in place */
static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer *peer,
int to_bss, const char *log_text)
{
struct gbproxy_patch_state *state = &peer->patch_state;
struct osmo_plmn_id old_plmn;
struct gprs_ra_id raid;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
GBPROX_PEER_CTR_RAID_PATCHED_BSS;
if (!state->local_plmn.mcc || !state->local_plmn.mnc)
return;
gsm48_parse_ra(&raid, (uint8_t *)raid_enc);
old_plmn = (struct osmo_plmn_id){
.mcc = raid.mcc,
.mnc = raid.mnc,
.mnc_3_digits = raid.mnc_3_digits,
};
if (!to_bss) {
/* BSS -> SGSN */
if (state->local_plmn.mcc)
raid.mcc = peer->cfg->core_plmn.mcc;
if (state->local_plmn.mnc) {
raid.mnc = peer->cfg->core_plmn.mnc;
raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;
}
} else {
/* SGSN -> BSS */
if (state->local_plmn.mcc)
raid.mcc = state->local_plmn.mcc;
if (state->local_plmn.mnc) {
raid.mnc = state->local_plmn.mnc;
raid.mnc_3_digits = state->local_plmn.mnc_3_digits;
}
}
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to %s: "
"%s-%d-%d -> %s\n",
log_text,
to_bss ? "BSS" : "SGSN",
osmo_plmn_name(&old_plmn), raid.lac, raid.rac,
osmo_rai_name(&raid));
gsm48_encode_ra(raid_enc, &raid);
rate_ctr_inc(&peer->ctrg->ctr[counter]);
}
static void gbproxy_patch_apn_ie(struct msgb *msg,
uint8_t *apn_ie, size_t apn_ie_len,
struct gbproxy_peer *peer,
size_t *new_apn_ie_len, const char *log_text)
{
struct apn_ie_hdr {
uint8_t iei;
uint8_t apn_len;
uint8_t apn[0];
} *hdr = (void *)apn_ie;
size_t apn_len = hdr->apn_len;
uint8_t *apn = hdr->apn;
OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
if (peer->cfg->core_apn_size == 0) {
char str1[110];
/* Remove the IE */
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to SGSN: Removing APN '%s'\n",
log_text,
osmo_apn_to_str(str1, apn, apn_len));
*new_apn_ie_len = 0;
msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
} else {
/* Resize the IE */
char str1[110];
char str2[110];
OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to SGSN: "
"Replacing APN '%s' -> '%s'\n",
log_text,
osmo_apn_to_str(str1, apn, apn_len),
osmo_apn_to_str(str2, peer->cfg->core_apn,
peer->cfg->core_apn_size));
*new_apn_ie_len = peer->cfg->core_apn_size + 2;
msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
hdr->apn_len = peer->cfg->core_apn_size;
}
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
}
static int gbproxy_patch_tlli(uint8_t *tlli_enc,
struct gbproxy_peer *peer,
uint32_t new_tlli,
int to_bss, const char *log_text)
{
uint32_t tlli_be;
uint32_t tlli;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
tlli = ntohl(tlli_be);
if (tlli == new_tlli)
return 0;
LOGP(DGPRS, LOGL_DEBUG,
"Patching %ss: "
"Replacing %08x -> %08x\n",
log_text, tlli, new_tlli);
tlli_be = htonl(new_tlli);
memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
rate_ctr_inc(&peer->ctrg->ctr[counter]);
return 1;
}
static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
struct gbproxy_peer *peer,
uint32_t new_ptmsi,
int to_bss, const char *log_text)
{
uint32_t ptmsi_be;
uint32_t ptmsi;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
memcpy(&ptmsi_be, ptmsi_enc, sizeof(ptmsi_be));
ptmsi = ntohl(ptmsi_be);
if (ptmsi == new_ptmsi)
return 0;
LOGP(DGPRS, LOGL_DEBUG,
"Patching %ss: "
"Replacing %08x -> %08x\n",
log_text, ptmsi, new_ptmsi);
ptmsi_be = htonl(new_ptmsi);
memcpy(ptmsi_enc, &ptmsi_be, sizeof(ptmsi_be));
rate_ctr_inc(&peer->ctrg->ctr[counter]);
return 1;
}
int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info, int *len_change,
struct gprs_gb_parse_context *parse_ctx)
{
struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
int have_patched = 0;
int fcs;
struct gbproxy_config *cfg = peer->cfg;
if (parse_ctx->ptmsi_enc && link_info &&
!parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
if (ptmsi != GSM_RESERVED_TMSI) {
if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "P-TMSI"))
have_patched = 1;
} else {
/* TODO: invalidate old RAI if present (see below) */
}
}
if (parse_ctx->new_ptmsi_enc && link_info && cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
OSMO_ASSERT(ptmsi);
if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "new P-TMSI"))
have_patched = 1;
}
if (parse_ctx->raid_enc) {
gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->raid_enc, peer, parse_ctx->to_bss,
parse_ctx->llc_msg_name);
have_patched = 1;
}
if (parse_ctx->old_raid_enc && !parse_ctx->old_raid_is_foreign) {
/* TODO: Patch to invalid if P-TMSI unknown. */
gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
parse_ctx->llc_msg_name);
have_patched = 1;
}
if (parse_ctx->apn_ie &&
cfg->core_apn &&
!parse_ctx->to_bss &&
gbproxy_imsi_matches(cfg, GBPROX_MATCH_PATCHING, link_info) &&
cfg->core_apn) {
size_t new_len;
gbproxy_patch_apn_ie(msg,
parse_ctx->apn_ie, parse_ctx->apn_ie_len,
peer, &new_len, parse_ctx->llc_msg_name);
*len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
have_patched = 1;
}
if (have_patched) {
llc_len += *len_change;
ghp->crc_length += *len_change;
/* Fix FCS */
fcs = gprs_llc_fcs(llc, ghp->crc_length);
LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
ghp->fcs, fcs);
llc[llc_len - 3] = fcs & 0xff;
llc[llc_len - 2] = (fcs >> 8) & 0xff;
llc[llc_len - 1] = (fcs >> 16) & 0xff;
}
return have_patched;
}
/* patch BSSGP message to use core_plmn.mcc/mnc on the SGSN side */
void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info, int *len_change,
struct gprs_gb_parse_context *parse_ctx)
{
const char *err_info = NULL;
int err_ctr = -1;
if (parse_ctx->bssgp_raid_enc)
gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->bssgp_raid_enc, peer,
parse_ctx->to_bss, "BSSGP");
if (parse_ctx->need_decryption &&
(peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
/* Patching LLC messages has been requested
* explicitly, but the message (including the
* type) is encrypted, so we possibly fail to
* patch the LLC part of the message. */
err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
err_info = "GMM message is encrypted";
goto patch_error;
}
if (!link_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
/* Happens with unknown (not cached) TLLI coming from
* the SGSN */
/* TODO: What shall be done with the message in this case? */
err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
err_info = "TLLI sent by the SGSN is unknown";
goto patch_error;
}
if (!link_info)
return;
if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
link_info, parse_ctx->to_bss);
if (tlli) {
gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
parse_ctx->to_bss, "TLLI");
parse_ctx->tlli = tlli;
} else {
/* Internal error */
err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
err_info = "Replacement TLLI is 0";
goto patch_error;
}
}
if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
if (ptmsi != GSM_RESERVED_TMSI)
gbproxy_patch_ptmsi(
parse_ctx->bssgp_ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "BSSGP P-TMSI");
}
if (parse_ctx->llc) {
uint8_t *llc = parse_ctx->llc;
size_t llc_len = parse_ctx->llc_len;
int llc_len_change = 0;
gbproxy_patch_llc(msg, llc, llc_len, peer, link_info,
&llc_len_change, parse_ctx);
/* Note that the APN might have been resized here, but no
* pointer int the parse_ctx will refer to an adress after the
* APN. So it's possible to patch first and do the TLLI
* handling afterwards. */
if (llc_len_change) {
llc_len += llc_len_change;
/* Fix LLC IE len */
/* TODO: This is a kludge, but the a pointer to the
* start of the IE is not available here */
if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
/* most probably a one byte length */
if (llc_len > 127) {
err_info = "Cannot increase size";
err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
goto patch_error;
}
llc[-1] = llc_len | 0x80;
} else {
llc[-2] = (llc_len >> 8) & 0x7f;
llc[-1] = llc_len & 0xff;
}
*len_change += llc_len_change;
}
/* Note that the tp struct might contain invalid pointers here
* if the LLC field has changed its size */
parse_ctx->llc_len = llc_len;
}
return;
patch_error:
OSMO_ASSERT(err_ctr >= 0);
rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
LOGP(DGPRS, LOGL_ERROR,
"NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
err_info);
}
void gbproxy_clear_patch_filter(struct gbproxy_match *match)
{
if (match->enable) {
regfree(&match->re_comp);
match->enable = false;
}
talloc_free(match->re_str);
match->re_str = NULL;
}
int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
const char **err_msg)
{
static char err_buf[300];
int rc;
gbproxy_clear_patch_filter(match);
if (!filter)
return 0;
rc = regcomp(&match->re_comp, filter,
REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (rc == 0) {
match->enable = true;
match->re_str = talloc_strdup(tall_sgsn_ctx, filter);
return 0;
}
if (err_msg) {
regerror(rc, &match->re_comp,
err_buf, sizeof(err_buf));
*err_msg = err_buf;
}
return -1;
}
int gbproxy_check_imsi(struct gbproxy_match *match,
const uint8_t *imsi, size_t imsi_len)
{
char mi_buf[200];
int rc;
if (!match->enable)
return 1;
rc = gprs_is_mi_imsi(imsi, imsi_len);
if (rc > 0)
rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
if (rc <= 0) {
LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
osmo_hexdump(imsi, imsi_len));
return -1;
}
LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
if (rc == REG_NOMATCH) {
LOGP(DGPRS, LOGL_INFO,
"IMSI '%s' doesn't match pattern '%s'\n",
mi_buf, match->re_str);
return 0;
}
return 1;
}

View File

@@ -1,240 +0,0 @@
/* Gb proxy peer handling */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010-2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/tlv.h>
#include <string.h>
extern void *tall_sgsn_ctx;
static const struct rate_ctr_desc peer_ctr_description[] = {
{ "blocked", "BVC Block " },
{ "unblocked", "BVC Unblock " },
{ "dropped", "BVC blocked, dropped packet " },
{ "inv-nsei", "NSEI mismatch " },
{ "tx-err", "NS Transmission error " },
{ "raid-mod:bss", "RAID patched (BSS )" },
{ "raid-mod:sgsn", "RAID patched (SGSN)" },
{ "apn-mod:sgsn", "APN patched " },
{ "tlli-mod:bss", "TLLI patched (BSS )" },
{ "tlli-mod:sgsn", "TLLI patched (SGSN)" },
{ "ptmsi-mod:bss", "P-TMSI patched (BSS )" },
{ "ptmsi-mod:sgsn","P-TMSI patched (SGSN)" },
{ "mod-crypt-err", "Patch error: encrypted " },
{ "mod-err", "Patch error: other " },
{ "attach-reqs", "Attach Request count " },
{ "attach-rejs", "Attach Reject count " },
{ "attach-acks", "Attach Accept count " },
{ "attach-cpls", "Attach Completed count " },
{ "ra-upd-reqs", "RoutingArea Update Request count" },
{ "ra-upd-rejs", "RoutingArea Update Reject count " },
{ "ra-upd-acks", "RoutingArea Update Accept count " },
{ "ra-upd-cpls", "RoutingArea Update Compltd count" },
{ "gmm-status", "GMM Status count (BSS)" },
{ "gmm-status", "GMM Status count (SGSN)" },
{ "detach-reqs", "Detach Request count " },
{ "detach-acks", "Detach Accept count " },
{ "pdp-act-reqs", "PDP Activation Request count " },
{ "pdp-act-rejs", "PDP Activation Reject count " },
{ "pdp-act-acks", "PDP Activation Accept count " },
{ "pdp-deact-reqs","PDP Deactivation Request count " },
{ "pdp-deact-acks","PDP Deactivation Accept count " },
{ "tlli-unknown", "TLLI from SGSN unknown " },
{ "tlli-cache", "TLLI cache size " },
};
osmo_static_assert(ARRAY_SIZE(peer_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described);
static const struct rate_ctr_group_desc peer_ctrg_desc = {
.group_name_prefix = "gbproxy:peer",
.group_description = "GBProxy Peer Statistics",
.num_ctr = ARRAY_SIZE(peer_ctr_description),
.ctr_desc = peer_ctr_description,
.class_id = OSMO_STATS_CLASS_PEER,
};
/* Find the gbprox_peer by its BVCI */
struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (peer->bvci == bvci)
return peer;
}
return NULL;
}
/* Find the gbprox_peer by its NSEI */
struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
uint16_t nsei)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (peer->nsei == nsei)
return peer;
}
return NULL;
}
/* look-up a peer by its Routeing Area Identification (RAI) */
struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
const uint8_t *ra)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra, ra, 6))
return peer;
}
return NULL;
}
/* look-up a peer by its Location Area Identification (LAI) */
struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra, la, 5))
return peer;
}
return NULL;
}
/* look-up a peer by its Location Area Code (LAC) */
struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra + 3, la + 3, 2))
return peer;
}
return NULL;
}
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg,
struct tlv_parsed *tp)
{
if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
uint16_t bvci;
bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
if (bvci >= 2)
return gbproxy_peer_by_bvci(cfg, bvci);
}
if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
/* Only compare LAC part, since MCC/MNC are possibly patched.
* Since the LAC of different BSS must be different when
* MCC/MNC are patched, collisions shouldn't happen. */
return gbproxy_peer_by_lac(cfg, rai);
}
if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
return gbproxy_peer_by_lac(cfg, lai);
}
return NULL;
}
static void clean_stale_timer_cb(void *data)
{
time_t now;
struct timespec ts = {0,};
struct gbproxy_peer *peer = (struct gbproxy_peer *) data;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
gbproxy_remove_stale_link_infos(peer, now);
if (peer->cfg->clean_stale_timer_freq != 0)
osmo_timer_schedule(&peer->clean_stale_timer,
peer->cfg->clean_stale_timer_freq, 0);
}
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_peer *peer;
peer = talloc_zero(tall_sgsn_ctx, struct gbproxy_peer);
if (!peer)
return NULL;
peer->bvci = bvci;
peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
if (!peer->ctrg) {
talloc_free(peer);
return NULL;
}
peer->cfg = cfg;
llist_add(&peer->list, &cfg->bts_peers);
INIT_LLIST_HEAD(&peer->patch_state.logical_links);
osmo_timer_setup(&peer->clean_stale_timer, clean_stale_timer_cb, peer);
if (peer->cfg->clean_stale_timer_freq != 0)
osmo_timer_schedule(&peer->clean_stale_timer,
peer->cfg->clean_stale_timer_freq, 0);
return peer;
}
void gbproxy_peer_free(struct gbproxy_peer *peer)
{
llist_del(&peer->list);
osmo_timer_del(&peer->clean_stale_timer);
gbproxy_delete_link_infos(peer);
rate_ctr_group_free(peer->ctrg);
peer->ctrg = NULL;
talloc_free(peer);
}
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
{
int counter = 0;
struct gbproxy_peer *peer, *tmp;
llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
if (peer->nsei != nsei)
continue;
if (bvci && peer->bvci != bvci)
continue;
gbproxy_peer_free(peer);
counter += 1;
}
return counter;
}

View File

@@ -1,723 +0,0 @@
/* Gb-proxy TLLI state handling */
/* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/gsm/gsm48.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gprs_gb_parse.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/talloc.h>
struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
uint32_t tlli)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->tlli.current == tlli ||
link_info->tlli.assigned == tlli)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
struct gbproxy_peer *peer,
uint32_t ptmsi)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (ptmsi == GSM_RESERVED_TMSI)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->tlli.ptmsi == ptmsi)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
/* Don't care about the NSEI */
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->sgsn_tlli.current == tlli ||
link_info->sgsn_tlli.assigned == tlli)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli, uint32_t sgsn_nsei)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if ((link_info->sgsn_tlli.current == tlli ||
link_info->sgsn_tlli.assigned == tlli) &&
link_info->sgsn_nsei == sgsn_nsei)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
struct gbproxy_peer *peer,
const uint8_t *imsi,
size_t imsi_len)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!gprs_is_mi_imsi(imsi, imsi_len))
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list) {
if (link_info->imsi_len != imsi_len)
continue;
if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
continue;
return link_info;
}
return NULL;
}
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
{
struct msgb *msg, *nxt;
llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
llist_del(&msg->list);
msgb_free(msg);
}
}
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
gbproxy_link_info_discard_messages(link_info);
llist_del(&link_info->list);
talloc_free(link_info);
state->logical_link_count -= 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
{
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state = &peer->patch_state;
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
gbproxy_delete_link_info(peer, link_info);
OSMO_ASSERT(state->logical_link_count == 0);
OSMO_ASSERT(llist_empty(&state->logical_links));
}
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
link_info->timestamp = now;
llist_add(&link_info->list, &state->logical_links);
state->logical_link_count += 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
{
struct gbproxy_patch_state *state = &peer->patch_state;
int exceeded_max_len = 0;
int deleted_count = 0;
int check_for_age;
if (peer->cfg->tlli_max_len > 0)
exceeded_max_len =
state->logical_link_count - peer->cfg->tlli_max_len;
check_for_age = peer->cfg->tlli_max_age > 0;
for (; exceeded_max_len > 0; exceeded_max_len--) {
struct gbproxy_link_info *link_info;
OSMO_ASSERT(!llist_empty(&state->logical_links));
link_info = llist_entry(state->logical_links.prev,
struct gbproxy_link_info,
list);
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list "
"(stale, length %d, max_len exceeded)\n",
link_info->tlli.current, state->logical_link_count);
gbproxy_delete_link_info(peer, link_info);
deleted_count += 1;
}
while (check_for_age && !llist_empty(&state->logical_links)) {
time_t age;
struct gbproxy_link_info *link_info;
link_info = llist_entry(state->logical_links.prev,
struct gbproxy_link_info,
list);
age = now - link_info->timestamp;
/* age < 0 only happens after system time jumps, discard entry */
if (age <= peer->cfg->tlli_max_age && age >= 0) {
check_for_age = 0;
continue;
}
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list "
"(stale, age %d, max_age exceeded)\n",
link_info->tlli.current, (int)age);
gbproxy_delete_link_info(peer, link_info);
deleted_count += 1;
}
return deleted_count;
}
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
{
struct gbproxy_link_info *link_info;
link_info = talloc_zero(peer, struct gbproxy_link_info);
link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
INIT_LLIST_HEAD(&link_info->stored_msgs);
return link_info;
}
void gbproxy_detach_link_info(
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
llist_del(&link_info->list);
OSMO_ASSERT(state->logical_link_count > 0);
state->logical_link_count -= 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
const uint8_t *imsi, size_t imsi_len)
{
if (!gprs_is_mi_imsi(imsi, imsi_len))
return;
link_info->imsi_len = imsi_len;
link_info->imsi =
talloc_realloc_size(link_info, link_info->imsi, imsi_len);
OSMO_ASSERT(link_info->imsi != NULL);
memcpy(link_info->imsi, imsi, imsi_len);
}
void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
struct gbproxy_peer *peer, uint32_t new_tlli)
{
if (new_tlli == tlli_state->current)
return;
LOGP(DGPRS, LOGL_INFO,
"The TLLI has been reassigned from %08x to %08x\n",
tlli_state->current, new_tlli);
/* Remember assigned TLLI */
tlli_state->assigned = new_tlli;
tlli_state->bss_validated = false;
tlli_state->net_validated = false;
}
uint32_t gbproxy_map_tlli(uint32_t other_tlli,
struct gbproxy_link_info *link_info, int to_bss)
{
uint32_t tlli = 0;
struct gbproxy_tlli_state *src, *dst;
if (to_bss) {
src = &link_info->sgsn_tlli;
dst = &link_info->tlli;
} else {
src = &link_info->tlli;
dst = &link_info->sgsn_tlli;
}
if (src->current == other_tlli)
tlli = dst->current;
else if (src->assigned == other_tlli)
tlli = dst->assigned;
return tlli;
}
static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
uint32_t tlli, int to_bss)
{
LOGP(DGPRS, LOGL_DEBUG,
"%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
__func__, tlli_state->current, tlli_state->assigned,
tlli_state->net_validated, tlli_state->bss_validated, tlli);
if (!tlli_state->assigned || tlli_state->assigned != tlli)
return;
/* TODO: Is this ok? Check spec */
if (gprs_tlli_type(tlli) != TLLI_LOCAL)
return;
/* See GSM 04.08, 4.7.1.5 */
if (to_bss)
tlli_state->net_validated = true;
else
tlli_state->bss_validated = true;
if (!tlli_state->bss_validated || !tlli_state->net_validated)
return;
LOGP(DGPRS, LOGL_INFO,
"The TLLI %08x has been validated (was %08x)\n",
tlli_state->assigned, tlli_state->current);
tlli_state->current = tlli;
tlli_state->assigned = 0;
}
static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
time_t now)
{
gbproxy_detach_link_info(peer, link_info);
gbproxy_attach_link_info(peer, now, link_info);
}
static int gbproxy_unregister_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
if (!link_info)
return 1;
if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
link_info->tlli.current);
gbproxy_delete_link_info(peer, link_info);
return 1;
}
link_info->tlli.current = 0;
link_info->tlli.assigned = 0;
link_info->sgsn_tlli.current = 0;
link_info->sgsn_tlli.assigned = 0;
link_info->is_deregistered = true;
gbproxy_reset_link(link_info);
return 0;
}
int gbproxy_imsi_matches(struct gbproxy_config *cfg,
enum gbproxy_match_id match_id,
struct gbproxy_link_info *link_info)
{
struct gbproxy_match *match;
OSMO_ASSERT(match_id >= 0 && match_id < ARRAY_SIZE(cfg->matches));
match = &cfg->matches[match_id];
if (!match->enable)
return 1;
return link_info != NULL && link_info->is_matching[match_id];
}
static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
struct gprs_gb_parse_context *parse_ctx)
{
int imsi_matches;
struct gbproxy_link_info *other_link_info;
enum gbproxy_match_id match_id;
/* Make sure that there is a second entry with the same IMSI */
other_link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (other_link_info && other_link_info != link_info) {
char mi_buf[200];
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
parse_ctx->imsi, parse_ctx->imsi_len);
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (IMSI %s re-used)\n",
other_link_info->tlli.current, mi_buf);
gbproxy_delete_link_info(peer, other_link_info);
}
/* Update the IMSI field */
gbproxy_update_link_info(link_info,
parse_ctx->imsi, parse_ctx->imsi_len);
/* Check, whether the IMSI matches */
OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
ARRAY_SIZE(peer->cfg->matches));
for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
++match_id) {
imsi_matches = gbproxy_check_imsi(
&peer->cfg->matches[match_id],
parse_ctx->imsi, parse_ctx->imsi_len);
if (imsi_matches >= 0)
link_info->is_matching[match_id] = imsi_matches ? true : false;
}
}
static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
const struct gbproxy_tlli_state *b)
{
if (a->current && a->current == b->current)
return 1;
if (a->assigned && a->assigned == b->assigned)
return 1;
if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
return 1;
return 0;
}
static void gbproxy_remove_matching_link_infos(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
{
struct gbproxy_link_info *info, *nxt;
struct gbproxy_patch_state *state = &peer->patch_state;
/* Make sure that there is no second entry with the same P-TMSI or TLLI */
llist_for_each_entry_safe(info, nxt, &state->logical_links, list) {
if (info == link_info)
continue;
if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
(link_info->sgsn_nsei != info->sgsn_nsei ||
!gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
continue;
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
info->tlli.current);
gbproxy_delete_link_info(peer, info);
}
}
static struct gbproxy_link_info *gbproxy_get_link_info_ul(
struct gbproxy_peer *peer,
int *tlli_is_valid,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
if (parse_ctx->tlli_enc) {
link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
if (link_info) {
*tlli_is_valid = 1;
return link_info;
}
}
*tlli_is_valid = 0;
if (!link_info && parse_ctx->imsi) {
link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
}
if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
uint32_t bss_ptmsi;
gprs_parse_tmsi(parse_ctx->ptmsi_enc, &bss_ptmsi);
link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
}
if (!link_info)
return NULL;
link_info->is_deregistered = false;
return link_info;
}
struct gbproxy_link_info *gbproxy_update_link_state_ul(
struct gbproxy_peer *peer,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info;
int tlli_is_valid;
link_info = gbproxy_get_link_info_ul(peer, &tlli_is_valid, parse_ctx);
if (parse_ctx->tlli_enc && parse_ctx->llc) {
uint32_t sgsn_tlli;
if (!link_info) {
LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
parse_ctx->tlli);
link_info = gbproxy_link_info_alloc(peer);
gbproxy_attach_link_info(peer, now, link_info);
/* Setup TLLIs */
sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
link_info->sgsn_tlli.current = sgsn_tlli;
link_info->tlli.current = parse_ctx->tlli;
} else if (!tlli_is_valid) {
/* New TLLI (info found by IMSI or P-TMSI) */
link_info->tlli.current = parse_ctx->tlli;
link_info->tlli.assigned = 0;
link_info->sgsn_tlli.current =
gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
link_info->sgsn_tlli.assigned = 0;
gbproxy_touch_link_info(peer, link_info, now);
} else {
sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
if (!sgsn_tlli)
sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
gbproxy_validate_tlli(&link_info->tlli,
parse_ctx->tlli, 0);
gbproxy_validate_tlli(&link_info->sgsn_tlli,
sgsn_tlli, 0);
gbproxy_touch_link_info(peer, link_info, now);
}
} else if (link_info) {
gbproxy_touch_link_info(peer, link_info, now);
}
if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
gbproxy_assign_imsi(peer, link_info, parse_ctx);
return link_info;
}
static struct gbproxy_link_info *gbproxy_get_link_info_dl(
struct gbproxy_peer *peer,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
/* Which key to use depends on its availability only, if that fails, do
* not retry it with another key (e.g. IMSI). */
if (parse_ctx->tlli_enc)
link_info = gbproxy_link_info_by_sgsn_tlli(peer, parse_ctx->tlli,
parse_ctx->peer_nsei);
/* TODO: Get link_info by (SGSN) P-TMSI if that is available (see
* GSM 08.18, 7.2) instead of using the IMSI as key. */
else if (parse_ctx->imsi)
link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (link_info)
link_info->is_deregistered = false;
return link_info;
}
struct gbproxy_link_info *gbproxy_update_link_state_dl(
struct gbproxy_peer *peer,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
/* A new P-TMSI has been signalled in the message,
* register new TLLI */
uint32_t new_sgsn_ptmsi;
uint32_t new_bss_ptmsi = GSM_RESERVED_TMSI;
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_sgsn_ptmsi);
if (link_info->sgsn_tlli.ptmsi == new_sgsn_ptmsi)
new_bss_ptmsi = link_info->tlli.ptmsi;
if (new_bss_ptmsi == GSM_RESERVED_TMSI)
new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Got new PTMSI %08x from SGSN, using %08x for BSS\n",
new_sgsn_ptmsi, new_bss_ptmsi);
/* Setup PTMSIs */
link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
link_info->tlli.ptmsi = new_bss_ptmsi;
} else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
!peer->cfg->patch_ptmsi) {
/* A new P-TMSI has been signalled in the message with an unknown
* TLLI, create a new link_info */
/* TODO: Add a test case for this branch */
uint32_t new_ptmsi;
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
parse_ctx->tlli, new_ptmsi);
link_info = gbproxy_link_info_alloc(peer);
link_info->sgsn_tlli.current = parse_ctx->tlli;
link_info->tlli.current = parse_ctx->tlli;
link_info->sgsn_tlli.ptmsi = new_ptmsi;
link_info->tlli.ptmsi = new_ptmsi;
gbproxy_attach_link_info(peer, now, link_info);
} else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
!peer->cfg->patch_ptmsi) {
/* Unknown SGSN TLLI, create a new link_info */
uint32_t new_ptmsi;
link_info = gbproxy_link_info_alloc(peer);
LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
parse_ctx->tlli);
gbproxy_attach_link_info(peer, now, link_info);
/* Setup TLLIs */
link_info->sgsn_tlli.current = parse_ctx->tlli;
link_info->tlli.current = parse_ctx->tlli;
if (!parse_ctx->new_ptmsi_enc)
return link_info;
/* A new P-TMSI has been signalled in the message */
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Assigning new P-TMSI %08x\n", new_ptmsi);
/* Setup P-TMSIs */
link_info->sgsn_tlli.ptmsi = new_ptmsi;
link_info->tlli.ptmsi = new_ptmsi;
} else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
link_info, 1);
gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
gbproxy_touch_link_info(peer, link_info, now);
} else if (link_info) {
gbproxy_touch_link_info(peer, link_info, now);
}
if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
gbproxy_assign_imsi(peer, link_info, parse_ctx);
return link_info;
}
int gbproxy_update_link_state_after(
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
int rc = 0;
if (parse_ctx->invalidate_tlli && link_info) {
int keep_info =
peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
(peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
parse_ctx->await_reattach) ||
(peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
link_info->imsi_len > 0);
if (keep_info) {
LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
link_info->tlli.current);
rc = gbproxy_unregister_link_info(peer, link_info);
} else {
LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
link_info->tlli.current);
gbproxy_delete_link_info(peer, link_info);
rc = 1;
}
} else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
parse_ctx->new_ptmsi_enc && link_info) {
/* A new PTMSI has been signaled in the message,
* register new TLLI */
uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
uint32_t new_sgsn_tlli;
uint32_t new_bss_tlli = 0;
new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
if (new_bss_ptmsi != GSM_RESERVED_TMSI)
new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
LOGP(DGPRS, LOGL_INFO,
"Assigning new TLLI %08x to SGSN, %08x to BSS\n",
new_sgsn_tlli, new_bss_tlli);
gbproxy_reassign_tlli(&link_info->sgsn_tlli,
peer, new_sgsn_tlli);
gbproxy_reassign_tlli(&link_info->tlli,
peer, new_bss_tlli);
gbproxy_remove_matching_link_infos(peer, link_info);
}
gbproxy_remove_stale_link_infos(peer, now);
return rc;
}

View File

@@ -1,926 +0,0 @@
/*
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <inttypes.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
static struct gbproxy_config *g_cfg = NULL;
/*
* vty code for gbproxy below
*/
static struct cmd_node gbproxy_node = {
GBPROXY_NODE,
"%s(config-gbproxy)# ",
1,
};
static const struct value_string keep_modes[] = {
{GBPROX_KEEP_NEVER, "never"},
{GBPROX_KEEP_REATTACH, "re-attach"},
{GBPROX_KEEP_IDENTIFIED, "identified"},
{GBPROX_KEEP_ALWAYS, "always"},
{0, NULL}
};
static const struct value_string match_ids[] = {
{GBPROX_MATCH_PATCHING, "patching"},
{GBPROX_MATCH_ROUTING, "routing"},
{0, NULL}
};
static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
{
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, peer->ra);
vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
"RAI %s", peer->nsei, peer->bvci, osmo_rai_name(&raid));
if (peer->blocked)
vty_out(vty, " [BVC-BLOCKED]");
vty_out(vty, "%s", VTY_NEWLINE);
}
static int config_write_gbproxy(struct vty *vty)
{
enum gbproxy_match_id match_id;
vty_out(vty, "gbproxy%s", VTY_NEWLINE);
vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
VTY_NEWLINE);
if (g_cfg->core_plmn.mcc > 0)
vty_out(vty, " core-mobile-country-code %s%s",
osmo_mcc_name(g_cfg->core_plmn.mcc), VTY_NEWLINE);
if (g_cfg->core_plmn.mnc > 0)
vty_out(vty, " core-mobile-network-code %s%s",
osmo_mnc_name(g_cfg->core_plmn.mnc, g_cfg->core_plmn.mnc_3_digits), VTY_NEWLINE);
for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id) {
struct gbproxy_match *match = &g_cfg->matches[match_id];
if (match->re_str)
vty_out(vty, " match-imsi %s %s%s",
get_value_string(match_ids, match_id),
match->re_str, VTY_NEWLINE);
}
if (g_cfg->core_apn != NULL) {
if (g_cfg->core_apn_size > 0) {
char str[500] = {0};
vty_out(vty, " core-access-point-name %s%s",
osmo_apn_to_str(str, g_cfg->core_apn,
g_cfg->core_apn_size),
VTY_NEWLINE);
} else {
vty_out(vty, " core-access-point-name none%s",
VTY_NEWLINE);
}
}
if (g_cfg->route_to_sgsn2)
vty_out(vty, " secondary-sgsn nsei %u%s", g_cfg->nsip_sgsn2_nsei,
VTY_NEWLINE);
if (g_cfg->clean_stale_timer_freq > 0)
vty_out(vty, " link-list clean-stale-timer %u%s",
g_cfg->clean_stale_timer_freq, VTY_NEWLINE);
if (g_cfg->tlli_max_age > 0)
vty_out(vty, " link-list max-age %d%s",
g_cfg->tlli_max_age, VTY_NEWLINE);
if (g_cfg->tlli_max_len > 0)
vty_out(vty, " link-list max-length %d%s",
g_cfg->tlli_max_len, VTY_NEWLINE);
vty_out(vty, " link-list keep-mode %s%s",
get_value_string(keep_modes, g_cfg->keep_link_infos),
VTY_NEWLINE);
if (g_cfg->stored_msgs_max_len > 0)
vty_out(vty, " link stored-msgs-max-length %"PRIu32"%s",
g_cfg->stored_msgs_max_len, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy,
cfg_gbproxy_cmd,
"gbproxy",
"Configure the Gb proxy")
{
vty->node = GBPROXY_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_nsip_sgsn_nsei,
cfg_nsip_sgsn_nsei_cmd,
"sgsn nsei <0-65534>",
"SGSN information\n"
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
{
unsigned int nsei = atoi(argv[0]);
if (g_cfg->route_to_sgsn2 && g_cfg->nsip_sgsn2_nsei == nsei) {
vty_out(vty, "SGSN NSEI %d conflicts with secondary SGSN NSEI%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->nsip_sgsn_nsei = nsei;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n"
DEFUN(cfg_gbproxy_core_mnc,
cfg_gbproxy_core_mnc_cmd,
"core-mobile-network-code <1-999>",
GBPROXY_CORE_MNC_STR "NCC value\n")
{
uint16_t mnc;
bool mnc_3_digits;
if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
vty_out(vty, "%% Invalid MNC: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->core_plmn.mnc = mnc;
g_cfg->core_plmn.mnc_3_digits = mnc_3_digits;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_core_mnc,
cfg_gbproxy_no_core_mnc_cmd,
"no core-mobile-network-code",
NO_STR GBPROXY_CORE_MNC_STR)
{
g_cfg->core_plmn.mnc = 0;
g_cfg->core_plmn.mnc_3_digits = false;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n"
DEFUN(cfg_gbproxy_core_mcc,
cfg_gbproxy_core_mcc_cmd,
"core-mobile-country-code <1-999>",
GBPROXY_CORE_MCC_STR "MCC value\n")
{
g_cfg->core_plmn.mcc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_core_mcc,
cfg_gbproxy_no_core_mcc_cmd,
"no core-mobile-country-code",
NO_STR GBPROXY_CORE_MCC_STR)
{
g_cfg->core_plmn.mcc = 0;
return CMD_SUCCESS;
}
#define GBPROXY_MATCH_IMSI_STR "Restrict actions to certain IMSIs\n"
DEFUN(cfg_gbproxy_match_imsi,
cfg_gbproxy_match_imsi_cmd,
"match-imsi (patching|routing) .REGEXP",
GBPROXY_MATCH_IMSI_STR
"Patch MS related information elements on match only\n"
"Route to the secondary SGSN on match only\n"
"Regular expression for the IMSI match\n")
{
const char *filter = argv[1];
const char *err_msg = NULL;
struct gbproxy_match *match;
enum gbproxy_match_id match_id = get_string_value(match_ids, argv[0]);
OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
match_id < GBPROX_MATCH_LAST);
match = &g_cfg->matches[match_id];
if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
vty_out(vty, "Match expression invalid: %s%s",
err_msg, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_match_imsi,
cfg_gbproxy_no_match_imsi_cmd,
"no match-imsi",
NO_STR GBPROXY_MATCH_IMSI_STR)
{
enum gbproxy_match_id match_id;
for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
g_cfg->acquire_imsi = false;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n"
#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n"
static int set_core_apn(struct vty *vty, const char *apn)
{
int apn_len;
if (!apn) {
talloc_free(g_cfg->core_apn);
g_cfg->core_apn = NULL;
g_cfg->core_apn_size = 0;
return CMD_SUCCESS;
}
apn_len = strlen(apn);
if (apn_len >= 100) {
vty_out(vty, "APN string too long (max 99 chars)%s",
VTY_NEWLINE);
return CMD_WARNING;
}
if (apn_len == 0) {
talloc_free(g_cfg->core_apn);
/* TODO: replace NULL */
g_cfg->core_apn = talloc_zero_size(NULL, 2);
g_cfg->core_apn_size = 0;
} else {
/* TODO: replace NULL */
g_cfg->core_apn =
talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1);
g_cfg->core_apn_size =
gprs_str_to_apn(g_cfg->core_apn, apn_len + 1, apn);
}
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_core_apn,
cfg_gbproxy_core_apn_cmd,
"core-access-point-name (APN|none)",
GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR)
{
if (strcmp(argv[0], "none") == 0)
return set_core_apn(vty, "");
else
return set_core_apn(vty, argv[0]);
}
DEFUN(cfg_gbproxy_no_core_apn,
cfg_gbproxy_no_core_apn_cmd,
"no core-access-point-name",
NO_STR GBPROXY_CORE_APN_STR)
{
return set_core_apn(vty, NULL);
}
/* TODO: Remove the patch-ptmsi command, since P-TMSI patching is enabled
* automatically when needed. This command is only left for manual testing
* (e.g. doing P-TMSI patching without using a secondary SGSN)
*/
#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
DEFUN(cfg_gbproxy_patch_ptmsi,
cfg_gbproxy_patch_ptmsi_cmd,
"patch-ptmsi",
GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = true;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_patch_ptmsi,
cfg_gbproxy_no_patch_ptmsi_cmd,
"no patch-ptmsi",
NO_STR GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = false;
return CMD_SUCCESS;
}
/* TODO: Remove the acquire-imsi command, since that feature is enabled
* automatically when IMSI matching is enabled. This command is only left for
* manual testing (e.g. doing IMSI acquisition without IMSI based patching)
*/
#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
DEFUN(cfg_gbproxy_acquire_imsi,
cfg_gbproxy_acquire_imsi_cmd,
"acquire-imsi",
GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_acquire_imsi,
cfg_gbproxy_no_acquire_imsi_cmd,
"no acquire-imsi",
NO_STR GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = false;
return CMD_SUCCESS;
}
#define GBPROXY_SECOND_SGSN_STR "Route matching LLC connections to a second SGSN (Experimental)\n"
DEFUN(cfg_gbproxy_secondary_sgsn,
cfg_gbproxy_secondary_sgsn_cmd,
"secondary-sgsn nsei <0-65534>",
GBPROXY_SECOND_SGSN_STR
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
{
unsigned int nsei = atoi(argv[0]);
if (g_cfg->nsip_sgsn_nsei == nsei) {
vty_out(vty, "Secondary SGSN NSEI %d conflicts with primary SGSN NSEI%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->route_to_sgsn2 = true;
g_cfg->nsip_sgsn2_nsei = nsei;
g_cfg->patch_ptmsi = true;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_secondary_sgsn,
cfg_gbproxy_no_secondary_sgsn_cmd,
"no secondary-sgsn",
NO_STR GBPROXY_SECOND_SGSN_STR)
{
g_cfg->route_to_sgsn2 = false;
g_cfg->nsip_sgsn2_nsei = 0xFFFF;
g_cfg->patch_ptmsi = false;
return CMD_SUCCESS;
}
#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
#define GBPROXY_LINK_STR "Set TLLI parameters\n"
#define GBPROXY_CLEAN_STALE_TIMER_STR "Periodic timer to clean stale links\n"
DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
cfg_gbproxy_link_list_clean_stale_timer_cmd,
"link-list clean-stale-timer <1-999999>",
GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR
"Frequency at which the periodic timer is fired (in seconds)\n")
{
struct gbproxy_peer *peer;
g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
/* Re-schedule running timers soon in case prev frequency was really big
and new frequency is desired to be lower. After initial run, periodic
time is used. Use random() to avoid firing timers for all peers at
the same time */
llist_for_each_entry(peer, &g_cfg->bts_peers, list)
osmo_timer_schedule(&peer->clean_stale_timer,
random() % 5, random() % 1000000);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
cfg_gbproxy_link_list_no_clean_stale_timer_cmd,
"no link-list clean-stale-timer",
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)
{
struct gbproxy_peer *peer;
g_cfg->clean_stale_timer_freq = 0;
llist_for_each_entry(peer, &g_cfg->bts_peers, list)
osmo_timer_del(&peer->clean_stale_timer);
return CMD_SUCCESS;
}
#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
DEFUN(cfg_gbproxy_link_list_max_age,
cfg_gbproxy_link_list_max_age_cmd,
"link-list max-age <1-999999>",
GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR
"Maximum age in seconds\n")
{
g_cfg->tlli_max_age = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_no_max_age,
cfg_gbproxy_link_list_no_max_age_cmd,
"no link-list max-age",
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR)
{
g_cfg->tlli_max_age = 0;
return CMD_SUCCESS;
}
#define GBPROXY_MAX_LEN_STR "Limit list length\n"
DEFUN(cfg_gbproxy_link_list_max_len,
cfg_gbproxy_link_list_max_len_cmd,
"link-list max-length <1-99999>",
GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR
"Maximum number of logical links in the list\n")
{
g_cfg->tlli_max_len = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_no_max_len,
cfg_gbproxy_link_list_no_max_len_cmd,
"no link-list max-length",
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR)
{
g_cfg->tlli_max_len = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_keep_mode,
cfg_gbproxy_link_list_keep_mode_cmd,
"link-list keep-mode (never|re-attach|identified|always)",
GBPROXY_LINK_LIST_STR "How to keep entries for detached logical links\n"
"Discard entry immediately after detachment\n"
"Keep entry if a re-attachment has be requested\n"
"Keep entry if it associated with an IMSI\n"
"Don't discard entries after detachment\n")
{
int val = get_string_value(keep_modes, argv[0]);
OSMO_ASSERT(val >= GBPROX_KEEP_NEVER && val <= GBPROX_KEEP_ALWAYS);
g_cfg->keep_link_infos = val;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_stored_msgs_max_len,
cfg_gbproxy_link_stored_msgs_max_len_cmd,
"link stored-msgs-max-length <1-99999>",
GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR
"Maximum number of msgb stored in the logical link waiting to acquire its IMSI\n")
{
g_cfg->stored_msgs_max_len = (uint32_t) atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_no_stored_msgs_max_len,
cfg_gbproxy_link_no_stored_msgs_max_len_cmd,
"no link stored-msgs-max-length",
NO_STR GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR)
{
g_cfg->stored_msgs_max_len = 0;
return CMD_SUCCESS;
}
DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
{
struct gbproxy_peer *peer;
int show_stats = argc >= 1;
if (show_stats)
vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
gbprox_vty_print_peer(vty, peer);
if (show_stats)
vty_out_rate_ctr_group(vty, " ", peer->ctrg);
}
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
{
struct gbproxy_peer *peer;
char mi_buf[200];
time_t now;
struct timespec ts = {0,};
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
gbprox_vty_print_peer(vty, peer);
llist_for_each_entry(link_info, &state->logical_links, list) {
time_t age = now - link_info->timestamp;
if (link_info->imsi > 0) {
snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
link_info->imsi,
link_info->imsi_len);
} else {
snprintf(mi_buf, sizeof(mi_buf), "(none)");
}
vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
link_info->tlli.current, mi_buf, (int)age);
if (link_info->stored_msgs_len)
vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
link_info->stored_msgs_len,
g_cfg->stored_msgs_max_len);
if (g_cfg->route_to_sgsn2)
vty_out(vty, ", SGSN NSEI %d",
link_info->sgsn_nsei);
if (link_info->is_deregistered)
vty_out(vty, ", DE-REGISTERED");
vty_out(vty, "%s", VTY_NEWLINE);
}
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
"delete-gbproxy-peer <0-65534> bvci <2-65534>",
"Delete a GBProxy peer by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete peer with a matching BVCI\n"
"BVCI number\n")
{
const uint16_t nsei = atoi(argv[0]);
const uint16_t bvci = atoi(argv[1]);
int counter;
counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
if (counter == 0) {
vty_out(vty, "BVC not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
"delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
"Delete a GBProxy peer by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete BSSGP connections (BVC)\n"
"Only delete dynamic NS connections (NS-VC)\n"
"Delete BVC and dynamic NS connections\n"
"Show what would be deleted instead of actually deleting\n"
)
{
const uint16_t nsei = atoi(argv[0]);
const char *mode = argv[1];
int dry_run = argc > 2;
int delete_bvc = 0;
int delete_nsvc = 0;
int counter;
if (strcmp(mode, "only-bvc") == 0)
delete_bvc = 1;
else if (strcmp(mode, "only-nsvc") == 0)
delete_nsvc = 1;
else
delete_bvc = delete_nsvc = 1;
if (delete_bvc) {
if (!dry_run)
counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
else {
struct gbproxy_peer *peer;
counter = 0;
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
if (peer->nsei != nsei)
continue;
vty_out(vty, "BVC: ");
gbprox_vty_print_peer(vty, peer);
counter += 1;
}
}
vty_out(vty, "%sDeleted %d BVC%s",
dry_run ? "Not " : "", counter, VTY_NEWLINE);
}
if (delete_nsvc) {
struct gprs_ns_inst *nsi = g_cfg->nsi;
struct gprs_nsvc *nsvc, *nsvc2;
counter = 0;
llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
if (nsvc->nsei != nsei)
continue;
if (nsvc->persistent)
continue;
if (!dry_run)
gprs_nsvc_delete(nsvc);
else
vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
"remote %s%s",
nsvc->nsei, nsvc->nsvci,
gprs_ns_ll_str(nsvc), VTY_NEWLINE);
counter += 1;
}
vty_out(vty, "%sDeleted %d NS-VC%s",
dry_run ? "Not " : "", counter, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
#define GBPROXY_DELETE_LINK_STR \
"Delete a GBProxy logical link entry by NSEI and identification\nNSEI number\n"
DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
"delete-gbproxy-link <0-65534> (tlli|imsi|sgsn-nsei) IDENT",
GBPROXY_DELETE_LINK_STR
"Delete entries with a matching TLLI (hex)\n"
"Delete entries with a matching IMSI\n"
"Delete entries with a matching SGSN NSEI\n"
"Identification to match\n")
{
const uint16_t nsei = atoi(argv[0]);
enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match;
uint32_t ident = 0;
const char *imsi = NULL;
struct gbproxy_peer *peer = 0;
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state;
char mi_buf[200];
int found = 0;
match = argv[1][0];
switch (match) {
case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break;
case MATCH_IMSI: imsi = argv[2]; break;
case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break;
};
peer = gbproxy_peer_by_nsei(g_cfg, nsei);
if (!peer) {
vty_out(vty, "Didn't find peer with NSEI %d%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
state = &peer->patch_state;
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
switch (match) {
case MATCH_TLLI:
if (link_info->tlli.current != ident)
continue;
break;
case MATCH_SGSN:
if (link_info->sgsn_nsei != ident)
continue;
break;
case MATCH_IMSI:
if (!link_info->imsi)
continue;
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
link_info->imsi,
link_info->imsi_len);
if (strcmp(mi_buf, imsi) != 0)
continue;
break;
}
vty_out(vty, "Deleting link with TLLI %08x%s", link_info->tlli.current,
VTY_NEWLINE);
gbproxy_delete_link_info(peer, link_info);
found += 1;
}
if (!found && argc >= 2) {
vty_out(vty, "Didn't find link entry with %s %s%s",
argv[1], argv[2], VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_link, delete_gb_link_cmd,
"delete-gbproxy-link <0-65534> (stale|de-registered)",
GBPROXY_DELETE_LINK_STR
"Delete stale entries\n"
"Delete de-registered entries\n")
{
const uint16_t nsei = atoi(argv[0]);
enum {MATCH_STALE = 's', MATCH_DEREGISTERED = 'd'} match;
struct gbproxy_peer *peer = 0;
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state;
time_t now;
struct timespec ts = {0,};
int found = 0;
match = argv[1][0];
peer = gbproxy_peer_by_nsei(g_cfg, nsei);
if (!peer) {
vty_out(vty, "Didn't find peer with NSEI %d%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
state = &peer->patch_state;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
if (match == MATCH_STALE) {
found = gbproxy_remove_stale_link_infos(peer, now);
if (found)
vty_out(vty, "Deleted %d stale logical link%s%s",
found, found == 1 ? "" : "s", VTY_NEWLINE);
} else {
llist_for_each_entry_safe(link_info, nxt,
&state->logical_links, list) {
if (!link_info->is_deregistered)
continue;
gbproxy_delete_link_info(peer, link_info);
found += 1;
}
}
if (found)
vty_out(vty, "Deleted %d %s logical link%s%s",
found, argv[1], found == 1 ? "" : "s", VTY_NEWLINE);
return CMD_SUCCESS;
}
/*
* legacy commands to provide an upgrade path from "broken" releases
* or pre-releases
*/
DEFUN_DEPRECATED(cfg_gbproxy_broken_apn_match,
cfg_gbproxy_broken_apn_match_cmd,
"core-access-point-name none match-imsi .REGEXP",
GBPROXY_CORE_APN_STR GBPROXY_MATCH_IMSI_STR "Remove APN\n"
"Patch MS related information elements on match only\n"
"Route to the secondary SGSN on match only\n"
"Regular expression for the IMSI match\n")
{
const char *filter = argv[0];
const char *err_msg = NULL;
struct gbproxy_match *match;
enum gbproxy_match_id match_id = get_string_value(match_ids, "patching");
/* apply APN none */
set_core_apn(vty, "");
/* do the matching... with copy and paste */
OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
match_id < GBPROX_MATCH_LAST);
match = &g_cfg->matches[match_id];
if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
vty_out(vty, "Match expression invalid: %s%s",
err_msg, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}
#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
#define GBPROXY_MAX_LEN_STR "Limit list length\n"
DEFUN_DEPRECATED(cfg_gbproxy_depr_tlli_list_max_len,
cfg_gbproxy_depr_tlli_list_max_len_cmd,
"tlli-list max-length <1-99999>",
GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR
"Maximum number of TLLIs in the list\n")
{
g_cfg->tlli_max_len = atoi(argv[0]);
return CMD_SUCCESS;
}
int gbproxy_vty_init(void)
{
install_element_ve(&show_gbproxy_cmd);
install_element_ve(&show_gbproxy_links_cmd);
install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
install_element(ENABLE_NODE, &delete_gb_link_by_id_cmd);
install_element(ENABLE_NODE, &delete_gb_link_cmd);
install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
install_node(&gbproxy_node, config_write_gbproxy);
install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_match_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_secondary_sgsn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_clean_stale_timer_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_keep_mode_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_stored_msgs_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_match_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_secondary_sgsn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_clean_stale_timer_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_no_stored_msgs_max_len_cmd);
/* broken or deprecated to allow an upgrade path */
install_element(GBPROXY_NODE, &cfg_gbproxy_broken_apn_match_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_depr_tlli_list_max_len_cmd);
return 0;
}
int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
{
int rc;
g_cfg = cfg;
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
return rc;
}
return 0;
}

View File

@@ -437,6 +437,47 @@ int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
}
/*! Determine the TLLI from the given BSSGP message.
* \param[in] bssgp pointer to start of BSSGP header
* \param[in] bssgp_len length of BSSGP message in octets
* \param[out] tlli TLLI (if any) in host byte order
* \returns 1 if TLLI found; 0 if none found; negative on parse error */
int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli)
{
const struct bssgp_normal_hdr *bgph;
uint8_t pdu_type;
if (bssgp_len < sizeof(struct bssgp_normal_hdr))
return -EINVAL;
bgph = (struct bssgp_normal_hdr *)bssgp;
pdu_type = bgph->pdu_type;
if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
pdu_type == BSSGP_PDUT_DL_UNITDATA) {
const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *)bssgp;
if (bssgp_len < sizeof(struct bssgp_ud_hdr))
return -EINVAL;
*tlli = osmo_load32be((const uint8_t *)&budh->tlli);
return 1;
} else {
const uint8_t *data = bgph->data;
size_t data_len = bssgp_len - sizeof(*bgph);
struct tlv_parsed tp;
if (bssgp_tlv_parse(&tp, data, data_len) < 0)
return -EINVAL;
if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
*tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
return 1;
}
}
/* No TLLI present in message */
return 0;
}
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
struct gprs_gb_parse_context *parse_ctx)
{
@@ -604,13 +645,12 @@ void gprs_gb_log_parse_context(int log_level,
}
if (parse_ctx->imsi) {
char mi_buf[200];
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
parse_ctx->imsi, parse_ctx->imsi_len);
LOGPC(DGPRS, log_level, "%s IMSI %s",
sep, mi_buf);
sep = ",";
struct osmo_mobile_identity mi;
if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0
&& mi.type == GSM_MI_TYPE_IMSI) {
LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);
sep = ",";
}
}
if (parse_ctx->invalidate_tlli) {
LOGPC(DGPRS, log_level, "%s invalidate", sep);

View File

@@ -22,7 +22,7 @@
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>

View File

@@ -51,8 +51,8 @@ static int ares_osmo_fd_cb(struct osmo_fd *fd, unsigned int what)
LOGP(DGPRS, LOGL_DEBUG, "C-ares fd(%d) ready(%d)\n", fd->fd, what);
ares_process_fd(sgsn->ares_channel,
(what & BSC_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
(what & BSC_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
(what & OSMO_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
(what & OSMO_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
osmo_ares_reschedule(sgsn);
return 0;
}
@@ -120,14 +120,14 @@ static void setup_ares_osmo_fd(void *data, int fd, int read, int write)
update_fd:
if (read)
ufd->fd.when |= BSC_FD_READ;
osmo_fd_read_enable(&ufd->fd);
else
ufd->fd.when &= ~BSC_FD_READ;
osmo_fd_read_disable(&ufd->fd);
if (write)
ufd->fd.when |= BSC_FD_WRITE;
osmo_fd_write_enable(&ufd->fd);
else
ufd->fd.when &= ~BSC_FD_WRITE;
osmo_fd_write_disable(&ufd->fd);
osmo_ares_reschedule(sgsn);
}

View File

@@ -59,15 +59,6 @@ void *osmo_gtphub_ctx;
/* TODO move this to osmocom/core/select.h ? */
typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
/* TODO move this to osmocom/core/linuxlist.h ? */
#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
#define llist_first(head, type, entry) \
llist_entry(__llist_first(head), type, entry)
#define __llist_last(head) (((head)->next == (head)) ? NULL : (head)->prev)
#define llist_last(head, type, entry) \
llist_entry(__llist_last(head), type, entry)
/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */
enum gtp_rc {
@@ -167,12 +158,12 @@ void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src)
}
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
const struct osmo_sockaddr *sa)
const struct sgsn_sockaddr *sa)
{
char addr_str[256];
char port_str[6];
if (osmo_sockaddr_to_strs(addr_str, sizeof(addr_str),
if (sgsn_sockaddr_to_strs(addr_str, sizeof(addr_str),
port_str, sizeof(port_str),
sa, (NI_NUMERICHOST | NI_NUMERICSERV))
!= 0) {
@@ -613,7 +604,7 @@ void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now)
OSMO_ASSERT(llist_empty(&exq->items)
|| (item->expiry
>= llist_last(&exq->items, struct expiring_item, entry)->expiry));
>= llist_last_entry(&exq->items, struct expiring_item, entry)->expiry));
/* Add/move to the tail to always sort by expiry, ascending. */
llist_del(&item->entry);
@@ -853,10 +844,7 @@ static int gtphub_sock_init(struct osmo_fd *ofd,
return -1;
}
ofd->when = BSC_FD_READ;
ofd->cb = cb;
ofd->data = data;
ofd->priv_nr = ofd_id;
osmo_fd_setup(ofd, -1, OSMO_FD_READ, cb, data, ofd_id);
int rc;
rc = osmo_sock_init_ofd(ofd,
@@ -925,7 +913,7 @@ static void gtphub_bind_stop(struct gtphub_bind *b) {
/* Recv datagram from from->fd, write sender's address to *from_addr.
* Return the number of bytes read, zero on error. */
static int gtphub_read(const struct osmo_fd *from,
struct osmo_sockaddr *from_addr,
struct sgsn_sockaddr *from_addr,
uint8_t *buf, size_t buf_len)
{
OSMO_ASSERT(from_addr);
@@ -946,7 +934,7 @@ static int gtphub_read(const struct osmo_fd *from,
}
LOG(LOGL_DEBUG, "Received %d bytes from %s: %s%s\n",
(int)received, osmo_sockaddr_to_str(from_addr),
(int)received, sgsn_sockaddr_to_str(from_addr),
osmo_hexdump(buf, received > 1000? 1000 : received),
received > 1000 ? "..." : "");
@@ -1145,9 +1133,7 @@ static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf,
if (llist_empty(&peer->addresses))
return "(addressless)";
struct gtphub_peer_addr *a = llist_first(&peer->addresses,
struct gtphub_peer_addr,
entry);
struct gtphub_peer_addr *a = llist_first_entry_or_null(&peer->addresses, struct gtphub_peer_addr, entry);
return gsn_addr_to_strb(&a->addr, buf, buflen);
}
@@ -1948,14 +1934,14 @@ static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what)
LOG(LOGL_DEBUG, "=== reading from SGSN (%s)\n",
gtphub_plane_idx_names[plane_idx]);
if (!(what & BSC_FD_READ))
if (!(what & OSMO_FD_READ))
return 0;
struct gtphub *hub = from_sgsns_ofd->data;
static uint8_t buf[4096];
struct osmo_sockaddr from_addr;
struct osmo_sockaddr to_addr;
struct sgsn_sockaddr from_addr;
struct sgsn_sockaddr to_addr;
struct osmo_fd *to_ofd;
int len;
uint8_t *reply_buf;
@@ -1979,14 +1965,14 @@ static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what)
OSMO_ASSERT(plane_idx < GTPH_PLANE_N);
LOG(LOGL_DEBUG, "=== reading from GGSN (%s)\n",
gtphub_plane_idx_names[plane_idx]);
if (!(what & BSC_FD_READ))
if (!(what & OSMO_FD_READ))
return 0;
struct gtphub *hub = from_ggsns_ofd->data;
static uint8_t buf[4096];
struct osmo_sockaddr from_addr;
struct osmo_sockaddr to_addr;
struct sgsn_sockaddr from_addr;
struct sgsn_sockaddr to_addr;
struct osmo_fd *to_ofd;
int len;
uint8_t *reply_buf;
@@ -2071,9 +2057,9 @@ static int gtphub_unmap(struct gtphub *hub,
static int gsn_addr_to_sockaddr(struct gsn_addr *src,
uint16_t port,
struct osmo_sockaddr *dst)
struct sgsn_sockaddr *dst)
{
return osmo_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
return sgsn_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
}
/* If p is an Echo request, replace p's data with the matching response and
@@ -2107,7 +2093,7 @@ static int gtphub_handle_echo_req(struct gtphub *hub, struct gtp_packet_desc *p,
}
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr);
const struct sgsn_sockaddr *addr);
/* Parse buffer as GTP packet, replace elements in-place and return the ofd and
* address to forward to. Return a pointer to the osmo_fd, but copy the
@@ -2117,13 +2103,13 @@ struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *b
int gtphub_handle_buf(struct gtphub *hub,
unsigned int side_idx,
unsigned int plane_idx,
const struct osmo_sockaddr *from_addr,
const struct sgsn_sockaddr *from_addr,
uint8_t *buf,
size_t received,
time_t now,
uint8_t **reply_buf,
struct osmo_fd **to_ofd,
struct osmo_sockaddr *to_addr)
struct sgsn_sockaddr *to_addr)
{
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
@@ -2138,7 +2124,7 @@ int gtphub_handle_buf(struct gtphub *hub,
(side_idx == GTPH_SIDE_GGSN)? "<-" : "->",
gtphub_plane_idx_names[plane_idx],
gtphub_side_idx_names[side_idx],
osmo_sockaddr_to_str(from_addr),
sgsn_sockaddr_to_str(from_addr),
gtp_type_str(p.type));
if (p.rc <= 0) {
@@ -2146,7 +2132,7 @@ int gtphub_handle_buf(struct gtphub *hub,
gtp_type_str(p.type),
gtphub_side_idx_names[side_idx],
gtphub_plane_idx_names[plane_idx],
osmo_sockaddr_to_str(from_addr));
sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2156,7 +2142,7 @@ int gtphub_handle_buf(struct gtphub *hub,
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
if (reply_len > 0) {
/* It was an echo. Nothing left to do. */
osmo_sockaddr_copy(to_addr, from_addr);
sgsn_sockaddr_copy(to_addr, from_addr);
*to_ofd = &from_bind->ofd;
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
@@ -2165,7 +2151,7 @@ int gtphub_handle_buf(struct gtphub *hub,
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
gtphub_side_idx_names[side_idx],
(int)reply_len, osmo_sockaddr_to_str(to_addr));
(int)reply_len, sgsn_sockaddr_to_str(to_addr));
return reply_len;
}
if (reply_len < 0)
@@ -2178,7 +2164,7 @@ int gtphub_handle_buf(struct gtphub *hub,
* so no-one else is allowed to talk to us from that side. */
struct gtphub_peer_port *from_peer = hub->proxy[side_idx][plane_idx];
if (from_peer) {
if (osmo_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
if (sgsn_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
LOG(LOGL_ERROR,
"Rejecting: %s proxy configured, but GTP packet"
" received on %s bind is from another sender:"
@@ -2186,7 +2172,7 @@ int gtphub_handle_buf(struct gtphub *hub,
gtphub_side_idx_names[side_idx],
gtphub_side_idx_names[side_idx],
gtphub_port_str(from_peer),
osmo_sockaddr_to_str(from_addr));
sgsn_sockaddr_to_str(from_addr));
return -1;
}
}
@@ -2204,7 +2190,7 @@ int gtphub_handle_buf(struct gtphub *hub,
if (side_idx == GTPH_SIDE_GGSN) {
LOG(LOGL_ERROR, "Dropping packet%s: unknown GGSN peer: %s\n",
gtp_type_str(p.type),
osmo_sockaddr_to_str(from_addr));
sgsn_sockaddr_to_str(from_addr));
return -1;
} else {
/* SGSN */
@@ -2216,7 +2202,7 @@ int gtphub_handle_buf(struct gtphub *hub,
"Dropping packet%s: User plane peer was not"
"announced by PDP Context: %s\n",
gtp_type_str(p.type),
osmo_sockaddr_to_str(from_addr));
sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2235,7 +2221,7 @@ int gtphub_handle_buf(struct gtphub *hub,
LOG(LOGL_ERROR, "Dropping packet%s: invalid %s peer: %s\n",
gtp_type_str(p.type),
gtphub_side_idx_names[side_idx],
osmo_sockaddr_to_str(from_addr));
sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2309,7 +2295,7 @@ int gtphub_handle_buf(struct gtphub *hub,
if (!to_peer_from_seq)
gtphub_map_seq(&p, from_peer, to_peer);
osmo_sockaddr_copy(to_addr, &to_peer->sa);
sgsn_sockaddr_copy(to_addr, &to_peer->sa);
*reply_buf = (uint8_t*)p.data;
@@ -2335,7 +2321,7 @@ int gtphub_handle_buf(struct gtphub *hub,
(side_idx == GTPH_SIDE_SGSN)? "-->" : "<--",
gtphub_side_idx_names[other_side_idx(side_idx)],
p.header_tei, p.seq,
(int)received, osmo_sockaddr_to_str(to_addr));
(int)received, sgsn_sockaddr_to_str(to_addr));
return received;
}
@@ -2645,7 +2631,7 @@ static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind,
}
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr)
const struct sgsn_sockaddr *addr)
{
struct gsn_addr gsna;
uint16_t port;
@@ -2762,7 +2748,7 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
/* Find a GGSN peer with a matching address. If the address is known but the
* port not, create a new port for that peer address. */
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr)
const struct sgsn_sockaddr *addr)
{
struct gtphub_peer_addr *pa;
struct gtphub_peer_port *pp;
@@ -2817,7 +2803,7 @@ static int gtphub_resolve_ggsn(struct gtphub *hub,
/* TODO move to osmocom/core/socket.c ? */
/* use this in osmo_sock_init() to remove dup. */
/* Internal: call getaddrinfo for osmo_sockaddr_init(). The caller is required
/* Internal: call getaddrinfo for sgsn_sockaddr_init(). The caller is required
to call freeaddrinfo(*result), iff zero is returned. */
static int _osmo_getaddrinfo(struct addrinfo **result,
uint16_t family, uint16_t type, uint8_t proto,
@@ -2844,7 +2830,7 @@ static int _osmo_getaddrinfo(struct addrinfo **result,
}
/* TODO move to osmocom/core/socket.c ? */
int osmo_sockaddr_init(struct osmo_sockaddr *addr,
int sgsn_sockaddr_init(struct sgsn_sockaddr *addr,
uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port)
{
@@ -2865,9 +2851,9 @@ int osmo_sockaddr_init(struct osmo_sockaddr *addr,
return 0;
}
int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
int sgsn_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
char *port_str, size_t port_str_len,
const struct osmo_sockaddr *addr,
const struct sgsn_sockaddr *addr,
int flags)
{
int rc;
@@ -2896,14 +2882,14 @@ int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
return rc;
}
const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
const char *sgsn_sockaddr_to_strb(const struct sgsn_sockaddr *addr,
char *buf, size_t buf_len)
{
char portbuf[6];
const int portbuf_len = 6;
OSMO_ASSERT(buf_len > portbuf_len);
char *portbuf = buf + buf_len - portbuf_len;
buf_len -= portbuf_len;
if (osmo_sockaddr_to_strs(buf, buf_len,
if (sgsn_sockaddr_to_strs(buf, buf_len,
portbuf, portbuf_len,
addr,
NI_NUMERICHOST | NI_NUMERICSERV))
@@ -2918,17 +2904,17 @@ const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
return buf;
}
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr)
const char *sgsn_sockaddr_to_str(const struct sgsn_sockaddr *addr)
{
static char buf[256];
const char *result = osmo_sockaddr_to_strb(addr, buf, sizeof(buf));
const char *result = sgsn_sockaddr_to_strb(addr, buf, sizeof(buf));
if (! result)
return "(invalid)";
return result;
}
int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
const struct osmo_sockaddr *b)
int sgsn_sockaddr_cmp(const struct sgsn_sockaddr *a,
const struct sgsn_sockaddr *b)
{
if (a == b)
return 0;
@@ -2938,7 +2924,7 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
return 1;
if (a->l != b->l) {
/* Lengths are not the same, but determine the order. Will
* anyone ever sort a list by osmo_sockaddr though...? */
* anyone ever sort a list by sgsn_sockaddr though...? */
int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l);
if (cmp == 0) {
if (a->l < b->l)
@@ -2951,8 +2937,8 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
return memcmp(&a->a, &b->a, a->l);
}
void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
const struct osmo_sockaddr *src)
void sgsn_sockaddr_copy(struct sgsn_sockaddr *dst,
const struct sgsn_sockaddr *src)
{
OSMO_ASSERT(src->l <= sizeof(dst->a));
memcpy(&dst->a, &src->a, src->l);

View File

@@ -95,11 +95,11 @@ void log_cfg(struct gtphub_cfg *cfg)
}
}
static void signal_handler(int signal)
static void signal_handler(int signum)
{
fprintf(stdout, "signal %d received\n", signal);
fprintf(stdout, "signal %d received\n", signum);
switch (signal) {
switch (signum) {
case SIGINT:
case SIGTERM:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
@@ -107,8 +107,16 @@ static void signal_handler(int signal)
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report_full(osmo_gtphub_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
case SIGUSR2:
talloc_report_full(osmo_gtphub_ctx, stderr);
@@ -118,44 +126,12 @@ static void signal_handler(int signal)
}
}
#if BUILD_IU
int gtphub_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
default:
osmo_ss7_vty_go_parent(vty);
}
return vty->node;
}
#endif
int gtphub_vty_is_config_node(struct vty *vty, int node)
{
/* Check if libosmo-sccp declares the node in
* question as config node */
#if BUILD_IU
if (osmo_ss7_is_config_node(vty, node))
return 1;
#endif
switch (node) {
/* add items that are not config */
case CONFIG_NODE:
return 0;
default:
return 1;
}
}
static struct vty_app_info vty_info = {
.name = "OsmoGTPhub",
.version = PACKAGE_VERSION,
#if BUILD_IU
.go_parent_cb = gtphub_vty_go_parent,
.go_parent_cb = osmo_ss7_vty_go_parent,
#endif
.is_config_node = gtphub_vty_is_config_node,
};
struct cmdline_cfg {

View File

@@ -33,13 +33,13 @@
LOGP(DGTPHUB, level, fmt, ##args)
int gtphub_write(const struct osmo_fd *to,
const struct osmo_sockaddr *to_addr,
const struct sgsn_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len)
{
errno = 0;
ssize_t sent = sendto(to->fd, buf, buf_len, 0,
(struct sockaddr*)&to_addr->a, to_addr->l);
LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr));
LOG(LOGL_DEBUG, "to %s\n", sgsn_sockaddr_to_str(to_addr));
if (sent == -1) {
LOG(LOGL_ERROR, "error: %s\n", strerror(errno));

View File

@@ -62,6 +62,7 @@ osmo_sgsn_SOURCES = \
sgsn_auth.c \
gprs_subscriber.c \
sgsn_cdr.c \
sgsn_rim.c \
slhc.c \
gprs_llc_xid.c \
v42bis.c \

View File

@@ -25,6 +25,9 @@
#include <osmocom/gprs/gprs_msgb.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/sgsn/gprs_llc.h>
#include "bscconfig.h"
@@ -35,7 +38,8 @@
#include <osmocom/sgsn/debug.h>
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx) {
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) {
msgid2mmctx(mmctx, msg);
if (mmctx->gb.llme)
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
}
@@ -53,10 +57,9 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
if (mmctx) {
msgid2mmctx(mmctx, msg);
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
mmctx->gb.llme = llme;
gprs_gb_recv_pdu(mmctx);
gprs_gb_recv_pdu(mmctx, msg);
}
/* MMCTX can be NULL */
@@ -103,3 +106,83 @@ int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
return rc;
}
/* called by the bssgp layer to send NS PDUs */
int gprs_gb_send_cb(void *ctx, struct msgb *msg)
{
struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
struct osmo_gprs_ns2_prim nsp = {};
nsp.nsei = msgb_nsei(msg);
nsp.bvci = msgb_bvci(msg);
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
return gprs_ns2_recv_prim(nsi, &nsp.oph);
}
void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
{
switch (nsp->u.status.cause) {
case GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED:
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d SNS configured.\n", nsp->nsei);
break;
case GPRS_NS2_AFF_CAUSE_RECOVERY:
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d became available\n", nsp->nsei);
/* workaround for broken BSS which doesn't respond correct to BSSGP status message.
* Sent a BSSGP Reset when a persistent NSVC comes up for the first time. */
if (nsp->u.status.first && nsp->u.status.persistent) {
struct bssgp_bvc_ctx bctx = {
.nsei = nsp->nsei,
};
bssgp_tx_bvc_reset2(&bctx, BVCI_SIGNALLING, BSSGP_CAUSE_EQUIP_FAIL, false);
}
break;
case GPRS_NS2_AFF_CAUSE_FAILURE:
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d became unavailable\n", nsp->nsei);
break;
default:
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
get_value_string(osmo_prim_op_names, nsp->oph.operation), nsp->oph.primitive);
break;
}
}
/* call-back function for the NS protocol */
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct osmo_gprs_ns2_prim *nsp;
int rc = 0;
if (oph->sap != SAP_NS)
return 0;
nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
if (oph->operation != PRIM_OP_INDICATION) {
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
get_value_string(osmo_prim_op_names, oph->operation),
oph->operation);
return 0;
}
switch (oph->primitive) {
case GPRS_NS2_PRIM_UNIT_DATA:
/* hand the message into the BSSGP implementation */
/* add required msg fields for Gb layer */
msgb_bssgph(oph->msg) = oph->msg->l3h;
msgb_bvci(oph->msg) = nsp->bvci;
msgb_nsei(oph->msg) = nsp->nsei;
rc = bssgp_rcvmsg(oph->msg);
break;
case GPRS_NS2_PRIM_STATUS:
gprs_ns_prim_status_cb(nsp);
break;
default:
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
get_value_string(osmo_prim_op_names, oph->operation), oph->primitive);
break;
}
if (oph->msg)
msgb_free(oph->msg);
return rc;
}

View File

@@ -280,8 +280,12 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");
struct gsm48_hdr *gh;
struct gsm48_attach_ack *aa;
uint8_t *mid;
unsigned long t;
#ifdef PTMSI_ALLOC
struct osmo_mobile_identity mi;
uint8_t *l;
int rc;
#endif
#if 0
uint8_t *ptsig;
#endif
@@ -300,7 +304,7 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
aa->att_result = 1; /* GPRS only */
t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1);
aa->ra_upd_timer = gprs_secs_to_tmr_floor(t);
aa->radio_prio = 4; /* lowest */
aa->radio_prio = 0x44; /* lowest */
gsm48_encode_ra(&aa->ra_id, &mm->ra);
#if 0
@@ -321,14 +325,26 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
#ifdef PTMSI_ALLOC
/* Optional: Allocated P-TMSI */
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
mi = (struct osmo_mobile_identity){
.type = GSM_MI_TYPE_TMSI,
.tmsi = mm->p_tmsi,
};
l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
if (rc < 0) {
LOGMMCTXP(LOGL_ERROR, mm, "Cannot encode Mobile Identity\n");
msgb_free(msg);
return -EINVAL;
}
*l = rc;
#endif
/* Optional: MS-identity (combined attach) */
/* Optional: GMM cause (partial attach result for combined attach) */
/* Optional: Network feature support 10.5.5.23 */
/* msgb_v_put(msg, GSM48_IE_GMM_NET_FEAT_SUPPORT | 0x00);*/
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
@@ -911,9 +927,9 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
ctx->t3350_mode = GMM_T3350_MODE_ATT;
#else
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = mmctx;
sig_data.mm = ctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
#endif
return gsm48_tx_gmm_att_ack(ctx);
@@ -1026,31 +1042,35 @@ void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx, int gmm_cause)
static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
long mi_typel = mi_type;
char mi_string[GSM48_MI_SIZE];
long mi_typel;
char mi_log_string[32];
struct osmo_mobile_identity mi;
gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
if (!ctx) {
DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));
return -EINVAL;
}
LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n",
gsm48_mi_type_name(mi_type), mi_string);
if (osmo_mobile_identity_decode(&mi, &gh->data[1], gh->data[0], false)) {
LOGMMCTXP(LOGL_ERROR, ctx, "-> GMM IDENTITY RESPONSE: cannot decode Mobile Identity\n");
return -EINVAL;
}
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n", mi_log_string);
if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
LOGMMCTXP(LOGL_NOTICE, ctx,
"Got unexpected IDENTITY RESPONSE: MI(%s)=%s, "
"Got unexpected IDENTITY RESPONSE: MI=%s, "
"ignoring message\n",
gsm48_mi_type_name(mi_type), mi_string);
mi_log_string);
return -EINVAL;
}
if (mi_type == ctx->t3370_id_type)
if (mi.type == ctx->t3370_id_type)
mmctx_timer_stop(ctx, 3370);
switch (mi_type) {
switch (mi.type) {
case GSM_MI_TYPE_IMSI:
/* we already have a mm context with current TLLI, but no
* P-TMSI / IMSI yet. What we now need to do is to fill
@@ -1058,7 +1078,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
if (strlen(ctx->imsi) == 0) {
/* Check if we already have a MM context for this IMSI */
struct sgsn_mm_ctx *ictx;
ictx = sgsn_mm_ctx_by_imsi(mi_string);
ictx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (ictx) {
/* Handle it like in gsm48_rx_gmm_det_req,
* except that no messages are sent to the BSS */
@@ -1070,16 +1090,17 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
}
}
osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
break;
case GSM_MI_TYPE_IMEI:
osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei));
OSMO_STRLCPY_ARRAY(ctx->imei, mi.imei);
break;
case GSM_MI_TYPE_IMEISV:
break;
}
/* Check if we can let the mobile station enter */
mi_typel = mi.type;
return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel);
}
@@ -1099,19 +1120,46 @@ static inline void ptmsi_update(struct sgsn_mm_ctx *ctx)
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
}
/* Detect if RAT has changed */
static bool mmctx_did_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
{
if (MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_UTRAN_Iu)
return true;
if (!MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_GERAN_Gb)
return true;
return false;
}
/* Notify the FSM of a RAT change */
static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_llc_llme *llme)
{
struct gmm_rat_change_data rat_chg = {
.llme = llme
};
rat_chg.new_ran_type = MSG_IU_UE_CTX(msg) ? MM_CTX_T_UTRAN_Iu : MM_CTX_T_GERAN_Gb;
if (rat_chg.new_ran_type != mmctx->ran_type)
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAT_CHANGE, (void *) &rat_chg);
else
LOGMMCTXP(LOGL_ERROR, mmctx, "RAT didn't change or not implemented (ran_type=%u, "
"msg_iu_ue_ctx=%p\n", mmctx->ran_type, MSG_IU_UE_CTX(msg));
}
/* 3GPP TS 24.008 § 9.4.1 Attach request */
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
struct gprs_llc_llme *llme)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap;
uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;
uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap;
uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len;
uint16_t drx_par;
uint32_t tmsi;
char mi_string[GSM48_MI_SIZE];
char mi_log_string[32];
struct gprs_ra_id ra_id;
uint16_t cid = 0;
enum gsm48_gmm_cause reject_cause;
struct osmo_mobile_identity mi;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
@@ -1155,15 +1203,15 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
mi_len = *cur++;
mi = cur;
if (mi_len > 8)
goto err_inval;
mi_type = *mi & GSM_MI_TYPE_MASK;
mi_data = cur;
cur += mi_len;
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
if (rc)
goto err_inval;
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
get_value_string(gprs_att_t_strs, att_type));
/* Old routing area identification 10.5.5.15. Skip it */
@@ -1180,11 +1228,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
switch (mi_type) {
switch (mi.type) {
case GSM_MI_TYPE_IMSI:
/* Try to find MM context based on IMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_imsi(mi_string);
ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (!ctx) {
if (MSG_IU_UE_CTX(msg))
ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));
@@ -1194,15 +1242,13 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
}
break;
case GSM_MI_TYPE_TMSI:
memcpy(&tmsi, mi+1, 4);
tmsi = ntohl(tmsi);
/* Try to find MM context based on P-TMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
if (!ctx) {
/* Allocate a context as most of our code expects one.
* Context will not have an IMSI ultil ID RESP is received */
@@ -1214,16 +1260,19 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
ctx->p_tmsi = tmsi;
ctx->p_tmsi = mi.tmsi;
}
break;
default:
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "
"MI type %s\n", gsm48_mi_type_name(mi_type));
"MI %s\n", mi_log_string);
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
goto rejected;
}
if (mmctx_did_rat_change(ctx, msg))
mmctx_handle_rat_change(ctx, msg, llme);
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
ctx->gb.tlli = msgb_tlli(msg);
ctx->gb.llme = llme;
@@ -1245,8 +1294,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
ctx->ciph_algo)) {
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
"type %s because MS do not support required %s "
"encryption\n", gsm48_mi_type_name(mi_type),
"%s because MS do not support required %s "
"encryption\n", mi_log_string,
get_value_string(gprs_cipher_names,ctx->ciph_algo));
goto rejected;
}
@@ -1393,8 +1442,12 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");
struct gsm48_hdr *gh;
struct gsm48_ra_upd_ack *rua;
uint8_t *mid;
unsigned long t;
#ifdef PTMSI_ALLOC
uint8_t *l;
int rc;
struct osmo_mobile_identity mi;
#endif
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
@@ -1424,9 +1477,17 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
#ifdef PTMSI_ALLOC
/* Optional: Allocated P-TMSI */
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
mi = (struct osmo_mobile_identity){
.type = GSM_MI_TYPE_TMSI,
.tmsi = mm->p_tmsi,
};
l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
if (rc < 0) {
msgb_free(msg);
return -EINVAL;
}
*l = rc;
#endif
/* Optional: Negotiated READY timer value */
@@ -1470,21 +1531,19 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
* being in state PDP-INACTIVE. */
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
if (pdp->nsapi < 8) {
if (!(pdp_status[0] & (1 << pdp->nsapi))) {
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
pdp->nsapi, pdp_status[1], pdp_status[0]);
sgsn_delete_pdp_ctx(pdp);
}
} else {
if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
pdp->nsapi, pdp_status[1], pdp_status[0]);
sgsn_delete_pdp_ctx(pdp);
}
}
bool inactive = (pdp->nsapi < 8) ?
!(pdp_status[0] & (1 << pdp->nsapi)) :
!(pdp_status[1] & (1 << (pdp->nsapi - 8)));
if (!inactive)
continue;
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE=0x%02x%02x\n",
pdp->nsapi, pdp_status[1], pdp_status[0]);
if (pdp->ggsn)
sgsn_delete_pdp_ctx(pdp);
else /* GTP side already detached, freeing */
sgsn_pdp_ctx_free(pdp);
}
}
@@ -1576,19 +1635,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
} else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
#ifdef BUILD_IU
/* In Iu mode search only for ptmsi */
char mi_string[GSM48_MI_SIZE];
uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
const uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;
uint32_t tmsi;
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
if (mi_type == GSM_MI_TYPE_TMSI) {
memcpy(&tmsi, mi+1, 4);
tmsi = ntohl(tmsi);
mmctx = sgsn_mm_ctx_by_ptmsi(tmsi);
struct osmo_mobile_identity mi;
if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI),
TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI), false)
|| mi.type != GSM_MI_TYPE_TMSI) {
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");
goto rejected;
}
mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
#else
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
"Rejecting GMM RA Update Request: No Iu support\n");
@@ -1604,21 +1658,36 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->p_tmsi, mmctx->p_tmsi_old,
mmctx->gb.tlli, mmctx->gb.tlli_new,
osmo_rai_name(&mmctx->ra));
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
/* A RAT change will trigger the common procedure
* below after handling the RAT change. Protect it
* here from being called twice */
if (!mmctx_did_rat_change(mmctx, msg))
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
}
} else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) ||
mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
{
/* We cannot use the mmctx */
LOGMMCTXP(LOGL_INFO, mmctx,
"The MM context cannot be used, RA: %s\n",
osmo_rai_name(&mmctx->ra));
/* mmctx is set to NULL and gprs_llgmm_unassign(llme) will be
called below, let's make sure we don't keep dangling llme
pointers in mmctx (OS#3957, OS#4245). */
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
mmctx->gb.llme = NULL;
mmctx = NULL;
/* We've received either a RAU for a MS which isn't registered
* or a RAU with an unknown RA ID. As long the SGSN doesn't support
* PS handover we treat this as invalid RAU */
struct gprs_ra_id new_ra_id;
char new_ra[32];
bssgp_parse_cell_id(&new_ra_id, msgb_bcid(msg));
osmo_rai_name_buf(new_ra, sizeof(new_ra), &new_ra_id);
if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
LOGMMCTXP(LOGL_INFO, mmctx,
"Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n",
osmo_rai_name(&old_ra_id), new_ra);
else
LOGMMCTXP(LOGL_INFO, mmctx,
"Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n",
osmo_rai_name(&old_ra_id), new_ra);
reject_cause = GMM_CAUSE_IMPL_DETACHED;
goto rejected;
}
if (!mmctx) {
@@ -1636,13 +1705,18 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
goto rejected;
}
if (mmctx_did_rat_change(mmctx, msg)) {
mmctx_handle_rat_change(mmctx, msg, llme);
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
}
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
msgid2mmctx(mmctx, msg);
/* Bump the statistics of received signalling msgs for this MM context */
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
/* Update the MM context with the new RA-ID */
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->gb.tlli = msgb_tlli(msg);
@@ -1660,7 +1734,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx_timer_start(mmctx, 3350);
#else
/* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */
osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = mmctx;
@@ -1762,11 +1836,11 @@ static int gsm48_rx_gmm_ptmsi_reall_compl(struct sgsn_mm_ctx *mmctx)
static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t *cur = gh->data, *mi;
uint8_t service_type, mi_len, mi_type;
uint32_t tmsi;
uint8_t *cur = gh->data, *mi_data;
uint8_t service_type, mi_len;
struct tlv_parsed tp;
char mi_string[GSM48_MI_SIZE];
struct osmo_mobile_identity mi;
char mi_log_string[32];
enum gsm48_gmm_cause reject_cause;
int rc;
@@ -1786,15 +1860,14 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
mi_len = *cur++;
mi = cur;
if (mi_len > 8)
goto err_inval;
mi_type = *mi & GSM_MI_TYPE_MASK;
mi_data = cur;
cur += mi_len;
rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
if (rc)
goto err_inval;
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
get_value_string(gprs_service_t_strs, service_type));
LOGPC(DMM, LOGL_INFO, "\n");
@@ -1802,11 +1875,11 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
/* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);
switch (mi_type) {
switch (mi.type) {
case GSM_MI_TYPE_IMSI:
/* Try to find MM context based on IMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_imsi(mi_string);
ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_IMPL_DETACHED;
@@ -1815,11 +1888,9 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
msgid2mmctx(ctx, msg);
break;
case GSM_MI_TYPE_TMSI:
memcpy(&tmsi, mi+1, 4);
tmsi = ntohl(tmsi);
/* Try to find MM context based on P-TMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_IMPL_DETACHED;
@@ -1829,7 +1900,7 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
break;
default:
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
"MI type %s\n", gsm48_mi_type_name(mi_type));
"MI %s\n", mi_log_string);
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
goto rejected;
}
@@ -1944,6 +2015,23 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
return rc;
}
/* A RAT change is only expected/allowed for RAU/Attach Req */
if (mmctx && mmctx_did_rat_change(mmctx, msg)) {
switch (gh->msg_type) {
case GSM48_MT_GMM_RA_UPD_REQ:
case GSM48_MT_GMM_ATTACH_REQ:
break;
default:
/* This shouldn't happen with other message types and
* we need to error out to prevent a crash */
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping GMM %s which was received on different "
"RAT (mmctx ran_type=%u, msg_iu_ue_ctx=%p\n",
get_value_string(gprs_msgt_gmm_names, gh->msg_type),
mmctx->ran_type, MSG_IU_UE_CTX(msg));
return -EINVAL;
}
}
/*
* For a few messages, mmctx may be NULL. For most, we want to ensure a
* non-NULL mmctx. At the same time, we want to keep the message

View File

@@ -1,6 +1,30 @@
/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
/*
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <osmocom/core/tdef.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
@@ -67,9 +91,12 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
case E_GMM_RESUME:
case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
break;
case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
break;
}
}
@@ -121,10 +148,12 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
.action = st_gmm_registered_normal,
},
[ST_GMM_REGISTERED_SUSPENDED] = {
.in_event_mask = X(E_GMM_RESUME),
.in_event_mask = X(E_GMM_RESUME) |
X(E_GMM_COMMON_PROC_INIT_REQ),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
X(ST_GMM_REGISTERED_NORMAL),
X(ST_GMM_REGISTERED_NORMAL) |
X(ST_GMM_COMMON_PROC_INIT),
.name = "Registered.SUSPENDED",
.action = st_gmm_registered_suspended,
},
@@ -149,11 +178,32 @@ const struct value_string gmm_fsm_event_names[] = {
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
OSMO_VALUE_STRING(E_GMM_SUSPEND),
OSMO_VALUE_STRING(E_GMM_CLEANUP),
OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
{ 0, NULL }
};
void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
struct sgsn_mm_ctx *mmctx = fi->priv;
struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
switch (event) {
case E_GMM_RAT_CHANGE:
switch (fi->state) {
case ST_GMM_COMMON_PROC_INIT:
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
default:
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
mmctx->gb.llme = rat_chg->llme;
}
mmctx->ran_type = rat_chg->new_ran_type;
break;
}
case E_GMM_CLEANUP:
switch (fi->state) {
case ST_GMM_DEREGISTERED:
@@ -175,7 +225,7 @@ struct osmo_fsm gmm_fsm = {
.states = gmm_fsm_states,
.num_states = ARRAY_SIZE(gmm_fsm_states),
.event_names = gmm_fsm_event_names,
.allstate_event_mask = X(E_GMM_CLEANUP),
.allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
.allstate_action = gmm_fsm_allstate_action,
.log_subsys = DMM,
.timer_cb = gmm_fsm_timer_cb,

View File

@@ -376,20 +376,24 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
* not yet have a MMC context (e.g. XID negotiation of primarly
* LLC connection from GMM sapi). */
if (mmctx) {
/* In rare cases the LLME is NULL in those cases don't
* use the mm radio capabilities */
dup.imsi = mmctx->imsi;
dup.drx_parms = mmctx->drx_parms;
dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
if (mmctx->gb.llme) {
dup.drx_parms = mmctx->drx_parms;
dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
/* make sure we only send it to the right llme */
if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
LOGP(DLLC, LOGL_ERROR,
"_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
" msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
msgb_free(msg);
return -EINVAL;
/* make sure we only send it to the right llme */
if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
LOGP(DLLC, LOGL_ERROR,
"_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
" msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
msgb_free(msg);
return -EINVAL;
}
}
}
memcpy(&dup.qos_profile, qos_profile_default,

View File

@@ -68,6 +68,9 @@ static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_MM_PDU_RECEPTION:
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
break;
case E_MM_IMPLICIT_DETACH:
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
break;
}
}
@@ -86,7 +89,7 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
.action = st_mm_ready,
},
[ST_MM_STANDBY] = {
.in_event_mask = X(E_MM_PDU_RECEPTION),
.in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_IMPLICIT_DETACH),
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
.name = "Standby",
.action = st_mm_standby,

View File

@@ -26,6 +26,7 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
#include <osmocom/gprs/gprs_msgb.h>
#include <osmocom/ranap/ranap_common.h>

View File

@@ -27,7 +27,7 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/backtrace.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/apn.h>
@@ -511,6 +511,11 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
if (osmo_timer_pending(&pdp->timer)) {
LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
osmo_timer_del(&pdp->timer);
}
rate_ctr_group_free(pdp->ctrg);
if (pdp->mm)
llist_del(&pdp->list);

View File

@@ -639,7 +639,11 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
}
return sgsn_delete_pdp_ctx(pdp);
if (pdp->ggsn)
return sgsn_delete_pdp_ctx(pdp);
/* GTP side already detached, freeing */
sgsn_pdp_ctx_free(pdp);
return 0;
}
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */

View File

@@ -28,6 +28,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/endian.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
@@ -164,27 +165,43 @@ static void debug_ip_packet(uint8_t *data, int len, int dir, char *info)
/* Chapter 7.2: SN-PDU Formats */
struct sndcp_common_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 1 */
uint8_t nsapi:4;
uint8_t more:1;
uint8_t type:1;
uint8_t first:1;
uint8_t spare:1;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
#endif
} __attribute__((packed));
/* PCOMP / DCOMP only exist in first fragment */
struct sndcp_comp_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 2 */
uint8_t pcomp:4;
uint8_t dcomp:4;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t dcomp:4, pcomp:4;
#endif
} __attribute__((packed));
struct sndcp_udata_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 3 */
uint8_t npdu_high:4;
uint8_t seg_nr:4;
/* octet 4 */
uint8_t npdu_low;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t seg_nr:4, npdu_high:4;
uint8_t npdu_low;
#endif
} __attribute__((packed));
@@ -366,8 +383,12 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
sne->nsapi, msg, npdu_len, expnd);
if (any_pcomp_or_dcomp_active(sgsn))
talloc_free(expnd);
/* we must free the memory we allocated above; ownership is not transferred
* downwards in the call above */
msgb_free(msg);
/* Note: We do not have to free expnd explicitly, because it is created
* within the talloc context of msg, which we just freed. */
return rc;
}
@@ -787,7 +808,7 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
lle, lle->llme->tlli, lle->sapi, sch->nsapi);
return -EIO;
}
gprs_gb_recv_pdu(mmctx);
gprs_gb_recv_pdu(mmctx, msg);
if (scomph) {
sne->defrag.pcomp = scomph->pcomp;

View File

@@ -812,7 +812,7 @@ static int gprs_subscr_query_auth_info(struct gprs_subscr *subscr,
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
int gprs_subscr_location_update(struct gprs_subscr *subscr)
int gprs_subscr_location_update(struct gprs_subscr *subscr, enum sgsn_ran_type ran_type)
{
struct osmo_gsup_message gsup_msg = {0};
@@ -820,6 +820,18 @@ int gprs_subscr_location_update(struct gprs_subscr *subscr)
"subscriber data is not available\n");
gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
switch (ran_type) {
case MM_CTX_T_GERAN_Gb:
gsup_msg.current_rat_type = OSMO_RAT_GERAN_A;
break;
case MM_CTX_T_UTRAN_Iu:
gsup_msg.current_rat_type = OSMO_RAT_UTRAN_IU;
break;
default:
break;
}
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
@@ -858,6 +870,8 @@ struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx
if (!subscr) {
subscr = gprs_subscr_get_or_create(mmctx->imsi);
if (!subscr)
return NULL;
subscr->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT;
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
}
@@ -881,10 +895,12 @@ int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
if (!subscr)
return -ENOMEM;
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
rc = gprs_subscr_location_update(subscr);
rc = gprs_subscr_location_update(subscr, mmctx->ran_type);
gprs_subscr_put(subscr);
return rc;
}
@@ -906,6 +922,8 @@ int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
if (!subscr)
return -ENOMEM;
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;

View File

@@ -167,6 +167,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
pdp->hisaddr0 = ggsn->remote_addr;
pdp->hisaddr1 = ggsn->remote_addr;
//pdp->cch_pdp = 512; /* Charging Flat Rate */
pdp->radio_pri = 0x4;
/* MS provided APN, subscription was verified by the caller */
pdp->selmode = 0xFC | 0x00;
@@ -311,11 +312,16 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
return pctx;
}
/* SGSN wants to delete a PDP context */
/* SGSN wants to delete a PDP context, send first DeleteCtxReq on the GTP side,
then upon DeleteCtx ACK it will send DeactPdpAcc to the MS if still
connected. */
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx)
{
LOGPDPCTXP(LOGL_INFO, pctx, "Delete PDP Context\n");
OSMO_ASSERT(pctx->ggsn);
OSMO_ASSERT(pctx->lib);
/* FIXME: decide if we need teardown or not ! */
return gtp_delete_context_req2(pctx->ggsn->gsn, pctx->lib, pctx, 1);
}
@@ -660,14 +666,18 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
switch (mm->gmm_fsm->state) {
case ST_GMM_REGISTERED_SUSPENDED:
/* initiate PS PAGING procedure */
gprs_gb_page_ps_ra(mm);
/* FIXME: queue the packet we received from GTP */
break;
LOGMMCTXP(LOGL_INFO, mm, "Dropping DL packet for MS in GMM state %s\n",
osmo_fsm_inst_state_name(mm->gmm_fsm));
msgb_free(msg);
return -1;
case ST_GMM_REGISTERED_NORMAL:
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY)
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) {
LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
osmo_fsm_inst_state_name(mm->gmm_fsm),
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
gprs_gb_page_ps_ra(mm);
}
/* FIXME: queue the packet we received from GTP */
break;
@@ -733,7 +743,7 @@ static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
struct sgsn_instance *sgi = fd->data;
int rc;
if (!(what & BSC_FD_READ))
if (!(what & OSMO_FD_READ))
return 0;
switch (fd->priv_nr) {
@@ -771,31 +781,19 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
if (gsn->mode != GTP_MODE_SGSN)
return -EINVAL;
sgi->gtp_fd0.fd = gsn->fd0;
sgi->gtp_fd0.priv_nr = 0;
sgi->gtp_fd0.data = sgi;
sgi->gtp_fd0.when = BSC_FD_READ;
sgi->gtp_fd0.cb = sgsn_gtp_fd_cb;
osmo_fd_setup(&sgi->gtp_fd0, gsn->fd0, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 0);
rc = osmo_fd_register(&sgi->gtp_fd0);
if (rc < 0)
return rc;
sgi->gtp_fd1c.fd = gsn->fd1c;
sgi->gtp_fd1c.priv_nr = 1;
sgi->gtp_fd1c.data = sgi;
sgi->gtp_fd1c.when = BSC_FD_READ;
sgi->gtp_fd1c.cb = sgsn_gtp_fd_cb;
osmo_fd_setup(&sgi->gtp_fd1c, gsn->fd1c, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 1);
rc = osmo_fd_register(&sgi->gtp_fd1c);
if (rc < 0) {
osmo_fd_unregister(&sgi->gtp_fd0);
return rc;
}
sgi->gtp_fd1u.fd = gsn->fd1u;
sgi->gtp_fd1u.priv_nr = 2;
sgi->gtp_fd1u.data = sgi;
sgi->gtp_fd1u.when = BSC_FD_READ;
sgi->gtp_fd1u.cb = sgsn_gtp_fd_cb;
osmo_fd_setup(&sgi->gtp_fd1u, gsn->fd1u, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 2);
rc = osmo_fd_register(&sgi->gtp_fd1u);
if (rc < 0) {
osmo_fd_unregister(&sgi->gtp_fd0);

View File

@@ -39,15 +39,18 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/misc.h>
#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/ctrl/control_vty.h>
@@ -58,11 +61,13 @@
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gb.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <gtp.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include "../../bscconfig.h"
@@ -78,7 +83,7 @@
void *tall_sgsn_ctx;
struct ctrl_handle *g_ctrlh;
struct gprs_ns_inst *sgsn_nsi;
struct gprs_ns2_inst *sgsn_nsi;
static int daemonize = 0;
const char *openbsc_copyright =
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
@@ -92,27 +97,6 @@ const char *openbsc_copyright =
struct sgsn_instance *sgsn;
/* call-back function for the NS protocol */
static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
struct msgb *msg, uint16_t bvci)
{
int rc = 0;
switch (event) {
case GPRS_NS_EVT_UNIT_DATA:
/* hand the message into the BSSGP implementation */
rc = bssgp_rcvmsg(msg);
break;
default:
LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
if (msg)
msgb_free(msg);
rc = -EIO;
break;
}
return rc;
}
/* call-back function for the BSSGP protocol */
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
@@ -137,15 +121,17 @@ int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
break;
case SAP_BSSGP_NM:
break;
case SAP_BSSGP_RIM:
return sgsn_rim_rx(bp, oph->msg);
}
return 0;
}
static void signal_handler(int signal)
static void signal_handler(int signum)
{
fprintf(stdout, "signal %u received\n", signal);
fprintf(stdout, "signal %u received\n", signum);
switch (signal) {
switch (signum) {
case SIGINT:
case SIGTERM:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
@@ -153,8 +139,17 @@ static void signal_handler(int signal)
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_sgsn_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_sgsn_ctx, stderr);
@@ -170,40 +165,12 @@ static void signal_handler(int signal)
/* NSI that BSSGP uses when transmitting on NS */
extern struct gprs_ns_inst *bssgp_nsi;
int sgsn_vty_is_config_node(struct vty *vty, int node)
{
/* So far the SGSN has no nested nodes that need parent node
* declaration, except for the ss7 vty nodes. */
switch (node) {
case SGSN_NODE:
return 1;
default:
#if BUILD_IU
return osmo_ss7_is_config_node(vty, node);
#else
return 0;
#endif
}
}
int sgsn_vty_go_parent(struct vty *vty)
{
/* So far the SGSN has no nested nodes that need parent node
* declaration, except for the ss7 vty nodes. */
#if BUILD_IU
return osmo_ss7_vty_go_parent(vty);
#else
vty->node = CONFIG_NODE;
vty->index = NULL;
return 0;
#endif
}
static struct vty_app_info vty_info = {
.name = "OsmoSGSN",
.version = PACKAGE_VERSION,
.go_parent_cb = sgsn_vty_go_parent,
.is_config_node = sgsn_vty_is_config_node,
#if BUILD_IU
.go_parent_cb = osmo_ss7_vty_go_parent,
#endif
};
static void print_help(void)
@@ -216,12 +183,43 @@ static void print_help(void)
printf(" -s --disable-color\n");
printf(" -c --config-file\tThe config file to use [%s]\n", CONFIG_FILE_DEFAULT);
printf(" -e --log-level number\tSet a global log level\n");
printf("\nVTY reference generation:\n");
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
}
static void handle_long_options(const char *prog_name, const int long_option)
{
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
switch (long_option) {
case 1:
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
if (vty_ref_mode < 0) {
fprintf(stderr, "%s: Unknown VTY reference generation "
"mode '%s'\n", prog_name, optarg);
exit(2);
}
break;
case 2:
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
exit(0);
default:
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
exit(2);
}
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
static int long_option = 0;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"debug", 1, 0, 'd'},
@@ -231,6 +229,8 @@ static void handle_options(int argc, char **argv)
{"timestamp", 0, 0, 'T'},
{ "version", 0, 0, 'V' },
{"log-level", 1, 0, 'e'},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{NULL, 0, 0, 0}
};
@@ -240,6 +240,9 @@ static void handle_options(int argc, char **argv)
break;
switch (c) {
case 0:
handle_long_options(argv[0], long_option);
break;
case 'h':
//print_usage();
print_help();
@@ -312,11 +315,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DBSSGP] = {
.name = "DBSSGP",
.description = "GPRS BSS Gateway Protocol (BSSGP)",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",
@@ -352,6 +350,11 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Tunnelling Protocol (GTP)",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DRIM] = {
.name = "DRIM",
.description = "RAN Information Management (RIM)",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
};
static const struct log_info gprs_log_info = {
@@ -396,6 +399,7 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds();
sgsn_vty_init(&sgsn->cfg);
ctrl_vty_init(tall_sgsn_ctx);
osmo_cpu_sched_vty_init(tall_sgsn_ctx);
#if BUILD_IU
OSMO_ASSERT(osmo_ss7_init() == 0);
@@ -403,6 +407,30 @@ int main(int argc, char **argv)
osmo_sccp_vty_init();
#endif
rate_ctr_init(tall_sgsn_ctx);
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
sgsn_nsi = gprs_ns2_instantiate(tall_sgsn_ctx, &gprs_ns_prim_cb, NULL);
if (!sgsn_nsi) {
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
sgsn->cfg.nsi = sgsn_nsi;
bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi);
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
sgsn_rate_ctr_init();
sgsn_inst_init(sgsn);
gprs_ns2_vty_init(sgsn_nsi);
bssgp_vty_init();
gprs_llc_vty_init();
gprs_sndcp_vty_init();
sgsn_auth_init(sgsn);
sgsn_cdr_init(sgsn);
handle_options(argc, argv);
/* Backwards compatibility: for years, the default config file name was
@@ -420,30 +448,6 @@ int main(int argc, char **argv)
osmo_talloc_replace_string(sgsn, &sgsn->config_file, CONFIG_FILE_DEFAULT);
}
rate_ctr_init(tall_sgsn_ctx);
gprs_ns_set_log_ss(DNS);
bssgp_set_log_ss(DBSSGP);
sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_sgsn_ctx);
if (!sgsn_nsi) {
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
bssgp_nsi = sgsn->cfg.nsi = sgsn_nsi;
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
sgsn_rate_ctr_init();
sgsn_inst_init(sgsn);
gprs_ns_vty_init(bssgp_nsi);
bssgp_vty_init();
gprs_llc_vty_init();
gprs_sndcp_vty_init();
sgsn_auth_init(sgsn);
sgsn_cdr_init(sgsn);
/* FIXME: register signal handler for SS_L_NS */
rc = sgsn_parse_config(sgsn->config_file);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Error in config file\n");
@@ -484,19 +488,6 @@ int main(int argc, char **argv)
exit(2);
}
rc = gprs_ns_nsip_listen(sgsn_nsi);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
exit(2);
}
rc = gprs_ns_frgre_listen(sgsn_nsi);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
"socket. Do you have CAP_NET_RAW?\n");
exit(2);
}
if (sgsn->cfg.dynamic_lookup) {
if (sgsn_ares_init(sgsn) != 0) {
LOGP(DGPRS, LOGL_FATAL,
@@ -512,8 +503,8 @@ int main(int argc, char **argv)
"OsmoSGSN",
(23 << 3) + 4,
OSMO_SS7_ASP_PROT_M3UA,
0, NULL,
0, "127.0.0.1");
0, "localhost",
0, "localhost");
if (!sccp) {
printf("Setting up SCCP client failed.\n");
return 8;

67
src/sgsn/sgsn_rim.c Normal file
View File

@@ -0,0 +1,67 @@
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/vty/logging.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/debug.h>
/* Find an NSEI for the destination cell, this function works only for GERAN! */
static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)
{
struct bssgp_bvc_ctx *bvc_ctx;
OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);
if (!bvc_ctx) {
LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);
return -EINVAL;
}
return bvc_ctx->nsei;
}
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)
{
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
int d_nsei;
uint16_t nsei = msgb_nsei(msg);
/* At the moment we only support GERAN, so we block all other network
* types here. */
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
"BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
nsei);
/* At the moment we can only handle GERAN addresses, any other
* type of address will be consideres as an invalid address.
* see also: 3GPP TS 48.018, section 8c.3.1.3 */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
}
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
"BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
/* See comment above */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
}
d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);
if (d_nsei < 0) {
LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",
nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));
/* In case of an invalid destination address we respond with
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
}
/* Forward PDU as it is to the correct interface */
return bssgp_tx_rim(pdu, (uint16_t) d_nsei);
}

View File

@@ -34,7 +34,7 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/vty.h>
@@ -186,6 +186,8 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, "sgsn%s", VTY_NEWLINE);
vty_out(vty, " gtp state-dir %s%s",
g_cfg->gtp_statedir, VTY_NEWLINE);
vty_out(vty, " gtp local-ip %s%s",
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
@@ -315,6 +317,17 @@ DEFUN(cfg_sgsn, cfg_sgsn_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
"gtp state-dir PATH",
"GTP Parameters\n"
"Set the directory for the GTP State file\n"
"Local Directory\n")
{
osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
"gtp local-ip A.B.C.D",
"GTP Parameters\n"
@@ -1007,6 +1020,10 @@ DEFUN(update_subscr_create, update_subscr_create_cmd,
}
subscr = gprs_subscr_get_or_create(imsi);
if (!subscr) {
vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
return CMD_WARNING;
}
subscr->keep_in_ram = 1;
gprs_subscr_put(subscr);
@@ -1432,6 +1449,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
install_node(&sgsn_node, config_write_sgsn);
install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);

View File

@@ -1,6 +1,5 @@
SUBDIRS = \
gprs \
gbproxy \
gtphub \
sgsn \
xid \
@@ -33,7 +32,7 @@ EXTRA_DIST = \
$(TESTSUITE) \
vty_test_runner.py \
ctrl_test_runner.py \
test_nodes.vty \
osmo-sgsn_test-nodes.vty \
$(NULL)
TESTSUITE = $(srcdir)/testsuite
@@ -64,7 +63,7 @@ vty-transcript-test:
osmo_verify_transcript_vty.py -v \
-n OsmoSGSN -p 4245 \
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
$(U) $${T:-$(srcdir)/*.vty}
$(U) $${T:-$(srcdir)/osmo-sgsn*.vty}
rm -f $(builddir)/sms.db $(builddir)/gsn_restart
# don't run multiple tests concurrently so that the ports don't conflict

View File

@@ -1,50 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
$(NULL)
EXTRA_DIST = \
gbproxy_test.ok \
$(NULL)
noinst_PROGRAMS = \
gbproxy_test \
$(NULL)
gbproxy_test_SOURCES = \
gbproxy_test.c \
$(NULL)
gbproxy_test_LDFLAGS = \
-Wl,--wrap=osmo_get_rand_id \
$(NULL)
gbproxy_test_LDADD = \
$(top_builddir)/src/gbproxy/gb_proxy.o \
$(top_builddir)/src/gbproxy/gb_proxy_patch.o \
$(top_builddir)/src/gbproxy/gb_proxy_peer.o \
$(top_builddir)/src/gbproxy/gb_proxy_tlli.o \
$(top_builddir)/src/gprs/gprs_gb_parse.o \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
$(top_builddir)/src/gprs/crc24.o \
$(top_builddir)/src/gprs/gprs_utils.o \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBRARY_DL) \
-lrt \
$(NULL)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,7 @@
void gtphub_init(struct gtphub *hub);
void gtphub_free(struct gtphub *hub);
void *osmo_gtphub_ctx;
extern void *osmo_gtphub_ctx;
static void nr_mapping_free(struct expiring_item *e)
{
@@ -378,37 +378,37 @@ static void test_expiry(void)
char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1];
char resolve_ggsn_got_ni[GSM_APN_LENGTH];
struct osmo_sockaddr resolved_ggsn_addr;
struct sgsn_sockaddr resolved_ggsn_addr;
static int resolve_to_ggsn(const char *addr, uint16_t port)
{
LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr,
LVL2_ASSERT(sgsn_sockaddr_init_udp(&resolved_ggsn_addr,
addr, port)
== 0);
return 1;
}
struct osmo_sockaddr resolved_sgsn_addr;
struct sgsn_sockaddr resolved_sgsn_addr;
static int resolve_to_sgsn(const char *addr, uint16_t port)
{
LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_sgsn_addr,
LVL2_ASSERT(sgsn_sockaddr_init_udp(&resolved_sgsn_addr,
addr, port)
== 0);
return 1;
}
struct osmo_sockaddr sgsn_sender;
struct sgsn_sockaddr sgsn_sender;
static int send_from_sgsn(const char *addr, uint16_t port)
{
LVL2_ASSERT(osmo_sockaddr_init_udp(&sgsn_sender,
LVL2_ASSERT(sgsn_sockaddr_init_udp(&sgsn_sender,
addr, port)
== 0);
return 1;
}
struct osmo_sockaddr ggsn_sender;
struct sgsn_sockaddr ggsn_sender;
static int send_from_ggsn(const char *addr, uint16_t port)
{
LVL2_ASSERT(osmo_sockaddr_init_udp(&ggsn_sender,
LVL2_ASSERT(sgsn_sockaddr_init_udp(&ggsn_sender,
addr, port)
== 0);
return 1;
@@ -491,18 +491,18 @@ int __wrap_gtphub_ares_init(struct gtphub *hub)
/* override, requires '-Wl,--wrap=gtphub_write' */
int __real_gtphub_write(const struct osmo_fd *to,
const struct osmo_sockaddr *to_addr,
const struct sgsn_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len);
int __wrap_gtphub_write(const struct osmo_fd *to,
const struct osmo_sockaddr *to_addr,
const struct sgsn_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len)
{
printf("Out-of-band gtphub_write(%d):\n"
"to %s\n"
"%s\n",
(int)buf_len,
osmo_sockaddr_to_str(to_addr),
sgsn_sockaddr_to_str(to_addr),
osmo_hexdump(buf, buf_len));
return 0;
}
@@ -529,6 +529,8 @@ static int _reply_is(const char *hex, const char *file, int line)
const char *dump = osmo_hexdump_nospc(reply_buf, len);
int cmp = strcmp(dump, hex);
OSMO_ASSERT(dump && hex);
if (cmp != 0) {
printf("\n%s:%d: reply_is(): MISMATCH\n"
" expecting:\n'%s'\n"
@@ -553,11 +555,11 @@ static int _reply_is(const char *hex, const char *file, int line)
}
#define same_addr(GOT, EXPECTED) _same_addr((GOT),(EXPECTED), __FILE__, __LINE__)
static int _same_addr(const struct osmo_sockaddr *got,
const struct osmo_sockaddr *expected,
static int _same_addr(const struct sgsn_sockaddr *got,
const struct sgsn_sockaddr *expected,
const char *file, int line)
{
int cmp = osmo_sockaddr_cmp(got, expected);
int cmp = sgsn_sockaddr_cmp(got, expected);
if (!cmp)
return 1;
char buf[256];
@@ -565,8 +567,8 @@ static int _same_addr(const struct osmo_sockaddr *got,
" expecting: '%s'\n"
" got: '%s'\n\n",
file, line,
osmo_sockaddr_to_str(expected),
osmo_sockaddr_to_strb(got, buf, sizeof(buf)));
sgsn_sockaddr_to_str(expected),
sgsn_sockaddr_to_strb(got, buf, sizeof(buf)));
return 0;
}
@@ -668,7 +670,7 @@ static void test_echo(void)
now = 123;
struct osmo_fd *to_ofd;
struct osmo_sockaddr to_addr;
struct sgsn_sockaddr to_addr;
struct gtphub_peer_port *pp;
int send;
@@ -855,13 +857,13 @@ static void test_echo(void)
#define msg_from_sgsn_c(A,B,C,D) msg_from_sgsn(GTPH_PLANE_CTRL, A,B,C,D)
#define msg_from_sgsn_u(A,B,C,D) msg_from_sgsn(GTPH_PLANE_USER, A,B,C,D)
static int msg_from_sgsn(int plane_idx,
struct osmo_sockaddr *_sgsn_sender,
struct osmo_sockaddr *ggsn_receiver,
struct sgsn_sockaddr *_sgsn_sender,
struct sgsn_sockaddr *ggsn_receiver,
const char *hex_from_sgsn,
const char *hex_to_ggsn)
{
struct osmo_fd *ggsn_ofd = NULL;
struct osmo_sockaddr ggsn_addr;
struct sgsn_sockaddr ggsn_addr;
int send;
send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, plane_idx, _sgsn_sender,
buf, msg(hex_from_sgsn), now,
@@ -875,13 +877,13 @@ static int msg_from_sgsn(int plane_idx,
#define msg_from_ggsn_c(A,B,C,D) msg_from_ggsn(GTPH_PLANE_CTRL, A,B,C,D)
#define msg_from_ggsn_u(A,B,C,D) msg_from_ggsn(GTPH_PLANE_USER, A,B,C,D)
static int msg_from_ggsn(int plane_idx,
struct osmo_sockaddr *ggsn_sender,
struct osmo_sockaddr *sgsn_receiver,
struct sgsn_sockaddr *ggsn_sender,
struct sgsn_sockaddr *sgsn_receiver,
const char *msg_from_ggsn,
const char *msg_to_sgsn)
{
struct osmo_fd *sgsn_ofd;
struct osmo_sockaddr sgsn_addr;
struct sgsn_sockaddr sgsn_addr;
int send;
send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, plane_idx, ggsn_sender,
buf, msg(msg_from_ggsn), now,

View File

@@ -27,6 +27,7 @@ OsmoSGSN(config)# list
OsmoSGSN(config)# sgsn
OsmoSGSN(config-sgsn)# list
...
gtp state-dir PATH
gtp local-ip A.B.C.D
ggsn <0-255> remote-ip A.B.C.D
ggsn <0-255> gtp-version (0|1)

View File

@@ -1625,11 +1625,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_INFO,
},
[DBSSGP] = {
.name = "DBSSGP",
.description = "GPRS BSS Gateway Protocol (BSSGP)",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",

View File

@@ -7,12 +7,6 @@ cat $abs_srcdir/gprs/gprs_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([gbproxy])
AT_KEYWORDS([gbproxy])
cat $abs_srcdir/gbproxy/gbproxy_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/gbproxy/gbproxy_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([sgsn])
AT_KEYWORDS([sgsn])
AT_CHECK([test "$enable_sgsn_test" != no || exit 77])

View File

@@ -67,55 +67,6 @@ class TestVTYBase(unittest.TestCase):
self.vty = None
osmoutil.end_proc(self.proc)
class TestVTYGbproxy(TestVTYBase):
def vty_command(self):
return ["./src/gbproxy/osmo-gbproxy", "-c",
"doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"]
def vty_app(self):
return (4246, "./src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy")
def testVtyTree(self):
self.vty.enable()
self.assertTrue(self.vty.verify('configure terminal', ['']))
self.assertEqual(self.vty.node(), 'config')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('ns', ['']))
self.assertEqual(self.vty.node(), 'config-ns')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEqual(self.vty.node(), 'config')
self.assertTrue(self.vty.verify('gbproxy', ['']))
self.assertEqual(self.vty.node(), 'config-gbproxy')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEqual(self.vty.node(), 'config')
def testVtyShow(self):
res = self.vty.command("show ns")
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
res = self.vty.command("show gbproxy stats")
self.assertTrue(res.find('GBProxy Global Statistics') >= 0)
def testVtyDeletePeer(self):
self.vty.enable()
self.assertTrue(self.vty.verify('delete-gbproxy-peer 9999 bvci 7777', ['BVC not found']))
res = self.vty.command("delete-gbproxy-peer 9999 all dry-run")
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
res = self.vty.command("delete-gbproxy-peer 9999 only-bvc dry-run")
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
self.assertTrue(res.find('Not Deleted 0 NS-VC') < 0)
res = self.vty.command("delete-gbproxy-peer 9999 only-nsvc dry-run")
self.assertTrue(res.find('Not Deleted 0 BVC') < 0)
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
res = self.vty.command("delete-gbproxy-peer 9999 all")
self.assertTrue(res.find('Deleted 0 BVC') >= 0)
self.assertTrue(res.find('Deleted 0 NS-VC') >= 0)
class TestVTYSGSN(TestVTYBase):
def vty_command(self):
@@ -143,7 +94,7 @@ class TestVTYSGSN(TestVTYBase):
def testVtyShow(self):
res = self.vty.command("show ns")
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
self.assertTrue(res.find('0 NS-VC:') >= 0)
self.assertTrue(self.vty.verify('show bssgp', ['']))
self.assertTrue(self.vty.verify('show bssgp stats', ['']))
self.assertTrue(self.vty.verify('show bssgp nsei 123', ['']))
@@ -276,13 +227,6 @@ class TestVTYSGSN(TestVTYBase):
for t in [3312, 3322, 3350, 3360, 3370, 3313, 3314, 3316, 3385, 3395, 3397]:
self.assertTrue(self.vty.verify('timer t%d 10' % t, ['']))
def add_gbproxy_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/gbproxy/osmo-gbproxy")):
print("Skipping the Gb-Proxy test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYGbproxy)
suite.addTest(test)
def add_sgsn_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
print("Skipping the SGSN test")
@@ -320,7 +264,6 @@ if __name__ == '__main__':
os.chdir(workdir)
print("Running tests for specific VTY commands")
suite = unittest.TestSuite()
add_gbproxy_test(suite, workdir)
add_sgsn_test(suite, workdir)
if args.test_name: