mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn.git
				synced 2025-11-04 06:03:15 +00:00 
			
		
		
		
	Compare commits
	
		
			270 Commits
		
	
	
		
			osmith/fix
			...
			pmaier/rim
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					78ecddd9c2 | ||
| 
						 | 
					f24970a7ca | ||
| 
						 | 
					2365fec0fb | ||
| 
						 | 
					5df65b6c30 | ||
| 
						 | 
					5f1020b963 | ||
| 
						 | 
					eda1b83f75 | ||
| 
						 | 
					b83aabaa95 | ||
| 
						 | 
					1bebd08a4b | ||
| 
						 | 
					a86056fdf3 | ||
| 
						 | 
					99ec755643 | ||
| 
						 | 
					d5dca3a67f | ||
| 
						 | 
					3c26a1dc3c | ||
| 
						 | 
					642019f288 | ||
| 
						 | 
					f8a5066ad0 | ||
| 
						 | 
					8c42673eba | ||
| 
						 | 
					07feb06d54 | ||
| 
						 | 
					86b630cfe1 | ||
| 
						 | 
					93bc518b53 | ||
| 
						 | 
					58101ea587 | ||
| 
						 | 
					6aad14c3fa | ||
| 
						 | 
					f44dfa8a0e | ||
| 
						 | 
					e931b39b3c | ||
| 
						 | 
					fd9e82da31 | ||
| 
						 | 
					f2307c483f | ||
| 
						 | 
					15a52d92c4 | ||
| 
						 | 
					05190c36bb | ||
| 
						 | 
					3d3c8c55f0 | ||
| 
						 | 
					164a1eeb8a | ||
| 
						 | 
					69569879ae | ||
| 
						 | 
					fd4d435442 | ||
| 
						 | 
					8ec269a0e0 | ||
| 
						 | 
					4bd6f663a7 | ||
| 
						 | 
					52c9b8e593 | ||
| 
						 | 
					51028e2c16 | ||
| 
						 | 
					e69f460ae7 | ||
| 
						 | 
					0e707fc83a | ||
| 
						 | 
					ffd6e37eb5 | ||
| 
						 | 
					44bde6b85a | ||
| 
						 | 
					e659f75cf1 | ||
| 
						 | 
					67e71eac1c | ||
| 
						 | 
					c1cf4af11b | ||
| 
						 | 
					f37aedbf76 | ||
| 
						 | 
					920c6c8c81 | ||
| 
						 | 
					df203361e8 | ||
| 
						 | 
					b61ab9b9ac | ||
| 
						 | 
					5f4736aa85 | ||
| 
						 | 
					fc1a5538d0 | ||
| 
						 | 
					eb967fccb2 | ||
| 
						 | 
					13c00008b4 | ||
| 
						 | 
					e5614e434f | ||
| 
						 | 
					b0b582bff8 | ||
| 
						 | 
					bc46812bd7 | ||
| 
						 | 
					4398ac073b | ||
| 
						 | 
					05d5f28e93 | ||
| 
						 | 
					7a74ae492e | ||
| 
						 | 
					749ca7c850 | ||
| 
						 | 
					e7ccfdb4aa | ||
| 
						 | 
					e39ff86dd9 | ||
| 
						 | 
					57b63875c7 | ||
| 
						 | 
					55e3dc8ec8 | ||
| 
						 | 
					acd967a177 | ||
| 
						 | 
					8501126031 | ||
| 
						 | 
					b43496a60d | ||
| 
						 | 
					caff83e702 | ||
| 
						 | 
					61f2186592 | ||
| 
						 | 
					559636a4a2 | ||
| 
						 | 
					13ccbc1e61 | ||
| 
						 | 
					d32852664d | ||
| 
						 | 
					77cdc424cb | ||
| 
						 | 
					fb6cf3221e | ||
| 
						 | 
					c63a8381e5 | ||
| 
						 | 
					328ed94040 | ||
| 
						 | 
					c230f0c283 | ||
| 
						 | 
					e2b9b7ee57 | ||
| 
						 | 
					199f295d36 | ||
| 
						 | 
					3c7656a481 | ||
| 
						 | 
					340a7e9339 | ||
| 
						 | 
					938ebfb129 | ||
| 
						 | 
					d06c717e30 | ||
| 
						 | 
					57425a3805 | ||
| 
						 | 
					f76428500a | ||
| 
						 | 
					0f9966e307 | ||
| 
						 | 
					245ac9501b | ||
| 
						 | 
					2d0e22960c | ||
| 
						 | 
					6cee1a1ded | ||
| 
						 | 
					c0e146467a | ||
| 
						 | 
					ab39b622cc | ||
| 
						 | 
					3aba7ad2ae | ||
| 
						 | 
					e9336a72a0 | ||
| 
						 | 
					2f898265d0 | ||
| 
						 | 
					a33f00637e | ||
| 
						 | 
					c12c1a6b0c | ||
| 
						 | 
					e5c8998f9c | ||
| 
						 | 
					8969db7a49 | ||
| 
						 | 
					0b0b59a8ff | ||
| 
						 | 
					888052e71c | ||
| 
						 | 
					913dbcd552 | ||
| 
						 | 
					922684f318 | ||
| 
						 | 
					3caa7f6d97 | ||
| 
						 | 
					223754fde5 | ||
| 
						 | 
					f025e582bb | ||
| 
						 | 
					e8cd6856a5 | ||
| 
						 | 
					c67c90b47e | ||
| 
						 | 
					c26072a77f | ||
| 
						 | 
					ce0a0e9beb | ||
| 
						 | 
					c8ace5a03c | ||
| 
						 | 
					183e6c3367 | ||
| 
						 | 
					8de4be261d | ||
| 
						 | 
					6fd19da165 | ||
| 
						 | 
					adcf97d095 | ||
| 
						 | 
					80adb30e93 | ||
| 
						 | 
					ebd39830cb | ||
| 
						 | 
					b05c1d0ce4 | ||
| 
						 | 
					999a776b70 | ||
| 
						 | 
					11ccc4305d | ||
| 
						 | 
					901ed14c89 | ||
| 
						 | 
					4be5ab3707 | ||
| 
						 | 
					c999c223ae | ||
| 
						 | 
					2ce050ba46 | ||
| 
						 | 
					43e5f8a2c6 | ||
| 
						 | 
					caf73b803c | ||
| 
						 | 
					0018d3e0ec | ||
| 
						 | 
					f955d078ed | ||
| 
						 | 
					93ccc3cf5d | ||
| 
						 | 
					10e0fcaae2 | ||
| 
						 | 
					592eb140f0 | ||
| 
						 | 
					c7b6aabac1 | ||
| 
						 | 
					873c8a55e7 | ||
| 
						 | 
					e0876bda26 | ||
| 
						 | 
					21afdf9a32 | ||
| 
						 | 
					c09cb29d78 | ||
| 
						 | 
					6ad4040f55 | ||
| 
						 | 
					45bf92feb4 | ||
| 
						 | 
					d367b8bc78 | ||
| 
						 | 
					5037b6817f | ||
| 
						 | 
					d245c0e542 | ||
| 
						 | 
					4380f94cf2 | ||
| 
						 | 
					0d170d61aa | ||
| 
						 | 
					fb5ccb468a | ||
| 
						 | 
					b96d5a6ead | ||
| 
						 | 
					6ff8d21fed | ||
| 
						 | 
					5b1122f717 | ||
| 
						 | 
					914484d561 | ||
| 
						 | 
					b6343a72d8 | ||
| 
						 | 
					ef0c2a4b85 | ||
| 
						 | 
					02b24c5a44 | ||
| 
						 | 
					cd7c7a74b7 | ||
| 
						 | 
					ddb3fbb0f2 | ||
| 
						 | 
					e245677cdd | ||
| 
						 | 
					1c33e4af05 | ||
| 
						 | 
					3844da98f8 | ||
| 
						 | 
					dee0bcc8e9 | ||
| 
						 | 
					51730f7a8c | ||
| 
						 | 
					f23e2db752 | ||
| 
						 | 
					8a33528854 | ||
| 
						 | 
					00c1f91ed7 | ||
| 
						 | 
					8d382c5337 | ||
| 
						 | 
					ef3c9af0f9 | ||
| 
						 | 
					5a21f07dff | ||
| 
						 | 
					ea0b5d0df6 | ||
| 
						 | 
					3054213e87 | ||
| 
						 | 
					3326ba7d4c | ||
| 
						 | 
					b6b2f14197 | ||
| 
						 | 
					959f77e34b | ||
| 
						 | 
					9e917647ae | ||
| 
						 | 
					784c59f87e | ||
| 
						 | 
					1aa0ae9db1 | ||
| 
						 | 
					cab8588242 | ||
| 
						 | 
					4b4c997dc5 | ||
| 
						 | 
					c4c1db9e78 | ||
| 
						 | 
					61ff273365 | ||
| 
						 | 
					bf69833b6d | ||
| 
						 | 
					7cb76a4321 | ||
| 
						 | 
					c91f53ca0a | ||
| 
						 | 
					5687ae65fa | ||
| 
						 | 
					7c86a1efce | ||
| 
						 | 
					453a51d1a1 | ||
| 
						 | 
					a54ed46bac | ||
| 
						 | 
					052d855449 | ||
| 
						 | 
					11ad5713f2 | ||
| 
						 | 
					d651edcce0 | ||
| 
						 | 
					56f5e74d7d | ||
| 
						 | 
					4bf53ef19a | ||
| 
						 | 
					91bb720449 | ||
| 
						 | 
					993d3f4d9a | ||
| 
						 | 
					78db244b42 | ||
| 
						 | 
					0e1b791c81 | ||
| 
						 | 
					8cd74407ab | ||
| 
						 | 
					6c4c6f08ae | ||
| 
						 | 
					fb7f8c5f07 | ||
| 
						 | 
					9a2fc908df | ||
| 
						 | 
					e794c1f00b | ||
| 
						 | 
					bd356a6d84 | ||
| 
						 | 
					e8c8ec9683 | ||
| 
						 | 
					55253716d2 | ||
| 
						 | 
					1239cf457e | ||
| 
						 | 
					ac44d6b2a2 | ||
| 
						 | 
					c8d98ac8f9 | ||
| 
						 | 
					6626bbc215 | ||
| 
						 | 
					103a7ec033 | ||
| 
						 | 
					6e8ed2784e | ||
| 
						 | 
					7418797027 | ||
| 
						 | 
					d97ff681c3 | ||
| 
						 | 
					83142beca2 | ||
| 
						 | 
					8c3d7fd263 | ||
| 
						 | 
					9e583c8d89 | ||
| 
						 | 
					5937dfd39f | ||
| 
						 | 
					cafa3881ad | ||
| 
						 | 
					447ad441e6 | ||
| 
						 | 
					f7a1aed0e6 | ||
| 
						 | 
					eb4233e505 | ||
| 
						 | 
					2636e89ff0 | ||
| 
						 | 
					bcd7709452 | ||
| 
						 | 
					7ffc6603e2 | ||
| 
						 | 
					826eaa327b | ||
| 
						 | 
					952fbf20c9 | ||
| 
						 | 
					8553f5532a | ||
| 
						 | 
					3375fa4d64 | ||
| 
						 | 
					e1ba4239b4 | ||
| 
						 | 
					638cddd8f1 | ||
| 
						 | 
					58937ce333 | ||
| 
						 | 
					02f2c34f8a | ||
| 
						 | 
					62fa6198ae | ||
| 
						 | 
					c42331f359 | ||
| 
						 | 
					15c9da226b | ||
| 
						 | 
					8bca8de5cb | ||
| 
						 | 
					82182d09c7 | ||
| 
						 | 
					08395b3369 | ||
| 
						 | 
					25998ddcc5 | ||
| 
						 | 
					60581ae7c9 | ||
| 
						 | 
					c70e8388c7 | ||
| 
						 | 
					5ce54ba1e6 | ||
| 
						 | 
					ff5b59a821 | ||
| 
						 | 
					be2330fde4 | ||
| 
						 | 
					8d2d7db818 | ||
| 
						 | 
					92ef0c8675 | ||
| 
						 | 
					68d9c5a468 | ||
| 
						 | 
					ef6205ba00 | ||
| 
						 | 
					86336af2a3 | ||
| 
						 | 
					6d92f148aa | ||
| 
						 | 
					27a0bf70e7 | ||
| 
						 | 
					d3c3ddeb51 | ||
| 
						 | 
					e6c5b4a970 | ||
| 
						 | 
					aae7daff81 | ||
| 
						 | 
					b32936d823 | ||
| 
						 | 
					d5dc143001 | ||
| 
						 | 
					65a5a0a27b | ||
| 
						 | 
					9d16b14345 | ||
| 
						 | 
					dd930a25ad | ||
| 
						 | 
					b3e10aa8eb | ||
| 
						 | 
					36ecddb705 | ||
| 
						 | 
					90dedcb2e7 | ||
| 
						 | 
					cfd307b4e8 | ||
| 
						 | 
					b26a5a82db | ||
| 
						 | 
					7369d449f1 | ||
| 
						 | 
					5e1a486a72 | ||
| 
						 | 
					627e285fd0 | ||
| 
						 | 
					5e0b829884 | ||
| 
						 | 
					bd6d677179 | ||
| 
						 | 
					482bb07301 | ||
| 
						 | 
					b63e19d7d2 | ||
| 
						 | 
					c6548bbaab | ||
| 
						 | 
					b2ebc59f30 | ||
| 
						 | 
					9d550cb369 | ||
| 
						 | 
					e6b2883f10 | ||
| 
						 | 
					6528e8c1cb | ||
| 
						 | 
					6e4cd085b5 | ||
| 
						 | 
					91a8bbd5db | ||
| 
						 | 
					d999e54aa2 | ||
| 
						 | 
					394aa533e9 | 
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -6,14 +6,15 @@ debian/*.log
 | 
			
		||||
.deps
 | 
			
		||||
Makefile
 | 
			
		||||
Makefile.in
 | 
			
		||||
bscconfig.h
 | 
			
		||||
bscconfig.h.in
 | 
			
		||||
config.h
 | 
			
		||||
config.h.in
 | 
			
		||||
*.*~
 | 
			
		||||
*.sw?
 | 
			
		||||
.libs
 | 
			
		||||
*.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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README
									
									
									
									
									
								
							@@ -1,17 +0,0 @@
 | 
			
		||||
About OsmoSGSN
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
OsmoSGSN originated from the OpenBSC project, as a separate program within
 | 
			
		||||
openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
 | 
			
		||||
OsmoSGSN was given its own separate git repository.
 | 
			
		||||
 | 
			
		||||
OsmoSGSN exposes
 | 
			
		||||
- GSUP towards OsmoHLR (or a MAP proxy);
 | 
			
		||||
- GTP towards a GGSN (e.g. OsmoGGSN);
 | 
			
		||||
- Gb towards a BSS (e.g. OsmoPCU);
 | 
			
		||||
- IuPS towards an RNC or HNB-GW (e.g. OsmoHNBGW) for 3G data;
 | 
			
		||||
- The Osmocom typical telnet VTY and CTRL interfaces.
 | 
			
		||||
 | 
			
		||||
Find OsmoSGSN issue tracker and wiki online at
 | 
			
		||||
https://osmocom.org/projects/osmosgsn
 | 
			
		||||
https://osmocom.org/projects/osmosgsn/wiki
 | 
			
		||||
							
								
								
									
										81
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
osmo-sgssn - Osmocom SGSN Implementation
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
This repository contains a C-language implementation of a GSM Serving GPRS
 | 
			
		||||
Support Node (SGSN) for 2G (GSM) and 3G (UMTS).  It is part of the
 | 
			
		||||
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
 | 
			
		||||
project.
 | 
			
		||||
 | 
			
		||||
OsmoSGSN exposes
 | 
			
		||||
 * Gb towards PCUs (e.g. OsmoPCU): Various GbIP flavors + Gb/FR/E1
 | 
			
		||||
 * GTP towards a GGSN (e.g. OsmoGGSN);
 | 
			
		||||
 * IuPS over IP towards RNCs / HNBGW (e.g. osmo-hnbgw)
 | 
			
		||||
 * The Osmocom typical telnet VTY and CTRL interfaces.
 | 
			
		||||
 * The Osmocom typical statsd exporter.
 | 
			
		||||
 * GSUP (custom MAP-like protocol) towards osmo-hlr
 | 
			
		||||
 | 
			
		||||
OsmoSGSN implements
 | 
			
		||||
 * GPRS mobility management
 | 
			
		||||
 * GPRS session management
 | 
			
		||||
 | 
			
		||||
Homepage
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
You can find the OsmoSGSN issue tracker and wiki online at
 | 
			
		||||
<https://osmocom.org/projects/osmosgsn> and <https://osmocom.org/projects/osmosgsn/wiki>.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GIT Repository
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
You can clone from the official osmo-sgsn.git repository using
 | 
			
		||||
 | 
			
		||||
        git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
 | 
			
		||||
 | 
			
		||||
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Documentation
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
User Manuals and VTY reference manuals are [optionally] built in PDF form
 | 
			
		||||
as part of the build process.
 | 
			
		||||
 | 
			
		||||
Pre-rendered PDF version of the current "master" can be found at
 | 
			
		||||
[User Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-usermanual.pdf)
 | 
			
		||||
as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-vty-reference.pdf)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Mailing List
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Discussions related to osmo-sgsn are happening on the
 | 
			
		||||
osmocom-net-gprs@lists.osmocom.org mailing list, please see
 | 
			
		||||
<https://lists.osmocom.org/postorius/lists/osmocom-net-gprs.lists.osmocom.org/> for subscription
 | 
			
		||||
options and the list archive.
 | 
			
		||||
 | 
			
		||||
Please observe the [Osmocom Mailing List
 | 
			
		||||
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
 | 
			
		||||
when posting.
 | 
			
		||||
 | 
			
		||||
Contributing
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Our coding standards are described at
 | 
			
		||||
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
 | 
			
		||||
 | 
			
		||||
We us a gerrit based patch submission/review process for managing
 | 
			
		||||
contributions.  Please see
 | 
			
		||||
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
 | 
			
		||||
more details
 | 
			
		||||
 | 
			
		||||
The current patch queue for osmo-sgsn can be seen at
 | 
			
		||||
<https://gerrit.osmocom.org/#/q/project:osmo-sgsn+status:open>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
History
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
OsmoSGSN originated from the OpenBSC project, as a separate program within
 | 
			
		||||
openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
 | 
			
		||||
OsmoSGSN was given its own separate git repository.
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
To run the configuration parsing and output (VTY) test suite, first install
 | 
			
		||||
 | 
			
		||||
  git://git.osmocom.org/python/osmo-python-tests
 | 
			
		||||
  https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests
 | 
			
		||||
 | 
			
		||||
and pass the following configure options here:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,2 @@
 | 
			
		||||
#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.
 | 
			
		||||
libosmcoore     >1.8.0          use GSM48_IE_GMM_RX_NPDU_NUM_LIST
 | 
			
		||||
							
								
								
									
										63
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								configure.ac
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
@@ -29,39 +34,32 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
 | 
			
		||||
fi
 | 
			
		||||
PKG_PROG_PKG_CONFIG([0.20])
 | 
			
		||||
 | 
			
		||||
dnl check for AX_CHECK_COMPILE_FLAG
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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.8.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.8.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.6.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.10.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.7.0)
 | 
			
		||||
    PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
 | 
			
		||||
    PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.4.0)
 | 
			
		||||
    PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.4.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(LIBCARES, libcares)
 | 
			
		||||
 | 
			
		||||
dnl checks for header files
 | 
			
		||||
@@ -110,15 +108,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
 | 
			
		||||
CFLAGS="$saved_CFLAGS"
 | 
			
		||||
AC_SUBST(SYMBOL_VISIBILITY)
 | 
			
		||||
 | 
			
		||||
CPPFLAGS="$CPPFLAGS -Wall"
 | 
			
		||||
CFLAGS="$CFLAGS -Wall"
 | 
			
		||||
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
 | 
			
		||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
 | 
			
		||||
CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs"
 | 
			
		||||
CFLAGS="$CFLAGS -Wall -Wno-trigraphs"
 | 
			
		||||
 | 
			
		||||
# Coverage build taken from WebKit's configure.in
 | 
			
		||||
AC_MSG_CHECKING([whether to enable code coverage support])
 | 
			
		||||
@@ -164,13 +155,13 @@ 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
 | 
			
		||||
		AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
 | 
			
		||||
		AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
			
		||||
@@ -239,21 +230,20 @@ AC_MSG_RESULT([CFLAGS="$CFLAGS"])
 | 
			
		||||
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
 | 
			
		||||
 | 
			
		||||
dnl Generate the output
 | 
			
		||||
AM_CONFIG_HEADER(bscconfig.h)
 | 
			
		||||
AM_CONFIG_HEADER(config.h)
 | 
			
		||||
 | 
			
		||||
AC_OUTPUT(
 | 
			
		||||
    include/Makefile
 | 
			
		||||
    include/osmocom/Makefile
 | 
			
		||||
    include/osmocom/gtphub/Makefile
 | 
			
		||||
    include/osmocom/sgsn/Makefile
 | 
			
		||||
    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 +255,5 @@ AC_OUTPUT(
 | 
			
		||||
    doc/manuals/Makefile
 | 
			
		||||
    contrib/Makefile
 | 
			
		||||
    contrib/systemd/Makefile
 | 
			
		||||
    contrib/osmo-sgsn.spec
 | 
			
		||||
    Makefile)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
demonstrate a unblock bug on the GB Proxy..
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
 | 
			
		||||
ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
 | 
			
		||||
 | 
			
		||||
bts_ns_unblock = "\x06"
 | 
			
		||||
ns_unblock_ack = "\x07"
 | 
			
		||||
 | 
			
		||||
bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
 | 
			
		||||
ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
 | 
			
		||||
 | 
			
		||||
bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import socket
 | 
			
		||||
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
			
		||||
socket.bind(("0.0.0.0", 0))
 | 
			
		||||
socket.setblocking(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
port = int(sys.argv[1])
 | 
			
		||||
print "Sending data to port: %d" % port
 | 
			
		||||
 | 
			
		||||
def send_and_receive(packet):
 | 
			
		||||
    socket.sendto(packet, ("127.0.0.1", port))
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        data, addr = socket.recvfrom(4096)
 | 
			
		||||
    except socket.error, e:
 | 
			
		||||
        print "ERROR", e
 | 
			
		||||
        import sys
 | 
			
		||||
        sys.exit(0)
 | 
			
		||||
    return data
 | 
			
		||||
 | 
			
		||||
#send stuff once
 | 
			
		||||
 | 
			
		||||
to_send = [
 | 
			
		||||
    (bts_ns_reset, ns_reset_ack, "reset ack"),
 | 
			
		||||
    (bts_ns_unblock, ns_unblock_ack, "unblock ack"),
 | 
			
		||||
    (bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
for (out, inp, type) in to_send:
 | 
			
		||||
    res = send_and_receive(out)
 | 
			
		||||
    if res != inp:
 | 
			
		||||
        print "Failed to get the %s" % type
 | 
			
		||||
        sys.exit(-1)
 | 
			
		||||
 | 
			
		||||
import time
 | 
			
		||||
time.sleep(3)
 | 
			
		||||
res = send_and_receive(bts_bvc_reset_8167)
 | 
			
		||||
print "Sent all messages... check wireshark for the last response"
 | 
			
		||||
@@ -37,20 +37,16 @@ osmo-build-dep.sh libosmo-netif
 | 
			
		||||
osmo-build-dep.sh osmo-ggsn
 | 
			
		||||
osmo-build-dep.sh osmo-hlr
 | 
			
		||||
 | 
			
		||||
enable_werror=""
 | 
			
		||||
if [ "x$IU" = "x--enable-iu" ]; then
 | 
			
		||||
    	osmo-build-dep.sh libosmo-sccp
 | 
			
		||||
	osmo-build-dep.sh libasn1c
 | 
			
		||||
	#osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh
 | 
			
		||||
	osmo-build-dep.sh osmo-iuh
 | 
			
		||||
else
 | 
			
		||||
	enable_werror="--enable-werror"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Additional configure options and depends
 | 
			
		||||
CONFIG=""
 | 
			
		||||
if [ "$WITH_MANUALS" = "1" ]; then
 | 
			
		||||
	osmo-build-dep.sh osmo-gsm-manuals
 | 
			
		||||
	CONFIG="--enable-manuals"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -64,18 +60,18 @@ set -x
 | 
			
		||||
 | 
			
		||||
cd "$base"
 | 
			
		||||
autoreconf --install --force
 | 
			
		||||
./configure --enable-sanitize $enable_werror $IU --enable-external-tests $CONFIG
 | 
			
		||||
./configure --enable-sanitize --enable-werror $IU --enable-external-tests $CONFIG
 | 
			
		||||
$MAKE $PARALLEL_MAKE
 | 
			
		||||
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 \
 | 
			
		||||
  DISTCHECK_CONFIGURE_FLAGS="--enable-werror $IU --enable-external-tests $CONFIG" \
 | 
			
		||||
  $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
									
								
							
							
						
						
									
										118
									
								
								contrib/osmo-sgsn.spec.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
#
 | 
			
		||||
# spec file for package osmo-sgsn
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
 | 
			
		||||
#
 | 
			
		||||
# All modifications and additions to the file contributed by third parties
 | 
			
		||||
# remain the property of their copyright owners, unless otherwise agreed
 | 
			
		||||
# upon. The license for this file, and modifications and additions to the
 | 
			
		||||
# file, is the same license as for the pristine package itself (unless the
 | 
			
		||||
# license for the pristine package is not an Open Source License, in which
 | 
			
		||||
# case the license is the MIT License). An "Open Source License" is a
 | 
			
		||||
# license that conforms to the Open Source Definition (Version 1.9)
 | 
			
		||||
# published by the Open Source Initiative.
 | 
			
		||||
 | 
			
		||||
## Disable LTO for now since it breaks compilation of the tests
 | 
			
		||||
## https://osmocom.org/issues/4116
 | 
			
		||||
%define _lto_cflags %{nil}
 | 
			
		||||
 | 
			
		||||
%define with_iu 1
 | 
			
		||||
Name:           osmo-sgsn
 | 
			
		||||
Version:        @VERSION@
 | 
			
		||||
Release:        0
 | 
			
		||||
Summary:        Osmocom's SGSN for 2G and 3G packet-switched mobile networks
 | 
			
		||||
License:        AGPL-3.0-or-later AND GPL-2.0-or-later
 | 
			
		||||
Group:          Productivity/Telephony/Servers
 | 
			
		||||
URL:            https://osmocom.org/projects/osmosgsn
 | 
			
		||||
Source:         %{name}-%{version}.tar.xz
 | 
			
		||||
BuildRequires:  autoconf
 | 
			
		||||
BuildRequires:  automake
 | 
			
		||||
BuildRequires:  libtool
 | 
			
		||||
BuildRequires:  pkgconfig
 | 
			
		||||
%if 0%{?suse_version}
 | 
			
		||||
BuildRequires:  systemd-rpm-macros
 | 
			
		||||
%endif
 | 
			
		||||
BuildRequires:  pkgconfig(libcares)
 | 
			
		||||
BuildRequires:  pkgconfig(libcrypto) >= 0.9.5
 | 
			
		||||
BuildRequires:  pkgconfig(libgtp) >= 1.10.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmo-gsup-client) >= 1.6.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.3.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.4.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmocore) >= 1.8.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.8.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmogb) >= 1.8.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.8.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmovty) >= 1.8.0
 | 
			
		||||
%{?systemd_requires}
 | 
			
		||||
%if %{with_iu}
 | 
			
		||||
BuildRequires:  pkgconfig(libasn1c)
 | 
			
		||||
BuildRequires:  pkgconfig(libosmo-ranap) >= 1.4.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmo-sigtran) >= 1.7.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.md
 | 
			
		||||
%dir %{_docdir}/%{name}/examples
 | 
			
		||||
%dir %{_docdir}/%{name}/examples/osmo-sgsn
 | 
			
		||||
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
 | 
			
		||||
%{_bindir}/osmo-sgsn
 | 
			
		||||
%dir %{_sysconfdir}/osmocom
 | 
			
		||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-sgsn.cfg
 | 
			
		||||
%{_unitdir}/%{name}.service
 | 
			
		||||
 | 
			
		||||
%files -n osmo-gtphub
 | 
			
		||||
%dir %{_docdir}/%{name}/examples
 | 
			
		||||
%dir %{_docdir}/%{name}/examples/osmo-gtphub
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub.cfg
 | 
			
		||||
%{_bindir}/osmo-gtphub
 | 
			
		||||
%dir %{_sysconfdir}/osmocom
 | 
			
		||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
 | 
			
		||||
%{_unitdir}/osmo-gtphub.service
 | 
			
		||||
 | 
			
		||||
%changelog
 | 
			
		||||
@@ -1,11 +1,9 @@
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
  osmo-gbproxy.service \
 | 
			
		||||
  osmo-gtphub.service \
 | 
			
		||||
  osmo-sgsn.service
 | 
			
		||||
 | 
			
		||||
if HAVE_SYSTEMD
 | 
			
		||||
SYSTEMD_SERVICES = \
 | 
			
		||||
  osmo-gbproxy.service \
 | 
			
		||||
  osmo-gtphub.service \
 | 
			
		||||
  osmo-sgsn.service
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Osmocom Gb proxy
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/bin/osmo-gbproxy -c /etc/osmocom/osmo-gbproxy.cfg
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
RestartPreventExitStatus=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Osmocom GTP Hub
 | 
			
		||||
After=network-online.target
 | 
			
		||||
Wants=network-online.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/bin/osmo-gtphub -c /etc/osmocom/osmo-gtphub.cfg
 | 
			
		||||
StateDirectory=osmocom
 | 
			
		||||
WorkingDirectory=%S/osmocom
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
RestartPreventExitStatus=1
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,13 @@ Description=Osmocom SGSN (Serving GPRS Support Node)
 | 
			
		||||
Wants=osmo-hlr.service
 | 
			
		||||
After=osmo-hlr.service
 | 
			
		||||
After=osmo-hnbgw.service
 | 
			
		||||
After=network-online.target
 | 
			
		||||
Wants=network-online.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
StateDirectory=osmocom
 | 
			
		||||
WorkingDirectory=%S/osmocom
 | 
			
		||||
Restart=always
 | 
			
		||||
ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
 | 
			
		||||
RestartSec=2
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										425
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										425
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,428 @@
 | 
			
		||||
osmo-sgsn (1.10.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * configure.ac: do not require unused dlsym/dlopen
 | 
			
		||||
  * gprs_llc: fix misleading spacing in gprs_llc_rcvmsg()
 | 
			
		||||
  * gprs_llc.h: use '#pragma once'
 | 
			
		||||
  * llc: gprs_llc_fcs(): make the input data pointer const
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Set working directory in systemd service file
 | 
			
		||||
  * SNDCP: log more details on failure
 | 
			
		||||
  * GTP: migrate from deprecated function
 | 
			
		||||
  * Constify LLC/SNDCP parameters
 | 
			
		||||
  * GMM: permit E_GMM_COMMON_PROC_SUCCESS in normal state
 | 
			
		||||
  * ctrl: take both address and port from vty config
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * vty: Make new libgtp tdefs configurable through VTY
 | 
			
		||||
  * sndcp: Put decompress handling code into helper function
 | 
			
		||||
  * Move gprs_gb_parse.[c,h] to tests/sgsn/
 | 
			
		||||
  * Create new specific file for BSSGP code
 | 
			
		||||
  * Move some functions gprs_gb.[c,h] -> gprs_gmm.[c,h]
 | 
			
		||||
  * Rename gprs_gb.[c,h] -> gprs_ns.[c,h]
 | 
			
		||||
  * Move gprs_tmr_to_secs() to tests/gprs/gprs_test.c
 | 
			
		||||
  * cosmetic: gprs_llc_vty.c: Fix trailing whitespace
 | 
			
		||||
  * vty: Fix wrong value_string used to print llme state
 | 
			
		||||
  * Standarize lle and llme state enum & value_string
 | 
			
		||||
  * Remove unused function gprs_parse_mi_tmsi()
 | 
			
		||||
  * Replace gprs_str_to_apn() with libosmocore API osmo_apn_from_str()
 | 
			
		||||
  * Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h}
 | 
			
		||||
  * gprs_subscriber: Move API declarations to correct header
 | 
			
		||||
  * Move gprs_sndcp_vty_init() declaration to gprs_sndcp.h
 | 
			
		||||
  * Introduce new header file sgsn/gtp.h
 | 
			
		||||
  * Fix -Werror=old-style-definition
 | 
			
		||||
  * Move related structs to gprs_subscriber.h
 | 
			
		||||
  * Remove unneeded extern declaration from libosmocotrl
 | 
			
		||||
  * Keep sgsn subsystems under struct sgsn_instance lifecycle
 | 
			
		||||
  * Move global ggsn_list into struct sgsn_instance
 | 
			
		||||
  * Move struct apn_ctx and APN related definitions to its own file
 | 
			
		||||
  * Move struct sgsn_subscriber_pdp_data to gprs_subscriber.h
 | 
			
		||||
  * sgsn.h: Drop declaration of non existing function
 | 
			
		||||
  * Properly split llc->sndcp->gtp unitdata pathi through extra func call
 | 
			
		||||
  * Move func defintions of funcs implemented in gprs_sndcp.c to gprs_sndcp.h
 | 
			
		||||
  * sndcp: Standarize unitdata function naming
 | 
			
		||||
  * Move gtp related functions to gtp.h
 | 
			
		||||
  * Move global apn_list inside struct sgsn_instance
 | 
			
		||||
  * gtp_{ggsn,mme}: Allocate contexts under struct sgsn_instance
 | 
			
		||||
  * Move extern declarations of tall_sgsn_ctx to sgsn.h
 | 
			
		||||
  * Drop extern declarations of global sgsn_instance in source files
 | 
			
		||||
  * Move sgsn_pdp_ctx to its own file pdpctx.{c,h}
 | 
			
		||||
  * Move global pdp_list inside struct sgsn_instance
 | 
			
		||||
  * Move gtphub header to include/osmocom/gtphub/
 | 
			
		||||
  * Move sgsn_ctrl_cmds_install() declaration to sgsn.h
 | 
			
		||||
  * Move LOGGSUBSCRP to gprs_subscriber.h
 | 
			
		||||
  * Rename bscconfig.h -> config.h
 | 
			
		||||
  * gtphub.h: Remove dependency on sgsn/gprs_sgsn.h
 | 
			
		||||
  * Split gprs_sgsn.{c,h} -> {auth,mmctx,sgsn}.{c,h}
 | 
			
		||||
  * Move global mmctx list into struct sgsn_instance
 | 
			
		||||
  * vty: Introduce encryption cipher-plugin-path command
 | 
			
		||||
  * Fix extra whitespace in pdpctx_ctr_description
 | 
			
		||||
 | 
			
		||||
  [ Oliver Smith ]
 | 
			
		||||
  * contrib/jenkins.sh: use enable-werror with IU too
 | 
			
		||||
  * sgsn_libgtp: cb_data_ind: remove mm_idle assert
 | 
			
		||||
  * osmo-gtphub.cfg: fix conflict with osmo-ggsn.cfg
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 07 Feb 2023 17:34:26 +0100
 | 
			
		||||
 | 
			
		||||
osmo-sgsn (1.9.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Oliver Smith ]
 | 
			
		||||
  * llme_free: clean up related sndcp
 | 
			
		||||
  * treewide: remove FSF address
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * Drop unneeded ax_check_compile_flag.m4
 | 
			
		||||
  * Revert "sgsn: Handle different levels of QoS"
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * s/cipher_support_mask/gea_encryption_mask
 | 
			
		||||
  * Iu: add UEA encryption
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * update git URLs (git -> https; gitea)
 | 
			
		||||
  * README: Major update
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Wed, 29 Jun 2022 11:45:08 +0200
 | 
			
		||||
 | 
			
		||||
osmo-sgsn (1.8.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * Remove bogus DNS log category
 | 
			
		||||
 | 
			
		||||
  [ Daniel Willmann ]
 | 
			
		||||
  * manuals: Regenerate counters/VTY through docker
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * main: resurrect removed 'ns' logging category as deprecated
 | 
			
		||||
  * doc/manuals: update configuration.adoc to use new command syntax
 | 
			
		||||
  * tests/Makefile.am: do not try removing non-existing files
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * ranap: log ranap iu event type name instead of number
 | 
			
		||||
  * gmm: log GMM msg type name instead of number
 | 
			
		||||
  * gmm: Expect E_VLR_ANSWERED when in ST_IU_SECURITY_CMD
 | 
			
		||||
  * gmm_fsm: Expect E_GMM_COMMON_PROC_INIT_REQ when in ST_GMM_COMMON_PROC_INIT
 | 
			
		||||
  * mm_iu: Send event E_PMM_PS_CONN_ESTABLISH upon rx GMM SERVICE REQUEST
 | 
			
		||||
  * mm_iu: Expect E_PMM_PS_ATTACH when in ST_PMM_IDLE
 | 
			
		||||
  * gprs_gmm.c: State proper GMM prefix logging rx/tx of GMM messages
 | 
			
		||||
  * mm_state_iu_fsm: T3314 expiry must lead to PMM IDLE, not PMM DETACHED
 | 
			
		||||
  * Iu: Drop timer X3314
 | 
			
		||||
  * gprs_ranap.c: Clean up code path releasing IU conn
 | 
			
		||||
  * mm_state_{gb,iu}_fsm: Add missing license block, improve spec references
 | 
			
		||||
  * mm_state_{gb,iu}_fsm: Improve naming for detach event
 | 
			
		||||
  * Drop unused GBRPOXY enum field
 | 
			
		||||
  * gtp: Delete ctx upon receive UpdateCtxResp with cause Non-existent
 | 
			
		||||
  * Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN
 | 
			
		||||
  * Use new stat item/ctr getter APIs
 | 
			
		||||
 | 
			
		||||
  [ Keith ]
 | 
			
		||||
  * vty: Fix optional display of pdp with mm-context
 | 
			
		||||
  * VTY: Don't display 'PDP Address: invalid' for IPv4v6
 | 
			
		||||
 | 
			
		||||
  [ Eric ]
 | 
			
		||||
  * add support for multiple encryption algorithms and a5/4
 | 
			
		||||
 | 
			
		||||
  [ Oliver Smith ]
 | 
			
		||||
  * gtphub: remove llist_first, llist_last macros
 | 
			
		||||
  * vty: add "page imsi"
 | 
			
		||||
  * debian/control: remove dh-systemd build-depend
 | 
			
		||||
  * Revert "Turn some compiler warnings into errors"
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 16 Nov 2021 17:57:50 +0100
 | 
			
		||||
 | 
			
		||||
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 ]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@@ -1 +1 @@
 | 
			
		||||
9
 | 
			
		||||
10
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,10 +1,9 @@
 | 
			
		||||
Source: osmo-sgsn
 | 
			
		||||
Section: net
 | 
			
		||||
Priority: extra
 | 
			
		||||
Maintainer: Alexander Couzens <lynxis@fe80.eu>
 | 
			
		||||
Build-Depends: debhelper (>=9),
 | 
			
		||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
			
		||||
Build-Depends: debhelper (>= 10),
 | 
			
		||||
               dh-autoreconf,
 | 
			
		||||
               dh-systemd (>= 1.5),
 | 
			
		||||
               autotools-dev,
 | 
			
		||||
               autoconf,
 | 
			
		||||
               automake,
 | 
			
		||||
@@ -12,19 +11,19 @@ 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.10.0),
 | 
			
		||||
               libosmocore-dev (>= 1.8.0),
 | 
			
		||||
               libosmo-abis-dev (>= 1.4.0),
 | 
			
		||||
               libosmo-netif-dev (>= 1.3.0),
 | 
			
		||||
               libosmo-gsup-client-dev (>= 1.6.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 (>= 1.4.0),
 | 
			
		||||
               libosmo-sigtran-dev (>= 1.7.0),
 | 
			
		||||
               libosmo-sccp-dev (>= 1.7.0),
 | 
			
		||||
               osmo-gsm-manuals-dev (>= 1.4.0)
 | 
			
		||||
Standards-Version: 3.9.8
 | 
			
		||||
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
 | 
			
		||||
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
 | 
			
		||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
 | 
			
		||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
 | 
			
		||||
Homepage: https://projects.osmocom.org/projects/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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
			
		||||
Upstream-Name: osmo-sgsn
 | 
			
		||||
Source: git://git.osmocom.org/osmo-sgsn
 | 
			
		||||
Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
 | 
			
		||||
 | 
			
		||||
Files:     .gitignore
 | 
			
		||||
           .gitreview
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -36,7 +33,6 @@ Files:     .gitignore
 | 
			
		||||
           include/osmocom/sgsn/crc24.h
 | 
			
		||||
           include/osmocom/sgsn/debug.h
 | 
			
		||||
           include/osmocom/sgsn/gb_proxy.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_gb_parse.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_gmm.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_llc.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_sgsn.h
 | 
			
		||||
@@ -51,13 +47,12 @@ 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
 | 
			
		||||
           tests/gtphub/Makefile.am
 | 
			
		||||
           tests/gtphub/gtphub_test.ok
 | 
			
		||||
           tests/sgsn/gprs_gb_parse.h
 | 
			
		||||
           tests/sgsn/Makefile.am
 | 
			
		||||
           tests/sgsn/sgsn_test.ok
 | 
			
		||||
           tests/slhc/Makefile.am
 | 
			
		||||
@@ -79,19 +74,12 @@ Files:     include/osmocom/sgsn/a_reset.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_sndcp_pcomp.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_sndcp_xid.h
 | 
			
		||||
           include/osmocom/sgsn/gprs_utils.h
 | 
			
		||||
           include/osmocom/sgsn/gtphub.h
 | 
			
		||||
           include/osmocom/gtphub/gtphub.h
 | 
			
		||||
           include/osmocom/sgsn/signal.h
 | 
			
		||||
           src/gprs/gprs_llc_parse.c
 | 
			
		||||
           src/gprs/crc24.c
 | 
			
		||||
           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
 | 
			
		||||
@@ -114,6 +102,7 @@ Files:     include/osmocom/sgsn/a_reset.h
 | 
			
		||||
           src/sgsn/sgsn_main.c
 | 
			
		||||
           src/sgsn/sgsn_vty.c
 | 
			
		||||
           tests/gtphub/gtphub_test.c
 | 
			
		||||
           tests/sgsn/gprs_gb_parse.c
 | 
			
		||||
           tests/sgsn/sgsn_test.c
 | 
			
		||||
           tests/slhc/slhc_test.c
 | 
			
		||||
           tests/sndcp_xid/sndcp_xid_test.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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								debian/osmo-gbproxy.init
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										151
									
								
								debian/osmo-gbproxy.init
									
									
									
									
										vendored
									
									
								
							@@ -1,151 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
### BEGIN INIT INFO
 | 
			
		||||
# Provides:          osmo-gbproxy
 | 
			
		||||
# Required-Start:    $network $local_fs
 | 
			
		||||
# Required-Stop:
 | 
			
		||||
# Default-Start:     2 3 4 5
 | 
			
		||||
# Default-Stop:      0 1 6
 | 
			
		||||
# Short-Description: Osmocom GBproxy
 | 
			
		||||
# Description:       A tool to proxy the GPRS Gb interface.
 | 
			
		||||
### END INIT INFO
 | 
			
		||||
 | 
			
		||||
# Author: Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 | 
			
		||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
 | 
			
		||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
 | 
			
		||||
NAME=osmo-gbproxy                      # Introduce the short server's name here
 | 
			
		||||
DESC="Osmocom GBProxy" # Introduce a short description here
 | 
			
		||||
DAEMON=/usr/bin/osmo-gbproxy           # Introduce the server's location here
 | 
			
		||||
SCRIPTNAME=/etc/init.d/osmocom-gbproxy
 | 
			
		||||
CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
 | 
			
		||||
 | 
			
		||||
# Exit if the package is not installed
 | 
			
		||||
[ -x $DAEMON ] || exit 0
 | 
			
		||||
 | 
			
		||||
# Read configuration variable file if it is present
 | 
			
		||||
[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
 | 
			
		||||
 | 
			
		||||
# Load the VERBOSE setting and other rcS variables
 | 
			
		||||
. /lib/init/vars.sh
 | 
			
		||||
 | 
			
		||||
# Define LSB log_* functions.
 | 
			
		||||
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
 | 
			
		||||
. /lib/lsb/init-functions
 | 
			
		||||
 | 
			
		||||
DAEMON_ARGS="-D -c $CONFIG_FILE"
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Function that starts the daemon/service
 | 
			
		||||
#
 | 
			
		||||
do_start()
 | 
			
		||||
{
 | 
			
		||||
	# Return
 | 
			
		||||
	#   0 if daemon has been started
 | 
			
		||||
	#   1 if daemon was already running
 | 
			
		||||
	#   2 if daemon could not be started
 | 
			
		||||
	start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
 | 
			
		||||
		|| return 1
 | 
			
		||||
	start-stop-daemon --start --quiet --exec $DAEMON -- \
 | 
			
		||||
		$DAEMON_ARGS \
 | 
			
		||||
		|| return 2
 | 
			
		||||
	# Add code here, if necessary, that waits for the process to be ready
 | 
			
		||||
	# to handle requests from services started subsequently which depend
 | 
			
		||||
	# on this one.  As a last resort, sleep for some time.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Function that stops the daemon/service
 | 
			
		||||
#
 | 
			
		||||
do_stop()
 | 
			
		||||
{
 | 
			
		||||
	# Return
 | 
			
		||||
	#   0 if daemon has been stopped
 | 
			
		||||
	#   1 if daemon was already stopped
 | 
			
		||||
	#   2 if daemon could not be stopped
 | 
			
		||||
	#   other if a failure occurred
 | 
			
		||||
	start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
 | 
			
		||||
	RETVAL="$?"
 | 
			
		||||
	[ "$RETVAL" = 2 ] && return 2
 | 
			
		||||
	# Wait for children to finish too if this is a daemon that forks
 | 
			
		||||
	# and if the daemon is only ever run from this initscript.
 | 
			
		||||
	# If the above conditions are not satisfied then add some other code
 | 
			
		||||
	# that waits for the process to drop all resources that could be
 | 
			
		||||
	# needed by services started subsequently.  A last resort is to
 | 
			
		||||
	# sleep for some time.
 | 
			
		||||
	start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
 | 
			
		||||
	[ "$?" = 2 ] && return 2
 | 
			
		||||
	return "$RETVAL"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Function that sends a SIGHUP to the daemon/service
 | 
			
		||||
#
 | 
			
		||||
do_reload() {
 | 
			
		||||
	#
 | 
			
		||||
	# If the daemon can reload its configuration without
 | 
			
		||||
	# restarting (for example, when it is sent a SIGHUP),
 | 
			
		||||
	# then implement that here.
 | 
			
		||||
	#
 | 
			
		||||
	start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
 | 
			
		||||
    do_start
 | 
			
		||||
    case "$?" in
 | 
			
		||||
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
 | 
			
		||||
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
 | 
			
		||||
	esac
 | 
			
		||||
  ;;
 | 
			
		||||
  stop)
 | 
			
		||||
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
 | 
			
		||||
	do_stop
 | 
			
		||||
	case "$?" in
 | 
			
		||||
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
 | 
			
		||||
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
 | 
			
		||||
	esac
 | 
			
		||||
	;;
 | 
			
		||||
  status)
 | 
			
		||||
       status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
 | 
			
		||||
       ;;
 | 
			
		||||
  #reload|force-reload)
 | 
			
		||||
	#
 | 
			
		||||
	# If do_reload() is not implemented then leave this commented out
 | 
			
		||||
	# and leave 'force-reload' as an alias for 'restart'.
 | 
			
		||||
	#
 | 
			
		||||
	#log_daemon_msg "Reloading $DESC" "$NAME"
 | 
			
		||||
	#do_reload
 | 
			
		||||
	#log_end_msg $?
 | 
			
		||||
	#;;
 | 
			
		||||
  restart|force-reload)
 | 
			
		||||
	#
 | 
			
		||||
	# If the "reload" option is implemented then remove the
 | 
			
		||||
	# 'force-reload' alias
 | 
			
		||||
	#
 | 
			
		||||
	log_daemon_msg "Restarting $DESC" "$NAME"
 | 
			
		||||
	do_stop
 | 
			
		||||
	case "$?" in
 | 
			
		||||
	  0|1)
 | 
			
		||||
		do_start
 | 
			
		||||
		case "$?" in
 | 
			
		||||
			0) log_end_msg 0 ;;
 | 
			
		||||
			1) log_end_msg 1 ;; # Old process is still running
 | 
			
		||||
			*) log_end_msg 1 ;; # Failed to start
 | 
			
		||||
		esac
 | 
			
		||||
		;;
 | 
			
		||||
	  *)
 | 
			
		||||
	  	# Failed to stop
 | 
			
		||||
		log_end_msg 1
 | 
			
		||||
		;;
 | 
			
		||||
	esac
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
 | 
			
		||||
	echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
 | 
			
		||||
	exit 3
 | 
			
		||||
	;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
:
 | 
			
		||||
							
								
								
									
										5
									
								
								debian/osmo-gbproxy.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/osmo-gbproxy.install
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +0,0 @@
 | 
			
		||||
etc/osmocom/osmo-gbproxy.cfg
 | 
			
		||||
lib/systemd/system/osmo-gbproxy.service
 | 
			
		||||
usr/bin/osmo-gbproxy
 | 
			
		||||
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg usr/share/doc/osmo-gbproxy/examples
 | 
			
		||||
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy.cfg usr/share/doc/osmo-gbproxy/examples
 | 
			
		||||
							
								
								
									
										1
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -58,7 +58,6 @@ override_dh_auto_configure:
 | 
			
		||||
override_dh_strip:
 | 
			
		||||
	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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoGbProxy (UNKNOWN) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
 logging filter all 1
 | 
			
		||||
 logging color 1
 | 
			
		||||
 logging timestamp 0
 | 
			
		||||
 logging level all debug
 | 
			
		||||
 logging level gprs debug
 | 
			
		||||
 logging level ns info
 | 
			
		||||
 logging level bssgp debug
 | 
			
		||||
 logging level lglobal notice
 | 
			
		||||
 logging level llapd notice
 | 
			
		||||
 logging level linp notice
 | 
			
		||||
 logging level lmux notice
 | 
			
		||||
 logging level lmi notice
 | 
			
		||||
 logging level lmib notice
 | 
			
		||||
 logging level lsms notice
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
ns
 | 
			
		||||
 nse 666 nsvci 666
 | 
			
		||||
 nse 666 remote-role sgsn
 | 
			
		||||
! nse 666 encapsulation framerelay-gre
 | 
			
		||||
! nse 666 remote-ip 172.16.1.70
 | 
			
		||||
! nse 666 fr-dlci 666
 | 
			
		||||
 timer tns-block 3
 | 
			
		||||
 timer tns-block-retries 3
 | 
			
		||||
 timer tns-reset 3
 | 
			
		||||
 timer tns-reset-retries 3
 | 
			
		||||
 timer tns-test 30
 | 
			
		||||
 timer tns-alive 3
 | 
			
		||||
 timer tns-alive-retries 10
 | 
			
		||||
 encapsulation udp local-port 23000
 | 
			
		||||
! encapsulation framerelay-gre enabled 1
 | 
			
		||||
gbproxy
 | 
			
		||||
 sgsn nsei 666
 | 
			
		||||
 core-mobile-country-code 666
 | 
			
		||||
 core-mobile-network-code 6
 | 
			
		||||
 core-access-point-name none match-imsi ^666066|^66607
 | 
			
		||||
 tlli-list max-length 200
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
!
 | 
			
		||||
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
gbproxy
 | 
			
		||||
 sgsn nsei 101
 | 
			
		||||
ns
 | 
			
		||||
 nse 101 nsvci 101
 | 
			
		||||
 nse 101 remote-role sgsn
 | 
			
		||||
 nse 101 encapsulation udp
 | 
			
		||||
 nse 101 remote-ip 192.168.100.239
 | 
			
		||||
 nse 101 remote-port 7777
 | 
			
		||||
 timer tns-block 3
 | 
			
		||||
 timer tns-block-retries 3
 | 
			
		||||
 timer tns-reset 3
 | 
			
		||||
 timer tns-reset-retries 3
 | 
			
		||||
 timer tns-test 30
 | 
			
		||||
 timer tns-alive 3
 | 
			
		||||
 timer tns-alive-retries 10
 | 
			
		||||
 encapsulation framerelay-gre enabled 0
 | 
			
		||||
 encapsulation framerelay-gre local-ip 0.0.0.0
 | 
			
		||||
 encapsulation udp local-ip 127.0.0.100
 | 
			
		||||
 encapsulation udp local-port 23000
 | 
			
		||||
@@ -9,7 +9,7 @@ gtphub
 | 
			
		||||
 ! Local addresses to listen on and send from, each on standard ports
 | 
			
		||||
 ! 2123 and 2152. Setting these addresses is mandatory.
 | 
			
		||||
 bind-to-sgsns 127.0.0.10
 | 
			
		||||
 bind-to-ggsns 127.0.0.2
 | 
			
		||||
 bind-to-ggsns 127.0.0.20
 | 
			
		||||
 | 
			
		||||
 ! Local nonstandard ports or separate IPs:
 | 
			
		||||
 !bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
!
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
!
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ cs7 instance 0
 | 
			
		||||
 point-code 0.23.4
 | 
			
		||||
 asp asp-clnt-OsmoSGSN-A 2905 0 m3ua
 | 
			
		||||
  remote-ip 172.18.8.200 ! where to reach the STP
 | 
			
		||||
  role asp
 | 
			
		||||
  sctp-role client
 | 
			
		||||
 as as-clnt-OsmoSGSN-A m3ua
 | 
			
		||||
  asp asp-clnt-OsmoSGSN-A
 | 
			
		||||
  routing-key 3 0.23.4
 | 
			
		||||
@@ -31,9 +33,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
 | 
			
		||||
!
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,8 @@ explicit configuration of each PCU connecting to the SGSN. The
 | 
			
		||||
administrator only has to ensure that the NS and BSSGP layer identities
 | 
			
		||||
(NSEI, NSVCI, BVCI) are unique for each PCU connecting to the SGSN.
 | 
			
		||||
 | 
			
		||||
=== Configuring the Gp interface
 | 
			
		||||
[[gp-if-ggsn]]
 | 
			
		||||
=== Configuring the Gp interface (towards GGSN)
 | 
			
		||||
 | 
			
		||||
The Gp interface is the GTP-C and GTP-U based interface between the SGSN
 | 
			
		||||
and the GGSNs.  It is implemented via UDP on well-known source and
 | 
			
		||||
@@ -67,6 +68,58 @@ OsmoSGSN(config-sgsn)# grx-dns-add 1.2.3.4 <3>
 | 
			
		||||
<2> Enable the dynamic GGSN resolving mode
 | 
			
		||||
<3> Specify the IP address of a DNS server for APN resolution
 | 
			
		||||
 | 
			
		||||
[[gp-if-mme]]
 | 
			
		||||
=== Configuring the Gp interface (towards MME)
 | 
			
		||||
 | 
			
		||||
The Gp interface also contains the GTP-C v1 based interface between the SGSN
 | 
			
		||||
and the MMEs. This interface between SGSN and MMEs is used to transfer _RAN
 | 
			
		||||
Information Relay_ GTP-C messages between them, which are used as containers to
 | 
			
		||||
allow PCUs under the SGSN and eNodeBs under MMEs to  exchange cell information
 | 
			
		||||
(RIM).
 | 
			
		||||
 | 
			
		||||
In the SGSN, this interface re-uses the same socket local configuration as per
 | 
			
		||||
the GGSN connections (see _gtp local-ip_ VTY command in <<gp-if-ggsn>>).
 | 
			
		||||
 | 
			
		||||
Similarly as with GGSNs, (again see <<gp-if-ggsn>>), selection of destination
 | 
			
		||||
peers for the _RAN Information Relay_ message can be configured statically or
 | 
			
		||||
dynamically over GRX.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
==== Static MME/TAI configuration
 | 
			
		||||
 | 
			
		||||
In this mode, there is a static list of MMEs and TAIs configured in
 | 
			
		||||
OsmoSGSN via the VTY / config file. One MME in the list can be configured as the
 | 
			
		||||
_default route_, where all unspecified TAIs are routed too.
 | 
			
		||||
 | 
			
		||||
This is a non-standard method outside of the 3GPP specifications for the
 | 
			
		||||
SGSN, and is typically only used in private/small GPRS networks without
 | 
			
		||||
any access to a GRX.
 | 
			
		||||
 | 
			
		||||
.Example: Static MME/TAI configuration (single catch-all GGSN)
 | 
			
		||||
----
 | 
			
		||||
sgsn
 | 
			
		||||
...
 | 
			
		||||
 gtp local-ip 192.168.0.10 <1>
 | 
			
		||||
 mme test-mme0 <2>
 | 
			
		||||
  gtp remote-ip 192.168.0.20 <3>
 | 
			
		||||
  gtp ran-info-relay 262 42 3 <4>
 | 
			
		||||
  gtp ran-info-relay 262 42 4
 | 
			
		||||
 mme test-mme1 <5>
 | 
			
		||||
  gtp remote-ip 192.168.0.30
 | 
			
		||||
  gtp ran-info-relay default  <6>
 | 
			
		||||
----
 | 
			
		||||
<1> Configure the local IP address at the SGSN used for Gp/GTP
 | 
			
		||||
<2> Configure an MME named "test-mme0"
 | 
			
		||||
<3> Specify the remote IP address of the MME (for MME "test-mme0")
 | 
			
		||||
<4> Route specified TAIs towards this MME
 | 
			
		||||
<5> Configure an MME named "test-mme1"
 | 
			
		||||
<6> Route all TAIs with an unspecified MME towards MM "test-mme1"
 | 
			
		||||
 | 
			
		||||
==== Dynamic MME/TAI configuration
 | 
			
		||||
 | 
			
		||||
Dynamic MME/TAI peer look up over GRX is not yet supported by OsmoSGSN.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[auth-pol]]
 | 
			
		||||
=== Authorization Policy
 | 
			
		||||
 | 
			
		||||
@@ -345,14 +398,35 @@ Encryption can be enabled if the auth-policy is set to remote and the
 | 
			
		||||
HLR subscriber entries contain the keys of the SIM card. See
 | 
			
		||||
<<sgsn-ex-gsup>> on how to connect to an external HLR.
 | 
			
		||||
 | 
			
		||||
.Example: Turn on encryption (GEA3)
 | 
			
		||||
.Example: Turn on encryption (GEA3 and GEA4)
 | 
			
		||||
----
 | 
			
		||||
sgsn
 | 
			
		||||
 encryption GEA3
 | 
			
		||||
 encryption gea 3 4
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.Example: Turn off encryption (GEA0)
 | 
			
		||||
----
 | 
			
		||||
sgsn
 | 
			
		||||
 encryption GEA0
 | 
			
		||||
 encryption gea 0
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
=== 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
 | 
			
		||||
  role asp
 | 
			
		||||
  sctp-role client
 | 
			
		||||
 as as-clnt-OsmoSGSN m3ua
 | 
			
		||||
  asp asp-clnt-OsmoSGSN
 | 
			
		||||
  routing-key 0 0.23.4
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
This configuration is explained in detail in <<cs7_config>>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
== Configuring OsmoGbPROXY
 | 
			
		||||
 | 
			
		||||
TBD.  Unfortunately this chapter of the manual still needs to be written.
 | 
			
		||||
Osmocom has very limited funding and support resources; Feel free to help
 | 
			
		||||
us completing this documentation by contributing with code, documentation
 | 
			
		||||
or by supporting the developers financially.
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
[[control]]
 | 
			
		||||
== Control interface
 | 
			
		||||
 | 
			
		||||
The actual protocol is described in <<common-control-if>>, the variables
 | 
			
		||||
common to all programs using it are described in <<ctrl_common_vars>>. Here we
 | 
			
		||||
describe variables specific to OsmoGbPROXY.
 | 
			
		||||
 | 
			
		||||
.Variables available over control interface
 | 
			
		||||
[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
 | 
			
		||||
|===
 | 
			
		||||
|Name|Access|Trap|Value|Comment
 | 
			
		||||
|nsvc-state|RO|No|"<nsei>,<nsvci>,<local-alive>,<local-blocked>,<remote-role>,<remote-alive>,<remote-blocked>"|See <<nsvc_state>> for details.
 | 
			
		||||
|gbproxy-state|RO|No|"<nsei>,<bvci>,<mcc>,<mnc>,<lac>,<rac>,<blocked>"|See <<gbproxy_state>> for details.
 | 
			
		||||
|number-of-peers|RO|No|"<num-of-bss>"|Count of concurrent BSS(BTS) peers.
 | 
			
		||||
|===
 | 
			
		||||
 | 
			
		||||
[[nsvc_state]]
 | 
			
		||||
=== nsvc-state
 | 
			
		||||
 | 
			
		||||
Return the list of active NS-VCs (NS Virtual Circuits), including information
 | 
			
		||||
on the key parameters, such as NSEI, NSVCI and the local + remote ALIVE
 | 
			
		||||
and BLOCKED state.
 | 
			
		||||
 | 
			
		||||
[[gbproxy_state]]
 | 
			
		||||
=== gbproxy-state
 | 
			
		||||
 | 
			
		||||
Return the list of active Peers, including information on the key
 | 
			
		||||
parameters, such as NSEI, BVCI, and the MCC-MNC-LAC-RAC of the attached
 | 
			
		||||
BSS, as well as the overall state (BLOCKED or UNBLOCKED).
 | 
			
		||||
@@ -1,127 +0,0 @@
 | 
			
		||||
[[chapter_overview]]
 | 
			
		||||
== Overview
 | 
			
		||||
 | 
			
		||||
=== About OsmoGbPROXY
 | 
			
		||||
 | 
			
		||||
OsmoGbPROXY is the Osmocom proxy for the 3GPP Gb interface.  The Gb
 | 
			
		||||
interface is defined by 3GPP as the protocol between the BSS and the
 | 
			
		||||
SGSN inside the 2G/2.5G/2.75G packet switched network domain.
 | 
			
		||||
 | 
			
		||||
As Osmocom implements a BTS-colocated PCU, there are potentially many
 | 
			
		||||
Gb interface connections between all those many PCUs in the network
 | 
			
		||||
and the SGSN.  This can be cumbersome to configure/maintain at the
 | 
			
		||||
SGSN sine.
 | 
			
		||||
 | 
			
		||||
OsmoGbPROXY aggregates many PCU-facing Gb connections into one Gb
 | 
			
		||||
connection to the SGSN.  This is achieved by
 | 
			
		||||
 | 
			
		||||
* maintaining sepaate NS-VCs on the PCU side and on the SGSN side
 | 
			
		||||
* more or less transparently routing BSSGP peer-to-peer Virtual Circuits
 | 
			
		||||
  (BVCs) through the proxy
 | 
			
		||||
* having some special handling for the signaling BVC (BVCI=0) which is
 | 
			
		||||
  shared among all the PCUs connected to the proxy
 | 
			
		||||
 | 
			
		||||
=== Data Model
 | 
			
		||||
 | 
			
		||||
==== gbproxy_config
 | 
			
		||||
 | 
			
		||||
This contains the parsed configuration of the OsmoGbPROXY.
 | 
			
		||||
 | 
			
		||||
==== gproxy_peer
 | 
			
		||||
 | 
			
		||||
A "peer" is any remote NS-entity that the proxy interacts with.  A peer
 | 
			
		||||
includes information about:
 | 
			
		||||
 | 
			
		||||
* the [unique] NSEI of the peer
 | 
			
		||||
* the [unique] BVCI of the peer
 | 
			
		||||
* the Routeing Area (RA) of the peer
 | 
			
		||||
 | 
			
		||||
==== gbproxy_tlli_state
 | 
			
		||||
 | 
			
		||||
One of the (unique) TLLI of any of the subscribers/UEs attached to any of
 | 
			
		||||
the BTSs/PCUs served by the proxy.
 | 
			
		||||
 | 
			
		||||
==== gbproxy_link_info
 | 
			
		||||
 | 
			
		||||
One of the [unique] subscribers/connections that are served through this
 | 
			
		||||
proxy.  The information includes
 | 
			
		||||
 | 
			
		||||
* the TLLI on BSS side
 | 
			
		||||
* the TLLI on SGSN side (may be different due to P-TMSI rewriting)
 | 
			
		||||
* the NSEI of the SGSN for this link
 | 
			
		||||
* a timestamp when we last conversed with this subscriber
 | 
			
		||||
* state related to IMSI acquisition
 | 
			
		||||
** a temporary queue of stored messages (until IMSI acquisition succeeds)
 | 
			
		||||
** N(U) rewriting state (inserting IDENTTIY REQ changes LLC sequence numbers)
 | 
			
		||||
 | 
			
		||||
==== gbproxy_match
 | 
			
		||||
 | 
			
		||||
A single matching rule against which IMSIs are matched.  The matching rule
 | 
			
		||||
is expressed as regular expression.  There can be one such matching rule for
 | 
			
		||||
each
 | 
			
		||||
 | 
			
		||||
* routing between two different SGSNs, see below
 | 
			
		||||
* patching of messages (e.g. APN, PLMN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== Advanced Features
 | 
			
		||||
 | 
			
		||||
==== PLMN patching
 | 
			
		||||
 | 
			
		||||
This feature permits to modify the PLMN inside any BSSGP messages
 | 
			
		||||
containing the Routing Area ID (RAID).
 | 
			
		||||
 | 
			
		||||
The configured core-mcc and core-mnc will be used towards the SGSN,
 | 
			
		||||
irrespective of which MCC/MNC the PCU is using/reporting on Gb.
 | 
			
		||||
 | 
			
		||||
==== APN patching
 | 
			
		||||
 | 
			
		||||
This will transparently re-write the APN name inside SM ACTIVATE PDP
 | 
			
		||||
REQUEST messages on the way from the MS to the SGSN.  The patching is
 | 
			
		||||
performed based on matching on the IMSI of the subscriber.
 | 
			
		||||
 | 
			
		||||
The configured core-apn will be used towards the SGSN, irrespective
 | 
			
		||||
of which APN the MS is requesting in its Layer3 signaling.
 | 
			
		||||
 | 
			
		||||
APN patching can only be performed if no GPRS encryption is enabled in
 | 
			
		||||
the network!
 | 
			
		||||
 | 
			
		||||
APN patching is useful in case a valid APN cannot reliably be
 | 
			
		||||
provisioned via other means, such as via the SIM Card, OTA-DM or via
 | 
			
		||||
CAMEL rewriting in the SGSN.
 | 
			
		||||
 | 
			
		||||
==== P-TMSI patching
 | 
			
		||||
 | 
			
		||||
This feature transparently rewrite the P-TMSI between MS and SGSN.  This
 | 
			
		||||
is required when using the Secondary SGSN support, as both SGSNs could
 | 
			
		||||
allocate overlapping TMSIs and we must make sure they're unique across
 | 
			
		||||
both SGSNs.
 | 
			
		||||
 | 
			
		||||
P-TMSI patching is required by (and hence automatically enablede if
 | 
			
		||||
secondary SGSN support is enabled.
 | 
			
		||||
 | 
			
		||||
P-TMSI patching can only be performed if no GPRS encryption is enabled in
 | 
			
		||||
the network!
 | 
			
		||||
 | 
			
		||||
==== IMSI Acquisition
 | 
			
		||||
 | 
			
		||||
This is a special feature where the proxy will by itself inject GMM IDENTITY
 | 
			
		||||
REQUEST messages for the IMSI into the downlink BSSGP traffic in order
 | 
			
		||||
to establish the IMSI of subscribers for which it is not otherwise known
 | 
			
		||||
 | 
			
		||||
IMSI acquisition is automatically enabled if secondary SGSN support is
 | 
			
		||||
enabled.
 | 
			
		||||
 | 
			
		||||
==== Secondary SGSN Support
 | 
			
		||||
 | 
			
		||||
This allows the proxy to connect not only to one SGSN, but to two
 | 
			
		||||
different SGSNs.  IMSI matching rules are applied to determine which of
 | 
			
		||||
the SGSNs is to be used for traffic of this subscriber.
 | 
			
		||||
 | 
			
		||||
One possible use case of this feature is to have a "local break-out" for
 | 
			
		||||
subscribers who are native to this network (and hence save
 | 
			
		||||
latencies/overhead of back-hauling all related traffic via the
 | 
			
		||||
SGSN+GGSN) while at the same time maintaining the classic behavior for
 | 
			
		||||
inbound roaming subscribers, where the roaming agreements mandate that
 | 
			
		||||
data traffic is brought back to the GGSN in the HPLMN via the SGSN of
 | 
			
		||||
the VPLMN.
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
== Running OsmoGbPROXY
 | 
			
		||||
 | 
			
		||||
The OsmoGbPROXY executable (`osmo-gbproxy`) offers the following command-line
 | 
			
		||||
options:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== SYNOPSIS
 | 
			
		||||
 | 
			
		||||
*osmo-gbproxy* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-e 'LOGLEVEL'] [-T]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== OPTIONS
 | 
			
		||||
 | 
			
		||||
*-h, --help*::
 | 
			
		||||
	Print a short help message about the supported options
 | 
			
		||||
*-V, --version*::
 | 
			
		||||
	Print the compile-time version number of the program
 | 
			
		||||
*-d, --debug 'DBGMASK','DBGLEVELS'*::
 | 
			
		||||
	Set the log subsystems and levels for logging to stderr. This
 | 
			
		||||
	has mostly been superseded by VTY-based logging configuration,
 | 
			
		||||
	see <<logging>> for further information.
 | 
			
		||||
*-D, --daemonize*::
 | 
			
		||||
	Fork the process as a daemon into background.
 | 
			
		||||
*-c, --config-file 'CONFIGFILE'*::
 | 
			
		||||
	Specify the file and path name of the configuration file to be
 | 
			
		||||
	used. If none is specified, use `osmo_sgsn.cfg` in the current
 | 
			
		||||
	working directory.
 | 
			
		||||
*-s, --disable-color*::
 | 
			
		||||
	Disable colors for logging to stderr. This has mostly been
 | 
			
		||||
	deprecated by VTY based logging configuration, see <<logging>>
 | 
			
		||||
	for more information.
 | 
			
		||||
*-e, --log-level 'LOGLEVEL'*::
 | 
			
		||||
	Set the global log level for logging to stderr. This has mostly
 | 
			
		||||
	been deprecated by VTY based logging configuration, see
 | 
			
		||||
	<<logging>> for more information.
 | 
			
		||||
*-T, --timestamp*::
 | 
			
		||||
        Enable prefixing each log line on stderr with a timestamp.  This
 | 
			
		||||
        has mostly been deprecated by VTY based logging configuration, see
 | 
			
		||||
        <<logging>> for more information.
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
<revhistory>
 | 
			
		||||
  <revision>
 | 
			
		||||
    <revnumber>1</revnumber>
 | 
			
		||||
    <date>March 21, 2019</date>
 | 
			
		||||
    <authorinitials>HW</authorinitials>
 | 
			
		||||
    <revremark>
 | 
			
		||||
      Initial version.
 | 
			
		||||
    </revremark>
 | 
			
		||||
  </revision>
 | 
			
		||||
</revhistory>
 | 
			
		||||
 | 
			
		||||
<authorgroup>
 | 
			
		||||
  <author>
 | 
			
		||||
    <firstname>Harald</firstname>
 | 
			
		||||
    <surname>Welte</surname>
 | 
			
		||||
    <email>hwelte@sysmocom.de</email>
 | 
			
		||||
    <authorinitials>HW</authorinitials>
 | 
			
		||||
    <affiliation>
 | 
			
		||||
      <shortaffil>sysmocom</shortaffil>
 | 
			
		||||
      <orgname>sysmocom - s.f.m.c. GmbH</orgname>
 | 
			
		||||
      <jobtitle>Managing Director</jobtitle>
 | 
			
		||||
    </affiliation>
 | 
			
		||||
  </author>
 | 
			
		||||
</authorgroup>
 | 
			
		||||
 | 
			
		||||
<copyright>
 | 
			
		||||
  <year>2013-2019</year>
 | 
			
		||||
  <holder>sysmocom - s.f.m.c. GmbH</holder>
 | 
			
		||||
</copyright>
 | 
			
		||||
 | 
			
		||||
<legalnotice>
 | 
			
		||||
  <para>
 | 
			
		||||
	Permission is granted to copy, distribute and/or modify this
 | 
			
		||||
	document under the terms of the GNU Free Documentation License,
 | 
			
		||||
	Version 1.3 or any later version published by the Free Software
 | 
			
		||||
	Foundation; with no Invariant Sections, no Front-Cover Texts,
 | 
			
		||||
	and no Back-Cover Texts.  A copy of the license is included in
 | 
			
		||||
	the section entitled "GNU Free Documentation License".
 | 
			
		||||
  </para>
 | 
			
		||||
  <para>
 | 
			
		||||
	The Asciidoc source code of this manual can be found at
 | 
			
		||||
	<ulink url="https://git.osmocom.org/osmo-sgsn/doc/">
 | 
			
		||||
		https://git.osmocom.org/osmo-sgsn/doc/
 | 
			
		||||
	</ulink>
 | 
			
		||||
  </para>
 | 
			
		||||
</legalnotice>
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
:gfdl-enabled:
 | 
			
		||||
 | 
			
		||||
OsmoGbPROXY User Manual
 | 
			
		||||
=======================
 | 
			
		||||
Harald Welte <hwelte@sysmocom.de>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/preface.adoc[]
 | 
			
		||||
 | 
			
		||||
include::{srcdir}/chapters/gbproxy-overview.adoc[]
 | 
			
		||||
 | 
			
		||||
include::{srcdir}/chapters/gbproxy-running.adoc[]
 | 
			
		||||
 | 
			
		||||
include::{srcdir}/chapters/gbproxy-control.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/vty.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/logging.adoc[]
 | 
			
		||||
 | 
			
		||||
include::{srcdir}/chapters/gbproxy-configuration.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/gb.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/control_if.adoc[]
 | 
			
		||||
 | 
			
		||||
//include::{srcdir}/chapters/counters.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/port_numbers.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/bibliography.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/glossary.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/gfdl.adoc[]
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
  ex:ts=2:sw=42sts=2:et
 | 
			
		||||
  -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
-->
 | 
			
		||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
 | 
			
		||||
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
 | 
			
		||||
<!ENTITY chapter-vty      SYSTEM      "./common/chapters/vty.xml" >
 | 
			
		||||
<!ENTITY sections-vty     SYSTEM      "generated/docbook_osmogbproxy-vty-reference.xml"  >
 | 
			
		||||
]>
 | 
			
		||||
 | 
			
		||||
<book>
 | 
			
		||||
  <info>
 | 
			
		||||
    <revhistory>
 | 
			
		||||
        <revision>
 | 
			
		||||
            <revnumber>v1</revnumber>
 | 
			
		||||
            <date>2nd December 2019</date>
 | 
			
		||||
            <authorinitials>hw</authorinitials>
 | 
			
		||||
            <revremark>Initial</revremark>
 | 
			
		||||
        </revision>
 | 
			
		||||
    </revhistory>
 | 
			
		||||
 | 
			
		||||
    <title>OsmoGbProxy VTY Reference</title>
 | 
			
		||||
 | 
			
		||||
    <copyright>
 | 
			
		||||
      <year>2019</year>
 | 
			
		||||
    </copyright>
 | 
			
		||||
 | 
			
		||||
    <legalnotice>
 | 
			
		||||
      <para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
 | 
			
		||||
      </para>
 | 
			
		||||
    </legalnotice>
 | 
			
		||||
  </info>
 | 
			
		||||
 | 
			
		||||
  <!-- Main chapters-->
 | 
			
		||||
  &chapter-vty;
 | 
			
		||||
</book>
 | 
			
		||||
 | 
			
		||||
@@ -19,6 +19,8 @@ include::./common/chapters/logging.adoc[]
 | 
			
		||||
 | 
			
		||||
include::{srcdir}/chapters/configuration.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/cs7-config.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/gb.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/control_if.adoc[]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,77 +1,17 @@
 | 
			
		||||
#!/bin/sh -e
 | 
			
		||||
#!/bin/sh -x
 | 
			
		||||
 | 
			
		||||
require_osmo_interact_vty() {
 | 
			
		||||
	if command -v osmo_interact_vty.py >/dev/null 2>&1; then
 | 
			
		||||
		return
 | 
			
		||||
	fi
 | 
			
		||||
	echo "ERROR: osmo_interact_vty.py not found. Are osmo-python-tests in PATH?"
 | 
			
		||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
 | 
			
		||||
	echo "You need to set DOCKER_PLAYGROUND"
 | 
			
		||||
	exit 1
 | 
			
		||||
}
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# $1: "update_vty_reference" or "update_counters"
 | 
			
		||||
# $2: output file
 | 
			
		||||
# $3: port
 | 
			
		||||
# $4-$n: command
 | 
			
		||||
interact_vty() {
 | 
			
		||||
	action="$1"
 | 
			
		||||
	output="$2"
 | 
			
		||||
	port="$3"
 | 
			
		||||
	log="/tmp/$4.log"
 | 
			
		||||
	shift 3
 | 
			
		||||
SCRIPT=$(realpath "$0")
 | 
			
		||||
MANUAL_DIR=$(dirname "$SCRIPT")
 | 
			
		||||
 | 
			
		||||
	echo "Starting in background: $@"
 | 
			
		||||
	"$@" > "$log" 2>&1 &
 | 
			
		||||
	pid="$!"
 | 
			
		||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
 | 
			
		||||
 | 
			
		||||
	sleep 0.5
 | 
			
		||||
	if ! kill -0 "$pid" 2>/dev/null; then
 | 
			
		||||
		echo "ERROR: start failed!"
 | 
			
		||||
		cat "$log"
 | 
			
		||||
		exit 1
 | 
			
		||||
	fi
 | 
			
		||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
 | 
			
		||||
 | 
			
		||||
	case "$action" in
 | 
			
		||||
		"update_vty_reference")
 | 
			
		||||
			echo "Updating VTY reference: $output"
 | 
			
		||||
			osmo_interact_vty.py -X -p "$port" -H 127.0.0.1 -O "$output"
 | 
			
		||||
			;;
 | 
			
		||||
		"update_counters")
 | 
			
		||||
			echo "Updating asciidoc counters: $output"
 | 
			
		||||
			osmo_interact_vty.py -c "enable;show asciidoc counters" -p "$port" -H 127.0.0.1 -O "$output"
 | 
			
		||||
			;;
 | 
			
		||||
		*)
 | 
			
		||||
			echo "ERROR: invalid argument: $action"
 | 
			
		||||
			exit 1
 | 
			
		||||
			;;
 | 
			
		||||
	esac
 | 
			
		||||
 | 
			
		||||
	kill "$pid"
 | 
			
		||||
	echo "Done (killed $1)"
 | 
			
		||||
	echo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DIR="$(cd "$(dirname "$0")"; pwd)"
 | 
			
		||||
cd "$DIR"
 | 
			
		||||
 | 
			
		||||
require_osmo_interact_vty
 | 
			
		||||
 | 
			
		||||
interact_vty \
 | 
			
		||||
	"update_vty_reference" \
 | 
			
		||||
	"vty/sgsn_vty_reference.xml" \
 | 
			
		||||
	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" \
 | 
			
		||||
	4245 \
 | 
			
		||||
	osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo "Done with all"
 | 
			
		||||
OSMO_BSC_BRANCH=$COMMIT ./regen_doc.sh osmo-sgsn 4245 \
 | 
			
		||||
	"$MANUAL_DIR/chapters/counters_generated.adoc" \
 | 
			
		||||
	"$MANUAL_DIR/vty/sgsn_vty_reference.xml"
 | 
			
		||||
 
 | 
			
		||||
@@ -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
											
										
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
SUBDIRS = \
 | 
			
		||||
	gtphub \
 | 
			
		||||
	sgsn \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								include/osmocom/gtphub/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								include/osmocom/gtphub/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
noinst_HEADERS = \
 | 
			
		||||
	gtphub.h \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
@@ -27,22 +27,20 @@
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
 | 
			
		||||
/* support */
 | 
			
		||||
 | 
			
		||||
/* 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 +51,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 +69,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 +96,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 +177,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 +387,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;
 | 
			
		||||
@@ -428,7 +426,7 @@ struct gtphub_resolved_ggsn {
 | 
			
		||||
 | 
			
		||||
	/* The APN OI, the Operator Identifier, is the combined address,
 | 
			
		||||
	 * including parts of the IMSI and APN NI, and ending with ".gprs". */
 | 
			
		||||
	char apn_oi_str[GSM_APN_LENGTH];
 | 
			
		||||
	char apn_oi_str[APN_MAXLEN+1];
 | 
			
		||||
 | 
			
		||||
	/* Which address and port we resolved that to. */
 | 
			
		||||
	struct gtphub_peer_port *peer;
 | 
			
		||||
@@ -496,13 +494,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 +508,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 +517,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);
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
noinst_HEADERS = \
 | 
			
		||||
	apn.h \
 | 
			
		||||
	auth.h \
 | 
			
		||||
	common.h \
 | 
			
		||||
	crc24.h \
 | 
			
		||||
	debug.h \
 | 
			
		||||
	gb_proxy.h \
 | 
			
		||||
	gprs_gb.h \
 | 
			
		||||
	gprs_gb_parse.h \
 | 
			
		||||
	gprs_bssgp.h \
 | 
			
		||||
	gprs_gmm.h \
 | 
			
		||||
	gprs_gmm_fsm.h \
 | 
			
		||||
	gprs_gmm_attach.h \
 | 
			
		||||
	gprs_mm_state_gb_fsm.h \
 | 
			
		||||
	gprs_mm_state_iu_fsm.h \
 | 
			
		||||
	gprs_ns.h \
 | 
			
		||||
	gprs_llc.h \
 | 
			
		||||
	gprs_llc_xid.h \
 | 
			
		||||
	gprs_ranap.h \
 | 
			
		||||
	gprs_sgsn.h \
 | 
			
		||||
	gprs_sm.h \
 | 
			
		||||
	gprs_sndcp_comp.h \
 | 
			
		||||
	gprs_sndcp_dcomp.h \
 | 
			
		||||
@@ -22,8 +22,13 @@ noinst_HEADERS = \
 | 
			
		||||
	gprs_sndcp_xid.h \
 | 
			
		||||
	gprs_subscriber.h \
 | 
			
		||||
	gprs_utils.h \
 | 
			
		||||
	gtphub.h \
 | 
			
		||||
	gtp.h \
 | 
			
		||||
	gtp_ggsn.h \
 | 
			
		||||
	gtp_mme.h \
 | 
			
		||||
	mmctx.h \
 | 
			
		||||
	pdpctx.h \
 | 
			
		||||
	sgsn.h \
 | 
			
		||||
	sgsn_rim.h \
 | 
			
		||||
	signal.h \
 | 
			
		||||
	slhc.h \
 | 
			
		||||
	v42bis.h \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								include/osmocom/sgsn/apn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								include/osmocom/sgsn/apn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_ggsn_ctx;
 | 
			
		||||
 | 
			
		||||
#define GSM_APN_LENGTH 102
 | 
			
		||||
 | 
			
		||||
struct apn_ctx {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	struct sgsn_ggsn_ctx *ggsn;
 | 
			
		||||
	char *name;
 | 
			
		||||
	char *imsi_prefix;
 | 
			
		||||
	char *description;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
 | 
			
		||||
void sgsn_apn_ctx_free(struct apn_ctx *actx);
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
 | 
			
		||||
							
								
								
									
										39
									
								
								include/osmocom/sgsn/auth.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/osmocom/sgsn/auth.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/* MS authorization and subscriber data handling */
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_config;
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct gsm_auth_tuple;
 | 
			
		||||
 | 
			
		||||
/* Authorization/ACL handling */
 | 
			
		||||
enum sgsn_auth_state {
 | 
			
		||||
	SGSN_AUTH_UNKNOWN,
 | 
			
		||||
	SGSN_AUTH_AUTHENTICATE,
 | 
			
		||||
	SGSN_AUTH_UMTS_RESYNC,
 | 
			
		||||
	SGSN_AUTH_ACCEPTED,
 | 
			
		||||
	SGSN_AUTH_REJECTED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string *sgsn_auth_state_names;
 | 
			
		||||
 | 
			
		||||
void sgsn_auth_init(struct sgsn_instance *sgsn);
 | 
			
		||||
/* Request authorization */
 | 
			
		||||
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
 | 
			
		||||
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
 | 
			
		||||
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
 | 
			
		||||
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
					   unsigned key_seq);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Authorization/ACL handling
 | 
			
		||||
 */
 | 
			
		||||
struct imsi_acl_entry {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	char imsi[OSMO_IMSI_BUF_SIZE];
 | 
			
		||||
};
 | 
			
		||||
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
 | 
			
		||||
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
 | 
			
		||||
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
 | 
			
		||||
@@ -5,6 +5,6 @@
 | 
			
		||||
 | 
			
		||||
#define INIT_CRC24	0xffffff
 | 
			
		||||
 | 
			
		||||
uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len);
 | 
			
		||||
uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -8,38 +8,25 @@
 | 
			
		||||
 | 
			
		||||
/* 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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
							
								
								
									
										12
									
								
								include/osmocom/sgsn/gprs_bssgp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								include/osmocom/sgsn/gprs_bssgp.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
 | 
			
		||||
/* Called by bssgp layer when a prim is received from lower layers. */
 | 
			
		||||
int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph);
 | 
			
		||||
 | 
			
		||||
/* called by the bssgp layer to send NS PDUs */
 | 
			
		||||
int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
/* page a MS in its routing area */
 | 
			
		||||
int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc.h>
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* page a MS in its routing area */
 | 
			
		||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
@@ -1,11 +1,15 @@
 | 
			
		||||
#ifndef _GPRS_GMM_H
 | 
			
		||||
#define _GPRS_GMM_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48.h>
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct gprs_llc_llme;
 | 
			
		||||
 | 
			
		||||
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
 | 
			
		||||
				      const struct osmo_auth_vector *vec,
 | 
			
		||||
				      uint8_t key_seq, bool force_standby);
 | 
			
		||||
@@ -28,6 +32,11 @@ int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli);
 | 
			
		||||
int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
 | 
			
		||||
		       uint8_t suspend_ref);
 | 
			
		||||
 | 
			
		||||
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, const struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
time_t gprs_max_time_to_idle(void);
 | 
			
		||||
 | 
			
		||||
int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,10 @@
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/fsm.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/mmctx.h>
 | 
			
		||||
 | 
			
		||||
struct gprs_llc_llme;
 | 
			
		||||
 | 
			
		||||
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
 | 
			
		||||
enum gmm_fsm_states {
 | 
			
		||||
	ST_GMM_DEREGISTERED,		/* 4.1.3.3.1.1 */
 | 
			
		||||
@@ -23,6 +27,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,16 @@
 | 
			
		||||
#ifndef _GPRS_LLC_H
 | 
			
		||||
#define _GPRS_LLC_H
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
#include <osmocom/crypt/gprs_cipher.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc_xid.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
 | 
			
		||||
/* Section 4.7 LLC Layer Structure */
 | 
			
		||||
enum gprs_llc_sapi {
 | 
			
		||||
	GPRS_SAPI_GMM		= 1,
 | 
			
		||||
@@ -91,6 +96,7 @@ enum gprs_llc_lle_state {
 | 
			
		||||
	GPRS_LLES_LOCAL_REL	= 6,	/* Local Release */
 | 
			
		||||
	GPRS_LLES_TIMER_REC 	= 7,	/* Timer Recovery */
 | 
			
		||||
};
 | 
			
		||||
extern const struct value_string gprs_llc_lle_state_names[];
 | 
			
		||||
 | 
			
		||||
enum gprs_llc_llme_state {
 | 
			
		||||
	GPRS_LLMS_UNASSIGNED	= 1,	/* No TLLI yet */
 | 
			
		||||
@@ -272,18 +278,15 @@ static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* LLC low level functions */
 | 
			
		||||
void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
 | 
			
		||||
void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
 | 
			
		||||
 | 
			
		||||
/* parse a GPRS LLC header, also check for invalid frames */
 | 
			
		||||
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
 | 
			
		||||
		       uint8_t *llc_hdr, int len);
 | 
			
		||||
void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle);
 | 
			
		||||
int gprs_llc_fcs(uint8_t *data, unsigned int len);
 | 
			
		||||
int gprs_llc_fcs(const uint8_t *data, unsigned int len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* LLME handling routines */
 | 
			
		||||
struct llist_head *gprs_llme_list(void);
 | 
			
		||||
struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
 | 
			
		||||
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
 | 
			
		||||
enum mm_state_gb_fsm_states {
 | 
			
		||||
	ST_MM_IDLE,
 | 
			
		||||
	ST_MM_READY,
 | 
			
		||||
@@ -14,9 +14,8 @@ enum mm_state_gb_fsm_states {
 | 
			
		||||
 | 
			
		||||
enum mm_state_gb_fsm_events {
 | 
			
		||||
	E_MM_GPRS_ATTACH,
 | 
			
		||||
	/* E_GPRS_DETACH, TODO: not used */
 | 
			
		||||
	E_MM_GPRS_DETACH,  /* MS becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
 | 
			
		||||
	E_MM_PDU_RECEPTION,
 | 
			
		||||
	E_MM_IMPLICIT_DETACH, /* = E_MM_CANCEL_LOCATION */
 | 
			
		||||
	E_MM_READY_TIMER_EXPIRY,
 | 
			
		||||
	/* E_FORCE_TO_STANDBY, TODO: not used */
 | 
			
		||||
	/* E_ABNSORMAL_RLC_CONDITION, TODO: not used */
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,7 @@
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
 | 
			
		||||
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
 | 
			
		||||
enum mm_state_iu_fsm_states {
 | 
			
		||||
	ST_PMM_DETACHED,
 | 
			
		||||
	ST_PMM_CONNECTED,
 | 
			
		||||
@@ -14,12 +13,10 @@ enum mm_state_iu_fsm_states {
 | 
			
		||||
 | 
			
		||||
enum mm_state_iu_fsm_events {
 | 
			
		||||
	E_PMM_PS_ATTACH,
 | 
			
		||||
	/* E_PS_DETACH, TODO: not used */
 | 
			
		||||
	E_PMM_PS_DETACH, /* UE becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
 | 
			
		||||
	E_PMM_PS_CONN_RELEASE,
 | 
			
		||||
	E_PMM_PS_CONN_ESTABLISH,
 | 
			
		||||
	E_PMM_IMPLICIT_DETACH, /* = E_PS_ATTACH_REJECT, E_RAU_REJECT */
 | 
			
		||||
	E_PMM_RA_UPDATE, /* = Serving RNC relocation */
 | 
			
		||||
	E_PMM_USER_INACTIVITY, /* when the inactivity timer runs out */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct osmo_fsm mm_state_iu_fsm;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								include/osmocom/sgsn/gprs_ns.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								include/osmocom/sgsn/gprs_ns.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc.h>
 | 
			
		||||
 | 
			
		||||
/* called by the ns layer */
 | 
			
		||||
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
 | 
			
		||||
@@ -1,13 +1,15 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
 | 
			
		||||
#ifdef BUILD_IU
 | 
			
		||||
#include <osmocom/ranap/ranap_ies_defs.h>
 | 
			
		||||
#include <osmocom/ranap/ranap_msg_factory.h>
 | 
			
		||||
#include <osmocom/ranap/iu_client.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct sgsn_pdp_ctx;
 | 
			
		||||
 | 
			
		||||
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx);
 | 
			
		||||
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
 | 
			
		||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct sgsn_pdp_ctx;
 | 
			
		||||
struct gprs_llc_llme;
 | 
			
		||||
 | 
			
		||||
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);
 | 
			
		||||
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48.h>
 | 
			
		||||
 | 
			
		||||
struct gprs_llc_lle;
 | 
			
		||||
 | 
			
		||||
/* A fragment queue header, maintaining list of fragments for one N-PDU */
 | 
			
		||||
struct defrag_state {
 | 
			
		||||
@@ -60,6 +63,8 @@ struct gprs_sndcp_entity {
 | 
			
		||||
 | 
			
		||||
extern struct llist_head gprs_sndcp_entities;
 | 
			
		||||
 | 
			
		||||
int gprs_sndcp_vty_init(void);
 | 
			
		||||
 | 
			
		||||
/* Set of SNDCP-XID negotiation (See also: TS 144 065,
 | 
			
		||||
 * Section 6.8 XID parameter negotiation) */
 | 
			
		||||
int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
@@ -68,7 +73,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
 * Section 6.8 XID parameter negotiation) */
 | 
			
		||||
int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
 | 
			
		||||
		     struct gprs_llc_xid_field *xid_field_response,
 | 
			
		||||
		     struct gprs_llc_lle *lle);
 | 
			
		||||
		     const struct gprs_llc_lle *lle);
 | 
			
		||||
 | 
			
		||||
/* Process SNDCP-XID indication
 | 
			
		||||
 * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
 | 
			
		||||
@@ -76,4 +81,21 @@ int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf,
 | 
			
		||||
		      struct gprs_llc_xid_field *xid_field_request,
 | 
			
		||||
		      struct gprs_llc_lle *lle);
 | 
			
		||||
 | 
			
		||||
/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
 | 
			
		||||
void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme);
 | 
			
		||||
 | 
			
		||||
/* Called by SNDCP when it has received/re-assembled a N-PDU */
 | 
			
		||||
int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne, struct msgb *msg,
 | 
			
		||||
		    uint32_t npdu_len, uint8_t *npdu);
 | 
			
		||||
int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
 | 
			
		||||
			void *mmcontext);
 | 
			
		||||
 | 
			
		||||
/* Entry point for the SNSM-ACTIVATE.indication */
 | 
			
		||||
int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
/* Entry point for the SNSM-DEACTIVATE.indication */
 | 
			
		||||
int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
 | 
			
		||||
int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
 | 
			
		||||
			 uint8_t *hdr, uint16_t len);
 | 
			
		||||
 | 
			
		||||
#endif	/* INT_SNDCP_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,64 @@
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/apn.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
 | 
			
		||||
extern struct llist_head * const gprs_subscribers;
 | 
			
		||||
 | 
			
		||||
#define GPRS_SUBSCRIBER_FIRST_CONTACT	0x00000001
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING	(1 << 16)
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING		(1 << 17)
 | 
			
		||||
#define GPRS_SUBSCRIBER_CANCELLED			(1 << 18)
 | 
			
		||||
#define GPRS_SUBSCRIBER_ENABLE_PURGE			(1 << 19)
 | 
			
		||||
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
 | 
			
		||||
		GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
 | 
			
		||||
		GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING  \
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
struct gsm_auth_tuple {
 | 
			
		||||
	int use_count;
 | 
			
		||||
	int key_seq;
 | 
			
		||||
	struct osmo_auth_vector vec;
 | 
			
		||||
};
 | 
			
		||||
#define GSM_KEY_SEQ_INVAL	7 /* GSM 04.08 - 10.5.1.2 */
 | 
			
		||||
 | 
			
		||||
struct sgsn_subscriber_data {
 | 
			
		||||
	struct sgsn_mm_ctx	*mm;
 | 
			
		||||
	struct gsm_auth_tuple	auth_triplets[5];
 | 
			
		||||
	int			auth_triplets_updated;
 | 
			
		||||
	struct llist_head	pdp_list;
 | 
			
		||||
	int			error_cause;
 | 
			
		||||
 | 
			
		||||
	uint8_t			msisdn[9];
 | 
			
		||||
	size_t			msisdn_len;
 | 
			
		||||
 | 
			
		||||
	uint8_t			hlr[9];
 | 
			
		||||
	size_t			hlr_len;
 | 
			
		||||
 | 
			
		||||
	uint8_t			pdp_charg[2];
 | 
			
		||||
	bool			has_pdp_charg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
 | 
			
		||||
/* see GSM 09.02, B.1, gprsSubscriptionData */
 | 
			
		||||
struct sgsn_subscriber_pdp_data {
 | 
			
		||||
	struct llist_head	list;
 | 
			
		||||
 | 
			
		||||
	unsigned int		context_id;
 | 
			
		||||
	uint16_t		pdp_type;
 | 
			
		||||
	char			apn_str[GSM_APN_LENGTH];
 | 
			
		||||
	uint8_t			qos_subscribed[20];
 | 
			
		||||
	size_t			qos_subscribed_len;
 | 
			
		||||
	uint8_t			pdp_charg[2];
 | 
			
		||||
	bool			has_pdp_charg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sgsn_subscriber_pdp_data *sgsn_subscriber_pdp_data_alloc(struct sgsn_subscriber_data *sdata);
 | 
			
		||||
 | 
			
		||||
struct gprs_subscr {
 | 
			
		||||
	struct llist_head entry;
 | 
			
		||||
	int use_count;
 | 
			
		||||
@@ -29,3 +85,22 @@ struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub,
 | 
			
		||||
				     const char *file, int line);
 | 
			
		||||
#define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __FILE__, __LINE__)
 | 
			
		||||
#define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __FILE__, __LINE__)
 | 
			
		||||
 | 
			
		||||
int gprs_subscr_init(struct sgsn_instance *sgi);
 | 
			
		||||
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
				  const uint8_t *auts,
 | 
			
		||||
				  const uint8_t *auts_rand);
 | 
			
		||||
void gprs_subscr_cleanup(struct gprs_subscr *subscr);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
 | 
			
		||||
void gprs_subscr_cancel(struct gprs_subscr *subscr);
 | 
			
		||||
void gprs_subscr_update(struct gprs_subscr *subscr);
 | 
			
		||||
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
 | 
			
		||||
int gprs_subscr_rx_gsup_message(struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
 | 
			
		||||
	LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
 | 
			
		||||
	     (subscr) ? (subscr)->imsi : "---", \
 | 
			
		||||
	     ## args)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,15 +29,11 @@
 | 
			
		||||
struct msgb;
 | 
			
		||||
struct gprs_ra_id;
 | 
			
		||||
 | 
			
		||||
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
 | 
			
		||||
 | 
			
		||||
/* GSM 04.08, 10.5.7.3 GPRS Timer */
 | 
			
		||||
int gprs_tmr_to_secs(uint8_t tmr);
 | 
			
		||||
uint8_t gprs_secs_to_tmr_floor(int secs);
 | 
			
		||||
 | 
			
		||||
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
 | 
			
		||||
int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
 | 
			
		||||
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
 | 
			
		||||
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi);
 | 
			
		||||
 | 
			
		||||
int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								include/osmocom/sgsn/gtp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								include/osmocom/sgsn/gtp.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp_rim.h>
 | 
			
		||||
 | 
			
		||||
struct gprs_ra_id;
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
struct sgsn_ggsn_ctx;
 | 
			
		||||
struct sgsn_pdp_ctx;
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct sgsn_mme_ctx;
 | 
			
		||||
 | 
			
		||||
int sgsn_gtp_init(struct sgsn_instance *sgi);
 | 
			
		||||
 | 
			
		||||
int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);
 | 
			
		||||
 | 
			
		||||
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
 | 
			
		||||
					 struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
					 uint16_t nsapi,
 | 
			
		||||
					 struct tlv_parsed *tp);
 | 
			
		||||
 | 
			
		||||
int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
 | 
			
		||||
		      struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
 | 
			
		||||
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
 | 
			
		||||
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
							
								
								
									
										41
									
								
								include/osmocom/sgsn/gtp_ggsn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/osmocom/sgsn/gtp_ggsn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/gprs/protocol/gsm_24_301.h>
 | 
			
		||||
 | 
			
		||||
struct gsn_t;
 | 
			
		||||
struct sgsn_pdp_ctx;
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
 | 
			
		||||
struct sgsn_ggsn_ctx {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	unsigned int gtp_version;
 | 
			
		||||
	struct in_addr remote_addr;
 | 
			
		||||
	int remote_restart_ctr;
 | 
			
		||||
	struct gsn_t *gsn;
 | 
			
		||||
	struct llist_head pdp_list;	/* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
 | 
			
		||||
	struct osmo_timer_list echo_timer;
 | 
			
		||||
	unsigned int echo_interval;
 | 
			
		||||
};
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id);
 | 
			
		||||
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id);
 | 
			
		||||
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
 | 
			
		||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
 | 
			
		||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
 | 
			
		||||
#define LOGGGSN(ggc, level, fmt, args...) { \
 | 
			
		||||
	char _buf[INET_ADDRSTRLEN]; \
 | 
			
		||||
	LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
							
								
								
									
										41
									
								
								include/osmocom/sgsn/gtp_mme.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/osmocom/sgsn/gtp_mme.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/gprs/protocol/gsm_24_301.h>
 | 
			
		||||
 | 
			
		||||
struct gsn_t;
 | 
			
		||||
 | 
			
		||||
struct mme_rim_route {
 | 
			
		||||
	struct llist_head list; /* item in struct sgsn_mme_ctx */
 | 
			
		||||
	struct osmo_eutran_tai tai;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sgsn_mme_ctx {
 | 
			
		||||
	struct llist_head list; /* item in sgsn_mme_ctxts */
 | 
			
		||||
	struct llist_head routes; /* list of struct mme_rim_route */
 | 
			
		||||
	struct sgsn_instance *sgsn; /* backpointer */
 | 
			
		||||
	char *name;
 | 
			
		||||
	struct in_addr remote_addr;
 | 
			
		||||
 | 
			
		||||
	/* is it the default route for outgoing message? are all incoming messages accepted? */
 | 
			
		||||
	bool default_route;
 | 
			
		||||
};
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);
 | 
			
		||||
void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);
 | 
			
		||||
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);
 | 
			
		||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);
 | 
			
		||||
 | 
			
		||||
void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
 | 
			
		||||
void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
 | 
			
		||||
 | 
			
		||||
#define LOGMME(mme, cat, level, fmt, args...) { \
 | 
			
		||||
	char _buf[INET_ADDRSTRLEN]; \
 | 
			
		||||
	LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
#ifndef _GPRS_SGSN_H
 | 
			
		||||
#define _GPRS_SGSN_H
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
@@ -14,12 +13,17 @@
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/apn.h>
 | 
			
		||||
#include <osmocom/sgsn/auth.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_subscriber.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_EXTENSION_LENGTH 15
 | 
			
		||||
#define GSM_APN_LENGTH 102
 | 
			
		||||
 | 
			
		||||
struct gprs_llc_lle;
 | 
			
		||||
struct ctrl_handle;
 | 
			
		||||
struct gprs_subscr;
 | 
			
		||||
struct sgsn_ggsn_ctx;
 | 
			
		||||
struct sgsn_pdp_ctx;
 | 
			
		||||
 | 
			
		||||
enum gsm48_gsm_cause;
 | 
			
		||||
 | 
			
		||||
@@ -37,13 +41,6 @@ enum gprs_mm_ctr {
 | 
			
		||||
	GMM_CTR_RA_UPDATE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gprs_pdp_ctx {
 | 
			
		||||
	PDP_CTR_PKTS_UDATA_IN,
 | 
			
		||||
	PDP_CTR_PKTS_UDATA_OUT,
 | 
			
		||||
	PDP_CTR_BYTES_UDATA_IN,
 | 
			
		||||
	PDP_CTR_BYTES_UDATA_OUT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gprs_t3350_mode {
 | 
			
		||||
	GMM_T3350_MODE_NONE,
 | 
			
		||||
	GMM_T3350_MODE_ATT,
 | 
			
		||||
@@ -51,17 +48,6 @@ enum gprs_t3350_mode {
 | 
			
		||||
	GMM_T3350_MODE_PTMSI_REALL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Authorization/ACL handling */
 | 
			
		||||
enum sgsn_auth_state {
 | 
			
		||||
	SGSN_AUTH_UNKNOWN,
 | 
			
		||||
	SGSN_AUTH_AUTHENTICATE,
 | 
			
		||||
	SGSN_AUTH_UMTS_RESYNC,
 | 
			
		||||
	SGSN_AUTH_ACCEPTED,
 | 
			
		||||
	SGSN_AUTH_REJECTED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MS_RADIO_ACCESS_CAPA
 | 
			
		||||
 | 
			
		||||
enum sgsn_ggsn_lookup_state {
 | 
			
		||||
	SGSN_GGSN_2DIGIT,
 | 
			
		||||
	SGSN_GGSN_3DIGIT,
 | 
			
		||||
@@ -104,13 +90,6 @@ struct service_info {
 | 
			
		||||
 | 
			
		||||
struct ranap_ue_conn_ctx;
 | 
			
		||||
 | 
			
		||||
struct gsm_auth_tuple {
 | 
			
		||||
        int use_count;
 | 
			
		||||
        int key_seq;
 | 
			
		||||
        struct osmo_auth_vector vec;
 | 
			
		||||
};
 | 
			
		||||
#define GSM_KEY_SEQ_INVAL       7       /* GSM 04.08 - 10.5.1.2 */
 | 
			
		||||
 | 
			
		||||
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
 | 
			
		||||
/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
 | 
			
		||||
struct sgsn_mm_ctx {
 | 
			
		||||
@@ -175,6 +154,7 @@ struct sgsn_mm_ctx {
 | 
			
		||||
	/* Iu: CK, IK, KSI */
 | 
			
		||||
	/* CKSN */
 | 
			
		||||
	enum gprs_ciph_algo	ciph_algo;
 | 
			
		||||
	uint8_t ue_cipher_mask;
 | 
			
		||||
	/* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */
 | 
			
		||||
	uint8_t ac_ref_nr_used;
 | 
			
		||||
 | 
			
		||||
@@ -294,64 +274,6 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
						enum gsm48_gsm_cause *gsm_cause,
 | 
			
		||||
						char *apn_str);
 | 
			
		||||
 | 
			
		||||
enum pdp_ctx_state {
 | 
			
		||||
	PDP_STATE_NONE,
 | 
			
		||||
	PDP_STATE_CR_REQ,
 | 
			
		||||
	PDP_STATE_CR_CONF,
 | 
			
		||||
 | 
			
		||||
	/* 04.08 / Figure 6.2 / 6.1.2.2 */
 | 
			
		||||
	PDP_STATE_INACT_PEND,
 | 
			
		||||
	PDP_STATE_INACTIVE = PDP_STATE_NONE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum pdp_type {
 | 
			
		||||
	PDP_TYPE_NONE,
 | 
			
		||||
	PDP_TYPE_ETSI_PPP,
 | 
			
		||||
	PDP_TYPE_IANA_IPv4,
 | 
			
		||||
	PDP_TYPE_IANA_IPv6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sgsn_pdp_ctx {
 | 
			
		||||
	struct llist_head	list;	/* list_head for mmctx->pdp_list */
 | 
			
		||||
	struct llist_head	g_list;	/* list_head for global list */
 | 
			
		||||
	struct sgsn_mm_ctx	*mm;	/* back pointer to MM CTX */
 | 
			
		||||
	int			destroy_ggsn; /* destroy it on destruction */
 | 
			
		||||
	struct sgsn_ggsn_ctx	*ggsn;	/* which GGSN serves this PDP */
 | 
			
		||||
	struct llist_head	ggsn_list;	/* list_head for ggsn->pdp_list */
 | 
			
		||||
	struct rate_ctr_group	*ctrg;
 | 
			
		||||
 | 
			
		||||
	//unsigned int		id;
 | 
			
		||||
	struct pdp_t		*lib;	/* pointer to libgtp PDP ctx */
 | 
			
		||||
	enum pdp_ctx_state	state;
 | 
			
		||||
	enum pdp_type		type;
 | 
			
		||||
	uint32_t		address;
 | 
			
		||||
	char 			*apn_subscribed;
 | 
			
		||||
	//char 			*apn_used;
 | 
			
		||||
	uint16_t		nsapi;	/* SNDCP */
 | 
			
		||||
	uint16_t		sapi;	/* LLC */
 | 
			
		||||
	uint8_t			ti;	/* transaction identifier */
 | 
			
		||||
	int			vplmn_allowed;
 | 
			
		||||
	uint32_t		qos_profile_subscr;
 | 
			
		||||
	//uint32_t		qos_profile_req;
 | 
			
		||||
	//uint32_t		qos_profile_neg;
 | 
			
		||||
	uint8_t			radio_prio;
 | 
			
		||||
	//uint32_t		charging_id;
 | 
			
		||||
 | 
			
		||||
	struct osmo_timer_list	timer;
 | 
			
		||||
	unsigned int		T;		/* Txxxx number */
 | 
			
		||||
	unsigned int		num_T_exp;	/* number of consecutive T expirations */
 | 
			
		||||
 | 
			
		||||
	struct osmo_timer_list	cdr_timer;	/* CDR record wird timer */
 | 
			
		||||
	struct timespec		cdr_start;	/* The start of the CDR */
 | 
			
		||||
	uint64_t		cdr_bytes_in;
 | 
			
		||||
	uint64_t		cdr_bytes_out;
 | 
			
		||||
	uint32_t		cdr_charging_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LOGPDPCTXP(level, pdp, fmt, args...) \
 | 
			
		||||
	LOGP(DGPRS, level, "PDP(%s/%u) " \
 | 
			
		||||
	     fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
 | 
			
		||||
 | 
			
		||||
/* look up PDP context by MM context and NSAPI */
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
 | 
			
		||||
					   uint8_t nsapi);
 | 
			
		||||
@@ -359,168 +281,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
 | 
			
		||||
					 uint8_t tid);
 | 
			
		||||
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
 | 
			
		||||
					struct sgsn_ggsn_ctx *ggsn,
 | 
			
		||||
					uint8_t nsapi);
 | 
			
		||||
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct sgsn_ggsn_ctx {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	unsigned int gtp_version;
 | 
			
		||||
	struct in_addr remote_addr;
 | 
			
		||||
	int remote_restart_ctr;
 | 
			
		||||
	struct gsn_t *gsn;
 | 
			
		||||
	struct llist_head pdp_list;	/* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
 | 
			
		||||
	struct osmo_timer_list echo_timer;
 | 
			
		||||
	unsigned int echo_interval;
 | 
			
		||||
};
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
 | 
			
		||||
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
 | 
			
		||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
 | 
			
		||||
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
 | 
			
		||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
 | 
			
		||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
 | 
			
		||||
#define LOGGGSN(ggc, level, fmt, args...) { \
 | 
			
		||||
	char _buf[INET_ADDRSTRLEN]; \
 | 
			
		||||
	LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
struct apn_ctx {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	struct sgsn_ggsn_ctx *ggsn;
 | 
			
		||||
	char *name;
 | 
			
		||||
	char *imsi_prefix;
 | 
			
		||||
	char *description;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
 | 
			
		||||
void sgsn_apn_ctx_free(struct apn_ctx *actx);
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
 | 
			
		||||
 | 
			
		||||
extern struct llist_head sgsn_mm_ctxts;
 | 
			
		||||
extern struct llist_head sgsn_ggsn_ctxts;
 | 
			
		||||
extern struct llist_head sgsn_apn_ctxts;
 | 
			
		||||
extern struct llist_head sgsn_pdp_ctxts;
 | 
			
		||||
 | 
			
		||||
uint32_t sgsn_alloc_ptmsi(void);
 | 
			
		||||
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
 | 
			
		||||
void sgsn_inst_init(struct sgsn_instance *sgsn);
 | 
			
		||||
 | 
			
		||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ctrl interface related work
 | 
			
		||||
 */
 | 
			
		||||
int sgsn_ctrl_cmds_install(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Authorization/ACL handling
 | 
			
		||||
 */
 | 
			
		||||
struct imsi_acl_entry {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	char imsi[OSMO_IMSI_BUF_SIZE];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
 | 
			
		||||
/* see GSM 09.02, B.1, gprsSubscriptionData */
 | 
			
		||||
struct sgsn_subscriber_pdp_data {
 | 
			
		||||
	struct llist_head	list;
 | 
			
		||||
 | 
			
		||||
	unsigned int		context_id;
 | 
			
		||||
	uint16_t		pdp_type;
 | 
			
		||||
	char			apn_str[GSM_APN_LENGTH];
 | 
			
		||||
	uint8_t			qos_subscribed[20];
 | 
			
		||||
	size_t			qos_subscribed_len;
 | 
			
		||||
	uint8_t			pdp_charg[2];
 | 
			
		||||
	bool			has_pdp_charg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sgsn_subscriber_data {
 | 
			
		||||
	struct sgsn_mm_ctx	*mm;
 | 
			
		||||
	struct gsm_auth_tuple	auth_triplets[5];
 | 
			
		||||
	int			auth_triplets_updated;
 | 
			
		||||
	struct llist_head	pdp_list;
 | 
			
		||||
	int			error_cause;
 | 
			
		||||
 | 
			
		||||
	uint8_t			msisdn[9];
 | 
			
		||||
	size_t			msisdn_len;
 | 
			
		||||
 | 
			
		||||
	uint8_t			hlr[9];
 | 
			
		||||
	size_t			hlr_len;
 | 
			
		||||
 | 
			
		||||
	uint8_t			pdp_charg[2];
 | 
			
		||||
	bool			has_pdp_charg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SGSN_ERROR_CAUSE_NONE (-1)
 | 
			
		||||
 | 
			
		||||
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
 | 
			
		||||
	LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
 | 
			
		||||
	     (subscr) ? (subscr)->imsi : "---", \
 | 
			
		||||
	     ## args)
 | 
			
		||||
 | 
			
		||||
struct sgsn_config;
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
extern const struct value_string *sgsn_auth_state_names;
 | 
			
		||||
 | 
			
		||||
void sgsn_auth_init(struct sgsn_instance *sgsn);
 | 
			
		||||
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
 | 
			
		||||
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
 | 
			
		||||
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
 | 
			
		||||
/* Request authorization */
 | 
			
		||||
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
 | 
			
		||||
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
 | 
			
		||||
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
 | 
			
		||||
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
					   unsigned key_seq);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * GPRS subscriber data
 | 
			
		||||
 */
 | 
			
		||||
#define GPRS_SUBSCRIBER_FIRST_CONTACT	0x00000001
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING	(1 << 16)
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING		(1 << 17)
 | 
			
		||||
#define GPRS_SUBSCRIBER_CANCELLED			(1 << 18)
 | 
			
		||||
#define GPRS_SUBSCRIBER_ENABLE_PURGE			(1 << 19)
 | 
			
		||||
 | 
			
		||||
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
 | 
			
		||||
		GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
 | 
			
		||||
		GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING  \
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
int gprs_subscr_init(struct sgsn_instance *sgi);
 | 
			
		||||
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
				  const uint8_t *auts,
 | 
			
		||||
				  const uint8_t *auts_rand);
 | 
			
		||||
int gprs_subscr_auth_sync(struct gprs_subscr *subscr,
 | 
			
		||||
			  const uint8_t *auts, const uint8_t *auts_rand);
 | 
			
		||||
void gprs_subscr_cleanup(struct gprs_subscr *subscr);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
 | 
			
		||||
void gprs_subscr_cancel(struct gprs_subscr *subscr);
 | 
			
		||||
void gprs_subscr_update(struct gprs_subscr *subscr);
 | 
			
		||||
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
 | 
			
		||||
int gprs_subscr_rx_gsup_message(struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
/* Called on subscriber data updates */
 | 
			
		||||
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx);
 | 
			
		||||
 | 
			
		||||
int gprs_sndcp_vty_init(void);
 | 
			
		||||
struct sgsn_instance;
 | 
			
		||||
int sgsn_gtp_init(struct sgsn_instance *sgi);
 | 
			
		||||
 | 
			
		||||
void sgsn_rate_ctr_init();
 | 
			
		||||
 | 
			
		||||
#endif /* _GPRS_SGSN_H */
 | 
			
		||||
							
								
								
									
										94
									
								
								include/osmocom/sgsn/pdpctx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								include/osmocom/sgsn/pdpctx.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/gsm48.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/crypt/gprs_cipher.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/apn.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_subscriber.h>
 | 
			
		||||
 | 
			
		||||
struct sgsn_mm_ctx;
 | 
			
		||||
struct sgsn_ggsn_ctx;
 | 
			
		||||
 | 
			
		||||
enum gprs_pdp_ctx {
 | 
			
		||||
	PDP_CTR_PKTS_UDATA_IN,
 | 
			
		||||
	PDP_CTR_PKTS_UDATA_OUT,
 | 
			
		||||
	PDP_CTR_BYTES_UDATA_IN,
 | 
			
		||||
	PDP_CTR_BYTES_UDATA_OUT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum pdp_ctx_state {
 | 
			
		||||
	PDP_STATE_NONE,
 | 
			
		||||
	PDP_STATE_CR_REQ,
 | 
			
		||||
	PDP_STATE_CR_CONF,
 | 
			
		||||
 | 
			
		||||
	/* 04.08 / Figure 6.2 / 6.1.2.2 */
 | 
			
		||||
	PDP_STATE_INACT_PEND,
 | 
			
		||||
	PDP_STATE_INACTIVE = PDP_STATE_NONE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum pdp_type {
 | 
			
		||||
	PDP_TYPE_NONE,
 | 
			
		||||
	PDP_TYPE_ETSI_PPP,
 | 
			
		||||
	PDP_TYPE_IANA_IPv4,
 | 
			
		||||
	PDP_TYPE_IANA_IPv6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sgsn_pdp_ctx {
 | 
			
		||||
	struct llist_head	list;	/* list_head for mmctx->pdp_list */
 | 
			
		||||
	struct llist_head	g_list;	/* list_head for global list */
 | 
			
		||||
	struct sgsn_mm_ctx	*mm;	/* back pointer to MM CTX */
 | 
			
		||||
	int			destroy_ggsn; /* destroy it on destruction */
 | 
			
		||||
	struct sgsn_ggsn_ctx	*ggsn;	/* which GGSN serves this PDP */
 | 
			
		||||
	struct llist_head	ggsn_list;	/* list_head for ggsn->pdp_list */
 | 
			
		||||
	struct rate_ctr_group	*ctrg;
 | 
			
		||||
 | 
			
		||||
	//unsigned int		id;
 | 
			
		||||
	struct pdp_t		*lib;	/* pointer to libgtp PDP ctx */
 | 
			
		||||
	enum pdp_ctx_state	state;
 | 
			
		||||
	enum pdp_type		type;
 | 
			
		||||
	uint32_t		address;
 | 
			
		||||
	char			*apn_subscribed;
 | 
			
		||||
	//char			*apn_used;
 | 
			
		||||
	uint16_t		nsapi;	/* SNDCP */
 | 
			
		||||
	uint16_t		sapi;	/* LLC */
 | 
			
		||||
	uint8_t			ti;	/* transaction identifier */
 | 
			
		||||
	int			vplmn_allowed;
 | 
			
		||||
	uint32_t		qos_profile_subscr;
 | 
			
		||||
	//uint32_t		qos_profile_req;
 | 
			
		||||
	//uint32_t		qos_profile_neg;
 | 
			
		||||
	uint8_t			radio_prio;
 | 
			
		||||
	//uint32_t		charging_id;
 | 
			
		||||
 | 
			
		||||
	struct osmo_timer_list	timer;
 | 
			
		||||
	unsigned int		T;		/* Txxxx number */
 | 
			
		||||
	unsigned int		num_T_exp;	/* number of consecutive T expirations */
 | 
			
		||||
 | 
			
		||||
	struct osmo_timer_list	cdr_timer;	/* CDR record wird timer */
 | 
			
		||||
	struct timespec		cdr_start;	/* The start of the CDR */
 | 
			
		||||
	uint64_t		cdr_bytes_in;
 | 
			
		||||
	uint64_t		cdr_bytes_out;
 | 
			
		||||
	uint32_t		cdr_charging_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LOGPDPCTXP(level, pdp, fmt, args...) \
 | 
			
		||||
	LOGP(DGPRS, level, "PDP(%s/%u) " \
 | 
			
		||||
	     fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
 | 
			
		||||
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
 | 
			
		||||
					struct sgsn_ggsn_ctx *ggsn,
 | 
			
		||||
					uint8_t nsapi);
 | 
			
		||||
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
 | 
			
		||||
 | 
			
		||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6);
 | 
			
		||||
 | 
			
		||||
@@ -3,14 +3,18 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/crypt/gprs_cipher.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_ns.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_ns2.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/auth.h>
 | 
			
		||||
#include <osmocom/sgsn/gtp_mme.h>
 | 
			
		||||
#include <osmocom/gsm/oap_client.h>
 | 
			
		||||
#include <osmocom/gsupclient/gsup_client.h>
 | 
			
		||||
#include <osmocom/sgsn/common.h>
 | 
			
		||||
 | 
			
		||||
#include "../../bscconfig.h"
 | 
			
		||||
#include "../../config.h"
 | 
			
		||||
 | 
			
		||||
#if BUILD_IU
 | 
			
		||||
#include <osmocom/ranap/iu_client.h>
 | 
			
		||||
@@ -21,6 +25,8 @@
 | 
			
		||||
 | 
			
		||||
struct hostent;
 | 
			
		||||
 | 
			
		||||
#define SGSN_ERROR_CAUSE_NONE (-1)
 | 
			
		||||
 | 
			
		||||
enum sgsn_auth_policy {
 | 
			
		||||
	SGSN_AUTH_POLICY_OPEN,
 | 
			
		||||
	SGSN_AUTH_POLICY_CLOSED,
 | 
			
		||||
@@ -69,10 +75,12 @@ struct sgsn_config {
 | 
			
		||||
	struct sockaddr_in gtp_listenaddr;
 | 
			
		||||
 | 
			
		||||
	/* misc */
 | 
			
		||||
	struct gprs_ns_inst *nsi;
 | 
			
		||||
	struct gprs_ns2_inst *nsi;
 | 
			
		||||
 | 
			
		||||
	char *crypt_cipher_plugin_path;
 | 
			
		||||
	enum sgsn_auth_policy auth_policy;
 | 
			
		||||
	enum gprs_ciph_algo cipher;
 | 
			
		||||
	uint8_t gea_encryption_mask;
 | 
			
		||||
	uint8_t uea_encryption_mask;
 | 
			
		||||
	struct llist_head imsi_acl;
 | 
			
		||||
 | 
			
		||||
	struct sockaddr_in gsup_server_addr;
 | 
			
		||||
@@ -88,6 +96,7 @@ struct sgsn_config {
 | 
			
		||||
 | 
			
		||||
	/* Timer defintions */
 | 
			
		||||
	struct osmo_tdef *T_defs;
 | 
			
		||||
	struct osmo_tdef *T_defs_gtp;
 | 
			
		||||
 | 
			
		||||
	int dynamic_lookup;
 | 
			
		||||
 | 
			
		||||
@@ -144,9 +153,23 @@ struct sgsn_instance {
 | 
			
		||||
	struct ares_addr_node *ares_servers;
 | 
			
		||||
 | 
			
		||||
	struct rate_ctr_group *rate_ctrs;
 | 
			
		||||
 | 
			
		||||
	struct llist_head apn_list; /* list of struct sgsn_apn_ctx */
 | 
			
		||||
	struct llist_head ggsn_list; /* list of struct sgsn_ggsn_ctx */
 | 
			
		||||
	struct llist_head mme_list; /* list of struct sgsn_mme_ctx */
 | 
			
		||||
	struct llist_head mm_list; /* list of struct sgsn_mm_ctx */
 | 
			
		||||
	struct llist_head pdp_list; /* list of struct sgsn_pdp_ctx */
 | 
			
		||||
 | 
			
		||||
	struct ctrl_handle *ctrlh;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct sgsn_instance *sgsn;
 | 
			
		||||
extern void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ctrl interface related work (sgsn_ctrl.c)
 | 
			
		||||
 */
 | 
			
		||||
int sgsn_ctrl_cmds_install(void);
 | 
			
		||||
 | 
			
		||||
/* sgsn_vty.c */
 | 
			
		||||
 | 
			
		||||
@@ -155,39 +178,13 @@ int sgsn_parse_config(const char *config_file);
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* sgsn_libgtp.c */
 | 
			
		||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
 | 
			
		||||
					 struct sgsn_mm_ctx *mmctx,
 | 
			
		||||
					 uint16_t nsapi,
 | 
			
		||||
					 struct tlv_parsed *tp);
 | 
			
		||||
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
 | 
			
		||||
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
 | 
			
		||||
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
 | 
			
		||||
 | 
			
		||||
/* gprs_sndcp.c */
 | 
			
		||||
 | 
			
		||||
/* Entry point for the SNSM-ACTIVATE.indication */
 | 
			
		||||
int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
/* Entry point for the SNSM-DEACTIVATE.indication */
 | 
			
		||||
int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
 | 
			
		||||
/* Called by SNDCP when it has received/re-assembled a N-PDU */
 | 
			
		||||
int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
 | 
			
		||||
			 struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
 | 
			
		||||
int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
 | 
			
		||||
			void *mmcontext);
 | 
			
		||||
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
 | 
			
		||||
			 uint8_t *hdr, uint16_t len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
 | 
			
		||||
int sgsn_inst_init(struct sgsn_instance *sgsn);
 | 
			
		||||
/*
 | 
			
		||||
 * CDR related functionality
 | 
			
		||||
 */
 | 
			
		||||
int sgsn_cdr_init(struct sgsn_instance *sgsn);
 | 
			
		||||
void sgsn_cdr_release(struct sgsn_instance *sgsn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								include/osmocom/sgsn/sgsn_rim.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								include/osmocom/sgsn/sgsn_rim.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
struct sgsn_mme_ctx;
 | 
			
		||||
 | 
			
		||||
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);
 | 
			
		||||
int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *ra, struct sgsn_mme_ctx *mme);
 | 
			
		||||
@@ -17,10 +17,6 @@
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! \page v42bis_page V.42bis modem data compression
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,6 @@
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
 | 
			
		||||
enum bsc_vty_node {
 | 
			
		||||
	GBPROXY_NODE = _LAST_OSMOVTY_NODE + 1,
 | 
			
		||||
	SGSN_NODE,
 | 
			
		||||
	SGSN_NODE = _LAST_OSMOVTY_NODE + 1,
 | 
			
		||||
	GTPHUB_NODE,
 | 
			
		||||
	MME_NODE,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#
 | 
			
		||||
# SYNOPSIS
 | 
			
		||||
#
 | 
			
		||||
#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
 | 
			
		||||
#
 | 
			
		||||
# DESCRIPTION
 | 
			
		||||
#
 | 
			
		||||
#   Check whether the given FLAG works with the current language's compiler
 | 
			
		||||
#   or gives an error.  (Warnings, however, are ignored)
 | 
			
		||||
#
 | 
			
		||||
#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
 | 
			
		||||
#   success/failure.
 | 
			
		||||
#
 | 
			
		||||
#   If EXTRA-FLAGS is defined, it is added to the current language's default
 | 
			
		||||
#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
 | 
			
		||||
#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
 | 
			
		||||
#   force the compiler to issue an error when a bad flag is given.
 | 
			
		||||
#
 | 
			
		||||
#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
 | 
			
		||||
#
 | 
			
		||||
#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
 | 
			
		||||
#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
 | 
			
		||||
#
 | 
			
		||||
# LICENSE
 | 
			
		||||
#
 | 
			
		||||
#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
 | 
			
		||||
#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
 | 
			
		||||
#
 | 
			
		||||
#   This program is free software: you can redistribute it and/or modify it
 | 
			
		||||
#   under the terms of the GNU General Public License as published by the
 | 
			
		||||
#   Free Software Foundation, either version 3 of the License, or (at your
 | 
			
		||||
#   option) any later version.
 | 
			
		||||
#
 | 
			
		||||
#   This program is distributed in the hope that it will be useful, but
 | 
			
		||||
#   WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 | 
			
		||||
#   Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
#   You should have received a copy of the GNU General Public License along
 | 
			
		||||
#   with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
#   As a special exception, the respective Autoconf Macro's copyright owner
 | 
			
		||||
#   gives unlimited permission to copy, distribute and modify the configure
 | 
			
		||||
#   scripts that are the output of Autoconf when processing the Macro. You
 | 
			
		||||
#   need not follow the terms of the GNU General Public License when using
 | 
			
		||||
#   or distributing such scripts, even though portions of the text of the
 | 
			
		||||
#   Macro appear in them. The GNU General Public License (GPL) does govern
 | 
			
		||||
#   all other use of the material that constitutes the Autoconf Macro.
 | 
			
		||||
#
 | 
			
		||||
#   This special exception to the GPL applies to versions of the Autoconf
 | 
			
		||||
#   Macro released by the Autoconf Archive. When you make and distribute a
 | 
			
		||||
#   modified version of the Autoconf Macro, you may extend this special
 | 
			
		||||
#   exception to the GPL to apply to your modified version as well.
 | 
			
		||||
 | 
			
		||||
#serial 4
 | 
			
		||||
 | 
			
		||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
 | 
			
		||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
 | 
			
		||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
 | 
			
		||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
 | 
			
		||||
  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
 | 
			
		||||
  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
 | 
			
		||||
  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
 | 
			
		||||
    [AS_VAR_SET(CACHEVAR,[yes])],
 | 
			
		||||
    [AS_VAR_SET(CACHEVAR,[no])])
 | 
			
		||||
  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
 | 
			
		||||
AS_VAR_IF(CACHEVAR,yes,
 | 
			
		||||
  [m4_default([$2], :)],
 | 
			
		||||
  [m4_default([$3], :)])
 | 
			
		||||
AS_VAR_POPDEF([CACHEVAR])dnl
 | 
			
		||||
])dnl AX_CHECK_COMPILE_FLAGS
 | 
			
		||||
@@ -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]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
SUBDIRS = \
 | 
			
		||||
	gprs \
 | 
			
		||||
	sgsn \
 | 
			
		||||
	gbproxy \
 | 
			
		||||
	gtphub \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
AM_CPPFLAGS = \
 | 
			
		||||
	$(all_includes) \
 | 
			
		||||
	-I$(top_srcdir)/include \
 | 
			
		||||
	-I$(top_builddir) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
AM_CFLAGS = \
 | 
			
		||||
	-Wall \
 | 
			
		||||
	-fno-strict-aliasing \
 | 
			
		||||
	$(LIBOSMOCORE_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOVTY_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOCTRL_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOABIS_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOGB_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOGSUPCLIENT_CFLAGS) \
 | 
			
		||||
	$(COVERAGE_CFLAGS) \
 | 
			
		||||
	$(LIBGTP_CFLAGS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
bin_PROGRAMS = \
 | 
			
		||||
	osmo-gbproxy \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmo_gbproxy_SOURCES = \
 | 
			
		||||
	gb_proxy.c \
 | 
			
		||||
	gb_proxy_main.c \
 | 
			
		||||
	gb_proxy_vty.c \
 | 
			
		||||
	gb_proxy_ctrl.c \
 | 
			
		||||
	gb_proxy_patch.c \
 | 
			
		||||
	gb_proxy_tlli.c \
 | 
			
		||||
	gb_proxy_peer.c \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
osmo_gbproxy_LDADD = \
 | 
			
		||||
	$(top_builddir)/src/gprs/gprs_gb_parse.o \
 | 
			
		||||
	$(top_builddir)/src/gprs/gprs_llc_parse.o \
 | 
			
		||||
	$(top_builddir)/src/gprs/crc24.o \
 | 
			
		||||
	$(top_builddir)/src/gprs/gprs_utils.o \
 | 
			
		||||
	$(LIBOSMOCORE_LIBS) \
 | 
			
		||||
	$(LIBOSMOGSM_LIBS) \
 | 
			
		||||
	$(LIBOSMOVTY_LIBS) \
 | 
			
		||||
	$(LIBOSMOCTRL_LIBS) \
 | 
			
		||||
	$(LIBOSMOGB_LIBS) \
 | 
			
		||||
	$(LIBGTP_LIBS) \
 | 
			
		||||
	-lrt \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,98 +0,0 @@
 | 
			
		||||
/* Control Interface Implementation for the Gb-proxy */
 | 
			
		||||
/*
 | 
			
		||||
 * (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Daniel Willmann
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_ns.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
#include <osmocom/ctrl/control_cmd.h>
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
extern vector ctrl_node_vec;
 | 
			
		||||
 | 
			
		||||
static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_config *cfg = data;
 | 
			
		||||
	struct gprs_ns_inst *nsi = cfg->nsi;
 | 
			
		||||
	struct gprs_nsvc *nsvc;
 | 
			
		||||
 | 
			
		||||
	cmd->reply = talloc_strdup(cmd, "");
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
 | 
			
		||||
		if (nsvc == nsi->unknown_nsvc)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		cmd->reply = gprs_nsvc_state_append(cmd->reply, nsvc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_RO(nsvc_state, "nsvc-state");
 | 
			
		||||
 | 
			
		||||
static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_config *cfg = data;
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
 | 
			
		||||
	cmd->reply = talloc_strdup(cmd, "");
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		struct gprs_ra_id raid;
 | 
			
		||||
		gsm48_parse_ra(&raid, peer->ra);
 | 
			
		||||
 | 
			
		||||
		cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
 | 
			
		||||
				peer->nsei, peer->bvci,
 | 
			
		||||
				raid.mcc, raid.mnc,
 | 
			
		||||
				raid.lac, raid.rac,
 | 
			
		||||
				peer->blocked ? "BLOCKED" : "UNBLOCKED");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_RO(gbproxy_state, "gbproxy-state");
 | 
			
		||||
 | 
			
		||||
static int get_num_peers(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_config *cfg = data;
 | 
			
		||||
 | 
			
		||||
	cmd->reply = talloc_strdup(cmd, "");
 | 
			
		||||
	cmd->reply = talloc_asprintf_append(cmd->reply, "%u", llist_count(&cfg->bts_peers));
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
CTRL_CMD_DEFINE_RO(num_peers, "number-of-peers");
 | 
			
		||||
 | 
			
		||||
int gb_ctrl_cmds_install(void)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_nsvc_state);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_gbproxy_state);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_num_peers);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,398 +0,0 @@
 | 
			
		||||
/* NS-over-IP proxy */
 | 
			
		||||
 | 
			
		||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010 by On-Waves
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <sys/fcntl.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/core/stats.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_ns.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/signal.h>
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/vty.h>
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/ctrl/control_vty.h>
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
#include <osmocom/ctrl/ports.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/vty/telnet_interface.h>
 | 
			
		||||
#include <osmocom/vty/logging.h>
 | 
			
		||||
#include <osmocom/vty/stats.h>
 | 
			
		||||
#include <osmocom/vty/ports.h>
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
 | 
			
		||||
#include "../../bscconfig.h"
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
 | 
			
		||||
void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
const char *openbsc_copyright =
 | 
			
		||||
	"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
 | 
			
		||||
	"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
 | 
			
		||||
	"This is free software: you are free to change and redistribute it.\r\n"
 | 
			
		||||
	"There is NO WARRANTY, to the extent permitted by law.\r\n";
 | 
			
		||||
 | 
			
		||||
#define CONFIG_FILE_DEFAULT "osmo-gbproxy.cfg"
 | 
			
		||||
#define CONFIG_FILE_LEGACY "osmo_gbproxy.cfg"
 | 
			
		||||
 | 
			
		||||
static char *config_file = NULL;
 | 
			
		||||
struct gbproxy_config *gbcfg;
 | 
			
		||||
static int daemonize = 0;
 | 
			
		||||
 | 
			
		||||
/* Pointer to the SGSN peer */
 | 
			
		||||
extern struct gbprox_peer *gbprox_peer_sgsn;
 | 
			
		||||
 | 
			
		||||
/* call-back function for the NS protocol */
 | 
			
		||||
static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
 | 
			
		||||
		      struct msgb *msg, uint16_t bvci)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case GPRS_NS_EVT_UNIT_DATA:
 | 
			
		||||
		rc = gbprox_rcvmsg(gbcfg, msg, nsvc->nsei, bvci, nsvc->nsvci);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
 | 
			
		||||
		if (msg)
 | 
			
		||||
			msgb_free(msg);
 | 
			
		||||
		rc = -EIO;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void signal_handler(int signal)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stdout, "signal %u received\n", signal);
 | 
			
		||||
 | 
			
		||||
	switch (signal) {
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
	case SIGTERM:
 | 
			
		||||
		osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
 | 
			
		||||
		sleep(1);
 | 
			
		||||
		exit(0);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGABRT:
 | 
			
		||||
		/* in case of abort, we want to obtain a talloc report
 | 
			
		||||
		 * and then return to the caller, who will abort the process */
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
		talloc_report(tall_vty_ctx, stderr);
 | 
			
		||||
		talloc_report_full(tall_sgsn_ctx, stderr);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGUSR2:
 | 
			
		||||
		talloc_report_full(tall_vty_ctx, stderr);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_usage()
 | 
			
		||||
{
 | 
			
		||||
	printf("Usage: bsc_hack\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_help()
 | 
			
		||||
{
 | 
			
		||||
	printf("  Some useful help...\n");
 | 
			
		||||
	printf("  -h --help this text\n");
 | 
			
		||||
	printf("  -d option --debug=DNS:DGPRS,0:0 enable debugging\n");
 | 
			
		||||
	printf("  -D --daemonize Fork the process into a background daemon\n");
 | 
			
		||||
	printf("  -c --config-file filename The config file to use [%s]\n", CONFIG_FILE_DEFAULT);
 | 
			
		||||
	printf("  -s --disable-color\n");
 | 
			
		||||
	printf("  -T --timestamp Prefix every log line with a timestamp\n");
 | 
			
		||||
	printf("  -V --version. Print the version.\n");
 | 
			
		||||
	printf("  -e --log-level number. Set a global loglevel.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_index = 0, c;
 | 
			
		||||
		static struct option long_options[] = {
 | 
			
		||||
			{ "help", 0, 0, 'h' },
 | 
			
		||||
			{ "debug", 1, 0, 'd' },
 | 
			
		||||
			{ "daemonize", 0, 0, 'D' },
 | 
			
		||||
			{ "config-file", 1, 0, 'c' },
 | 
			
		||||
			{ "disable-color", 0, 0, 's' },
 | 
			
		||||
			{ "timestamp", 0, 0, 'T' },
 | 
			
		||||
			{ "version", 0, 0, 'V' },
 | 
			
		||||
			{ "log-level", 1, 0, 'e' },
 | 
			
		||||
			{ 0, 0, 0, 0 }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		c = getopt_long(argc, argv, "hd:Dc:sTVe:",
 | 
			
		||||
				long_options, &option_index);
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_usage();
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(0);
 | 
			
		||||
		case 's':
 | 
			
		||||
			log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			log_parse_category_mask(osmo_stderr_target, optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'D':
 | 
			
		||||
			daemonize = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'c':
 | 
			
		||||
			config_file = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'T':
 | 
			
		||||
			log_set_print_timestamp(osmo_stderr_target, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'e':
 | 
			
		||||
			log_set_log_level(osmo_stderr_target, atoi(optarg));
 | 
			
		||||
			break;
 | 
			
		||||
		case 'V':
 | 
			
		||||
			print_version(1);
 | 
			
		||||
			exit(0);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc > optind) {
 | 
			
		||||
		fprintf(stderr, "Unsupported positional arguments on command line\n");
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_vty_is_config_node(struct vty *vty, int node)
 | 
			
		||||
{
 | 
			
		||||
        switch (node) {
 | 
			
		||||
        /* add items that are not config */
 | 
			
		||||
        case CONFIG_NODE:
 | 
			
		||||
                return 0;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
                return 1;
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_vty_go_parent(struct vty *vty)
 | 
			
		||||
{
 | 
			
		||||
        switch (vty->node) {
 | 
			
		||||
        case GBPROXY_NODE:
 | 
			
		||||
        default:
 | 
			
		||||
                if (gbproxy_vty_is_config_node(vty, vty->node))
 | 
			
		||||
                        vty->node = CONFIG_NODE;
 | 
			
		||||
                else
 | 
			
		||||
                        vty->node = ENABLE_NODE;
 | 
			
		||||
 | 
			
		||||
                vty->index = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return vty->node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct vty_app_info vty_info = {
 | 
			
		||||
	.name 		= "OsmoGbProxy",
 | 
			
		||||
	.version	= PACKAGE_VERSION,
 | 
			
		||||
	.go_parent_cb	= gbproxy_vty_go_parent,
 | 
			
		||||
	.is_config_node	= gbproxy_vty_is_config_node,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* default categories */
 | 
			
		||||
static struct log_info_cat gprs_categories[] = {
 | 
			
		||||
	[DGPRS] = {
 | 
			
		||||
		.name = "DGPRS",
 | 
			
		||||
		.description = "GPRS Packet Service",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
	},
 | 
			
		||||
	[DNS] = {
 | 
			
		||||
		.name = "DNS",
 | 
			
		||||
		.description = "GPRS Network Service (NS)",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_INFO,
 | 
			
		||||
	},
 | 
			
		||||
	[DBSSGP] = {
 | 
			
		||||
		.name = "DBSSGP",
 | 
			
		||||
		.description = "GPRS BSS Gateway Protocol (BSSGP)",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct log_info gprs_log_info = {
 | 
			
		||||
	.filter_fn = gprs_log_filter_fn,
 | 
			
		||||
	.cat = gprs_categories,
 | 
			
		||||
	.num_cat = ARRAY_SIZE(gprs_categories),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool file_exists(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct stat sb;
 | 
			
		||||
	return stat(path, &sb) ? false : true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct ctrl_handle *ctrl;
 | 
			
		||||
 | 
			
		||||
	tall_sgsn_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
 | 
			
		||||
	msgb_talloc_ctx_init(tall_sgsn_ctx, 0);
 | 
			
		||||
	vty_info.tall_ctx = tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
	signal(SIGINT, &signal_handler);
 | 
			
		||||
	signal(SIGTERM, &signal_handler);
 | 
			
		||||
	signal(SIGABRT, &signal_handler);
 | 
			
		||||
	signal(SIGUSR1, &signal_handler);
 | 
			
		||||
	signal(SIGUSR2, &signal_handler);
 | 
			
		||||
	osmo_init_ignore_signals();
 | 
			
		||||
 | 
			
		||||
	osmo_init_logging2(tall_sgsn_ctx, &gprs_log_info);
 | 
			
		||||
 | 
			
		||||
	vty_info.copyright = openbsc_copyright;
 | 
			
		||||
	vty_init(&vty_info);
 | 
			
		||||
	logging_vty_add_cmds();
 | 
			
		||||
	osmo_talloc_vty_add_cmds();
 | 
			
		||||
	osmo_stats_vty_add_cmds();
 | 
			
		||||
	gbproxy_vty_init();
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	/* Backwards compatibility: for years, the default config file name was
 | 
			
		||||
	 * osmo_gbproxy.cfg. All other Osmocom programs use osmo-*.cfg with a
 | 
			
		||||
	 * dash. To be able to use the new config file name without breaking
 | 
			
		||||
	 * previous setups that might rely on the legacy default config file
 | 
			
		||||
	 * name, we need to look for the old config file if no -c option was
 | 
			
		||||
	 * passed AND no file exists with the new default file name. */
 | 
			
		||||
	if (!config_file) {
 | 
			
		||||
		/* No -c option was passed */
 | 
			
		||||
		if (file_exists(CONFIG_FILE_LEGACY)
 | 
			
		||||
		    && !file_exists(CONFIG_FILE_DEFAULT))
 | 
			
		||||
			config_file = CONFIG_FILE_LEGACY;
 | 
			
		||||
		else
 | 
			
		||||
			config_file = CONFIG_FILE_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rate_ctr_init(tall_sgsn_ctx);
 | 
			
		||||
	osmo_stats_init(tall_sgsn_ctx);
 | 
			
		||||
 | 
			
		||||
	bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_sgsn_ctx);
 | 
			
		||||
	if (!bssgp_nsi) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gbcfg = talloc_zero(tall_sgsn_ctx, struct gbproxy_config);
 | 
			
		||||
	if (!gbcfg) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Unable to allocate config\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	gbproxy_init_config(gbcfg);
 | 
			
		||||
	gbcfg->nsi = bssgp_nsi;
 | 
			
		||||
	gprs_ns_vty_init(bssgp_nsi);
 | 
			
		||||
	gprs_ns_set_log_ss(DNS);
 | 
			
		||||
	bssgp_set_log_ss(DBSSGP);
 | 
			
		||||
	osmo_signal_register_handler(SS_L_NS, &gbprox_signal, gbcfg);
 | 
			
		||||
 | 
			
		||||
	rc = gbproxy_parse_config(config_file, gbcfg);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file '%s'\n", config_file);
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* start telnet after reading config for vty_get_bind_addr() */
 | 
			
		||||
	rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
 | 
			
		||||
			       vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
 | 
			
		||||
	if (rc < 0)
 | 
			
		||||
		exit(1);
 | 
			
		||||
 | 
			
		||||
	/* Start control interface after getting config for
 | 
			
		||||
	 * ctrl_vty_get_bind_addr() */
 | 
			
		||||
	ctrl = ctrl_interface_setup_dynip(gbcfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_GBPROXY, NULL);
 | 
			
		||||
	if (!ctrl) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Failed to create CTRL interface.\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (gb_ctrl_cmds_install() != 0) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Failed to install CTRL commands.\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!gprs_nsvc_by_nsei(gbcfg->nsi, gbcfg->nsip_sgsn_nsei)) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u "
 | 
			
		||||
			"without creating that NSEI before\n",
 | 
			
		||||
			gbcfg->nsip_sgsn_nsei);
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = gprs_ns_nsip_listen(bssgp_nsi);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = gprs_ns_frgre_listen(bssgp_nsi);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
 | 
			
		||||
			"socket. Do you have CAP_NET_RAW?\n");
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (daemonize) {
 | 
			
		||||
		rc = osmo_daemonize();
 | 
			
		||||
		if (rc < 0) {
 | 
			
		||||
			perror("Error during daemonize");
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Reset all the persistent NS-VCs that we've read from the config */
 | 
			
		||||
	gbprox_reset_persistent_nsvcs(bssgp_nsi);
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		rc = osmo_select_main(0);
 | 
			
		||||
		if (rc < 0)
 | 
			
		||||
			exit(3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exit(0);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,465 +0,0 @@
 | 
			
		||||
/* Gb-proxy message patching */
 | 
			
		||||
 | 
			
		||||
/* (C) 2014 by On-Waves
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_utils.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gb_parse.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/protocol/gsm_08_18.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
 | 
			
		||||
extern void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
/* patch RA identifier in place */
 | 
			
		||||
static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer *peer,
 | 
			
		||||
			       int to_bss, const char *log_text)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
	struct osmo_plmn_id old_plmn;
 | 
			
		||||
	struct gprs_ra_id raid;
 | 
			
		||||
	enum gbproxy_peer_ctr counter =
 | 
			
		||||
		to_bss ?
 | 
			
		||||
		GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
 | 
			
		||||
		GBPROX_PEER_CTR_RAID_PATCHED_BSS;
 | 
			
		||||
 | 
			
		||||
	if (!state->local_plmn.mcc || !state->local_plmn.mnc)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	gsm48_parse_ra(&raid, (uint8_t *)raid_enc);
 | 
			
		||||
 | 
			
		||||
	old_plmn = (struct osmo_plmn_id){
 | 
			
		||||
		.mcc = raid.mcc,
 | 
			
		||||
		.mnc = raid.mnc,
 | 
			
		||||
		.mnc_3_digits = raid.mnc_3_digits,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (!to_bss) {
 | 
			
		||||
		/* BSS -> SGSN */
 | 
			
		||||
		if (state->local_plmn.mcc)
 | 
			
		||||
			raid.mcc = peer->cfg->core_plmn.mcc;
 | 
			
		||||
 | 
			
		||||
		if (state->local_plmn.mnc) {
 | 
			
		||||
			raid.mnc = peer->cfg->core_plmn.mnc;
 | 
			
		||||
			raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/* SGSN -> BSS */
 | 
			
		||||
		if (state->local_plmn.mcc)
 | 
			
		||||
			raid.mcc = state->local_plmn.mcc;
 | 
			
		||||
 | 
			
		||||
		if (state->local_plmn.mnc) {
 | 
			
		||||
			raid.mnc = state->local_plmn.mnc;
 | 
			
		||||
			raid.mnc_3_digits = state->local_plmn.mnc_3_digits;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
	     "Patching %s to %s: "
 | 
			
		||||
	     "%s-%d-%d -> %s\n",
 | 
			
		||||
	     log_text,
 | 
			
		||||
	     to_bss ? "BSS" : "SGSN",
 | 
			
		||||
	     osmo_plmn_name(&old_plmn), raid.lac, raid.rac,
 | 
			
		||||
	     osmo_rai_name(&raid));
 | 
			
		||||
 | 
			
		||||
	gsm48_encode_ra(raid_enc, &raid);
 | 
			
		||||
	rate_ctr_inc(&peer->ctrg->ctr[counter]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gbproxy_patch_apn_ie(struct msgb *msg,
 | 
			
		||||
				 uint8_t *apn_ie, size_t apn_ie_len,
 | 
			
		||||
				 struct gbproxy_peer *peer,
 | 
			
		||||
				 size_t *new_apn_ie_len, const char *log_text)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ie_hdr {
 | 
			
		||||
		uint8_t iei;
 | 
			
		||||
		uint8_t apn_len;
 | 
			
		||||
		uint8_t apn[0];
 | 
			
		||||
	} *hdr = (void *)apn_ie;
 | 
			
		||||
 | 
			
		||||
	size_t apn_len = hdr->apn_len;
 | 
			
		||||
	uint8_t *apn = hdr->apn;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
 | 
			
		||||
	OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
 | 
			
		||||
 | 
			
		||||
	if (peer->cfg->core_apn_size == 0) {
 | 
			
		||||
		char str1[110];
 | 
			
		||||
		/* Remove the IE */
 | 
			
		||||
		LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
		     "Patching %s to SGSN: Removing APN '%s'\n",
 | 
			
		||||
		     log_text,
 | 
			
		||||
		     osmo_apn_to_str(str1, apn, apn_len));
 | 
			
		||||
 | 
			
		||||
		*new_apn_ie_len = 0;
 | 
			
		||||
		msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Resize the IE */
 | 
			
		||||
		char str1[110];
 | 
			
		||||
		char str2[110];
 | 
			
		||||
 | 
			
		||||
		OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
 | 
			
		||||
 | 
			
		||||
		LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
		     "Patching %s to SGSN: "
 | 
			
		||||
		     "Replacing APN '%s' -> '%s'\n",
 | 
			
		||||
		     log_text,
 | 
			
		||||
		     osmo_apn_to_str(str1, apn, apn_len),
 | 
			
		||||
		     osmo_apn_to_str(str2, peer->cfg->core_apn,
 | 
			
		||||
				       peer->cfg->core_apn_size));
 | 
			
		||||
 | 
			
		||||
		*new_apn_ie_len = peer->cfg->core_apn_size + 2;
 | 
			
		||||
		msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
 | 
			
		||||
		memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
 | 
			
		||||
		hdr->apn_len = peer->cfg->core_apn_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gbproxy_patch_tlli(uint8_t *tlli_enc,
 | 
			
		||||
			      struct gbproxy_peer *peer,
 | 
			
		||||
			      uint32_t new_tlli,
 | 
			
		||||
			      int to_bss, const char *log_text)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t tlli_be;
 | 
			
		||||
	uint32_t tlli;
 | 
			
		||||
	enum gbproxy_peer_ctr counter =
 | 
			
		||||
		to_bss ?
 | 
			
		||||
		GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
 | 
			
		||||
		GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
 | 
			
		||||
 | 
			
		||||
	memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
 | 
			
		||||
	tlli = ntohl(tlli_be);
 | 
			
		||||
 | 
			
		||||
	if (tlli == new_tlli)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
	     "Patching %ss: "
 | 
			
		||||
	     "Replacing %08x -> %08x\n",
 | 
			
		||||
	     log_text, tlli, new_tlli);
 | 
			
		||||
 | 
			
		||||
	tlli_be = htonl(new_tlli);
 | 
			
		||||
	memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&peer->ctrg->ctr[counter]);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
 | 
			
		||||
			       struct gbproxy_peer *peer,
 | 
			
		||||
			       uint32_t new_ptmsi,
 | 
			
		||||
			       int to_bss, const char *log_text)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t ptmsi_be;
 | 
			
		||||
	uint32_t ptmsi;
 | 
			
		||||
	enum gbproxy_peer_ctr counter =
 | 
			
		||||
		to_bss ?
 | 
			
		||||
		GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
 | 
			
		||||
		GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
 | 
			
		||||
	memcpy(&ptmsi_be, ptmsi_enc, sizeof(ptmsi_be));
 | 
			
		||||
	ptmsi = ntohl(ptmsi_be);
 | 
			
		||||
 | 
			
		||||
	if (ptmsi == new_ptmsi)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
	     "Patching %ss: "
 | 
			
		||||
	     "Replacing %08x -> %08x\n",
 | 
			
		||||
	     log_text, ptmsi, new_ptmsi);
 | 
			
		||||
 | 
			
		||||
	ptmsi_be = htonl(new_ptmsi);
 | 
			
		||||
	memcpy(ptmsi_enc, &ptmsi_be, sizeof(ptmsi_be));
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&peer->ctrg->ctr[counter]);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
 | 
			
		||||
		     struct gbproxy_peer *peer,
 | 
			
		||||
		     struct gbproxy_link_info *link_info, int *len_change,
 | 
			
		||||
		     struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
 | 
			
		||||
	int have_patched = 0;
 | 
			
		||||
	int fcs;
 | 
			
		||||
	struct gbproxy_config *cfg = peer->cfg;
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->ptmsi_enc && link_info &&
 | 
			
		||||
	    !parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
 | 
			
		||||
		uint32_t ptmsi;
 | 
			
		||||
		if (parse_ctx->to_bss)
 | 
			
		||||
			ptmsi = link_info->tlli.ptmsi;
 | 
			
		||||
		else
 | 
			
		||||
			ptmsi = link_info->sgsn_tlli.ptmsi;
 | 
			
		||||
 | 
			
		||||
		if (ptmsi != GSM_RESERVED_TMSI) {
 | 
			
		||||
			if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
 | 
			
		||||
						ptmsi, parse_ctx->to_bss, "P-TMSI"))
 | 
			
		||||
				have_patched = 1;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* TODO: invalidate old RAI if present (see below) */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->new_ptmsi_enc && link_info && cfg->patch_ptmsi) {
 | 
			
		||||
		uint32_t ptmsi;
 | 
			
		||||
		if (parse_ctx->to_bss)
 | 
			
		||||
			ptmsi = link_info->tlli.ptmsi;
 | 
			
		||||
		else
 | 
			
		||||
			ptmsi = link_info->sgsn_tlli.ptmsi;
 | 
			
		||||
 | 
			
		||||
		OSMO_ASSERT(ptmsi);
 | 
			
		||||
		if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
 | 
			
		||||
					ptmsi, parse_ctx->to_bss, "new P-TMSI"))
 | 
			
		||||
			have_patched = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->raid_enc) {
 | 
			
		||||
		gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->raid_enc, peer, parse_ctx->to_bss,
 | 
			
		||||
				   parse_ctx->llc_msg_name);
 | 
			
		||||
		have_patched = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->old_raid_enc && !parse_ctx->old_raid_is_foreign) {
 | 
			
		||||
		/* TODO: Patch to invalid if P-TMSI unknown. */
 | 
			
		||||
		gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
 | 
			
		||||
				   parse_ctx->llc_msg_name);
 | 
			
		||||
		have_patched = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->apn_ie &&
 | 
			
		||||
	    cfg->core_apn &&
 | 
			
		||||
	    !parse_ctx->to_bss &&
 | 
			
		||||
	    gbproxy_imsi_matches(cfg, GBPROX_MATCH_PATCHING, link_info) &&
 | 
			
		||||
	    cfg->core_apn) {
 | 
			
		||||
		size_t new_len;
 | 
			
		||||
		gbproxy_patch_apn_ie(msg,
 | 
			
		||||
				     parse_ctx->apn_ie, parse_ctx->apn_ie_len,
 | 
			
		||||
				     peer, &new_len, parse_ctx->llc_msg_name);
 | 
			
		||||
		*len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
 | 
			
		||||
 | 
			
		||||
		have_patched = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (have_patched) {
 | 
			
		||||
		llc_len += *len_change;
 | 
			
		||||
		ghp->crc_length += *len_change;
 | 
			
		||||
 | 
			
		||||
		/* Fix FCS */
 | 
			
		||||
		fcs = gprs_llc_fcs(llc, ghp->crc_length);
 | 
			
		||||
		LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
 | 
			
		||||
		     ghp->fcs, fcs);
 | 
			
		||||
 | 
			
		||||
		llc[llc_len - 3] = fcs & 0xff;
 | 
			
		||||
		llc[llc_len - 2] = (fcs >> 8) & 0xff;
 | 
			
		||||
		llc[llc_len - 1] = (fcs >> 16) & 0xff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return have_patched;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* patch BSSGP message to use core_plmn.mcc/mnc on the SGSN side */
 | 
			
		||||
void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
 | 
			
		||||
			 struct gbproxy_peer *peer,
 | 
			
		||||
			 struct gbproxy_link_info *link_info, int *len_change,
 | 
			
		||||
			 struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	const char *err_info = NULL;
 | 
			
		||||
	int err_ctr = -1;
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->bssgp_raid_enc)
 | 
			
		||||
		gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->bssgp_raid_enc, peer,
 | 
			
		||||
				   parse_ctx->to_bss, "BSSGP");
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->need_decryption &&
 | 
			
		||||
	    (peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
 | 
			
		||||
		/* Patching LLC messages has been requested
 | 
			
		||||
		 * explicitly, but the message (including the
 | 
			
		||||
		 * type) is encrypted, so we possibly fail to
 | 
			
		||||
		 * patch the LLC part of the message. */
 | 
			
		||||
		err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
 | 
			
		||||
		err_info = "GMM message is encrypted";
 | 
			
		||||
		goto patch_error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!link_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
 | 
			
		||||
		/* Happens with unknown (not cached) TLLI coming from
 | 
			
		||||
		 * the SGSN */
 | 
			
		||||
		/* TODO: What shall be done with the message in this case? */
 | 
			
		||||
		err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
 | 
			
		||||
		err_info = "TLLI sent by the SGSN is unknown";
 | 
			
		||||
		goto patch_error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!link_info)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
 | 
			
		||||
		uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
 | 
			
		||||
						 link_info, parse_ctx->to_bss);
 | 
			
		||||
 | 
			
		||||
		if (tlli) {
 | 
			
		||||
			gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
 | 
			
		||||
					   parse_ctx->to_bss, "TLLI");
 | 
			
		||||
			parse_ctx->tlli = tlli;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Internal error */
 | 
			
		||||
			err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
 | 
			
		||||
			err_info = "Replacement TLLI is 0";
 | 
			
		||||
			goto patch_error;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
 | 
			
		||||
		uint32_t ptmsi;
 | 
			
		||||
		if (parse_ctx->to_bss)
 | 
			
		||||
			ptmsi = link_info->tlli.ptmsi;
 | 
			
		||||
		else
 | 
			
		||||
			ptmsi = link_info->sgsn_tlli.ptmsi;
 | 
			
		||||
 | 
			
		||||
		if (ptmsi != GSM_RESERVED_TMSI)
 | 
			
		||||
			gbproxy_patch_ptmsi(
 | 
			
		||||
				parse_ctx->bssgp_ptmsi_enc, peer,
 | 
			
		||||
				ptmsi, parse_ctx->to_bss, "BSSGP P-TMSI");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->llc) {
 | 
			
		||||
		uint8_t *llc = parse_ctx->llc;
 | 
			
		||||
		size_t llc_len = parse_ctx->llc_len;
 | 
			
		||||
		int llc_len_change = 0;
 | 
			
		||||
 | 
			
		||||
		gbproxy_patch_llc(msg, llc, llc_len, peer, link_info,
 | 
			
		||||
				  &llc_len_change, parse_ctx);
 | 
			
		||||
		/* Note that the APN might have been resized here, but no
 | 
			
		||||
		 * pointer int the parse_ctx will refer to an adress after the
 | 
			
		||||
		 * APN. So it's possible to patch first and do the TLLI
 | 
			
		||||
		 * handling afterwards. */
 | 
			
		||||
 | 
			
		||||
		if (llc_len_change) {
 | 
			
		||||
			llc_len += llc_len_change;
 | 
			
		||||
 | 
			
		||||
			/* Fix LLC IE len */
 | 
			
		||||
			/* TODO: This is a kludge, but the a pointer to the
 | 
			
		||||
			 * start of the IE is not available here */
 | 
			
		||||
			if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
 | 
			
		||||
				/* most probably a one byte length */
 | 
			
		||||
				if (llc_len > 127) {
 | 
			
		||||
					err_info = "Cannot increase size";
 | 
			
		||||
					err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
 | 
			
		||||
					goto patch_error;
 | 
			
		||||
				}
 | 
			
		||||
				llc[-1] = llc_len | 0x80;
 | 
			
		||||
			} else {
 | 
			
		||||
				llc[-2] = (llc_len >> 8) & 0x7f;
 | 
			
		||||
				llc[-1] = llc_len & 0xff;
 | 
			
		||||
			}
 | 
			
		||||
			*len_change += llc_len_change;
 | 
			
		||||
		}
 | 
			
		||||
		/* Note that the tp struct might contain invalid pointers here
 | 
			
		||||
		 * if the LLC field has changed its size */
 | 
			
		||||
		parse_ctx->llc_len = llc_len;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
patch_error:
 | 
			
		||||
	OSMO_ASSERT(err_ctr >= 0);
 | 
			
		||||
	rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
 | 
			
		||||
	LOGP(DGPRS, LOGL_ERROR,
 | 
			
		||||
	     "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
 | 
			
		||||
	     msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
 | 
			
		||||
	     err_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_clear_patch_filter(struct gbproxy_match *match)
 | 
			
		||||
{
 | 
			
		||||
	if (match->enable) {
 | 
			
		||||
		regfree(&match->re_comp);
 | 
			
		||||
		match->enable = false;
 | 
			
		||||
	}
 | 
			
		||||
	talloc_free(match->re_str);
 | 
			
		||||
	match->re_str = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
 | 
			
		||||
		const char **err_msg)
 | 
			
		||||
{
 | 
			
		||||
	static char err_buf[300];
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	gbproxy_clear_patch_filter(match);
 | 
			
		||||
 | 
			
		||||
	if (!filter)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	rc = regcomp(&match->re_comp, filter,
 | 
			
		||||
		     REG_EXTENDED | REG_NOSUB | REG_ICASE);
 | 
			
		||||
 | 
			
		||||
	if (rc == 0) {
 | 
			
		||||
		match->enable = true;
 | 
			
		||||
		match->re_str = talloc_strdup(tall_sgsn_ctx, filter);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (err_msg) {
 | 
			
		||||
		regerror(rc, &match->re_comp,
 | 
			
		||||
			 err_buf, sizeof(err_buf));
 | 
			
		||||
		*err_msg = err_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_check_imsi(struct gbproxy_match *match,
 | 
			
		||||
		       const uint8_t *imsi, size_t imsi_len)
 | 
			
		||||
{
 | 
			
		||||
	char mi_buf[200];
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (!match->enable)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	rc = gprs_is_mi_imsi(imsi, imsi_len);
 | 
			
		||||
	if (rc > 0)
 | 
			
		||||
		rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
 | 
			
		||||
	if (rc <= 0) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
 | 
			
		||||
		     osmo_hexdump(imsi, imsi_len));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
 | 
			
		||||
 | 
			
		||||
	rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
 | 
			
		||||
	if (rc == REG_NOMATCH) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		       "IMSI '%s' doesn't match pattern '%s'\n",
 | 
			
		||||
		       mi_buf, match->re_str);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,240 +0,0 @@
 | 
			
		||||
/* Gb proxy peer handling */
 | 
			
		||||
 | 
			
		||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010-2013 by On-Waves
 | 
			
		||||
 * (C) 2013 by Holger Hans Peter Freyther
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/protocol/gsm_08_18.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/core/stats.h>
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
extern void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
static const struct rate_ctr_desc peer_ctr_description[] = {
 | 
			
		||||
	{ "blocked",	   "BVC Block                       " },
 | 
			
		||||
	{ "unblocked",	   "BVC Unblock                     " },
 | 
			
		||||
	{ "dropped",	   "BVC blocked, dropped packet     " },
 | 
			
		||||
	{ "inv-nsei",	   "NSEI mismatch                   " },
 | 
			
		||||
	{ "tx-err",	   "NS Transmission error           " },
 | 
			
		||||
	{ "raid-mod:bss",  "RAID patched              (BSS )" },
 | 
			
		||||
	{ "raid-mod:sgsn", "RAID patched              (SGSN)" },
 | 
			
		||||
	{ "apn-mod:sgsn",  "APN patched                     " },
 | 
			
		||||
	{ "tlli-mod:bss",  "TLLI patched              (BSS )" },
 | 
			
		||||
	{ "tlli-mod:sgsn", "TLLI patched              (SGSN)" },
 | 
			
		||||
	{ "ptmsi-mod:bss", "P-TMSI patched            (BSS )" },
 | 
			
		||||
	{ "ptmsi-mod:sgsn","P-TMSI patched            (SGSN)" },
 | 
			
		||||
	{ "mod-crypt-err", "Patch error: encrypted          " },
 | 
			
		||||
	{ "mod-err",	   "Patch error: other              " },
 | 
			
		||||
	{ "attach-reqs",   "Attach Request count            " },
 | 
			
		||||
	{ "attach-rejs",   "Attach Reject count             " },
 | 
			
		||||
	{ "attach-acks",   "Attach Accept count             " },
 | 
			
		||||
	{ "attach-cpls",   "Attach Completed count          " },
 | 
			
		||||
	{ "ra-upd-reqs",   "RoutingArea Update Request count" },
 | 
			
		||||
	{ "ra-upd-rejs",   "RoutingArea Update Reject count " },
 | 
			
		||||
	{ "ra-upd-acks",   "RoutingArea Update Accept count " },
 | 
			
		||||
	{ "ra-upd-cpls",   "RoutingArea Update Compltd count" },
 | 
			
		||||
	{ "gmm-status",    "GMM Status count           (BSS)" },
 | 
			
		||||
	{ "gmm-status",    "GMM Status count          (SGSN)" },
 | 
			
		||||
	{ "detach-reqs",   "Detach Request count            " },
 | 
			
		||||
	{ "detach-acks",   "Detach Accept count             " },
 | 
			
		||||
	{ "pdp-act-reqs",  "PDP Activation Request count    " },
 | 
			
		||||
	{ "pdp-act-rejs",  "PDP Activation Reject count     " },
 | 
			
		||||
	{ "pdp-act-acks",  "PDP Activation Accept count     " },
 | 
			
		||||
	{ "pdp-deact-reqs","PDP Deactivation Request count  " },
 | 
			
		||||
	{ "pdp-deact-acks","PDP Deactivation Accept count   " },
 | 
			
		||||
	{ "tlli-unknown",  "TLLI from SGSN unknown          " },
 | 
			
		||||
	{ "tlli-cache",    "TLLI cache size                 " },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
osmo_static_assert(ARRAY_SIZE(peer_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described);
 | 
			
		||||
 | 
			
		||||
static const struct rate_ctr_group_desc peer_ctrg_desc = {
 | 
			
		||||
	.group_name_prefix = "gbproxy:peer",
 | 
			
		||||
	.group_description = "GBProxy Peer Statistics",
 | 
			
		||||
	.num_ctr = ARRAY_SIZE(peer_ctr_description),
 | 
			
		||||
	.ctr_desc = peer_ctr_description,
 | 
			
		||||
	.class_id = OSMO_STATS_CLASS_PEER,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Find the gbprox_peer by its BVCI */
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		if (peer->bvci == bvci)
 | 
			
		||||
			return peer;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find the gbprox_peer by its NSEI */
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
 | 
			
		||||
					  uint16_t nsei)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		if (peer->nsei == nsei)
 | 
			
		||||
			return peer;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* look-up a peer by its Routeing Area Identification (RAI) */
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
 | 
			
		||||
					 const uint8_t *ra)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		if (!memcmp(peer->ra, ra, 6))
 | 
			
		||||
			return peer;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* look-up a peer by its Location Area Identification (LAI) */
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
 | 
			
		||||
					 const uint8_t *la)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		if (!memcmp(peer->ra, la, 5))
 | 
			
		||||
			return peer;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* look-up a peer by its Location Area Code (LAC) */
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
 | 
			
		||||
					 const uint8_t *la)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	llist_for_each_entry(peer, &cfg->bts_peers, list) {
 | 
			
		||||
		if (!memcmp(peer->ra + 3, la + 3, 2))
 | 
			
		||||
			return peer;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg,
 | 
			
		||||
					       struct tlv_parsed *tp)
 | 
			
		||||
{
 | 
			
		||||
	if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
 | 
			
		||||
		uint16_t bvci;
 | 
			
		||||
 | 
			
		||||
		bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
 | 
			
		||||
		if (bvci >= 2)
 | 
			
		||||
			return gbproxy_peer_by_bvci(cfg, bvci);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
 | 
			
		||||
		uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
 | 
			
		||||
		/* Only compare LAC part, since MCC/MNC are possibly patched.
 | 
			
		||||
		 * Since the LAC of different BSS must be different when
 | 
			
		||||
		 * MCC/MNC are patched, collisions shouldn't happen. */
 | 
			
		||||
		return gbproxy_peer_by_lac(cfg, rai);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
 | 
			
		||||
		uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
 | 
			
		||||
		return gbproxy_peer_by_lac(cfg, lai);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clean_stale_timer_cb(void *data)
 | 
			
		||||
{
 | 
			
		||||
	time_t now;
 | 
			
		||||
	struct timespec ts = {0,};
 | 
			
		||||
	struct gbproxy_peer *peer = (struct gbproxy_peer *) data;
 | 
			
		||||
 | 
			
		||||
	osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
	now = ts.tv_sec;
 | 
			
		||||
	gbproxy_remove_stale_link_infos(peer, now);
 | 
			
		||||
	if (peer->cfg->clean_stale_timer_freq != 0)
 | 
			
		||||
		osmo_timer_schedule(&peer->clean_stale_timer,
 | 
			
		||||
					peer->cfg->clean_stale_timer_freq, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
 | 
			
		||||
	peer = talloc_zero(tall_sgsn_ctx, struct gbproxy_peer);
 | 
			
		||||
	if (!peer)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	peer->bvci = bvci;
 | 
			
		||||
	peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
 | 
			
		||||
	if (!peer->ctrg) {
 | 
			
		||||
		talloc_free(peer);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	peer->cfg = cfg;
 | 
			
		||||
 | 
			
		||||
	llist_add(&peer->list, &cfg->bts_peers);
 | 
			
		||||
 | 
			
		||||
	INIT_LLIST_HEAD(&peer->patch_state.logical_links);
 | 
			
		||||
 | 
			
		||||
	osmo_timer_setup(&peer->clean_stale_timer, clean_stale_timer_cb, peer);
 | 
			
		||||
	if (peer->cfg->clean_stale_timer_freq != 0)
 | 
			
		||||
		osmo_timer_schedule(&peer->clean_stale_timer,
 | 
			
		||||
					peer->cfg->clean_stale_timer_freq, 0);
 | 
			
		||||
 | 
			
		||||
	return peer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_peer_free(struct gbproxy_peer *peer)
 | 
			
		||||
{
 | 
			
		||||
	llist_del(&peer->list);
 | 
			
		||||
	osmo_timer_del(&peer->clean_stale_timer);
 | 
			
		||||
	gbproxy_delete_link_infos(peer);
 | 
			
		||||
 | 
			
		||||
	rate_ctr_group_free(peer->ctrg);
 | 
			
		||||
	peer->ctrg = NULL;
 | 
			
		||||
 | 
			
		||||
	talloc_free(peer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
 | 
			
		||||
{
 | 
			
		||||
	int counter = 0;
 | 
			
		||||
	struct gbproxy_peer *peer, *tmp;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
 | 
			
		||||
		if (peer->nsei != nsei)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (bvci && peer->bvci != bvci)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		gbproxy_peer_free(peer);
 | 
			
		||||
		counter += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return counter;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,723 +0,0 @@
 | 
			
		||||
/* Gb-proxy TLLI state handling */
 | 
			
		||||
 | 
			
		||||
/* (C) 2014 by On-Waves
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/gsm48.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_utils.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gb_parse.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
 | 
			
		||||
					    uint32_t tlli)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	if (!tlli)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(link_info, &state->logical_links, list)
 | 
			
		||||
		if (link_info->tlli.current == tlli ||
 | 
			
		||||
		    link_info->tlli.assigned == tlli)
 | 
			
		||||
			return link_info;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	uint32_t ptmsi)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	if (ptmsi == GSM_RESERVED_TMSI)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(link_info, &state->logical_links, list)
 | 
			
		||||
		if (link_info->tlli.ptmsi == ptmsi)
 | 
			
		||||
			return link_info;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	uint32_t tlli)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	if (!tlli)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Don't care about the NSEI */
 | 
			
		||||
	llist_for_each_entry(link_info, &state->logical_links, list)
 | 
			
		||||
		if (link_info->sgsn_tlli.current == tlli ||
 | 
			
		||||
		     link_info->sgsn_tlli.assigned == tlli)
 | 
			
		||||
			return link_info;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	uint32_t tlli, uint32_t sgsn_nsei)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	if (!tlli)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(link_info, &state->logical_links, list)
 | 
			
		||||
		if ((link_info->sgsn_tlli.current == tlli ||
 | 
			
		||||
		     link_info->sgsn_tlli.assigned == tlli) &&
 | 
			
		||||
		    link_info->sgsn_nsei == sgsn_nsei)
 | 
			
		||||
			return link_info;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	const uint8_t *imsi,
 | 
			
		||||
	size_t imsi_len)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	if (!gprs_is_mi_imsi(imsi, imsi_len))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(link_info, &state->logical_links, list) {
 | 
			
		||||
		if (link_info->imsi_len != imsi_len)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		return link_info;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg, *nxt;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
 | 
			
		||||
		llist_del(&msg->list);
 | 
			
		||||
		msgb_free(msg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
 | 
			
		||||
			 struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	gbproxy_link_info_discard_messages(link_info);
 | 
			
		||||
 | 
			
		||||
	llist_del(&link_info->list);
 | 
			
		||||
	talloc_free(link_info);
 | 
			
		||||
	state->logical_link_count -= 1;
 | 
			
		||||
 | 
			
		||||
	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
 | 
			
		||||
		state->logical_link_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info, *nxt;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
 | 
			
		||||
		gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(state->logical_link_count == 0);
 | 
			
		||||
	OSMO_ASSERT(llist_empty(&state->logical_links));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
 | 
			
		||||
			      struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	link_info->timestamp = now;
 | 
			
		||||
	llist_add(&link_info->list, &state->logical_links);
 | 
			
		||||
	state->logical_link_count += 1;
 | 
			
		||||
 | 
			
		||||
	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
 | 
			
		||||
		state->logical_link_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
	int exceeded_max_len = 0;
 | 
			
		||||
	int deleted_count = 0;
 | 
			
		||||
	int check_for_age;
 | 
			
		||||
 | 
			
		||||
	if (peer->cfg->tlli_max_len > 0)
 | 
			
		||||
		exceeded_max_len =
 | 
			
		||||
			state->logical_link_count - peer->cfg->tlli_max_len;
 | 
			
		||||
 | 
			
		||||
	check_for_age = peer->cfg->tlli_max_age > 0;
 | 
			
		||||
 | 
			
		||||
	for (; exceeded_max_len > 0; exceeded_max_len--) {
 | 
			
		||||
		struct gbproxy_link_info *link_info;
 | 
			
		||||
		OSMO_ASSERT(!llist_empty(&state->logical_links));
 | 
			
		||||
		link_info = llist_entry(state->logical_links.prev,
 | 
			
		||||
					struct gbproxy_link_info,
 | 
			
		||||
					list);
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Removing TLLI %08x from list "
 | 
			
		||||
		     "(stale, length %d, max_len exceeded)\n",
 | 
			
		||||
		     link_info->tlli.current, state->logical_link_count);
 | 
			
		||||
 | 
			
		||||
		gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
		deleted_count += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (check_for_age && !llist_empty(&state->logical_links)) {
 | 
			
		||||
		time_t age;
 | 
			
		||||
		struct gbproxy_link_info *link_info;
 | 
			
		||||
		link_info = llist_entry(state->logical_links.prev,
 | 
			
		||||
					struct gbproxy_link_info,
 | 
			
		||||
					list);
 | 
			
		||||
		age = now - link_info->timestamp;
 | 
			
		||||
		/* age < 0 only happens after system time jumps, discard entry */
 | 
			
		||||
		if (age <= peer->cfg->tlli_max_age && age >= 0) {
 | 
			
		||||
			check_for_age = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Removing TLLI %08x from list "
 | 
			
		||||
		     "(stale, age %d, max_age exceeded)\n",
 | 
			
		||||
		     link_info->tlli.current, (int)age);
 | 
			
		||||
 | 
			
		||||
		gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
		deleted_count += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return deleted_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
 | 
			
		||||
	link_info = talloc_zero(peer, struct gbproxy_link_info);
 | 
			
		||||
	link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
 | 
			
		||||
	link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
 | 
			
		||||
 | 
			
		||||
	link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
 | 
			
		||||
 | 
			
		||||
	INIT_LLIST_HEAD(&link_info->stored_msgs);
 | 
			
		||||
 | 
			
		||||
	return link_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_detach_link_info(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	llist_del(&link_info->list);
 | 
			
		||||
	OSMO_ASSERT(state->logical_link_count > 0);
 | 
			
		||||
	state->logical_link_count -= 1;
 | 
			
		||||
 | 
			
		||||
	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
 | 
			
		||||
		state->logical_link_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
 | 
			
		||||
			      const uint8_t *imsi, size_t imsi_len)
 | 
			
		||||
{
 | 
			
		||||
	if (!gprs_is_mi_imsi(imsi, imsi_len))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	link_info->imsi_len = imsi_len;
 | 
			
		||||
	link_info->imsi =
 | 
			
		||||
		talloc_realloc_size(link_info, link_info->imsi, imsi_len);
 | 
			
		||||
	OSMO_ASSERT(link_info->imsi != NULL);
 | 
			
		||||
	memcpy(link_info->imsi, imsi, imsi_len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
 | 
			
		||||
			   struct gbproxy_peer *peer, uint32_t new_tlli)
 | 
			
		||||
{
 | 
			
		||||
	if (new_tlli == tlli_state->current)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
	     "The TLLI has been reassigned from %08x to %08x\n",
 | 
			
		||||
	     tlli_state->current, new_tlli);
 | 
			
		||||
 | 
			
		||||
	/* Remember assigned TLLI */
 | 
			
		||||
	tlli_state->assigned = new_tlli;
 | 
			
		||||
	tlli_state->bss_validated = false;
 | 
			
		||||
	tlli_state->net_validated = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t gbproxy_map_tlli(uint32_t other_tlli,
 | 
			
		||||
			  struct gbproxy_link_info *link_info, int to_bss)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t tlli = 0;
 | 
			
		||||
	struct gbproxy_tlli_state *src, *dst;
 | 
			
		||||
	if (to_bss) {
 | 
			
		||||
		src = &link_info->sgsn_tlli;
 | 
			
		||||
		dst = &link_info->tlli;
 | 
			
		||||
	} else {
 | 
			
		||||
		src = &link_info->tlli;
 | 
			
		||||
		dst = &link_info->sgsn_tlli;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->current == other_tlli)
 | 
			
		||||
		tlli = dst->current;
 | 
			
		||||
	else if (src->assigned == other_tlli)
 | 
			
		||||
		tlli = dst->assigned;
 | 
			
		||||
 | 
			
		||||
	return tlli;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
 | 
			
		||||
				  uint32_t tlli, int to_bss)
 | 
			
		||||
{
 | 
			
		||||
	LOGP(DGPRS, LOGL_DEBUG,
 | 
			
		||||
	     "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
 | 
			
		||||
	     __func__, tlli_state->current, tlli_state->assigned,
 | 
			
		||||
	     tlli_state->net_validated, tlli_state->bss_validated, tlli);
 | 
			
		||||
 | 
			
		||||
	if (!tlli_state->assigned || tlli_state->assigned != tlli)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* TODO: Is this ok? Check spec */
 | 
			
		||||
	if (gprs_tlli_type(tlli) != TLLI_LOCAL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* See GSM 04.08, 4.7.1.5 */
 | 
			
		||||
	if (to_bss)
 | 
			
		||||
		tlli_state->net_validated = true;
 | 
			
		||||
	else
 | 
			
		||||
		tlli_state->bss_validated = true;
 | 
			
		||||
 | 
			
		||||
	if (!tlli_state->bss_validated || !tlli_state->net_validated)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
	     "The TLLI %08x has been validated (was %08x)\n",
 | 
			
		||||
	     tlli_state->assigned, tlli_state->current);
 | 
			
		||||
 | 
			
		||||
	tlli_state->current = tlli;
 | 
			
		||||
	tlli_state->assigned = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
 | 
			
		||||
				    struct gbproxy_link_info *link_info,
 | 
			
		||||
				    time_t now)
 | 
			
		||||
{
 | 
			
		||||
	gbproxy_detach_link_info(peer, link_info);
 | 
			
		||||
	gbproxy_attach_link_info(peer, now, link_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gbproxy_unregister_link_info(struct gbproxy_peer *peer,
 | 
			
		||||
					 struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	if (!link_info)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
 | 
			
		||||
		     link_info->tlli.current);
 | 
			
		||||
		gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	link_info->tlli.current = 0;
 | 
			
		||||
	link_info->tlli.assigned = 0;
 | 
			
		||||
	link_info->sgsn_tlli.current = 0;
 | 
			
		||||
	link_info->sgsn_tlli.assigned = 0;
 | 
			
		||||
 | 
			
		||||
	link_info->is_deregistered = true;
 | 
			
		||||
 | 
			
		||||
	gbproxy_reset_link(link_info);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_imsi_matches(struct gbproxy_config *cfg,
 | 
			
		||||
			 enum gbproxy_match_id match_id,
 | 
			
		||||
			 struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_match *match;
 | 
			
		||||
	OSMO_ASSERT(match_id >= 0 && match_id < ARRAY_SIZE(cfg->matches));
 | 
			
		||||
 | 
			
		||||
	match = &cfg->matches[match_id];
 | 
			
		||||
	if (!match->enable)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return link_info != NULL && link_info->is_matching[match_id];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
 | 
			
		||||
			 struct gbproxy_link_info *link_info,
 | 
			
		||||
			 struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	int imsi_matches;
 | 
			
		||||
	struct gbproxy_link_info *other_link_info;
 | 
			
		||||
	enum gbproxy_match_id match_id;
 | 
			
		||||
 | 
			
		||||
	/* Make sure that there is a second entry with the same IMSI */
 | 
			
		||||
	other_link_info = gbproxy_link_info_by_imsi(
 | 
			
		||||
		peer, parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
 | 
			
		||||
	if (other_link_info && other_link_info != link_info) {
 | 
			
		||||
		char mi_buf[200];
 | 
			
		||||
		mi_buf[0] = '\0';
 | 
			
		||||
		gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
 | 
			
		||||
				   parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Removing TLLI %08x from list (IMSI %s re-used)\n",
 | 
			
		||||
		     other_link_info->tlli.current, mi_buf);
 | 
			
		||||
		gbproxy_delete_link_info(peer, other_link_info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Update the IMSI field */
 | 
			
		||||
	gbproxy_update_link_info(link_info,
 | 
			
		||||
				 parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
 | 
			
		||||
	/* Check, whether the IMSI matches */
 | 
			
		||||
	OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
 | 
			
		||||
		    ARRAY_SIZE(peer->cfg->matches));
 | 
			
		||||
	for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
 | 
			
		||||
	     ++match_id) {
 | 
			
		||||
		imsi_matches = gbproxy_check_imsi(
 | 
			
		||||
			&peer->cfg->matches[match_id],
 | 
			
		||||
			parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
		if (imsi_matches >= 0)
 | 
			
		||||
			link_info->is_matching[match_id] = imsi_matches ? true : false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
 | 
			
		||||
			      const struct gbproxy_tlli_state *b)
 | 
			
		||||
{
 | 
			
		||||
	if (a->current && a->current == b->current)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (a->assigned && a->assigned == b->assigned)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gbproxy_remove_matching_link_infos(
 | 
			
		||||
	struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *info, *nxt;
 | 
			
		||||
	struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	/* Make sure that there is no second entry with the same P-TMSI or TLLI */
 | 
			
		||||
	llist_for_each_entry_safe(info, nxt, &state->logical_links, list) {
 | 
			
		||||
		if (info == link_info)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
 | 
			
		||||
		    (link_info->sgsn_nsei != info->sgsn_nsei ||
 | 
			
		||||
		     !gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
 | 
			
		||||
		     info->tlli.current);
 | 
			
		||||
		gbproxy_delete_link_info(peer, info);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gbproxy_link_info *gbproxy_get_link_info_ul(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	int *tlli_is_valid,
 | 
			
		||||
	struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info = NULL;
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->tlli_enc) {
 | 
			
		||||
		link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
 | 
			
		||||
 | 
			
		||||
		if (link_info) {
 | 
			
		||||
			*tlli_is_valid = 1;
 | 
			
		||||
			return link_info;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*tlli_is_valid = 0;
 | 
			
		||||
 | 
			
		||||
	if (!link_info && parse_ctx->imsi) {
 | 
			
		||||
		link_info = gbproxy_link_info_by_imsi(
 | 
			
		||||
			peer, parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
 | 
			
		||||
		uint32_t bss_ptmsi;
 | 
			
		||||
		gprs_parse_tmsi(parse_ctx->ptmsi_enc, &bss_ptmsi);
 | 
			
		||||
		link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!link_info)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	link_info->is_deregistered = false;
 | 
			
		||||
 | 
			
		||||
	return link_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_update_link_state_ul(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	time_t now,
 | 
			
		||||
	struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info;
 | 
			
		||||
	int tlli_is_valid;
 | 
			
		||||
 | 
			
		||||
	link_info = gbproxy_get_link_info_ul(peer, &tlli_is_valid, parse_ctx);
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->tlli_enc && parse_ctx->llc) {
 | 
			
		||||
		uint32_t sgsn_tlli;
 | 
			
		||||
 | 
			
		||||
		if (!link_info) {
 | 
			
		||||
			LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
 | 
			
		||||
			    parse_ctx->tlli);
 | 
			
		||||
			link_info = gbproxy_link_info_alloc(peer);
 | 
			
		||||
			gbproxy_attach_link_info(peer, now, link_info);
 | 
			
		||||
 | 
			
		||||
			/* Setup TLLIs */
 | 
			
		||||
			sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
 | 
			
		||||
							   parse_ctx->tlli);
 | 
			
		||||
			link_info->sgsn_tlli.current = sgsn_tlli;
 | 
			
		||||
			link_info->tlli.current = parse_ctx->tlli;
 | 
			
		||||
		} else if (!tlli_is_valid) {
 | 
			
		||||
			/* New TLLI (info found by IMSI or P-TMSI) */
 | 
			
		||||
			link_info->tlli.current = parse_ctx->tlli;
 | 
			
		||||
			link_info->tlli.assigned = 0;
 | 
			
		||||
			link_info->sgsn_tlli.current =
 | 
			
		||||
				gbproxy_make_sgsn_tlli(peer, link_info,
 | 
			
		||||
						       parse_ctx->tlli);
 | 
			
		||||
			link_info->sgsn_tlli.assigned = 0;
 | 
			
		||||
			gbproxy_touch_link_info(peer, link_info, now);
 | 
			
		||||
		} else {
 | 
			
		||||
			sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
 | 
			
		||||
			if (!sgsn_tlli)
 | 
			
		||||
				sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
 | 
			
		||||
								   parse_ctx->tlli);
 | 
			
		||||
 | 
			
		||||
			gbproxy_validate_tlli(&link_info->tlli,
 | 
			
		||||
					      parse_ctx->tlli, 0);
 | 
			
		||||
			gbproxy_validate_tlli(&link_info->sgsn_tlli,
 | 
			
		||||
					      sgsn_tlli, 0);
 | 
			
		||||
			gbproxy_touch_link_info(peer, link_info, now);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (link_info) {
 | 
			
		||||
		gbproxy_touch_link_info(peer, link_info, now);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
 | 
			
		||||
		gbproxy_assign_imsi(peer, link_info, parse_ctx);
 | 
			
		||||
 | 
			
		||||
	return link_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gbproxy_link_info *gbproxy_get_link_info_dl(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Which key to use depends on its availability only, if that fails, do
 | 
			
		||||
	 * not retry it with another key (e.g. IMSI). */
 | 
			
		||||
	if (parse_ctx->tlli_enc)
 | 
			
		||||
		link_info = gbproxy_link_info_by_sgsn_tlli(peer, parse_ctx->tlli,
 | 
			
		||||
							   parse_ctx->peer_nsei);
 | 
			
		||||
 | 
			
		||||
	/* TODO: Get link_info by (SGSN) P-TMSI if that is available (see
 | 
			
		||||
	 * GSM 08.18, 7.2) instead of using the IMSI as key. */
 | 
			
		||||
	else if (parse_ctx->imsi)
 | 
			
		||||
		link_info = gbproxy_link_info_by_imsi(
 | 
			
		||||
			peer, parse_ctx->imsi, parse_ctx->imsi_len);
 | 
			
		||||
 | 
			
		||||
	if (link_info)
 | 
			
		||||
		link_info->is_deregistered = false;
 | 
			
		||||
 | 
			
		||||
	return link_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gbproxy_link_info *gbproxy_update_link_state_dl(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	time_t now,
 | 
			
		||||
	struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_link_info *link_info = NULL;
 | 
			
		||||
 | 
			
		||||
	link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
 | 
			
		||||
		/* A new P-TMSI has been signalled in the message,
 | 
			
		||||
		 * register new TLLI */
 | 
			
		||||
		uint32_t new_sgsn_ptmsi;
 | 
			
		||||
		uint32_t new_bss_ptmsi = GSM_RESERVED_TMSI;
 | 
			
		||||
		gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_sgsn_ptmsi);
 | 
			
		||||
 | 
			
		||||
		if (link_info->sgsn_tlli.ptmsi == new_sgsn_ptmsi)
 | 
			
		||||
			new_bss_ptmsi = link_info->tlli.ptmsi;
 | 
			
		||||
 | 
			
		||||
		if (new_bss_ptmsi == GSM_RESERVED_TMSI)
 | 
			
		||||
			new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
 | 
			
		||||
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Got new PTMSI %08x from SGSN, using %08x for BSS\n",
 | 
			
		||||
		     new_sgsn_ptmsi, new_bss_ptmsi);
 | 
			
		||||
		/* Setup PTMSIs */
 | 
			
		||||
		link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
 | 
			
		||||
		link_info->tlli.ptmsi = new_bss_ptmsi;
 | 
			
		||||
	} else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
 | 
			
		||||
		   !peer->cfg->patch_ptmsi) {
 | 
			
		||||
		/* A new P-TMSI has been signalled in the message with an unknown
 | 
			
		||||
		 * TLLI, create a new link_info */
 | 
			
		||||
		/* TODO: Add a test case for this branch */
 | 
			
		||||
		uint32_t new_ptmsi;
 | 
			
		||||
		gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
 | 
			
		||||
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
 | 
			
		||||
		     parse_ctx->tlli, new_ptmsi);
 | 
			
		||||
 | 
			
		||||
		link_info = gbproxy_link_info_alloc(peer);
 | 
			
		||||
		link_info->sgsn_tlli.current = parse_ctx->tlli;
 | 
			
		||||
		link_info->tlli.current = parse_ctx->tlli;
 | 
			
		||||
		link_info->sgsn_tlli.ptmsi = new_ptmsi;
 | 
			
		||||
		link_info->tlli.ptmsi = new_ptmsi;
 | 
			
		||||
		gbproxy_attach_link_info(peer, now, link_info);
 | 
			
		||||
	} else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
 | 
			
		||||
		   !peer->cfg->patch_ptmsi) {
 | 
			
		||||
		/* Unknown SGSN TLLI, create a new link_info */
 | 
			
		||||
		uint32_t new_ptmsi;
 | 
			
		||||
		link_info = gbproxy_link_info_alloc(peer);
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
 | 
			
		||||
		     parse_ctx->tlli);
 | 
			
		||||
 | 
			
		||||
		gbproxy_attach_link_info(peer, now, link_info);
 | 
			
		||||
 | 
			
		||||
		/* Setup TLLIs */
 | 
			
		||||
		link_info->sgsn_tlli.current = parse_ctx->tlli;
 | 
			
		||||
		link_info->tlli.current = parse_ctx->tlli;
 | 
			
		||||
 | 
			
		||||
		if (!parse_ctx->new_ptmsi_enc)
 | 
			
		||||
			return link_info;
 | 
			
		||||
		/* A new P-TMSI has been signalled in the message */
 | 
			
		||||
 | 
			
		||||
		gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Assigning new P-TMSI %08x\n", new_ptmsi);
 | 
			
		||||
		/* Setup P-TMSIs */
 | 
			
		||||
		link_info->sgsn_tlli.ptmsi = new_ptmsi;
 | 
			
		||||
		link_info->tlli.ptmsi = new_ptmsi;
 | 
			
		||||
	} else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
 | 
			
		||||
		uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
 | 
			
		||||
						     link_info, 1);
 | 
			
		||||
		gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
 | 
			
		||||
		gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
 | 
			
		||||
		gbproxy_touch_link_info(peer, link_info, now);
 | 
			
		||||
	} else if (link_info) {
 | 
			
		||||
		gbproxy_touch_link_info(peer, link_info, now);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
 | 
			
		||||
		gbproxy_assign_imsi(peer, link_info, parse_ctx);
 | 
			
		||||
 | 
			
		||||
	return link_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_update_link_state_after(
 | 
			
		||||
	struct gbproxy_peer *peer,
 | 
			
		||||
	struct gbproxy_link_info *link_info,
 | 
			
		||||
	time_t now,
 | 
			
		||||
	struct gprs_gb_parse_context *parse_ctx)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	if (parse_ctx->invalidate_tlli && link_info) {
 | 
			
		||||
		int keep_info =
 | 
			
		||||
			peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
 | 
			
		||||
			(peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
 | 
			
		||||
			 parse_ctx->await_reattach) ||
 | 
			
		||||
			(peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
 | 
			
		||||
			 link_info->imsi_len > 0);
 | 
			
		||||
		if (keep_info) {
 | 
			
		||||
			LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
 | 
			
		||||
			     link_info->tlli.current);
 | 
			
		||||
			rc = gbproxy_unregister_link_info(peer, link_info);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
 | 
			
		||||
			     link_info->tlli.current);
 | 
			
		||||
			gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
			rc = 1;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
 | 
			
		||||
		   parse_ctx->new_ptmsi_enc && link_info) {
 | 
			
		||||
		/* A new PTMSI has been signaled in the message,
 | 
			
		||||
		 * register new TLLI */
 | 
			
		||||
		uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
 | 
			
		||||
		uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
 | 
			
		||||
		uint32_t new_sgsn_tlli;
 | 
			
		||||
		uint32_t new_bss_tlli = 0;
 | 
			
		||||
 | 
			
		||||
		new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
 | 
			
		||||
		if (new_bss_ptmsi != GSM_RESERVED_TMSI)
 | 
			
		||||
			new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
 | 
			
		||||
		LOGP(DGPRS, LOGL_INFO,
 | 
			
		||||
		     "Assigning new TLLI %08x to SGSN, %08x to BSS\n",
 | 
			
		||||
		     new_sgsn_tlli, new_bss_tlli);
 | 
			
		||||
 | 
			
		||||
		gbproxy_reassign_tlli(&link_info->sgsn_tlli,
 | 
			
		||||
				      peer, new_sgsn_tlli);
 | 
			
		||||
		gbproxy_reassign_tlli(&link_info->tlli,
 | 
			
		||||
				      peer, new_bss_tlli);
 | 
			
		||||
		gbproxy_remove_matching_link_infos(peer, link_info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gbproxy_remove_stale_link_infos(peer, now);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,926 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * (C) 2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010 by On-Waves
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_ns.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/gb_proxy.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_utils.h>
 | 
			
		||||
#include <osmocom/sgsn/vty.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
 | 
			
		||||
static struct gbproxy_config *g_cfg = NULL;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * vty code for gbproxy below
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_node gbproxy_node = {
 | 
			
		||||
	GBPROXY_NODE,
 | 
			
		||||
	"%s(config-gbproxy)# ",
 | 
			
		||||
	1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct value_string keep_modes[] = {
 | 
			
		||||
	{GBPROX_KEEP_NEVER, "never"},
 | 
			
		||||
	{GBPROX_KEEP_REATTACH, "re-attach"},
 | 
			
		||||
	{GBPROX_KEEP_IDENTIFIED, "identified"},
 | 
			
		||||
	{GBPROX_KEEP_ALWAYS, "always"},
 | 
			
		||||
	{0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct value_string match_ids[] = {
 | 
			
		||||
	{GBPROX_MATCH_PATCHING, "patching"},
 | 
			
		||||
	{GBPROX_MATCH_ROUTING, "routing"},
 | 
			
		||||
	{0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_ra_id raid;
 | 
			
		||||
	gsm48_parse_ra(&raid, peer->ra);
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
 | 
			
		||||
		"RAI %s", peer->nsei, peer->bvci, osmo_rai_name(&raid));
 | 
			
		||||
	if (peer->blocked)
 | 
			
		||||
		vty_out(vty, " [BVC-BLOCKED]");
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%s", VTY_NEWLINE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int config_write_gbproxy(struct vty *vty)
 | 
			
		||||
{
 | 
			
		||||
	enum gbproxy_match_id match_id;
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "gbproxy%s", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
 | 
			
		||||
		VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->core_plmn.mcc > 0)
 | 
			
		||||
		vty_out(vty, " core-mobile-country-code %s%s",
 | 
			
		||||
			osmo_mcc_name(g_cfg->core_plmn.mcc), VTY_NEWLINE);
 | 
			
		||||
	if (g_cfg->core_plmn.mnc > 0)
 | 
			
		||||
		vty_out(vty, " core-mobile-network-code %s%s",
 | 
			
		||||
			osmo_mnc_name(g_cfg->core_plmn.mnc, g_cfg->core_plmn.mnc_3_digits), VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id) {
 | 
			
		||||
		struct gbproxy_match *match = &g_cfg->matches[match_id];
 | 
			
		||||
		if (match->re_str)
 | 
			
		||||
			vty_out(vty, " match-imsi %s %s%s",
 | 
			
		||||
				get_value_string(match_ids, match_id),
 | 
			
		||||
				match->re_str, VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->core_apn != NULL) {
 | 
			
		||||
	       if (g_cfg->core_apn_size > 0) {
 | 
			
		||||
		       char str[500] = {0};
 | 
			
		||||
		       vty_out(vty, " core-access-point-name %s%s",
 | 
			
		||||
			       osmo_apn_to_str(str, g_cfg->core_apn,
 | 
			
		||||
						 g_cfg->core_apn_size),
 | 
			
		||||
			       VTY_NEWLINE);
 | 
			
		||||
	       } else {
 | 
			
		||||
		       vty_out(vty, " core-access-point-name none%s",
 | 
			
		||||
			       VTY_NEWLINE);
 | 
			
		||||
	       }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->route_to_sgsn2)
 | 
			
		||||
		vty_out(vty, " secondary-sgsn nsei %u%s", g_cfg->nsip_sgsn2_nsei,
 | 
			
		||||
			VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->clean_stale_timer_freq > 0)
 | 
			
		||||
		vty_out(vty, " link-list clean-stale-timer %u%s",
 | 
			
		||||
			g_cfg->clean_stale_timer_freq, VTY_NEWLINE);
 | 
			
		||||
	if (g_cfg->tlli_max_age > 0)
 | 
			
		||||
		vty_out(vty, " link-list max-age %d%s",
 | 
			
		||||
			g_cfg->tlli_max_age, VTY_NEWLINE);
 | 
			
		||||
	if (g_cfg->tlli_max_len > 0)
 | 
			
		||||
		vty_out(vty, " link-list max-length %d%s",
 | 
			
		||||
			g_cfg->tlli_max_len, VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, " link-list keep-mode %s%s",
 | 
			
		||||
		get_value_string(keep_modes, g_cfg->keep_link_infos),
 | 
			
		||||
		VTY_NEWLINE);
 | 
			
		||||
	if (g_cfg->stored_msgs_max_len > 0)
 | 
			
		||||
		vty_out(vty, " link stored-msgs-max-length %"PRIu32"%s",
 | 
			
		||||
			g_cfg->stored_msgs_max_len, VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy,
 | 
			
		||||
      cfg_gbproxy_cmd,
 | 
			
		||||
      "gbproxy",
 | 
			
		||||
      "Configure the Gb proxy")
 | 
			
		||||
{
 | 
			
		||||
	vty->node = GBPROXY_NODE;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_nsip_sgsn_nsei,
 | 
			
		||||
      cfg_nsip_sgsn_nsei_cmd,
 | 
			
		||||
      "sgsn nsei <0-65534>",
 | 
			
		||||
      "SGSN information\n"
 | 
			
		||||
      "NSEI to be used in the connection with the SGSN\n"
 | 
			
		||||
      "The NSEI\n")
 | 
			
		||||
{
 | 
			
		||||
	unsigned int nsei = atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->route_to_sgsn2 && g_cfg->nsip_sgsn2_nsei == nsei) {
 | 
			
		||||
		vty_out(vty, "SGSN NSEI %d conflicts with secondary SGSN NSEI%s",
 | 
			
		||||
			nsei, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_cfg->nsip_sgsn_nsei = nsei;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_core_mnc,
 | 
			
		||||
      cfg_gbproxy_core_mnc_cmd,
 | 
			
		||||
      "core-mobile-network-code <1-999>",
 | 
			
		||||
      GBPROXY_CORE_MNC_STR "NCC value\n")
 | 
			
		||||
{
 | 
			
		||||
	uint16_t mnc;
 | 
			
		||||
	bool mnc_3_digits;
 | 
			
		||||
	if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
 | 
			
		||||
		vty_out(vty, "%% Invalid MNC: %s%s", argv[0], VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
	g_cfg->core_plmn.mnc = mnc;
 | 
			
		||||
	g_cfg->core_plmn.mnc_3_digits = mnc_3_digits;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_core_mnc,
 | 
			
		||||
      cfg_gbproxy_no_core_mnc_cmd,
 | 
			
		||||
      "no core-mobile-network-code",
 | 
			
		||||
      NO_STR GBPROXY_CORE_MNC_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->core_plmn.mnc = 0;
 | 
			
		||||
	g_cfg->core_plmn.mnc_3_digits = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_core_mcc,
 | 
			
		||||
      cfg_gbproxy_core_mcc_cmd,
 | 
			
		||||
      "core-mobile-country-code <1-999>",
 | 
			
		||||
      GBPROXY_CORE_MCC_STR "MCC value\n")
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->core_plmn.mcc = atoi(argv[0]);
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_core_mcc,
 | 
			
		||||
      cfg_gbproxy_no_core_mcc_cmd,
 | 
			
		||||
      "no core-mobile-country-code",
 | 
			
		||||
      NO_STR GBPROXY_CORE_MCC_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->core_plmn.mcc = 0;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_MATCH_IMSI_STR "Restrict actions to certain IMSIs\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_match_imsi,
 | 
			
		||||
      cfg_gbproxy_match_imsi_cmd,
 | 
			
		||||
      "match-imsi (patching|routing) .REGEXP",
 | 
			
		||||
      GBPROXY_MATCH_IMSI_STR
 | 
			
		||||
      "Patch MS related information elements on match only\n"
 | 
			
		||||
      "Route to the secondary SGSN on match only\n"
 | 
			
		||||
      "Regular expression for the IMSI match\n")
 | 
			
		||||
{
 | 
			
		||||
	const char *filter = argv[1];
 | 
			
		||||
	const char *err_msg = NULL;
 | 
			
		||||
	struct gbproxy_match *match;
 | 
			
		||||
	enum gbproxy_match_id match_id = get_string_value(match_ids, argv[0]);
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
 | 
			
		||||
		    match_id < GBPROX_MATCH_LAST);
 | 
			
		||||
	match = &g_cfg->matches[match_id];
 | 
			
		||||
 | 
			
		||||
	if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
 | 
			
		||||
		vty_out(vty, "Match expression invalid: %s%s",
 | 
			
		||||
			err_msg, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_cfg->acquire_imsi = true;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_match_imsi,
 | 
			
		||||
      cfg_gbproxy_no_match_imsi_cmd,
 | 
			
		||||
      "no match-imsi",
 | 
			
		||||
      NO_STR GBPROXY_MATCH_IMSI_STR)
 | 
			
		||||
{
 | 
			
		||||
	enum gbproxy_match_id match_id;
 | 
			
		||||
 | 
			
		||||
	for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
 | 
			
		||||
		gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
 | 
			
		||||
 | 
			
		||||
	g_cfg->acquire_imsi = false;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n"
 | 
			
		||||
#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n"
 | 
			
		||||
 | 
			
		||||
static int set_core_apn(struct vty *vty, const char *apn)
 | 
			
		||||
{
 | 
			
		||||
	int apn_len;
 | 
			
		||||
 | 
			
		||||
	if (!apn) {
 | 
			
		||||
		talloc_free(g_cfg->core_apn);
 | 
			
		||||
		g_cfg->core_apn = NULL;
 | 
			
		||||
		g_cfg->core_apn_size = 0;
 | 
			
		||||
		return CMD_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	apn_len = strlen(apn);
 | 
			
		||||
 | 
			
		||||
	if (apn_len >= 100) {
 | 
			
		||||
		vty_out(vty, "APN string too long (max 99 chars)%s",
 | 
			
		||||
			VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (apn_len == 0) {
 | 
			
		||||
		talloc_free(g_cfg->core_apn);
 | 
			
		||||
		/* TODO: replace NULL */
 | 
			
		||||
		g_cfg->core_apn = talloc_zero_size(NULL, 2);
 | 
			
		||||
		g_cfg->core_apn_size = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* TODO: replace NULL */
 | 
			
		||||
		g_cfg->core_apn =
 | 
			
		||||
			talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1);
 | 
			
		||||
		g_cfg->core_apn_size =
 | 
			
		||||
			gprs_str_to_apn(g_cfg->core_apn, apn_len + 1, apn);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_core_apn,
 | 
			
		||||
      cfg_gbproxy_core_apn_cmd,
 | 
			
		||||
      "core-access-point-name (APN|none)",
 | 
			
		||||
      GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR)
 | 
			
		||||
{
 | 
			
		||||
	if (strcmp(argv[0], "none") == 0)
 | 
			
		||||
		return set_core_apn(vty, "");
 | 
			
		||||
	else
 | 
			
		||||
		return set_core_apn(vty, argv[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_core_apn,
 | 
			
		||||
      cfg_gbproxy_no_core_apn_cmd,
 | 
			
		||||
      "no core-access-point-name",
 | 
			
		||||
      NO_STR GBPROXY_CORE_APN_STR)
 | 
			
		||||
{
 | 
			
		||||
	return set_core_apn(vty, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TODO: Remove the patch-ptmsi command, since P-TMSI patching is enabled
 | 
			
		||||
 * automatically when needed. This command is only left for manual testing
 | 
			
		||||
 * (e.g. doing P-TMSI patching without using a secondary SGSN)
 | 
			
		||||
 */
 | 
			
		||||
#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_patch_ptmsi,
 | 
			
		||||
      cfg_gbproxy_patch_ptmsi_cmd,
 | 
			
		||||
      "patch-ptmsi",
 | 
			
		||||
      GBPROXY_PATCH_PTMSI_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->patch_ptmsi = true;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_patch_ptmsi,
 | 
			
		||||
      cfg_gbproxy_no_patch_ptmsi_cmd,
 | 
			
		||||
      "no patch-ptmsi",
 | 
			
		||||
      NO_STR GBPROXY_PATCH_PTMSI_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->patch_ptmsi = false;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TODO: Remove the acquire-imsi command, since that feature is enabled
 | 
			
		||||
 * automatically when IMSI matching is enabled. This command is only left for
 | 
			
		||||
 * manual testing (e.g. doing IMSI acquisition without IMSI based patching)
 | 
			
		||||
 */
 | 
			
		||||
#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_acquire_imsi,
 | 
			
		||||
      cfg_gbproxy_acquire_imsi_cmd,
 | 
			
		||||
      "acquire-imsi",
 | 
			
		||||
      GBPROXY_ACQUIRE_IMSI_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->acquire_imsi = true;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_acquire_imsi,
 | 
			
		||||
      cfg_gbproxy_no_acquire_imsi_cmd,
 | 
			
		||||
      "no acquire-imsi",
 | 
			
		||||
      NO_STR GBPROXY_ACQUIRE_IMSI_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->acquire_imsi = false;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_SECOND_SGSN_STR "Route matching LLC connections to a second SGSN (Experimental)\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_secondary_sgsn,
 | 
			
		||||
      cfg_gbproxy_secondary_sgsn_cmd,
 | 
			
		||||
      "secondary-sgsn nsei <0-65534>",
 | 
			
		||||
      GBPROXY_SECOND_SGSN_STR
 | 
			
		||||
      "NSEI to be used in the connection with the SGSN\n"
 | 
			
		||||
      "The NSEI\n")
 | 
			
		||||
{
 | 
			
		||||
	unsigned int nsei = atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	if (g_cfg->nsip_sgsn_nsei == nsei) {
 | 
			
		||||
		vty_out(vty, "Secondary SGSN NSEI %d conflicts with primary SGSN NSEI%s",
 | 
			
		||||
			nsei, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_cfg->route_to_sgsn2 = true;
 | 
			
		||||
	g_cfg->nsip_sgsn2_nsei = nsei;
 | 
			
		||||
 | 
			
		||||
	g_cfg->patch_ptmsi = true;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_no_secondary_sgsn,
 | 
			
		||||
      cfg_gbproxy_no_secondary_sgsn_cmd,
 | 
			
		||||
      "no secondary-sgsn",
 | 
			
		||||
      NO_STR GBPROXY_SECOND_SGSN_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->route_to_sgsn2 = false;
 | 
			
		||||
	g_cfg->nsip_sgsn2_nsei = 0xFFFF;
 | 
			
		||||
 | 
			
		||||
	g_cfg->patch_ptmsi = false;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
 | 
			
		||||
#define GBPROXY_LINK_STR "Set TLLI parameters\n"
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_CLEAN_STALE_TIMER_STR "Periodic timer to clean stale links\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
 | 
			
		||||
      cfg_gbproxy_link_list_clean_stale_timer_cmd,
 | 
			
		||||
      "link-list clean-stale-timer <1-999999>",
 | 
			
		||||
      GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR
 | 
			
		||||
      "Frequency at which the periodic timer is fired (in seconds)\n")
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	/* Re-schedule running timers soon in case prev frequency was really big
 | 
			
		||||
	   and new frequency is desired to be lower. After initial run, periodic
 | 
			
		||||
	   time is used. Use random() to avoid firing timers for all peers at
 | 
			
		||||
	   the same time */
 | 
			
		||||
	llist_for_each_entry(peer, &g_cfg->bts_peers, list)
 | 
			
		||||
		osmo_timer_schedule(&peer->clean_stale_timer,
 | 
			
		||||
					random() % 5, random() % 1000000);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
 | 
			
		||||
      cfg_gbproxy_link_list_no_clean_stale_timer_cmd,
 | 
			
		||||
      "no link-list clean-stale-timer",
 | 
			
		||||
      NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	g_cfg->clean_stale_timer_freq = 0;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(peer, &g_cfg->bts_peers, list)
 | 
			
		||||
		osmo_timer_del(&peer->clean_stale_timer);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_max_age,
 | 
			
		||||
      cfg_gbproxy_link_list_max_age_cmd,
 | 
			
		||||
      "link-list max-age <1-999999>",
 | 
			
		||||
      GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR
 | 
			
		||||
      "Maximum age in seconds\n")
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->tlli_max_age = atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_no_max_age,
 | 
			
		||||
      cfg_gbproxy_link_list_no_max_age_cmd,
 | 
			
		||||
      "no link-list max-age",
 | 
			
		||||
      NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->tlli_max_age = 0;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_MAX_LEN_STR "Limit list length\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_max_len,
 | 
			
		||||
      cfg_gbproxy_link_list_max_len_cmd,
 | 
			
		||||
      "link-list max-length <1-99999>",
 | 
			
		||||
      GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR
 | 
			
		||||
      "Maximum number of logical links in the list\n")
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->tlli_max_len = atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_no_max_len,
 | 
			
		||||
      cfg_gbproxy_link_list_no_max_len_cmd,
 | 
			
		||||
      "no link-list max-length",
 | 
			
		||||
      NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->tlli_max_len = 0;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_list_keep_mode,
 | 
			
		||||
      cfg_gbproxy_link_list_keep_mode_cmd,
 | 
			
		||||
      "link-list keep-mode (never|re-attach|identified|always)",
 | 
			
		||||
      GBPROXY_LINK_LIST_STR "How to keep entries for detached logical links\n"
 | 
			
		||||
      "Discard entry immediately after detachment\n"
 | 
			
		||||
      "Keep entry if a re-attachment has be requested\n"
 | 
			
		||||
      "Keep entry if it associated with an IMSI\n"
 | 
			
		||||
      "Don't discard entries after detachment\n")
 | 
			
		||||
{
 | 
			
		||||
	int val = get_string_value(keep_modes, argv[0]);
 | 
			
		||||
	OSMO_ASSERT(val >= GBPROX_KEEP_NEVER && val <= GBPROX_KEEP_ALWAYS);
 | 
			
		||||
	g_cfg->keep_link_infos = val;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_stored_msgs_max_len,
 | 
			
		||||
      cfg_gbproxy_link_stored_msgs_max_len_cmd,
 | 
			
		||||
      "link stored-msgs-max-length <1-99999>",
 | 
			
		||||
      GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR
 | 
			
		||||
      "Maximum number of msgb stored in the logical link waiting to acquire its IMSI\n")
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->stored_msgs_max_len = (uint32_t) atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_gbproxy_link_no_stored_msgs_max_len,
 | 
			
		||||
      cfg_gbproxy_link_no_stored_msgs_max_len_cmd,
 | 
			
		||||
      "no link stored-msgs-max-length",
 | 
			
		||||
      NO_STR GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR)
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->stored_msgs_max_len = 0;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
 | 
			
		||||
       SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	int show_stats = argc >= 1;
 | 
			
		||||
 | 
			
		||||
	if (show_stats)
 | 
			
		||||
		vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
 | 
			
		||||
		gbprox_vty_print_peer(vty, peer);
 | 
			
		||||
 | 
			
		||||
		if (show_stats)
 | 
			
		||||
			vty_out_rate_ctr_group(vty, "  ", peer->ctrg);
 | 
			
		||||
	}
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
 | 
			
		||||
       SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
 | 
			
		||||
{
 | 
			
		||||
	struct gbproxy_peer *peer;
 | 
			
		||||
	char mi_buf[200];
 | 
			
		||||
	time_t now;
 | 
			
		||||
	struct timespec ts = {0,};
 | 
			
		||||
 | 
			
		||||
	osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
	now = ts.tv_sec;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
 | 
			
		||||
		struct gbproxy_link_info *link_info;
 | 
			
		||||
		struct gbproxy_patch_state *state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
		gbprox_vty_print_peer(vty, peer);
 | 
			
		||||
 | 
			
		||||
		llist_for_each_entry(link_info, &state->logical_links, list) {
 | 
			
		||||
			time_t age = now - link_info->timestamp;
 | 
			
		||||
 | 
			
		||||
			if (link_info->imsi > 0) {
 | 
			
		||||
				snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
 | 
			
		||||
				gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
 | 
			
		||||
						   link_info->imsi,
 | 
			
		||||
						   link_info->imsi_len);
 | 
			
		||||
			} else {
 | 
			
		||||
				snprintf(mi_buf, sizeof(mi_buf), "(none)");
 | 
			
		||||
			}
 | 
			
		||||
			vty_out(vty, "  TLLI %08x, IMSI %s, AGE %d",
 | 
			
		||||
				link_info->tlli.current, mi_buf, (int)age);
 | 
			
		||||
 | 
			
		||||
			if (link_info->stored_msgs_len)
 | 
			
		||||
				vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
 | 
			
		||||
					link_info->stored_msgs_len,
 | 
			
		||||
					g_cfg->stored_msgs_max_len);
 | 
			
		||||
 | 
			
		||||
			if (g_cfg->route_to_sgsn2)
 | 
			
		||||
				vty_out(vty, ", SGSN NSEI %d",
 | 
			
		||||
					link_info->sgsn_nsei);
 | 
			
		||||
 | 
			
		||||
			if (link_info->is_deregistered)
 | 
			
		||||
				vty_out(vty, ", DE-REGISTERED");
 | 
			
		||||
 | 
			
		||||
			vty_out(vty, "%s", VTY_NEWLINE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
 | 
			
		||||
	"delete-gbproxy-peer <0-65534> bvci <2-65534>",
 | 
			
		||||
	"Delete a GBProxy peer by NSEI and optionally BVCI\n"
 | 
			
		||||
	"NSEI number\n"
 | 
			
		||||
	"Only delete peer with a matching BVCI\n"
 | 
			
		||||
	"BVCI number\n")
 | 
			
		||||
{
 | 
			
		||||
	const uint16_t nsei = atoi(argv[0]);
 | 
			
		||||
	const uint16_t bvci = atoi(argv[1]);
 | 
			
		||||
	int counter;
 | 
			
		||||
 | 
			
		||||
	counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
 | 
			
		||||
 | 
			
		||||
	if (counter == 0) {
 | 
			
		||||
		vty_out(vty, "BVC not found%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
 | 
			
		||||
	"delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
 | 
			
		||||
	"Delete a GBProxy peer by NSEI and optionally BVCI\n"
 | 
			
		||||
	"NSEI number\n"
 | 
			
		||||
	"Only delete BSSGP connections (BVC)\n"
 | 
			
		||||
	"Only delete dynamic NS connections (NS-VC)\n"
 | 
			
		||||
	"Delete BVC and dynamic NS connections\n"
 | 
			
		||||
	"Show what would be deleted instead of actually deleting\n"
 | 
			
		||||
	)
 | 
			
		||||
{
 | 
			
		||||
	const uint16_t nsei = atoi(argv[0]);
 | 
			
		||||
	const char *mode = argv[1];
 | 
			
		||||
	int dry_run = argc > 2;
 | 
			
		||||
	int delete_bvc = 0;
 | 
			
		||||
	int delete_nsvc = 0;
 | 
			
		||||
	int counter;
 | 
			
		||||
 | 
			
		||||
	if (strcmp(mode, "only-bvc") == 0)
 | 
			
		||||
		delete_bvc = 1;
 | 
			
		||||
	else if (strcmp(mode, "only-nsvc") == 0)
 | 
			
		||||
		delete_nsvc = 1;
 | 
			
		||||
	else
 | 
			
		||||
		delete_bvc = delete_nsvc = 1;
 | 
			
		||||
 | 
			
		||||
	if (delete_bvc) {
 | 
			
		||||
		if (!dry_run)
 | 
			
		||||
			counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
 | 
			
		||||
		else {
 | 
			
		||||
			struct gbproxy_peer *peer;
 | 
			
		||||
			counter = 0;
 | 
			
		||||
			llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
 | 
			
		||||
				if (peer->nsei != nsei)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				vty_out(vty, "BVC: ");
 | 
			
		||||
				gbprox_vty_print_peer(vty, peer);
 | 
			
		||||
				counter += 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		vty_out(vty, "%sDeleted %d BVC%s",
 | 
			
		||||
			dry_run ? "Not " : "", counter, VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (delete_nsvc) {
 | 
			
		||||
		struct gprs_ns_inst *nsi = g_cfg->nsi;
 | 
			
		||||
		struct gprs_nsvc *nsvc, *nsvc2;
 | 
			
		||||
 | 
			
		||||
		counter = 0;
 | 
			
		||||
		llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
 | 
			
		||||
			if (nsvc->nsei != nsei)
 | 
			
		||||
				continue;
 | 
			
		||||
			if (nsvc->persistent)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			if (!dry_run)
 | 
			
		||||
				gprs_nsvc_delete(nsvc);
 | 
			
		||||
			else
 | 
			
		||||
				vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
 | 
			
		||||
					"remote %s%s",
 | 
			
		||||
					nsvc->nsei, nsvc->nsvci,
 | 
			
		||||
					gprs_ns_ll_str(nsvc), VTY_NEWLINE);
 | 
			
		||||
			counter += 1;
 | 
			
		||||
		}
 | 
			
		||||
		vty_out(vty, "%sDeleted %d NS-VC%s",
 | 
			
		||||
			dry_run ? "Not " : "", counter, VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_DELETE_LINK_STR \
 | 
			
		||||
	"Delete a GBProxy logical link entry by NSEI and identification\nNSEI number\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
 | 
			
		||||
	"delete-gbproxy-link <0-65534> (tlli|imsi|sgsn-nsei) IDENT",
 | 
			
		||||
	GBPROXY_DELETE_LINK_STR
 | 
			
		||||
	"Delete entries with a matching TLLI (hex)\n"
 | 
			
		||||
	"Delete entries with a matching IMSI\n"
 | 
			
		||||
	"Delete entries with a matching SGSN NSEI\n"
 | 
			
		||||
	"Identification to match\n")
 | 
			
		||||
{
 | 
			
		||||
	const uint16_t nsei = atoi(argv[0]);
 | 
			
		||||
	enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match;
 | 
			
		||||
	uint32_t ident = 0;
 | 
			
		||||
	const char *imsi = NULL;
 | 
			
		||||
	struct gbproxy_peer *peer = 0;
 | 
			
		||||
	struct gbproxy_link_info *link_info, *nxt;
 | 
			
		||||
	struct gbproxy_patch_state *state;
 | 
			
		||||
	char mi_buf[200];
 | 
			
		||||
	int found = 0;
 | 
			
		||||
 | 
			
		||||
	match = argv[1][0];
 | 
			
		||||
 | 
			
		||||
	switch (match) {
 | 
			
		||||
	case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break;
 | 
			
		||||
	case MATCH_IMSI: imsi = argv[2]; break;
 | 
			
		||||
	case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	peer = gbproxy_peer_by_nsei(g_cfg, nsei);
 | 
			
		||||
	if (!peer) {
 | 
			
		||||
		vty_out(vty, "Didn't find peer with NSEI %d%s",
 | 
			
		||||
			nsei, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
 | 
			
		||||
		switch (match) {
 | 
			
		||||
		case MATCH_TLLI:
 | 
			
		||||
			if (link_info->tlli.current != ident)
 | 
			
		||||
				continue;
 | 
			
		||||
			break;
 | 
			
		||||
		case MATCH_SGSN:
 | 
			
		||||
			if (link_info->sgsn_nsei != ident)
 | 
			
		||||
				continue;
 | 
			
		||||
			break;
 | 
			
		||||
		case MATCH_IMSI:
 | 
			
		||||
			if (!link_info->imsi)
 | 
			
		||||
				continue;
 | 
			
		||||
			mi_buf[0] = '\0';
 | 
			
		||||
			gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
 | 
			
		||||
					   link_info->imsi,
 | 
			
		||||
					   link_info->imsi_len);
 | 
			
		||||
 | 
			
		||||
			if (strcmp(mi_buf, imsi) != 0)
 | 
			
		||||
				continue;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		vty_out(vty, "Deleting link with TLLI %08x%s", link_info->tlli.current,
 | 
			
		||||
			VTY_NEWLINE);
 | 
			
		||||
		gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
		found += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!found && argc >= 2) {
 | 
			
		||||
		vty_out(vty, "Didn't find link entry with %s %s%s",
 | 
			
		||||
			argv[1], argv[2], VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(delete_gb_link, delete_gb_link_cmd,
 | 
			
		||||
	"delete-gbproxy-link <0-65534> (stale|de-registered)",
 | 
			
		||||
	GBPROXY_DELETE_LINK_STR
 | 
			
		||||
	"Delete stale entries\n"
 | 
			
		||||
	"Delete de-registered entries\n")
 | 
			
		||||
{
 | 
			
		||||
	const uint16_t nsei = atoi(argv[0]);
 | 
			
		||||
	enum {MATCH_STALE = 's', MATCH_DEREGISTERED = 'd'} match;
 | 
			
		||||
	struct gbproxy_peer *peer = 0;
 | 
			
		||||
	struct gbproxy_link_info *link_info, *nxt;
 | 
			
		||||
	struct gbproxy_patch_state *state;
 | 
			
		||||
	time_t now;
 | 
			
		||||
	struct timespec ts = {0,};
 | 
			
		||||
 | 
			
		||||
	int found = 0;
 | 
			
		||||
 | 
			
		||||
	match = argv[1][0];
 | 
			
		||||
 | 
			
		||||
	peer = gbproxy_peer_by_nsei(g_cfg, nsei);
 | 
			
		||||
	if (!peer) {
 | 
			
		||||
		vty_out(vty, "Didn't find peer with NSEI %d%s",
 | 
			
		||||
			nsei, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = &peer->patch_state;
 | 
			
		||||
 | 
			
		||||
	osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
	now = ts.tv_sec;
 | 
			
		||||
 | 
			
		||||
	if (match == MATCH_STALE) {
 | 
			
		||||
		found = gbproxy_remove_stale_link_infos(peer, now);
 | 
			
		||||
		if (found)
 | 
			
		||||
			vty_out(vty, "Deleted %d stale logical link%s%s",
 | 
			
		||||
				found, found == 1 ? "" : "s", VTY_NEWLINE);
 | 
			
		||||
	} else {
 | 
			
		||||
		llist_for_each_entry_safe(link_info, nxt,
 | 
			
		||||
					  &state->logical_links, list) {
 | 
			
		||||
			if (!link_info->is_deregistered)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			gbproxy_delete_link_info(peer, link_info);
 | 
			
		||||
			found += 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (found)
 | 
			
		||||
		vty_out(vty, "Deleted %d %s logical link%s%s",
 | 
			
		||||
			found, argv[1], found == 1 ? "" : "s", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * legacy commands to provide an upgrade path from "broken" releases
 | 
			
		||||
 * or pre-releases
 | 
			
		||||
 */
 | 
			
		||||
DEFUN_DEPRECATED(cfg_gbproxy_broken_apn_match,
 | 
			
		||||
      cfg_gbproxy_broken_apn_match_cmd,
 | 
			
		||||
      "core-access-point-name none match-imsi .REGEXP",
 | 
			
		||||
      GBPROXY_CORE_APN_STR GBPROXY_MATCH_IMSI_STR "Remove APN\n"
 | 
			
		||||
      "Patch MS related information elements on match only\n"
 | 
			
		||||
      "Route to the secondary SGSN on match only\n"
 | 
			
		||||
      "Regular expression for the IMSI match\n")
 | 
			
		||||
{
 | 
			
		||||
	const char *filter = argv[0];
 | 
			
		||||
	const char *err_msg = NULL;
 | 
			
		||||
	struct gbproxy_match *match;
 | 
			
		||||
	enum gbproxy_match_id match_id = get_string_value(match_ids, "patching");
 | 
			
		||||
 | 
			
		||||
	/* apply APN none */
 | 
			
		||||
	set_core_apn(vty, "");
 | 
			
		||||
 | 
			
		||||
	/* do the matching... with copy and paste */
 | 
			
		||||
	OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
 | 
			
		||||
		    match_id < GBPROX_MATCH_LAST);
 | 
			
		||||
	match = &g_cfg->matches[match_id];
 | 
			
		||||
 | 
			
		||||
	if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
 | 
			
		||||
		vty_out(vty, "Match expression invalid: %s%s",
 | 
			
		||||
			err_msg, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_cfg->acquire_imsi = true;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
 | 
			
		||||
#define GBPROXY_MAX_LEN_STR "Limit list length\n"
 | 
			
		||||
DEFUN_DEPRECATED(cfg_gbproxy_depr_tlli_list_max_len,
 | 
			
		||||
      cfg_gbproxy_depr_tlli_list_max_len_cmd,
 | 
			
		||||
      "tlli-list max-length <1-99999>",
 | 
			
		||||
      GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR
 | 
			
		||||
      "Maximum number of TLLIs in the list\n")
 | 
			
		||||
{
 | 
			
		||||
	g_cfg->tlli_max_len = atoi(argv[0]);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_vty_init(void)
 | 
			
		||||
{
 | 
			
		||||
	install_element_ve(&show_gbproxy_cmd);
 | 
			
		||||
	install_element_ve(&show_gbproxy_links_cmd);
 | 
			
		||||
 | 
			
		||||
	install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
 | 
			
		||||
	install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
 | 
			
		||||
	install_element(ENABLE_NODE, &delete_gb_link_by_id_cmd);
 | 
			
		||||
	install_element(ENABLE_NODE, &delete_gb_link_cmd);
 | 
			
		||||
 | 
			
		||||
	install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
 | 
			
		||||
	install_node(&gbproxy_node, config_write_gbproxy);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_match_imsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_secondary_sgsn_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_clean_stale_timer_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_age_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_len_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_keep_mode_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_stored_msgs_max_len_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_match_imsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_secondary_sgsn_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_clean_stale_timer_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_age_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_len_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_link_no_stored_msgs_max_len_cmd);
 | 
			
		||||
 | 
			
		||||
	/* broken or deprecated to allow an upgrade path */
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_broken_apn_match_cmd);
 | 
			
		||||
	install_element(GBPROXY_NODE, &cfg_gbproxy_depr_tlli_list_max_len_cmd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	g_cfg = cfg;
 | 
			
		||||
	rc = vty_read_config_file(config_file, NULL);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -29,7 +29,6 @@ endif
 | 
			
		||||
noinst_LTLIBRARIES = libcommon.la
 | 
			
		||||
 | 
			
		||||
libcommon_la_SOURCES = \
 | 
			
		||||
	gprs_gb_parse.c \
 | 
			
		||||
	gprs_llc_parse.c \
 | 
			
		||||
	crc24.c \
 | 
			
		||||
	gprs_utils.c \
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ static const uint32_t tbl_crc24[256] = {
 | 
			
		||||
 | 
			
		||||
#define INIT_CRC24	0xffffff
 | 
			
		||||
 | 
			
		||||
uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len)
 | 
			
		||||
uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	while (len--)
 | 
			
		||||
		fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
#include <osmocom/sgsn/mmctx.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gmm.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc.h>
 | 
			
		||||
#include <osmocom/sgsn/crc24.h>
 | 
			
		||||
@@ -55,7 +55,7 @@ static const struct value_string llc_cmd_strs[] = {
 | 
			
		||||
#define N202		4
 | 
			
		||||
#define CRC24_LENGTH	3
 | 
			
		||||
 | 
			
		||||
int gprs_llc_fcs(uint8_t *data, unsigned int len)
 | 
			
		||||
int gprs_llc_fcs(const uint8_t *data, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t fcs_calc;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -30,56 +30,6 @@
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t *last_len_field;
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	/* Can we even write the length field to the output? */
 | 
			
		||||
	if (max_len == 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	/* Remember where we need to put the length once we know it */
 | 
			
		||||
	last_len_field = apn_enc;
 | 
			
		||||
	len = 1;
 | 
			
		||||
	apn_enc += 1;
 | 
			
		||||
 | 
			
		||||
	while (str[0]) {
 | 
			
		||||
		if (len >= max_len)
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		if (str[0] == '.') {
 | 
			
		||||
			*last_len_field = (apn_enc - last_len_field) - 1;
 | 
			
		||||
			last_len_field = apn_enc;
 | 
			
		||||
		} else {
 | 
			
		||||
			*apn_enc = str[0];
 | 
			
		||||
		}
 | 
			
		||||
		apn_enc += 1;
 | 
			
		||||
		str += 1;
 | 
			
		||||
		len += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*last_len_field = (apn_enc - last_len_field) - 1;
 | 
			
		||||
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* GSM 04.08, 10.5.7.3 GPRS Timer */
 | 
			
		||||
int gprs_tmr_to_secs(uint8_t tmr)
 | 
			
		||||
{
 | 
			
		||||
	switch (tmr & GPRS_TMR_UNIT_MASK) {
 | 
			
		||||
	case GPRS_TMR_2SECONDS:
 | 
			
		||||
		return 2 * (tmr & GPRS_TMR_FACT_MASK);
 | 
			
		||||
	default:
 | 
			
		||||
	case GPRS_TMR_MINUTE:
 | 
			
		||||
		return 60 * (tmr & GPRS_TMR_FACT_MASK);
 | 
			
		||||
	case GPRS_TMR_6MINUTE:
 | 
			
		||||
		return 360 * (tmr & GPRS_TMR_FACT_MASK);
 | 
			
		||||
	case GPRS_TMR_DEACTIVATED:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This functions returns a tmr value such that
 | 
			
		||||
 *   - f is monotonic
 | 
			
		||||
 *   - f(s) <= s
 | 
			
		||||
@@ -132,19 +82,6 @@ int gprs_is_mi_imsi(const uint8_t *value, size_t value_len)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t tmsi_be;
 | 
			
		||||
 | 
			
		||||
	if (!gprs_is_mi_tmsi(value, value_len))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	memcpy(&tmsi_be, value + 1, sizeof(tmsi_be));
 | 
			
		||||
 | 
			
		||||
	*tmsi = ntohl(tmsi_be);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t tmsi_be;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,6 @@
 | 
			
		||||
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
 | 
			
		||||
extern void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
struct cares_event_fd {
 | 
			
		||||
	struct llist_head head;
 | 
			
		||||
	struct osmo_fd fd;
 | 
			
		||||
@@ -51,8 +49,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 +118,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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
#include <gtp.h>
 | 
			
		||||
#include <gtpie.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gtphub.h>
 | 
			
		||||
#include <osmocom/gtphub/gtphub.h>
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_utils.h>
 | 
			
		||||
 | 
			
		||||
@@ -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) {
 | 
			
		||||
@@ -484,7 +475,7 @@ static int get_ie_imsi_str(union gtpie_member *ie[], int i,
 | 
			
		||||
 * present but cannot be decoded. */
 | 
			
		||||
static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str)
 | 
			
		||||
{
 | 
			
		||||
	static char apn_buf[GSM_APN_LENGTH];
 | 
			
		||||
	static char apn_buf[APN_MAXLEN+1];
 | 
			
		||||
	unsigned int len;
 | 
			
		||||
	if (gtpie_gettlv(ie, GTPIE_APN, 0,
 | 
			
		||||
			 &len, apn_buf, sizeof(apn_buf)) != 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 ? "..." : "");
 | 
			
		||||
 | 
			
		||||
@@ -983,7 +971,7 @@ static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei)
 | 
			
		||||
 | 
			
		||||
static void gtphub_mapping_del_cb(struct expiring_item *expi);
 | 
			
		||||
 | 
			
		||||
static struct nr_mapping *gtphub_mapping_new()
 | 
			
		||||
static struct nr_mapping *gtphub_mapping_new(void)
 | 
			
		||||
{
 | 
			
		||||
	struct nr_mapping *nrm;
 | 
			
		||||
	nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping);
 | 
			
		||||
@@ -1007,7 +995,7 @@ static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun,
 | 
			
		||||
	char *pos = buf;
 | 
			
		||||
	int left = sizeof(buf);
 | 
			
		||||
	int l;
 | 
			
		||||
	                 
 | 
			
		||||
 | 
			
		||||
	struct gtphub_tunnel_endpoint *c, *u;
 | 
			
		||||
	c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL];
 | 
			
		||||
	u = &tun->endpoint[side_idx][GTPH_PLANE_USER];
 | 
			
		||||
@@ -1116,7 +1104,7 @@ static void gtphub_tunnel_del_cb(struct expiring_item *expi)
 | 
			
		||||
/* rate counter index for hubs: [7; 10] */
 | 
			
		||||
#define CTR_IDX_HUB(s, p) CTR_IDX(s, p, 3, 2)
 | 
			
		||||
 | 
			
		||||
static struct gtphub_tunnel *gtphub_tunnel_new()
 | 
			
		||||
static struct gtphub_tunnel *gtphub_tunnel_new(void)
 | 
			
		||||
{
 | 
			
		||||
	struct gtphub_tunnel *tun;
 | 
			
		||||
	tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel);
 | 
			
		||||
@@ -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,18 +2103,18 @@ 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];
 | 
			
		||||
 | 
			
		||||
	rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_IN],
 | 
			
		||||
	rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_IN),
 | 
			
		||||
		     received);
 | 
			
		||||
 | 
			
		||||
	struct gtp_packet_desc p;
 | 
			
		||||
@@ -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,26 +2132,26 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_IN]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_IN));
 | 
			
		||||
 | 
			
		||||
	int reply_len;
 | 
			
		||||
	reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
 | 
			
		||||
	if (reply_len > 0) {
 | 
			
		||||
		/* It was an echo. Nothing left to do. */
 | 
			
		||||
		osmo_sockaddr_copy(to_addr, from_addr);
 | 
			
		||||
		sgsn_sockaddr_copy(to_addr, from_addr);
 | 
			
		||||
		*to_ofd = &from_bind->ofd;
 | 
			
		||||
 | 
			
		||||
		rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
 | 
			
		||||
		rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_OUT));
 | 
			
		||||
		rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_OUT),
 | 
			
		||||
			     reply_len);
 | 
			
		||||
		LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
 | 
			
		||||
		    (side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
 | 
			
		||||
		    gtphub_side_idx_names[side_idx],
 | 
			
		||||
		    (int)reply_len, osmo_sockaddr_to_str(to_addr));
 | 
			
		||||
		    (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,13 +2221,13 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rate_ctr_add(&from_peer->counters_io->ctr[GTPH_CTR_BYTES_IN],
 | 
			
		||||
	rate_ctr_add(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_BYTES_IN),
 | 
			
		||||
		     received);
 | 
			
		||||
	rate_ctr_inc(&from_peer->counters_io->ctr[GTPH_CTR_PKTS_IN]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_PKTS_IN));
 | 
			
		||||
 | 
			
		||||
	LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx],
 | 
			
		||||
	    gtphub_port_str(from_peer));
 | 
			
		||||
@@ -2260,9 +2246,9 @@ int gtphub_handle_buf(struct gtphub *hub,
 | 
			
		||||
 | 
			
		||||
	if (p.tun) {
 | 
			
		||||
		struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[p.side_idx][p.plane_idx];
 | 
			
		||||
		rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_IN],
 | 
			
		||||
		rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_IN),
 | 
			
		||||
			     received);
 | 
			
		||||
		rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_IN]);
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_IN));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((!to_peer) && (side_idx == GTPH_SIDE_SGSN)) {
 | 
			
		||||
@@ -2297,7 +2283,7 @@ int gtphub_handle_buf(struct gtphub *hub,
 | 
			
		||||
		    != 0)
 | 
			
		||||
			return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	/* Either to_peer was resolved from an existing tunnel,
 | 
			
		||||
	 * or a PDP Ctx and thus a tunnel has just been created,
 | 
			
		||||
	 * or the tunnel has been deleted due to this message. */
 | 
			
		||||
@@ -2309,24 +2295,24 @@ 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;
 | 
			
		||||
 | 
			
		||||
	if (received) {
 | 
			
		||||
		rate_ctr_inc(&to_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
 | 
			
		||||
		rate_ctr_add(&to_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_PKTS_OUT));
 | 
			
		||||
		rate_ctr_add(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_BYTES_OUT),
 | 
			
		||||
			     received);
 | 
			
		||||
 | 
			
		||||
		rate_ctr_inc(&to_peer->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
 | 
			
		||||
		rate_ctr_add(&to_peer->counters_io->ctr[GTPH_CTR_BYTES_OUT],
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_PKTS_OUT));
 | 
			
		||||
		rate_ctr_add(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_BYTES_OUT),
 | 
			
		||||
			     received);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p.tun) {
 | 
			
		||||
		struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[other_side_idx(p.side_idx)][p.plane_idx];
 | 
			
		||||
		rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
 | 
			
		||||
		rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_OUT],
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_OUT));
 | 
			
		||||
		rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_OUT),
 | 
			
		||||
			     received);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -2704,7 +2690,7 @@ static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub,
 | 
			
		||||
	struct gtphub_peer *peer = gtphub_peer_new(hub, bind);
 | 
			
		||||
 | 
			
		||||
	a = gtphub_peer_add_addr(peer, addr);
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	LOG(LOGL_DEBUG, "New peer address: %s %s\n",
 | 
			
		||||
	    bind->label,
 | 
			
		||||
	    gsn_addr_to_str(&a->addr));
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,12 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gtphub.h>
 | 
			
		||||
#include <osmocom/gtphub/gtphub.h>
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
 | 
			
		||||
 | 
			
		||||
/* TODO split GRX ares from sgsn into a separate struct and allow use without
 | 
			
		||||
 * globals. */
 | 
			
		||||
@@ -56,8 +57,8 @@ struct ggsn_lookup {
 | 
			
		||||
	struct gtphub *hub;
 | 
			
		||||
 | 
			
		||||
	char imsi_str[GSM23003_IMSI_MAX_DIGITS+1];
 | 
			
		||||
	char apn_ni_str[GSM_APN_LENGTH];
 | 
			
		||||
	char apn_oi_str[GSM_APN_LENGTH];
 | 
			
		||||
	char apn_ni_str[APN_MAXLEN+1];
 | 
			
		||||
	char apn_oi_str[APN_MAXLEN+1];
 | 
			
		||||
	int have_3dig_mnc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/logging.h>
 | 
			
		||||
#include <osmocom/vty/telnet_interface.h>
 | 
			
		||||
@@ -41,10 +42,10 @@
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/gtphub.h>
 | 
			
		||||
#include <osmocom/gtphub/gtphub.h>
 | 
			
		||||
#include <osmocom/sgsn/vty.h>
 | 
			
		||||
 | 
			
		||||
#include "../../bscconfig.h"
 | 
			
		||||
#include "../../config.h"
 | 
			
		||||
 | 
			
		||||
#if BUILD_IU
 | 
			
		||||
#include <osmocom/sigtran/osmo_ss7.h>
 | 
			
		||||
@@ -95,11 +96,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 +108,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 +127,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 {
 | 
			
		||||
@@ -377,8 +354,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* start telnet after reading config for vty_get_bind_addr() */
 | 
			
		||||
	rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
 | 
			
		||||
			       OSMO_VTY_PORT_GTPHUB);
 | 
			
		||||
	rc = telnet_init_default(osmo_gtphub_ctx, NULL, OSMO_VTY_PORT_GTPHUB);
 | 
			
		||||
	if (rc < 0)
 | 
			
		||||
		exit(1);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,12 @@
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gtphub.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gtphub/gtphub.h>
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
 | 
			
		||||
/* Convenience makro, note: only within this C file. */
 | 
			
		||||
@@ -33,13 +38,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));
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/vty.h>
 | 
			
		||||
#include <osmocom/sgsn/gtphub.h>
 | 
			
		||||
#include <osmocom/gtphub/gtphub.h>
 | 
			
		||||
 | 
			
		||||
/* TODO split GRX ares from sgsn into a separate struct and allow use without
 | 
			
		||||
 * globals. */
 | 
			
		||||
 
 | 
			
		||||
@@ -40,12 +40,13 @@ bin_PROGRAMS = \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmo_sgsn_SOURCES = \
 | 
			
		||||
	gprs_gb.c \
 | 
			
		||||
	apn.c \
 | 
			
		||||
	gprs_bssgp.c \
 | 
			
		||||
	gprs_gmm_attach.c \
 | 
			
		||||
	gprs_gmm.c \
 | 
			
		||||
	gprs_gmm_fsm.c \
 | 
			
		||||
	gprs_mm_state_gb_fsm.c \
 | 
			
		||||
	gprs_sgsn.c \
 | 
			
		||||
	gprs_ns.c \
 | 
			
		||||
	gprs_sm.c \
 | 
			
		||||
	gprs_sndcp.c \
 | 
			
		||||
	gprs_sndcp_comp.c \
 | 
			
		||||
@@ -53,15 +54,21 @@ osmo_sgsn_SOURCES = \
 | 
			
		||||
	gprs_sndcp_pcomp.c \
 | 
			
		||||
	gprs_sndcp_vty.c \
 | 
			
		||||
	gprs_sndcp_xid.c \
 | 
			
		||||
	gtp_ggsn.c \
 | 
			
		||||
	gtp_mme.c \
 | 
			
		||||
	sgsn.c \
 | 
			
		||||
	sgsn_main.c \
 | 
			
		||||
	sgsn_vty.c \
 | 
			
		||||
	sgsn_libgtp.c \
 | 
			
		||||
	gprs_llc.c \
 | 
			
		||||
	gprs_llc_vty.c \
 | 
			
		||||
	mmctx.c \
 | 
			
		||||
	pdpctx.c \
 | 
			
		||||
	sgsn_ctrl.c \
 | 
			
		||||
	sgsn_auth.c \
 | 
			
		||||
	gprs_subscriber.c \
 | 
			
		||||
	sgsn_cdr.c \
 | 
			
		||||
	sgsn_rim.c \
 | 
			
		||||
	slhc.c \
 | 
			
		||||
	gprs_llc_xid.c \
 | 
			
		||||
	v42bis.c \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										123
									
								
								src/sgsn/apn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/sgsn/apn.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
/* APN contexts */
 | 
			
		||||
 | 
			
		||||
/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010 by On-Waves
 | 
			
		||||
 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <string.h>
 | 
			
		||||
#include <talloc.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/apn.h>
 | 
			
		||||
#include <osmocom/sgsn/sgsn.h>
 | 
			
		||||
 | 
			
		||||
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ctx *actx;
 | 
			
		||||
 | 
			
		||||
	actx = talloc_zero(sgsn, struct apn_ctx);
 | 
			
		||||
	if (!actx)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	actx->name = talloc_strdup(actx, ap_name);
 | 
			
		||||
	actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
 | 
			
		||||
 | 
			
		||||
	llist_add_tail(&actx->list, &sgsn->apn_list);
 | 
			
		||||
 | 
			
		||||
	return actx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sgsn_apn_ctx_free(struct apn_ctx *actx)
 | 
			
		||||
{
 | 
			
		||||
	llist_del(&actx->list);
 | 
			
		||||
	talloc_free(actx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ctx *actx;
 | 
			
		||||
	struct apn_ctx *found_actx = NULL;
 | 
			
		||||
	size_t imsi_prio = 0;
 | 
			
		||||
	size_t name_prio = 0;
 | 
			
		||||
	size_t name_req_len = strlen(name);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(actx, &sgsn->apn_list, list) {
 | 
			
		||||
		size_t name_ref_len, imsi_ref_len;
 | 
			
		||||
		const char *name_ref_start, *name_match_start;
 | 
			
		||||
 | 
			
		||||
		imsi_ref_len = strlen(actx->imsi_prefix);
 | 
			
		||||
		if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (imsi_ref_len < imsi_prio)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* IMSI matches */
 | 
			
		||||
 | 
			
		||||
		name_ref_start = &actx->name[0];
 | 
			
		||||
		if (name_ref_start[0] == '*') {
 | 
			
		||||
			/* Suffix match */
 | 
			
		||||
			name_ref_start += 1;
 | 
			
		||||
			name_ref_len = strlen(name_ref_start);
 | 
			
		||||
			if (name_ref_len > name_req_len)
 | 
			
		||||
				continue;
 | 
			
		||||
		} else {
 | 
			
		||||
			name_ref_len = strlen(name_ref_start);
 | 
			
		||||
			if (name_ref_len != name_req_len)
 | 
			
		||||
				continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name_match_start = name + (name_req_len - name_ref_len);
 | 
			
		||||
		if (strcasecmp(name_match_start, name_ref_start) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* IMSI and name match */
 | 
			
		||||
 | 
			
		||||
		if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
 | 
			
		||||
			/* Lower priority, skip */
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		imsi_prio = imsi_ref_len;
 | 
			
		||||
		name_prio = name_ref_len;
 | 
			
		||||
		found_actx = actx;
 | 
			
		||||
	}
 | 
			
		||||
	return found_actx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ctx *actx;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(actx, &sgsn->apn_list, list) {
 | 
			
		||||
		if (strcasecmp(name, actx->name) == 0 &&
 | 
			
		||||
		    strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
 | 
			
		||||
			return actx;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ctx *actx;
 | 
			
		||||
 | 
			
		||||
	actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
 | 
			
		||||
	if (!actx)
 | 
			
		||||
		actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
 | 
			
		||||
 | 
			
		||||
	return actx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								src/sgsn/gprs_bssgp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/sgsn/gprs_bssgp.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
 | 
			
		||||
 | 
			
		||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010 by On-Waves
 | 
			
		||||
 * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 *
 | 
			
		||||
 * 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/core/prim.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_ns2.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gmm.h>
 | 
			
		||||
#include <osmocom/sgsn/sgsn_rim.h>
 | 
			
		||||
#include <osmocom/sgsn/mmctx.h>
 | 
			
		||||
 | 
			
		||||
/* call-back function for the BSSGP protocol */
 | 
			
		||||
int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_bssgp_prim *bp;
 | 
			
		||||
	bp = container_of(oph, struct osmo_bssgp_prim, oph);
 | 
			
		||||
 | 
			
		||||
	switch (oph->sap) {
 | 
			
		||||
	case SAP_BSSGP_LL:
 | 
			
		||||
		switch (oph->primitive) {
 | 
			
		||||
		case PRIM_BSSGP_UL_UD:
 | 
			
		||||
			return gprs_llc_rcvmsg(oph->msg, bp->tp);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case SAP_BSSGP_GMM:
 | 
			
		||||
		switch (oph->primitive) {
 | 
			
		||||
		case PRIM_BSSGP_GMM_SUSPEND:
 | 
			
		||||
			return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
 | 
			
		||||
		case PRIM_BSSGP_GMM_RESUME:
 | 
			
		||||
			return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
 | 
			
		||||
						  bp->u.resume.suspend_ref);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case SAP_BSSGP_NM:
 | 
			
		||||
		break;
 | 
			
		||||
	case SAP_BSSGP_RIM:
 | 
			
		||||
		return sgsn_rim_rx_from_gb(bp, oph->msg);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx)
 | 
			
		||||
{
 | 
			
		||||
	struct bssgp_paging_info pinfo;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: page whole routing area, not only the last known cell */
 | 
			
		||||
 | 
			
		||||
	/* initiate PS PAGING procedure */
 | 
			
		||||
	memset(&pinfo, 0, sizeof(pinfo));
 | 
			
		||||
	pinfo.mode = BSSGP_PAGING_PS;
 | 
			
		||||
	pinfo.scope = BSSGP_PAGING_BVCI;
 | 
			
		||||
	pinfo.bvci = mmctx->gb.bvci;
 | 
			
		||||
	pinfo.imsi = mmctx->imsi;
 | 
			
		||||
	pinfo.ptmsi = &mmctx->p_tmsi;
 | 
			
		||||
	pinfo.drx_params = mmctx->drx_parms;
 | 
			
		||||
	pinfo.qos[0] = 0; // FIXME
 | 
			
		||||
	rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS));
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the bssgp layer to send NS PDUs */
 | 
			
		||||
int sgsn_bssgp_dispatch_ns_unitdata_req_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);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,105 +0,0 @@
 | 
			
		||||
/* Messages on the Gb interface (A/Gb mode) */
 | 
			
		||||
 | 
			
		||||
/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2010 by On-Waves
 | 
			
		||||
 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 *
 | 
			
		||||
 * 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/core/rate_ctr.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_msgb.h>
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
 | 
			
		||||
#include "bscconfig.h"
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gmm.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sm.h>
 | 
			
		||||
#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) {
 | 
			
		||||
	if (mmctx->gb.llme)
 | 
			
		||||
		osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Main entry point for incoming 04.08 GPRS messages from Gb */
 | 
			
		||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
 | 
			
		||||
			   bool drop_cipherable)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
 | 
			
		||||
	uint8_t pdisc = gsm48_hdr_pdisc(gh);
 | 
			
		||||
	struct sgsn_mm_ctx *mmctx;
 | 
			
		||||
	struct gprs_ra_id ra_id;
 | 
			
		||||
	int rc = -EINVAL;
 | 
			
		||||
 | 
			
		||||
	bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
 | 
			
		||||
	mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
 | 
			
		||||
	if (mmctx) {
 | 
			
		||||
		msgid2mmctx(mmctx, msg);
 | 
			
		||||
		rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
 | 
			
		||||
		mmctx->gb.llme = llme;
 | 
			
		||||
		gprs_gb_recv_pdu(mmctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MMCTX can be NULL */
 | 
			
		||||
 | 
			
		||||
	switch (pdisc) {
 | 
			
		||||
	case GSM48_PDISC_MM_GPRS:
 | 
			
		||||
		rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM48_PDISC_SM_GPRS:
 | 
			
		||||
		rc = gsm0408_rcv_gsm(mmctx, msg, llme);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGMMCTXP(LOGL_NOTICE, mmctx,
 | 
			
		||||
			"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
 | 
			
		||||
			pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
 | 
			
		||||
		/* FIXME: return status message */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MMCTX can be invalid */
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
 | 
			
		||||
{
 | 
			
		||||
	struct bssgp_paging_info pinfo;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: page whole routing area, not only the last known cell */
 | 
			
		||||
 | 
			
		||||
	/* initiate PS PAGING procedure */
 | 
			
		||||
	memset(&pinfo, 0, sizeof(pinfo));
 | 
			
		||||
	pinfo.mode = BSSGP_PAGING_PS;
 | 
			
		||||
	pinfo.scope = BSSGP_PAGING_BVCI;
 | 
			
		||||
	pinfo.bvci = mmctx->gb.bvci;
 | 
			
		||||
	pinfo.imsi = mmctx->imsi;
 | 
			
		||||
	pinfo.ptmsi = &mmctx->p_tmsi;
 | 
			
		||||
	pinfo.drx_params = mmctx->drx_parms;
 | 
			
		||||
	pinfo.qos[0] = 0; // FIXME
 | 
			
		||||
	rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
 | 
			
		||||
	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PAGING_PS]);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#include "bscconfig.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
@@ -41,13 +41,14 @@
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/tdef.h>
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
#include <osmocom/crypt/utran_cipher.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gprs/gprs_bssgp.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/sgsn/debug.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_llc.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sgsn.h>
 | 
			
		||||
#include <osmocom/sgsn/mmctx.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_gmm.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_utils.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_subscriber.h>
 | 
			
		||||
@@ -59,17 +60,17 @@
 | 
			
		||||
#include <osmocom/sgsn/signal.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sndcp.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_ranap.h>
 | 
			
		||||
#include <osmocom/sgsn/gprs_sm.h>
 | 
			
		||||
#include <osmocom/sgsn/gtp.h>
 | 
			
		||||
#include <osmocom/sgsn/pdpctx.h>
 | 
			
		||||
 | 
			
		||||
#include <pdp.h>
 | 
			
		||||
 | 
			
		||||
#define PTMSI_ALLOC
 | 
			
		||||
 | 
			
		||||
extern struct sgsn_instance *sgsn;
 | 
			
		||||
extern void *tall_sgsn_ctx;
 | 
			
		||||
 | 
			
		||||
static const struct tlv_definition gsm48_gmm_att_tlvdef = {
 | 
			
		||||
	.def = {
 | 
			
		||||
		[GSM48_IE_GMM_CIPH_CKSN]	= { TLV_TYPE_FIXED, 1 },
 | 
			
		||||
		[GSM48_IE_GMM_CIPH_CKSN]	= { TLV_TYPE_SINGLE_TV, 1 },
 | 
			
		||||
		[GSM48_IE_GMM_TIMER_READY]	= { TLV_TYPE_TV, 1 },
 | 
			
		||||
		[GSM48_IE_GMM_ALLOC_PTMSI]	= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_PTMSI_SIG]	= { TLV_TYPE_FIXED, 3 },
 | 
			
		||||
@@ -78,6 +79,7 @@ static const struct tlv_definition gsm48_gmm_att_tlvdef = {
 | 
			
		||||
		[GSM48_IE_GMM_AUTH_RES_EXT]	= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_AUTH_FAIL_PAR]	= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_IMEISV]		= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_RX_NPDU_NUM_LIST] = { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_DRX_PARAM]	= { TLV_TYPE_FIXED, 2 },
 | 
			
		||||
		[GSM48_IE_GMM_MS_NET_CAPA]	= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
		[GSM48_IE_GMM_PDP_CTX_STATUS]	= { TLV_TYPE_TLV, 0 },
 | 
			
		||||
@@ -131,7 +133,7 @@ int gsm48_gmm_sendmsg(struct msgb *msg, int command,
 | 
			
		||||
			     struct sgsn_mm_ctx *mm, bool encryptable)
 | 
			
		||||
{
 | 
			
		||||
	if (mm) {
 | 
			
		||||
		rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_SIG_OUT));
 | 
			
		||||
#ifdef BUILD_IU
 | 
			
		||||
		if (mm->ran_type == MM_CTX_T_UTRAN_Iu)
 | 
			
		||||
			return ranap_iu_tx(msg, GPRS_SAPI_GMM);
 | 
			
		||||
@@ -197,10 +199,10 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
 | 
			
		||||
 | 
			
		||||
	switch(ctx->ran_type) {
 | 
			
		||||
	case MM_CTX_T_UTRAN_Iu:
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
 | 
			
		||||
		break;
 | 
			
		||||
	case MM_CTX_T_GERAN_Gb:
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -215,7 +217,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause,
 | 
			
		||||
 | 
			
		||||
	/* MMCTX might be NULL! */
 | 
			
		||||
 | 
			
		||||
	DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
 | 
			
		||||
	DEBUGP(DMM, "<- GMM STATUS (cause: %s)\n",
 | 
			
		||||
		get_value_string(gsm48_gmm_cause_names, cause));
 | 
			
		||||
 | 
			
		||||
	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 | 
			
		||||
@@ -241,7 +243,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
 | 
			
		||||
 | 
			
		||||
	/* MMCTX might be NULL! */
 | 
			
		||||
 | 
			
		||||
	DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n",
 | 
			
		||||
	DEBUGP(DMM, "<- GMM DETACH REQ (type: %s, cause: %s)\n",
 | 
			
		||||
		get_value_string(gprs_det_t_mt_strs, detach_type),
 | 
			
		||||
		get_value_string(gsm48_gmm_cause_names, cause));
 | 
			
		||||
 | 
			
		||||
@@ -280,14 +282,18 @@ 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
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]);
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GMM ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_ACKED));
 | 
			
		||||
 | 
			
		||||
	mmctx2msgid(msg, mm);
 | 
			
		||||
 | 
			
		||||
@@ -300,7 +306,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 +327,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -338,9 +356,9 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n",
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM ATTACH REJECT: %s\n",
 | 
			
		||||
		  get_value_string(gsm48_gmm_cause_names, gmm_cause));
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REJECTED));
 | 
			
		||||
 | 
			
		||||
	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 | 
			
		||||
	gh->proto_discr = GSM48_PDISC_MM_GPRS;
 | 
			
		||||
@@ -372,8 +390,8 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
 | 
			
		||||
 | 
			
		||||
	/* MMCTX might be NULL! */
 | 
			
		||||
 | 
			
		||||
	DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby);
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]);
 | 
			
		||||
	DEBUGP(DMM, "<- GMM DETACH ACC (force-standby: %d)\n", force_stby);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_ACKED));
 | 
			
		||||
 | 
			
		||||
	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 | 
			
		||||
	gh->proto_discr = GSM48_PDISC_MM_GPRS;
 | 
			
		||||
@@ -405,7 +423,7 @@ int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
 | 
			
		||||
	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n",
 | 
			
		||||
	LOGMMCTXP(LOGL_DEBUG, mm, "<- GMM IDENTITY REQUEST: mi_type=%s\n",
 | 
			
		||||
		  gsm48_mi_type_name(id_type));
 | 
			
		||||
 | 
			
		||||
	mmctx2msgid(msg, mm);
 | 
			
		||||
@@ -429,6 +447,17 @@ static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) {
 | 
			
		||||
	uint8_t common_mask = net_mask & ms_mask;
 | 
			
		||||
	uint8_t r = 0;
 | 
			
		||||
 | 
			
		||||
	while (common_mask >>= 1) {
 | 
			
		||||
		r++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */
 | 
			
		||||
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
 | 
			
		||||
				      const struct osmo_auth_vector *vec,
 | 
			
		||||
@@ -440,7 +469,7 @@ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
 | 
			
		||||
	uint8_t *m_rand, *m_cksn, rbyte;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s,"
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GMM AUTH AND CIPHERING REQ (rand = %s,"
 | 
			
		||||
		  " mmctx_is_r99=%d, vec->auth_types=0x%x",
 | 
			
		||||
		  osmo_hexdump(vec->rand, sizeof(vec->rand)),
 | 
			
		||||
		  mmctx_is_r99(mm), vec->auth_types);
 | 
			
		||||
@@ -503,7 +532,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
 | 
			
		||||
	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n");
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM AUTH AND CIPH REJECT\n");
 | 
			
		||||
 | 
			
		||||
	mmctx2msgid(msg, mm);
 | 
			
		||||
 | 
			
		||||
@@ -583,7 +612,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
 | 
			
		||||
	uint8_t res_len;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n");
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH RESPONSE\n");
 | 
			
		||||
 | 
			
		||||
	if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
 | 
			
		||||
		LOGMMCTXP(LOGL_NOTICE, ctx,
 | 
			
		||||
@@ -634,7 +663,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
 | 
			
		||||
	ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len);
 | 
			
		||||
	if (!sgsn_mm_ctx_is_authenticated(ctx)) {
 | 
			
		||||
		rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT");
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GMM AUTH AND CIPH REJECT");
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -657,7 +686,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
 | 
			
		||||
	const uint8_t *auts;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n",
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n",
 | 
			
		||||
		  get_value_string(gsm48_gmm_cause_names, gmm_cause));
 | 
			
		||||
 | 
			
		||||
	tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0);
 | 
			
		||||
@@ -697,7 +726,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
 | 
			
		||||
	rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
 | 
			
		||||
	mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE");
 | 
			
		||||
	mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE");
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -776,7 +805,7 @@ static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
 | 
			
		||||
	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GMM SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
 | 
			
		||||
 | 
			
		||||
	mmctx2msgid(msg, mm);
 | 
			
		||||
 | 
			
		||||
@@ -797,7 +826,7 @@ static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
 | 
			
		||||
	LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM SERVICE REJECT: %s\n",
 | 
			
		||||
		  get_value_string(gsm48_gmm_cause_names, gmm_cause));
 | 
			
		||||
 | 
			
		||||
	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 | 
			
		||||
@@ -889,7 +918,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
 | 
			
		||||
	/* The MS is authorized */
 | 
			
		||||
#ifdef BUILD_IU
 | 
			
		||||
	if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
 | 
			
		||||
		rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
 | 
			
		||||
		/* Is any encryption above UEA0 enabled? */
 | 
			
		||||
		bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
 | 
			
		||||
		LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
 | 
			
		||||
			  send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
 | 
			
		||||
		/* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
 | 
			
		||||
		 * is not possible in the iu_client API. See OS#5487. */
 | 
			
		||||
		rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
 | 
			
		||||
		ctx->iu.new_key = 0;
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
@@ -911,16 +946,16 @@ 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);
 | 
			
		||||
#ifdef BUILD_IU
 | 
			
		||||
	case GSM48_MT_GMM_SERVICE_REQ:
 | 
			
		||||
		ctx->pending_req = 0;
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
 | 
			
		||||
		osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
 | 
			
		||||
		rc = gsm48_tx_gmm_service_ack(ctx);
 | 
			
		||||
 | 
			
		||||
		if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
 | 
			
		||||
@@ -1026,31 +1061,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 +1097,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 */
 | 
			
		||||
@@ -1067,19 +1106,20 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
 | 
			
		||||
				       "p_tmsi_old=0x%08x\n",
 | 
			
		||||
					ictx->p_tmsi);
 | 
			
		||||
 | 
			
		||||
				mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
 | 
			
		||||
				mm_ctx_cleanup_free(ictx, "GMM 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,23 +1139,65 @@ 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));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t mask = (1 << GPRS_ALGO_GEA0);
 | 
			
		||||
	mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0;
 | 
			
		||||
 | 
			
		||||
	if (cap_len < 2)
 | 
			
		||||
		return mask;
 | 
			
		||||
 | 
			
		||||
	/* extended GEA bits start from 2nd bit of the next byte */
 | 
			
		||||
	mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0;
 | 
			
		||||
	mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0;
 | 
			
		||||
	mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0;
 | 
			
		||||
	return mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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 ");
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST));
 | 
			
		||||
 | 
			
		||||
	/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
 | 
			
		||||
	 * with a foreign TLLI (P-TMSI that was allocated to the MS before),
 | 
			
		||||
@@ -1155,15 +1237,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 +1262,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 +1276,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 +1294,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;
 | 
			
		||||
@@ -1241,15 +1324,27 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
 | 
			
		||||
		ctx->ms_radio_access_capa.len);
 | 
			
		||||
	ctx->ms_network_capa.len = msnc_len;
 | 
			
		||||
	memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
 | 
			
		||||
	if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
 | 
			
		||||
					   ctx->ciph_algo)) {
 | 
			
		||||
 | 
			
		||||
	ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);
 | 
			
		||||
 | 
			
		||||
	if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) {
 | 
			
		||||
		reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
 | 
			
		||||
		LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
 | 
			
		||||
			  "type %s because MS do not support required %s "
 | 
			
		||||
			  "encryption\n", gsm48_mi_type_name(mi_type),
 | 
			
		||||
			  get_value_string(gprs_cipher_names,ctx->ciph_algo));
 | 
			
		||||
			  "%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n",
 | 
			
		||||
				  mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
 | 
			
		||||
		goto rejected;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* just assume that everythig is fine if the phone offers a5/4:
 | 
			
		||||
	 * it requires a valid umts security context which we can only have after
 | 
			
		||||
	 * 1) IDENTITY REQUEST to know what to ask the HLR for
 | 
			
		||||
	 * 2) and AUTHENTICATION AND CIPHERING REQUEST
 | 
			
		||||
	 * ... but 2) already requires selecting a cipher mode.
 | 
			
		||||
	 * So let's just assume we will have the auth data required to make it work.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
 | 
			
		||||
 | 
			
		||||
#ifdef PTMSI_ALLOC
 | 
			
		||||
	/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
 | 
			
		||||
	ptmsi_update(ctx);
 | 
			
		||||
@@ -1281,7 +1376,7 @@ rejected:
 | 
			
		||||
		  get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
 | 
			
		||||
	rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause);
 | 
			
		||||
	if (ctx)
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ");
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GMM ATTACH REJ");
 | 
			
		||||
	else if (llme)
 | 
			
		||||
		gprs_llgmm_unassign(llme);
 | 
			
		||||
 | 
			
		||||
@@ -1294,7 +1389,7 @@ static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx)
 | 
			
		||||
{
 | 
			
		||||
	struct sgsn_signal_data sig_data;
 | 
			
		||||
	/* only in case SGSN offered new P-TMSI */
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n");
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n");
 | 
			
		||||
 | 
			
		||||
	#ifdef BUILD_IU
 | 
			
		||||
	if (mmctx->iu.ue_ctx) {
 | 
			
		||||
@@ -1361,7 +1456,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
 | 
			
		||||
	power_off = gh->data[0] & 0x8;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_REQUEST));
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
 | 
			
		||||
		msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
 | 
			
		||||
		power_off ? "Power-off" : "");
 | 
			
		||||
@@ -1381,7 +1476,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
 | 
			
		||||
		memset(&sig_data, 0, sizeof(sig_data));
 | 
			
		||||
		sig_data.mm = ctx;
 | 
			
		||||
		osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST");
 | 
			
		||||
		mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
@@ -1393,11 +1488,15 @@ 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");
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_ACKED));
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mm, "<- GMM ROUTING AREA UPDATE ACCEPT\n");
 | 
			
		||||
 | 
			
		||||
	mmctx2msgid(msg, mm);
 | 
			
		||||
 | 
			
		||||
@@ -1424,9 +1523,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 */
 | 
			
		||||
@@ -1444,7 +1551,7 @@ int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT));
 | 
			
		||||
 | 
			
		||||
	gmm_copy_id(msg, old_msg);
 | 
			
		||||
 | 
			
		||||
@@ -1470,21 +1577,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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1526,7 +1631,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
 | 
			
		||||
	/* Update Type 10.5.5.18 */
 | 
			
		||||
	upd_type = *cur++ & 0x07;
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REQUEST));
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
 | 
			
		||||
		get_value_string(gprs_upd_t_strs, upd_type));
 | 
			
		||||
 | 
			
		||||
@@ -1576,19 +1681,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 +1704,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,21 +1751,30 @@ 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]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, 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);
 | 
			
		||||
	}
 | 
			
		||||
	/* Update the MM context with the new DRX params */
 | 
			
		||||
	if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM))
 | 
			
		||||
		memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms));
 | 
			
		||||
 | 
			
		||||
	/* FIXME: Update the MM context with the MS radio acc capabilities */
 | 
			
		||||
	/* FIXME: Update the MM context with the MS network capabilities */
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE));
 | 
			
		||||
 | 
			
		||||
#ifdef PTMSI_ALLOC
 | 
			
		||||
	ptmsi_update(mmctx);
 | 
			
		||||
@@ -1660,7 +1784,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;
 | 
			
		||||
@@ -1696,7 +1820,7 @@ rejected:
 | 
			
		||||
		  get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
 | 
			
		||||
	rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
 | 
			
		||||
	if (mmctx)
 | 
			
		||||
		mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
 | 
			
		||||
		mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
 | 
			
		||||
	else if (llme)
 | 
			
		||||
		gprs_llgmm_unassign(llme);
 | 
			
		||||
#ifdef BUILD_IU
 | 
			
		||||
@@ -1762,11 +1886,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 +1910,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 +1925,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 +1938,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 +1950,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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1881,7 +2002,7 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_hdr *gh = msgb_l3(msg);
 | 
			
		||||
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n",
 | 
			
		||||
	LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM STATUS (cause: %s)\n",
 | 
			
		||||
		get_value_string(gsm48_gmm_cause_names, gh->data[0]));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -1944,6 +2065,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
 | 
			
		||||
@@ -1983,7 +2121,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
 | 
			
		||||
		if (!mmctx)
 | 
			
		||||
			goto null_mmctx;
 | 
			
		||||
		LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
 | 
			
		||||
		mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK");
 | 
			
		||||
		mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK");
 | 
			
		||||
		rc = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM48_MT_GMM_ATTACH_COMPL:
 | 
			
		||||
@@ -2023,9 +2161,9 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
 | 
			
		||||
 | 
			
		||||
null_mmctx:
 | 
			
		||||
	LOGGBIUP(llme, msg, LOGL_ERROR,
 | 
			
		||||
	     "Received GSM 04.08 message type 0x%02x,"
 | 
			
		||||
	     "Received GSM 04.08 message type %s,"
 | 
			
		||||
	     " but no MM context available\n",
 | 
			
		||||
	     gh->msg_type);
 | 
			
		||||
	     get_value_string(gprs_msgt_gmm_names, gh->msg_type));
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2092,7 +2230,7 @@ static void mmctx_timer_cb(void *_mm)
 | 
			
		||||
		if (mm->num_T_exp >= 5) {
 | 
			
		||||
			LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
 | 
			
		||||
			gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
 | 
			
		||||
			mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)");
 | 
			
		||||
			mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		/* re-tranmit IDENTITY REQUEST and re-start timer */
 | 
			
		||||
@@ -2180,3 +2318,51 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
 | 
			
		||||
	osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RESUME, NULL);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Main entry point for incoming 04.08 GPRS messages from Gb */
 | 
			
		||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
 | 
			
		||||
			   bool drop_cipherable)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
 | 
			
		||||
	uint8_t pdisc = gsm48_hdr_pdisc(gh);
 | 
			
		||||
	struct sgsn_mm_ctx *mmctx;
 | 
			
		||||
	struct gprs_ra_id ra_id;
 | 
			
		||||
	int rc = -EINVAL;
 | 
			
		||||
 | 
			
		||||
	bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
 | 
			
		||||
	mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
 | 
			
		||||
	if (mmctx) {
 | 
			
		||||
		rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
 | 
			
		||||
		mmctx->gb.llme = llme;
 | 
			
		||||
		gprs_gb_recv_pdu(mmctx, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MMCTX can be NULL */
 | 
			
		||||
 | 
			
		||||
	switch (pdisc) {
 | 
			
		||||
	case GSM48_PDISC_MM_GPRS:
 | 
			
		||||
		rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM48_PDISC_SM_GPRS:
 | 
			
		||||
		rc = gsm0408_rcv_gsm(mmctx, msg, llme);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGMMCTXP(LOGL_NOTICE, mmctx,
 | 
			
		||||
			"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
 | 
			
		||||
			pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
 | 
			
		||||
		/* FIXME: return status message */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MMCTX can be invalid */
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user