mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
				synced 2025-11-04 06:03:23 +00:00 
			
		
		
		
	Compare commits
	
		
			279 Commits
		
	
	
		
			pespin/spl
			...
			1.8.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a3ca2d185b | ||
| 
						 | 
					8cbdd21867 | ||
| 
						 | 
					ae81195418 | ||
| 
						 | 
					6ee5fa939a | ||
| 
						 | 
					b6a0e3fd2e | ||
| 
						 | 
					bd2b55679e | ||
| 
						 | 
					f32c6a9095 | ||
| 
						 | 
					2eed6ec5ec | ||
| 
						 | 
					641206ad5e | ||
| 
						 | 
					bfd3119ae4 | ||
| 
						 | 
					4b9b19e998 | ||
| 
						 | 
					00e0559e17 | ||
| 
						 | 
					0b1d9dbc40 | ||
| 
						 | 
					5379273ea3 | ||
| 
						 | 
					ecef920b8f | ||
| 
						 | 
					eb9267b15e | ||
| 
						 | 
					1efb2bcd90 | ||
| 
						 | 
					878593f205 | ||
| 
						 | 
					1596463985 | ||
| 
						 | 
					9d82492e49 | ||
| 
						 | 
					303aeea8a8 | ||
| 
						 | 
					18898b4a9f | ||
| 
						 | 
					17cee2056c | ||
| 
						 | 
					67a3c833af | ||
| 
						 | 
					b1f641b5b7 | ||
| 
						 | 
					f01ce65f5b | ||
| 
						 | 
					be1cf99e9a | ||
| 
						 | 
					7710080ffd | ||
| 
						 | 
					798a81d48d | ||
| 
						 | 
					51930f7b63 | ||
| 
						 | 
					00ef1b0d6e | ||
| 
						 | 
					02a82c3c9b | ||
| 
						 | 
					349cbfcf50 | ||
| 
						 | 
					51f99ae250 | ||
| 
						 | 
					12304c0e5a | ||
| 
						 | 
					1719abb409 | ||
| 
						 | 
					3ddf4c6933 | ||
| 
						 | 
					fb2a7298e0 | ||
| 
						 | 
					568ac5ee8e | ||
| 
						 | 
					23c832bb4b | ||
| 
						 | 
					4831851ca3 | ||
| 
						 | 
					080dcfaabe | ||
| 
						 | 
					cbc07bdd82 | ||
| 
						 | 
					aedae4c971 | ||
| 
						 | 
					b36eb9d12f | ||
| 
						 | 
					8df01fad14 | ||
| 
						 | 
					c8020b959d | ||
| 
						 | 
					2154607fb0 | ||
| 
						 | 
					d08a15b343 | ||
| 
						 | 
					4e37fb356a | ||
| 
						 | 
					6a8a389c47 | ||
| 
						 | 
					569e46cbf9 | ||
| 
						 | 
					91d9410157 | ||
| 
						 | 
					065ddb6416 | ||
| 
						 | 
					53244a2132 | ||
| 
						 | 
					db98f309a9 | ||
| 
						 | 
					04715d284f | ||
| 
						 | 
					962146085c | ||
| 
						 | 
					e2b0961f18 | ||
| 
						 | 
					ff2ebee03b | ||
| 
						 | 
					2a1cedd2dc | ||
| 
						 | 
					c43e887e9e | ||
| 
						 | 
					e5d71639e5 | ||
| 
						 | 
					a1b3deefda | ||
| 
						 | 
					964f08a919 | ||
| 
						 | 
					ee1529e5ac | ||
| 
						 | 
					29e7bd0510 | ||
| 
						 | 
					cdcaeda81c | ||
| 
						 | 
					98f8126b98 | ||
| 
						 | 
					a1503b902c | ||
| 
						 | 
					8398bccb0b | ||
| 
						 | 
					5552872733 | ||
| 
						 | 
					61b010c25a | ||
| 
						 | 
					20d9d154c5 | ||
| 
						 | 
					1c8ae66654 | ||
| 
						 | 
					fcdaf31aa8 | ||
| 
						 | 
					9366f4c034 | ||
| 
						 | 
					28c6a32677 | ||
| 
						 | 
					107c813eee | ||
| 
						 | 
					90d1732be1 | ||
| 
						 | 
					1c3505b885 | ||
| 
						 | 
					20539f0271 | ||
| 
						 | 
					ad6eaa2881 | ||
| 
						 | 
					b629240a35 | ||
| 
						 | 
					b283c32027 | ||
| 
						 | 
					e71e0f2af8 | ||
| 
						 | 
					bd8f028bff | ||
| 
						 | 
					a55454d58e | ||
| 
						 | 
					f1be1df0d3 | ||
| 
						 | 
					c22205bec8 | ||
| 
						 | 
					fdf3358959 | ||
| 
						 | 
					1bf41e4f36 | ||
| 
						 | 
					c94837c6a4 | ||
| 
						 | 
					68c5a74557 | ||
| 
						 | 
					bdf2cf9038 | ||
| 
						 | 
					00a6171b8d | ||
| 
						 | 
					26e300fda0 | ||
| 
						 | 
					4e605b32d4 | ||
| 
						 | 
					494d873fe3 | ||
| 
						 | 
					b4c98e7397 | ||
| 
						 | 
					3eb05d2c1a | ||
| 
						 | 
					f5fbb419ef | ||
| 
						 | 
					5d8b226597 | ||
| 
						 | 
					c602d7cf00 | ||
| 
						 | 
					a019631c0b | ||
| 
						 | 
					88ce94c2bd | ||
| 
						 | 
					310ea1db10 | ||
| 
						 | 
					012d51ed7d | ||
| 
						 | 
					1ef2621d3f | ||
| 
						 | 
					f612ffea82 | ||
| 
						 | 
					421f22e8cf | ||
| 
						 | 
					03cce86941 | ||
| 
						 | 
					95cd897c3f | ||
| 
						 | 
					f7884e880e | ||
| 
						 | 
					60ee0dbfa4 | ||
| 
						 | 
					d950134c53 | ||
| 
						 | 
					623c5b36e9 | ||
| 
						 | 
					aab47afe58 | ||
| 
						 | 
					67aebc9d1c | ||
| 
						 | 
					ea1cb3fa33 | ||
| 
						 | 
					0036a60c44 | ||
| 
						 | 
					e47932976c | ||
| 
						 | 
					f1e01517bc | ||
| 
						 | 
					ad252e70aa | ||
| 
						 | 
					08ca425bc2 | ||
| 
						 | 
					1eeb113c34 | ||
| 
						 | 
					d0ba664fec | ||
| 
						 | 
					ec1d8c4004 | ||
| 
						 | 
					36e12d4db8 | ||
| 
						 | 
					2404c5b0b7 | ||
| 
						 | 
					32b76ee1af | ||
| 
						 | 
					7bdc80de00 | ||
| 
						 | 
					83f5266f43 | ||
| 
						 | 
					e725d87d13 | ||
| 
						 | 
					8b90bce962 | ||
| 
						 | 
					f0829ff34b | ||
| 
						 | 
					e589c6544c | ||
| 
						 | 
					d1a2ddfee6 | ||
| 
						 | 
					7b52f00192 | ||
| 
						 | 
					25ab381c0f | ||
| 
						 | 
					9fbcb10568 | ||
| 
						 | 
					eefa30dce8 | ||
| 
						 | 
					5560001af5 | ||
| 
						 | 
					a469a90d5e | ||
| 
						 | 
					84515f4b8b | ||
| 
						 | 
					1cde2c1691 | ||
| 
						 | 
					93dd798a99 | ||
| 
						 | 
					8651573632 | ||
| 
						 | 
					0d0b0592f0 | ||
| 
						 | 
					aad77a0acf | ||
| 
						 | 
					9ee8d3264b | ||
| 
						 | 
					de72d26f49 | ||
| 
						 | 
					ceac078d77 | ||
| 
						 | 
					cd87c5f963 | ||
| 
						 | 
					154f93da51 | ||
| 
						 | 
					742a6b55ce | ||
| 
						 | 
					72ab4bc547 | ||
| 
						 | 
					fb62504160 | ||
| 
						 | 
					d7030d268c | ||
| 
						 | 
					2e8e57a3de | ||
| 
						 | 
					ca276e01eb | ||
| 
						 | 
					977b339abe | ||
| 
						 | 
					9272d212c3 | ||
| 
						 | 
					f653c5bc33 | ||
| 
						 | 
					549417e675 | ||
| 
						 | 
					42c9fa4958 | ||
| 
						 | 
					df404c4296 | ||
| 
						 | 
					ffa227307c | ||
| 
						 | 
					3fc9cc97de | ||
| 
						 | 
					f5a268a96d | ||
| 
						 | 
					6da888c5d0 | ||
| 
						 | 
					33c537e5a7 | ||
| 
						 | 
					aa69034c00 | ||
| 
						 | 
					bf47f71785 | ||
| 
						 | 
					2b7a860ffb | ||
| 
						 | 
					932eeec240 | ||
| 
						 | 
					6f7aabf6a3 | ||
| 
						 | 
					a491e42129 | ||
| 
						 | 
					1ce111f72b | ||
| 
						 | 
					e010dea56e | ||
| 
						 | 
					f4530447f6 | ||
| 
						 | 
					e7361067ac | ||
| 
						 | 
					606837597f | ||
| 
						 | 
					5f8b332e6b | ||
| 
						 | 
					43001cbc7a | ||
| 
						 | 
					65d61c347b | ||
| 
						 | 
					c8ca02b937 | ||
| 
						 | 
					3ce5a3648a | ||
| 
						 | 
					a4cb02699e | ||
| 
						 | 
					f0fb2c2ddd | ||
| 
						 | 
					8a1e7b8658 | ||
| 
						 | 
					b7782d4d41 | ||
| 
						 | 
					b0b9c28284 | ||
| 
						 | 
					3730c550cd | ||
| 
						 | 
					cc8181fefe | ||
| 
						 | 
					7327360d10 | ||
| 
						 | 
					e405c2f196 | ||
| 
						 | 
					411ff3b984 | ||
| 
						 | 
					aee905b790 | ||
| 
						 | 
					fb75adfeda | ||
| 
						 | 
					7b9230acfe | ||
| 
						 | 
					5662cb2152 | ||
| 
						 | 
					e1412d9493 | ||
| 
						 | 
					d1e2342f91 | ||
| 
						 | 
					381b723543 | ||
| 
						 | 
					ee44b82b96 | ||
| 
						 | 
					b5f93346df | ||
| 
						 | 
					8e8c7ef3c7 | ||
| 
						 | 
					57238889eb | ||
| 
						 | 
					d70ab97fa4 | ||
| 
						 | 
					d1bd6fce9c | ||
| 
						 | 
					a32e4c4fb8 | ||
| 
						 | 
					3b84e92ab3 | ||
| 
						 | 
					3e0baa6146 | ||
| 
						 | 
					b673d1c438 | ||
| 
						 | 
					6a2856bab5 | ||
| 
						 | 
					0d95ca59f9 | ||
| 
						 | 
					906c2099da | ||
| 
						 | 
					ac07625086 | ||
| 
						 | 
					36c4fac9c9 | ||
| 
						 | 
					a06b2d3877 | ||
| 
						 | 
					546884d9a1 | ||
| 
						 | 
					f2286395e9 | ||
| 
						 | 
					9eebe15cd1 | ||
| 
						 | 
					31e1dab2c0 | ||
| 
						 | 
					db0366c9e4 | ||
| 
						 | 
					47adad0817 | ||
| 
						 | 
					c5efb5bccb | ||
| 
						 | 
					9a6da455b9 | ||
| 
						 | 
					b4c0828039 | ||
| 
						 | 
					df3dcac439 | ||
| 
						 | 
					0757504a86 | ||
| 
						 | 
					042a445cf3 | ||
| 
						 | 
					a16c7501a4 | ||
| 
						 | 
					9f98822255 | ||
| 
						 | 
					fc8357a2db | ||
| 
						 | 
					3e443ca502 | ||
| 
						 | 
					2c10211d60 | ||
| 
						 | 
					5fdda13f89 | ||
| 
						 | 
					dbeaa044f8 | ||
| 
						 | 
					7ad4d5e8cb | ||
| 
						 | 
					ab4db10750 | ||
| 
						 | 
					dddbbaaee1 | ||
| 
						 | 
					134855c45e | ||
| 
						 | 
					a4942e6566 | ||
| 
						 | 
					4e43ef5ab0 | ||
| 
						 | 
					4ae8d8232d | ||
| 
						 | 
					0bdd8bf5bc | ||
| 
						 | 
					5b1ef9589c | ||
| 
						 | 
					7d54ed48e7 | ||
| 
						 | 
					07730bb9cc | ||
| 
						 | 
					7b38af5cd3 | ||
| 
						 | 
					85ef5833cb | ||
| 
						 | 
					a2a08f7602 | ||
| 
						 | 
					282d4e3dda | ||
| 
						 | 
					42d3250d17 | ||
| 
						 | 
					5aed8de11d | ||
| 
						 | 
					5f5fcff5f3 | ||
| 
						 | 
					a884a95a7b | ||
| 
						 | 
					a4aada0b5f | ||
| 
						 | 
					732131d4d0 | ||
| 
						 | 
					36b940d1fe | ||
| 
						 | 
					e661277b48 | ||
| 
						 | 
					6f539aa259 | ||
| 
						 | 
					1c8c62667f | ||
| 
						 | 
					e5a082d64a | ||
| 
						 | 
					37c45e3998 | ||
| 
						 | 
					f5e40b7011 | ||
| 
						 | 
					02e21af657 | ||
| 
						 | 
					bffc3f9012 | ||
| 
						 | 
					7c4de0776b | ||
| 
						 | 
					077b903e11 | ||
| 
						 | 
					2d6a69e69a | ||
| 
						 | 
					4f0343233b | ||
| 
						 | 
					bcab7fb4af | ||
| 
						 | 
					427699e6eb | ||
| 
						 | 
					9c0f4f49e9 | ||
| 
						 | 
					ac51c7e68e | ||
| 
						 | 
					55d639f0fb | 
							
								
								
									
										17
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -16,7 +16,6 @@ install-sh
 | 
				
			|||||||
libtool
 | 
					libtool
 | 
				
			||||||
ltmain.sh
 | 
					ltmain.sh
 | 
				
			||||||
missing
 | 
					missing
 | 
				
			||||||
osmo-ggsn.spec
 | 
					 | 
				
			||||||
stamp-h1
 | 
					stamp-h1
 | 
				
			||||||
INSTALL
 | 
					INSTALL
 | 
				
			||||||
m4/
 | 
					m4/
 | 
				
			||||||
@@ -28,7 +27,7 @@ osmo-ggsn-*.tar*
 | 
				
			|||||||
# debian
 | 
					# debian
 | 
				
			||||||
debian/osmo-ggsn/
 | 
					debian/osmo-ggsn/
 | 
				
			||||||
debian/*.debhelper
 | 
					debian/*.debhelper
 | 
				
			||||||
debian/libgtp1
 | 
					debian/libgtp*/
 | 
				
			||||||
debian/osmo-ggsn-dbg
 | 
					debian/osmo-ggsn-dbg
 | 
				
			||||||
debian/*.log
 | 
					debian/*.log
 | 
				
			||||||
debian/autoreconf.*
 | 
					debian/autoreconf.*
 | 
				
			||||||
@@ -69,3 +68,17 @@ tests/*/*_test
 | 
				
			|||||||
tests/testsuite
 | 
					tests/testsuite
 | 
				
			||||||
tests/testsuite.log
 | 
					tests/testsuite.log
 | 
				
			||||||
tests/package.m4
 | 
					tests/package.m4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# manuals
 | 
				
			||||||
 | 
					doc/manuals/*.html
 | 
				
			||||||
 | 
					doc/manuals/*.svg
 | 
				
			||||||
 | 
					doc/manuals/*.pdf
 | 
				
			||||||
 | 
					doc/manuals/*__*.png
 | 
				
			||||||
 | 
					doc/manuals/*.check
 | 
				
			||||||
 | 
					doc/manuals/generated/
 | 
				
			||||||
 | 
					doc/manuals/osmomsc-usermanual.xml
 | 
				
			||||||
 | 
					doc/manuals/common
 | 
				
			||||||
 | 
					doc/manuals/build
 | 
				
			||||||
 | 
					doc/manuals/vty/ggsn_vty_reference.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contrib/osmo-ggsn.spec
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
## Process this file with automake to produce Makefile.in
 | 
					## Process this file with automake to produce Makefile.in
 | 
				
			||||||
SUBDIRS = lib gtp ggsn sgsnemu doc tests
 | 
					SUBDIRS = lib gtp ggsn sgsnemu doc contrib utils tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pkgconfigdir = $(libdir)/pkgconfig
 | 
					pkgconfigdir = $(libdir)/pkgconfig
 | 
				
			||||||
pkgconfig_DATA = libgtp.pc
 | 
					pkgconfig_DATA = libgtp.pc
 | 
				
			||||||
@@ -10,6 +10,17 @@ $(top_srcdir)/.version:
 | 
				
			|||||||
dist-hook:
 | 
					dist-hook:
 | 
				
			||||||
	echo $(VERSION) > $(distdir)/.tarball-version
 | 
						echo $(VERSION) > $(distdir)/.tarball-version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = git-version-gen .version README.md README.FreeBSD README.MacOSX
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 | 
						     .version \
 | 
				
			||||||
 | 
						     README.FreeBSD \
 | 
				
			||||||
 | 
						     README.MacOSX \
 | 
				
			||||||
 | 
						     README.md \
 | 
				
			||||||
 | 
						     contrib/osmo-ggsn.spec.in \
 | 
				
			||||||
 | 
						     debian \
 | 
				
			||||||
 | 
						     git-version-gen \
 | 
				
			||||||
 | 
						     $(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AM_DISTCHECK_CONFIGURE_FLAGS = \
 | 
				
			||||||
 | 
						--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RELMAKE@
 | 
					@RELMAKE@
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -263,8 +263,7 @@ following:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
1. Install sgsnemu on a Linux Box. See under installation above.
 | 
					1. Install sgsnemu on a Linux Box. See under installation above.
 | 
				
			||||||
2. Connect your Linux box with sgsnemu installed to the GPRS core
 | 
					2. Connect your Linux box with sgsnemu installed to the GPRS core
 | 
				
			||||||
network. Use the same LAN switch as the one your SGSN is connected
 | 
					network. You also need a free IP address that can be used by sgsnemu.
 | 
				
			||||||
to. You also need a free IP address that can be used by sgsnemu.
 | 
					 | 
				
			||||||
3. You need to configure networking in terms of interface address,
 | 
					3. You need to configure networking in terms of interface address,
 | 
				
			||||||
subnet mask and default route. See the Linux Networking HOWTO for
 | 
					subnet mask and default route. See the Linux Networking HOWTO for
 | 
				
			||||||
details.
 | 
					details.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										133
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								configure.ac
									
									
									
									
									
								
							@@ -1,14 +1,15 @@
 | 
				
			|||||||
# Process this file with autoconf to produce a configure script.
 | 
					# Process this file with autoconf to produce a configure script.
 | 
				
			||||||
AC_INIT(osmo-ggsn, m4_esyscmd([./git-version-gen .tarball-version]), osmocom-net-gprs@lists.osmocom.org)
 | 
					AC_INIT([osmo-ggsn],[m4_esyscmd(./git-version-gen .tarball-version)],[osmocom-net-gprs@lists.osmocom.org])
 | 
				
			||||||
AC_CONFIG_SRCDIR([gtp/gtp.c])
 | 
					AC_CONFIG_SRCDIR([gtp/gtp.c])
 | 
				
			||||||
AM_CONFIG_HEADER([config.h])
 | 
					AC_CONFIG_HEADERS([config.h])
 | 
				
			||||||
#AC_CONFIG_HEADER([config.h])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
 | 
					dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
 | 
				
			||||||
AC_CONFIG_AUX_DIR([.])
 | 
					AC_CONFIG_AUX_DIR([.])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_CONFIG_TESTDIR(tests)
 | 
					AC_CONFIG_TESTDIR(tests)
 | 
				
			||||||
AC_CANONICAL_SYSTEM
 | 
					AC_CANONICAL_HOST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS="$CFLAGS -std=gnu11"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl kernel style compile messages
 | 
					dnl kernel style compile messages
 | 
				
			||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
					m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
				
			||||||
@@ -18,9 +19,13 @@ AC_PROG_CC
 | 
				
			|||||||
AC_PROG_INSTALL
 | 
					AC_PROG_INSTALL
 | 
				
			||||||
AC_PROG_AWK
 | 
					AC_PROG_AWK
 | 
				
			||||||
AC_PROG_CPP
 | 
					AC_PROG_CPP
 | 
				
			||||||
AC_PROG_CXX
 | 
					 | 
				
			||||||
LT_INIT
 | 
					LT_INIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
 | 
				
			||||||
 | 
					AS_CASE(["$LD"],[*clang*],
 | 
				
			||||||
 | 
					  [AS_CASE(["${host_os}"],
 | 
				
			||||||
 | 
					     [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
 | 
					dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
 | 
				
			||||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
 | 
					AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
 | 
				
			||||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
 | 
					if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
 | 
				
			||||||
@@ -39,9 +44,9 @@ AC_SUBST(EXEC_LDFLAGS)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
case "${host}" in
 | 
					case "${host}" in
 | 
				
			||||||
  i*86-*-linux-gnu*) 
 | 
					  i*86-*-linux-gnu*)
 | 
				
			||||||
    EXEC_LDADD="" ;;
 | 
					    EXEC_LDADD="" ;;
 | 
				
			||||||
  *solaris*) 
 | 
					  *solaris*)
 | 
				
			||||||
    EXEC_LDADD="-lresolv -lsocket -lnsl" ;;
 | 
					    EXEC_LDADD="-lresolv -lsocket -lnsl" ;;
 | 
				
			||||||
esac
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,7 +71,7 @@ AC_ARG_ENABLE([gtp-linux],
 | 
				
			|||||||
	[enable_gtp_linux="$enableval"], [enable_gtp_linux="no"])
 | 
						[enable_gtp_linux="$enableval"], [enable_gtp_linux="no"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AS_IF([test "x$enable_gtp_linux" = "xyes"], [
 | 
					AS_IF([test "x$enable_gtp_linux" = "xyes"], [
 | 
				
			||||||
	PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0])
 | 
						PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.2.0])
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_linux" = "yes"])
 | 
					AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_linux" = "yes"])
 | 
				
			||||||
@@ -76,8 +81,12 @@ AC_HEADER_STDC
 | 
				
			|||||||
AC_HEADER_SYS_WAIT
 | 
					AC_HEADER_SYS_WAIT
 | 
				
			||||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
 | 
					AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check for if header
 | 
					# Check for if header. Some versions of linux/if.h fail without sys/socket.h included beforehand:
 | 
				
			||||||
AC_CHECK_HEADERS([linux/if.h net/if.h])
 | 
					# see https://algorithmicallyrandom.blogspot.com/2012/07/error-on-including-include.html
 | 
				
			||||||
 | 
					AC_CHECK_HEADERS([linux/if.h net/if.h], [], [], [#ifdef HAVE_SYS_SOCKET_H
 | 
				
			||||||
 | 
					                                                # include <sys/socket.h>
 | 
				
			||||||
 | 
					                                                # endif
 | 
				
			||||||
 | 
					                                                ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check for tun header
 | 
					# Check for tun header
 | 
				
			||||||
AC_CHECK_HEADERS([linux/if_tun.h net/if_tun.h])
 | 
					AC_CHECK_HEADERS([linux/if_tun.h net/if_tun.h])
 | 
				
			||||||
@@ -124,10 +133,19 @@ AC_EGREP_HEADER(struct iphdr, netinet/ip.h,
 | 
				
			|||||||
 AC_DEFINE([HAVE_IPHDR])],
 | 
					 AC_DEFINE([HAVE_IPHDR])],
 | 
				
			||||||
 AC_MSG_RESULT(no))
 | 
					 AC_MSG_RESULT(no))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Address generation modes (enum) implemented in linux 3.17 (bc91b0f07ada5535427373a4e2050877bcc12218)
 | 
				
			||||||
 | 
					# /proc/sys/net/ipv6/conf/${iface}/addr_gen_mode was added in linux 4.11 (d35a00b8e33dab7385f724e713ae71c8be0a49f4)
 | 
				
			||||||
 | 
					AC_MSG_CHECKING(whether enum in6_addr_gen_mode.IN6_ADDR_GEN_MODE_NONE exists)
 | 
				
			||||||
 | 
					AH_TEMPLATE(HAVE_IN6_ADDR_GEN_MODE_NONE)
 | 
				
			||||||
 | 
					AC_EGREP_HEADER(IN6_ADDR_GEN_MODE_NONE, linux/if_link.h,
 | 
				
			||||||
 | 
					[AC_MSG_RESULT(yes)
 | 
				
			||||||
 | 
					 AC_DEFINE([HAVE_IN6_ADDR_GEN_MODE_NONE])],
 | 
				
			||||||
 | 
					 AC_MSG_RESULT(no))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Checks for library functions.
 | 
					# Checks for library functions.
 | 
				
			||||||
AC_PROG_GCC_TRADITIONAL
 | 
					AC_PROG_GCC_TRADITIONAL
 | 
				
			||||||
# AC_FUNC_MALLOC
 | 
					# AC_FUNC_MALLOC
 | 
				
			||||||
# AC_FUNC_MEMCMP 
 | 
					# AC_FUNC_MEMCMP
 | 
				
			||||||
AC_CHECK_FUNCS([gethostbyname inet_ntoa memset select socket strdup strerror strtol])
 | 
					AC_CHECK_FUNCS([gethostbyname inet_ntoa memset select socket strdup strerror strtol])
 | 
				
			||||||
AC_CHECK_FUNCS(inet_aton inet_addr, break)
 | 
					AC_CHECK_FUNCS(inet_aton inet_addr, break)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,9 +154,9 @@ adl_FUNC_GETOPT_LONG
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AM_INIT_AUTOMAKE([foreign])
 | 
					AM_INIT_AUTOMAKE([foreign])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -152,6 +170,85 @@ then
 | 
				
			|||||||
	CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
 | 
						CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AC_ARG_ENABLE(werror,
 | 
				
			||||||
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
 | 
							[--enable-werror],
 | 
				
			||||||
 | 
							[Turn all compiler warnings into errors, with exceptions:
 | 
				
			||||||
 | 
							 a) deprecation (allow upstream to mark deprecation without breaking builds);
 | 
				
			||||||
 | 
							 b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
 | 
				
			||||||
 | 
							]
 | 
				
			||||||
 | 
						)],
 | 
				
			||||||
 | 
						[werror=$enableval], [werror="no"])
 | 
				
			||||||
 | 
					if test x"$werror" = x"yes"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						WERROR_FLAGS="-Werror"
 | 
				
			||||||
 | 
						WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
				
			||||||
 | 
						WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
				
			||||||
 | 
						CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
				
			||||||
 | 
						CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate manuals
 | 
				
			||||||
 | 
					AC_ARG_ENABLE(manuals,
 | 
				
			||||||
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
 | 
							[--enable-manuals],
 | 
				
			||||||
 | 
							[Generate manual PDFs [default=no]],
 | 
				
			||||||
 | 
						)],
 | 
				
			||||||
 | 
						[osmo_ac_build_manuals=$enableval], [osmo_ac_build_manuals="no"])
 | 
				
			||||||
 | 
					AM_CONDITIONAL([BUILD_MANUALS], [test x"$osmo_ac_build_manuals" = x"yes"])
 | 
				
			||||||
 | 
					AC_ARG_VAR(OSMO_GSM_MANUALS_DIR, [path to common osmo-gsm-manuals files, overriding pkg-config and "../osmo-gsm-manuals"
 | 
				
			||||||
 | 
						fallback])
 | 
				
			||||||
 | 
					if test x"$osmo_ac_build_manuals" = x"yes"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						# Find OSMO_GSM_MANUALS_DIR (env, pkg-conf, fallback)
 | 
				
			||||||
 | 
						if test -n "$OSMO_GSM_MANUALS_DIR"; then
 | 
				
			||||||
 | 
							echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from env)"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							OSMO_GSM_MANUALS_DIR="$($PKG_CONFIG osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)"
 | 
				
			||||||
 | 
							if test -n "$OSMO_GSM_MANUALS_DIR"; then
 | 
				
			||||||
 | 
								echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from pkg-conf)"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								OSMO_GSM_MANUALS_DIR="../osmo-gsm-manuals"
 | 
				
			||||||
 | 
								echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (fallback)"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						if ! test -d "$OSMO_GSM_MANUALS_DIR"; then
 | 
				
			||||||
 | 
							AC_MSG_ERROR("OSMO_GSM_MANUALS_DIR does not exist! Install osmo-gsm-manuals or set OSMO_GSM_MANUALS_DIR.")
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Find and run check-depends
 | 
				
			||||||
 | 
						CHECK_DEPENDS="$OSMO_GSM_MANUALS_DIR/check-depends.sh"
 | 
				
			||||||
 | 
						if ! test -x "$CHECK_DEPENDS"; then
 | 
				
			||||||
 | 
							CHECK_DEPENDS="osmo-gsm-manuals-check-depends"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						if ! $CHECK_DEPENDS; then
 | 
				
			||||||
 | 
							AC_MSG_ERROR("missing dependencies for --enable-manuals")
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Put in Makefile with absolute path
 | 
				
			||||||
 | 
						OSMO_GSM_MANUALS_DIR="$(realpath "$OSMO_GSM_MANUALS_DIR")"
 | 
				
			||||||
 | 
						AC_SUBST([OSMO_GSM_MANUALS_DIR])
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# https://www.freedesktop.org/software/systemd/man/daemon.html
 | 
				
			||||||
 | 
					AC_ARG_WITH([systemdsystemunitdir],
 | 
				
			||||||
 | 
					     [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
 | 
				
			||||||
 | 
					     [with_systemdsystemunitdir=auto])
 | 
				
			||||||
 | 
					AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
 | 
				
			||||||
 | 
					     def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     AS_IF([test "x$def_systemdsystemunitdir" = "x"],
 | 
				
			||||||
 | 
					   [AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
 | 
				
			||||||
 | 
					    [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
 | 
				
			||||||
 | 
					    with_systemdsystemunitdir=no],
 | 
				
			||||||
 | 
					   [with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
 | 
				
			||||||
 | 
					AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
 | 
				
			||||||
 | 
					      [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
 | 
				
			||||||
 | 
					AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AC_MSG_RESULT([CFLAGS="$CFLAGS"])
 | 
				
			||||||
 | 
					AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_CONFIG_FILES([Makefile
 | 
					AC_CONFIG_FILES([Makefile
 | 
				
			||||||
                 doc/Makefile
 | 
					                 doc/Makefile
 | 
				
			||||||
                 doc/examples/Makefile
 | 
					                 doc/examples/Makefile
 | 
				
			||||||
@@ -160,12 +257,16 @@ AC_CONFIG_FILES([Makefile
 | 
				
			|||||||
                 lib/Makefile
 | 
					                 lib/Makefile
 | 
				
			||||||
                 intl/Makefile
 | 
					                 intl/Makefile
 | 
				
			||||||
                 po/Makefile
 | 
					                 po/Makefile
 | 
				
			||||||
 | 
					                 utils/Makefile
 | 
				
			||||||
                 sgsnemu/Makefile
 | 
					                 sgsnemu/Makefile
 | 
				
			||||||
 | 
					                 doc/manuals/Makefile
 | 
				
			||||||
 | 
					                 contrib/Makefile
 | 
				
			||||||
 | 
					                 contrib/systemd/Makefile
 | 
				
			||||||
 | 
					                 contrib/osmo-ggsn.spec
 | 
				
			||||||
                 tests/Makefile
 | 
					                 tests/Makefile
 | 
				
			||||||
                 tests/lib/Makefile
 | 
					                 tests/lib/Makefile
 | 
				
			||||||
                 tests/gtp/Makefile
 | 
					                 tests/gtp/Makefile
 | 
				
			||||||
                 libgtp.pc
 | 
					                 libgtp.pc])
 | 
				
			||||||
                 osmo-ggsn.spec])
 | 
					 | 
				
			||||||
AC_OUTPUT
 | 
					AC_OUTPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "
 | 
					echo "
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								contrib/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								contrib/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					SUBDIRS = systemd
 | 
				
			||||||
@@ -1,5 +1,11 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
# jenkins build helper script for openbsc.  This is how we build on jenkins.osmocom.org
 | 
					# jenkins build helper script for openbsc.  This is how we build on jenkins.osmocom.org
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# environment variables:
 | 
				
			||||||
 | 
					# * GTP: configure GTP tunneling Linux kernel (values: "--enable-gtp-linux" or "--disable-gtp-linux")
 | 
				
			||||||
 | 
					# * WITH_MANUALS: build manual PDFs if set to "1"
 | 
				
			||||||
 | 
					# * PUBLISH: upload manuals after building if set to "1" (ignored without WITH_MANUALS = "1")
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
 | 
					if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
 | 
				
			||||||
	echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
 | 
						echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
 | 
				
			||||||
@@ -18,12 +24,22 @@ osmo-clean-workspace.sh
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
mkdir "$deps" || true
 | 
					mkdir "$deps" || true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "x$GTP" == "x--enable-gtp-linux" ]; then
 | 
				
			||||||
 | 
						osmo-build-dep.sh libgtpnl
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
 | 
					osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
					verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
					export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
				
			||||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
					export LD_LIBRARY_PATH="$inst/lib"
 | 
				
			||||||
 | 
					export PATH="$inst/bin:$PATH"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Additional configure options and depends
 | 
				
			||||||
 | 
					CONFIG=""
 | 
				
			||||||
 | 
					if [ "$WITH_MANUALS" = "1" ]; then
 | 
				
			||||||
 | 
						CONFIG="--enable-manuals"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set +x
 | 
					set +x
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
@@ -35,8 +51,13 @@ set -x
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
cd "$base"
 | 
					cd "$base"
 | 
				
			||||||
autoreconf --install --force
 | 
					autoreconf --install --force
 | 
				
			||||||
./configure CFLAGS="-Werror" CPPFLAGS="-Werror" $GTP
 | 
					./configure --enable-sanitize --enable-werror $GTP $CONFIG
 | 
				
			||||||
$MAKE $PARALLEL_MAKE
 | 
					$MAKE $PARALLEL_MAKE
 | 
				
			||||||
$MAKE distcheck
 | 
					DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE $PARALLEL_MAKE distcheck
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
 | 
				
			||||||
 | 
						make -C "$base/doc/manuals" publish
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$MAKE $PARALLEL_MAKE maintainer-clean
 | 
				
			||||||
osmo-clean-workspace.sh
 | 
					osmo-clean-workspace.sh
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										137
									
								
								contrib/osmo-ggsn.spec.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								contrib/osmo-ggsn.spec.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# spec file for package osmo-ggsn
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 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/4114
 | 
				
			||||||
 | 
					%define _lto_cflags %{nil}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Name:           osmo-ggsn
 | 
				
			||||||
 | 
					Version:        @VERSION@
 | 
				
			||||||
 | 
					Release:        0
 | 
				
			||||||
 | 
					Summary:        GPRS Support Node
 | 
				
			||||||
 | 
					License:        GPL-2.0-only AND LGPL-2.1-or-later
 | 
				
			||||||
 | 
					Group:          Productivity/Telephony/Servers
 | 
				
			||||||
 | 
					URL:            https://osmocom.org/projects/openggsn
 | 
				
			||||||
 | 
					Source:         %{name}-%{version}.tar.xz
 | 
				
			||||||
 | 
					BuildRequires:  libtool >= 2
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig >= 0.20
 | 
				
			||||||
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
 | 
					%endif
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libgtpnl) >= 1.2.0
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.5.0
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.5.0
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.5.0
 | 
				
			||||||
 | 
					Obsoletes:      openggsn
 | 
				
			||||||
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%description
 | 
				
			||||||
 | 
					Osmo-GGSN is a C-language implementation of a GGSN (Gateway GPRS
 | 
				
			||||||
 | 
					Support Node), a core network element of ETSI/3GPP cellular networks
 | 
				
			||||||
 | 
					such as GPRS, EDGE, UMTS or HSPA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%package -n libgtp6
 | 
				
			||||||
 | 
					Summary:        Library implementing GTP between SGSN and GGSN
 | 
				
			||||||
 | 
					License:        GPL-2.0-only
 | 
				
			||||||
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%description -n libgtp6
 | 
				
			||||||
 | 
					libgtp implements the GPRS Tunneling Protocol between SGSN and GGSN.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%package -n libgtp-devel
 | 
				
			||||||
 | 
					Summary:        Development files for the GTP library
 | 
				
			||||||
 | 
					License:        GPL-2.0-only
 | 
				
			||||||
 | 
					Group:          Development/Libraries/C and C++
 | 
				
			||||||
 | 
					Requires:       libgtp6 = %{version}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%description -n libgtp-devel
 | 
				
			||||||
 | 
					libgtp implements the GPRS Tunneling Protocol between SGSN and GGSN.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This subpackage contains libraries and header files for developing
 | 
				
			||||||
 | 
					applications that want to make use of libgtp.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%package -n gtp-echo-responder
 | 
				
			||||||
 | 
					Summary:        Small program answering GTP ECHO Request with GTP ECHO Response
 | 
				
			||||||
 | 
					License:        MIT
 | 
				
			||||||
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%description -n gtp-echo-responder
 | 
				
			||||||
 | 
					Small program answering GTP ECHO Request with GTP ECHO Response for both GTPCv1
 | 
				
			||||||
 | 
					and GTPCv2.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%prep
 | 
				
			||||||
 | 
					%setup -q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%build
 | 
				
			||||||
 | 
					echo "%{version}" >.tarball-version
 | 
				
			||||||
 | 
					autoreconf -fi
 | 
				
			||||||
 | 
					%configure \
 | 
				
			||||||
 | 
					  --enable-gtp-linux \
 | 
				
			||||||
 | 
					  --disable-static \
 | 
				
			||||||
 | 
					  --docdir="%{_docdir}/%{name}" \
 | 
				
			||||||
 | 
					  --with-systemdsystemunitdir=%{_unitdir} \
 | 
				
			||||||
 | 
					  --includedir="%{_includedir}/%{name}"
 | 
				
			||||||
 | 
					make %{?_smp_mflags} V=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%install
 | 
				
			||||||
 | 
					%make_install
 | 
				
			||||||
 | 
					find %{buildroot} -type f -name "*.la" -delete -print
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%check
 | 
				
			||||||
 | 
					make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
 | 
					%pre
 | 
				
			||||||
 | 
					%service_add_pre %{name}.service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%post
 | 
				
			||||||
 | 
					%service_add_post %{name}.service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%preun
 | 
				
			||||||
 | 
					%service_del_preun %{name}.service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%postun
 | 
				
			||||||
 | 
					%service_del_postun %{name}.service
 | 
				
			||||||
 | 
					%endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%post   -n libgtp6 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					%postun -n libgtp6 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%files
 | 
				
			||||||
 | 
					%license COPYING
 | 
				
			||||||
 | 
					%doc AUTHORS README.md
 | 
				
			||||||
 | 
					%{_bindir}/osmo-ggsn
 | 
				
			||||||
 | 
					%{_bindir}/sgsnemu
 | 
				
			||||||
 | 
					%{_mandir}/man8/osmo-ggsn.8%{?ext_man}
 | 
				
			||||||
 | 
					%{_mandir}/man8/sgsnemu.8%{?ext_man}
 | 
				
			||||||
 | 
					%{_unitdir}/%{name}.service
 | 
				
			||||||
 | 
					%dir %{_docdir}/%{name}/examples
 | 
				
			||||||
 | 
					%{_docdir}/%{name}/examples/osmo-ggsn-kernel-gtp.cfg
 | 
				
			||||||
 | 
					%{_docdir}/%{name}/examples/osmo-ggsn.cfg
 | 
				
			||||||
 | 
					%{_docdir}/%{name}/examples/sgsnemu.conf
 | 
				
			||||||
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-ggsn.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%files -n libgtp6
 | 
				
			||||||
 | 
					%{_libdir}/libgtp.so.6*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%files -n libgtp-devel
 | 
				
			||||||
 | 
					%{_includedir}/%{name}/
 | 
				
			||||||
 | 
					%{_libdir}/libgtp.so
 | 
				
			||||||
 | 
					%{_libdir}/pkgconfig/libgtp.pc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%files -n gtp-echo-responder
 | 
				
			||||||
 | 
					%{_bindir}/gtp-echo-responder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%changelog
 | 
				
			||||||
							
								
								
									
										10
									
								
								contrib/systemd/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contrib/systemd/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 | 
						osmo-ggsn.service \
 | 
				
			||||||
 | 
						ggsn.network \
 | 
				
			||||||
 | 
						apn0.netdev \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if HAVE_SYSTEMD
 | 
				
			||||||
 | 
					systemdsystemunit_DATA = \
 | 
				
			||||||
 | 
					  osmo-ggsn.service
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										7
									
								
								contrib/systemd/apn0.netdev
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								contrib/systemd/apn0.netdev
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					[NetDev]
 | 
				
			||||||
 | 
					Name=apn0
 | 
				
			||||||
 | 
					Kind=tun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Tun]
 | 
				
			||||||
 | 
					User=username
 | 
				
			||||||
 | 
					Group=username
 | 
				
			||||||
							
								
								
									
										6
									
								
								contrib/systemd/ggsn.network
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								contrib/systemd/ggsn.network
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					[Match]
 | 
				
			||||||
 | 
					Name=apn0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Network]
 | 
				
			||||||
 | 
					Address=192.168.7.1/24
 | 
				
			||||||
 | 
					IPMasquerade=yes
 | 
				
			||||||
@@ -5,7 +5,7 @@ After=networking.service
 | 
				
			|||||||
[Service]
 | 
					[Service]
 | 
				
			||||||
Type=simple
 | 
					Type=simple
 | 
				
			||||||
Restart=always
 | 
					Restart=always
 | 
				
			||||||
ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg -f
 | 
					ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg
 | 
				
			||||||
RestartSec=2
 | 
					RestartSec=2
 | 
				
			||||||
RestartPreventExitStatus=1
 | 
					RestartPreventExitStatus=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										426
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										426
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,429 @@
 | 
				
			|||||||
 | 
					osmo-ggsn (1.8.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * doc/examples/Makefile.am: add sgsnemu.conf
 | 
				
			||||||
 | 
					  * doc/examples/osmo-ggsn-kernel-gtp.cfg: new file
 | 
				
			||||||
 | 
					  * doc/manuals: describe GTP-U kernel module
 | 
				
			||||||
 | 
					  * gitignore: add ggsn_vty_reference.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Don't install osmo-ggsn-kernel-gtp.cfg to /etc/osmocom/
 | 
				
			||||||
 | 
					  * Don't install sgsnemu.conf to /etc/osmocom/
 | 
				
			||||||
 | 
					  * ggsn: Reject PDP CTX ACT for static IP addresses
 | 
				
			||||||
 | 
					  * vty: Inform user that static IP addresses are not supported
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * gtp: Update teic_confirmed only on resp success
 | 
				
			||||||
 | 
					  * gtp: Rework parsing logic of UpdatePdpCtxResponse
 | 
				
			||||||
 | 
					  * ggsn: Improve logging on incoming DL data packets
 | 
				
			||||||
 | 
					  * gtp: Improve logging of failing pdp ctx resolution from TEI/TID
 | 
				
			||||||
 | 
					  * cosmetic: gtpie.c: Fix trailing whitespace
 | 
				
			||||||
 | 
					  * gtp: constify pointer arg
 | 
				
			||||||
 | 
					  * gtp: Support tx/rx RAN Information Relay message
 | 
				
			||||||
 | 
					  * ggsn: Log tun fd write errors
 | 
				
			||||||
 | 
					  * ggsn: Fix heap-use-after-free during Recovery without associated PDP
 | 
				
			||||||
 | 
					  * cosmetic: configure.ac: Fix tabulation in line
 | 
				
			||||||
 | 
					  * Introduce program gtp-echo-responder
 | 
				
			||||||
 | 
					  * gtp_echo_responder: report invalid chars present in node-feautres cmdline arg as error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 16 Nov 2021 13:49:16 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.7.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
 | 
				
			||||||
 | 
					  * manuals: generate vty reference xml at build time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 23 Feb 2021 17:31:24 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.7.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * debian/control: change maintainer to the Osmocom team / mailing list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * configure.ac: Fix trailing whitespace
 | 
				
			||||||
 | 
					  * doc: Update VTY reference xml file
 | 
				
			||||||
 | 
					  * Support setting rt-prio and cpu-affinity mask through VTY
 | 
				
			||||||
 | 
					  * contrib/jenkins: Enable parallel make in make distcheck
 | 
				
			||||||
 | 
					  * ggsn: generate coredump and exit upon SIGABRT received
 | 
				
			||||||
 | 
					  * tests: Explicitly drop category from log
 | 
				
			||||||
 | 
					  * tests: Replace deprecated API log_set_print_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Keith ]
 | 
				
			||||||
 | 
					  * Fix vty PDP lookups by IMSI
 | 
				
			||||||
 | 
					  * Prevent Crash in show pdp-context from vty
 | 
				
			||||||
 | 
					  * Minor: remove code duplication
 | 
				
			||||||
 | 
					  * Use imsi_str2gtp() in sgsnemu
 | 
				
			||||||
 | 
					  * sgsnemu: relax check on length of IMSI cmdline arg.
 | 
				
			||||||
 | 
					  * GTP: Replace recently introduced imsi_str2gtp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Use OSMO_FD_* instead of deprecated BSC_FD_*
 | 
				
			||||||
 | 
					  * gtp-kernel: Remove duplicate #include section
 | 
				
			||||||
 | 
					  * gtp-kernel: don't #include libmnl headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * contrib/jenkins: don't build osmo-gsm-manuals
 | 
				
			||||||
 | 
					  * configure.ac: set -std=gnu11
 | 
				
			||||||
 | 
					  * apn_start: avoid segfault if missing tun-device
 | 
				
			||||||
 | 
					  * .gitignore: ignore debian/libgtp*
 | 
				
			||||||
 | 
					  * deb/rpm: build with --enable-gtp-linux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@espeweb.net>  Tue, 23 Feb 2021 13:34:39 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.6.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * cosmetic: Fix comment typo
 | 
				
			||||||
 | 
					  * netns: Improve error checking
 | 
				
			||||||
 | 
					  * sgsnemu: cmdline: Drop unused function cmdline_parser_params_create()
 | 
				
			||||||
 | 
					  * sgsnemu: Pass array of in64_addr to in46a_from_eua()
 | 
				
			||||||
 | 
					  * sgsnemu: Rename sgsnemu's libgtp cb_conf
 | 
				
			||||||
 | 
					  * sgsnemu: Set its default loglevel category to INFO
 | 
				
			||||||
 | 
					  * Move icmpv6 and checksum files from ggsn/ dir to lib/
 | 
				
			||||||
 | 
					  * netdev_addaddr6: Use prefixlen arg
 | 
				
			||||||
 | 
					  * sgsnemu: Avoid adding extra autogenerated local link ipv6 addr to tun iface
 | 
				
			||||||
 | 
					  * sgsnemu: Fix ping transmitted statistics output
 | 
				
			||||||
 | 
					  * cosmetic: icmpv6.c: fix typo in comment
 | 
				
			||||||
 | 
					  * icmpv6.c: Mark internal function as static
 | 
				
			||||||
 | 
					  * sgsnemu: Get rid of duplicated options.destaddr
 | 
				
			||||||
 | 
					  * sgsnemu: Get rid of duplicated options.net
 | 
				
			||||||
 | 
					  * sgsnemu: tun_addaddr: Don't set local addr as dstaddr
 | 
				
			||||||
 | 
					  * icmpv6.c: Move code generating ipv6 hdr to its own function
 | 
				
			||||||
 | 
					  * Rename netdev_*route to end in route4
 | 
				
			||||||
 | 
					  * sgsnemu: Fix build/run against linux < 4.11 (no sysctl addr_gen_mode support)
 | 
				
			||||||
 | 
					  * sgsnemu: Handle IPv6 SLAAC in tun iface manually
 | 
				
			||||||
 | 
					  * sgsnemu: Implement ping on IPv6 APNs
 | 
				
			||||||
 | 
					  * sgsnemu: Fix assumption ipv6 Interface-Identifier of public addr == announced Prefix
 | 
				
			||||||
 | 
					  * gtp: queue_test: Fix printf gcc warn under ARM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Andreas Schultz ]
 | 
				
			||||||
 | 
					  * add Linux network namespace support for TUN device
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * lib/netns: fix open_ns(): return fd from open()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * doc: do not use random ip address for dns in default conf
 | 
				
			||||||
 | 
					  * doc: use 127.0.0.2 instead of 127.0.0.6 as bind ip.
 | 
				
			||||||
 | 
					  * debug: use LOGL_NOTICE instead of LOGL_DEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Eric ]
 | 
				
			||||||
 | 
					  * configure.ac: fix libtool issue  with clang and sanitizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * lib/netns.c: Add comments to the code, including doxygen API docs
 | 
				
			||||||
 | 
					  * lib/netns: OSMO_ASSERT() if user doesn't call init_netns()
 | 
				
			||||||
 | 
					  * lib/netns: Fix up error paths
 | 
				
			||||||
 | 
					  * example config: use RFC1918 addresses for GGSN pools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dmitri Kalashnik ]
 | 
				
			||||||
 | 
					  * sgsnemu: use real tun device name after the device is up.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * osmo-ggsn.spec.in: remove
 | 
				
			||||||
 | 
					  * contrib: import RPM spec
 | 
				
			||||||
 | 
					  * contrib: integrate RPM spec
 | 
				
			||||||
 | 
					  * Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Harald Welte <laforge@osmocom.org>  Thu, 13 Aug 2020 12:26:20 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.5.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Jan Engelhardt ]
 | 
				
			||||||
 | 
					  * build: switch AC_CANONICAL_TARGET for AC_CANONICAL_HOST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * libgtp: Remove packets in tx queue belonging pdp being freed
 | 
				
			||||||
 | 
					  * libgtp: announce pdp ctx deletion upon CreatePdpCtx being rejected
 | 
				
			||||||
 | 
					  * Introduce in46a_is_v{4,6}() helpers
 | 
				
			||||||
 | 
					  * ggsn: Move PCO handling code into its own file
 | 
				
			||||||
 | 
					  * in46_addr: Improve in46a_ntop documentation
 | 
				
			||||||
 | 
					  * ggsn_vty.c: Fix wrong use of in46a_from_eua, print IPv6 euas
 | 
				
			||||||
 | 
					  * ggsn: Split application lifecycle related code into ggsn_main.c
 | 
				
			||||||
 | 
					  * Move pdp_get_peer_ipv() to lib/util.*
 | 
				
			||||||
 | 
					  * gtp-kernel.c: Fix wrong use of in46a_from_eua, print IPv6 euas
 | 
				
			||||||
 | 
					  * Introduce LOGTUN log helper
 | 
				
			||||||
 | 
					  * ggsn_vty.c: Avoid printing duplicates for pdp context with v4v6 EUAs
 | 
				
			||||||
 | 
					  * pdp: constify param in pdp_count_secondary()
 | 
				
			||||||
 | 
					  * ggsn_vty.c: Improve output of VTY show pdp-context
 | 
				
			||||||
 | 
					  * doc: Update vty reference xml file
 | 
				
			||||||
 | 
					  * libgtp: Introduce cb_recovery3
 | 
				
			||||||
 | 
					  * ggsn: Implement echo req/resp and recovery
 | 
				
			||||||
 | 
					  * cosmetic: fix formatting in if line
 | 
				
			||||||
 | 
					  * gtp: Log msg retransmits and timeouts
 | 
				
			||||||
 | 
					  * cosmetic: gtp: Drop commented out code calling pdp_freepdp()
 | 
				
			||||||
 | 
					  * cosmetic: gtp: Improve documentation of gtp_delete_context_req2()
 | 
				
			||||||
 | 
					  * ggsn: rx DeletePdpReq confirmation: Improve documentation and use gtp_freepdp()
 | 
				
			||||||
 | 
					  * gtp: Manage queue timers internally
 | 
				
			||||||
 | 
					  * ggsn, sgsnemu: Drop use of no-op deprecated gtp_retrans* APIs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * gtp_update_pdp_ind(): fix NULL-pointer dereference
 | 
				
			||||||
 | 
					  * gtp_error_ind_conf(): fix: guard against an unknown GTP version
 | 
				
			||||||
 | 
					  * gtp/gtp.c: cosmetic: use get_tid() where we need TID
 | 
				
			||||||
 | 
					  * manuals/configuration.adoc: fix Network Address without prefix length
 | 
				
			||||||
 | 
					  * manuals/configuration.adoc: fix IPv4 address mismatch in <<ggsn_no_root>>
 | 
				
			||||||
 | 
					  * contrib/systemd: add systemd-networkd examples from manuals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * sgsnemu: Fix null-pointer format string argument
 | 
				
			||||||
 | 
					  * manual: Fix copy+paste error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Thu, 02 Jan 2020 20:39:39 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.4.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Max ]
 | 
				
			||||||
 | 
					  * Don't return error on normal shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * process_pco() const-ify 'apn' argument
 | 
				
			||||||
 | 
					  * ggsn: Remove magic numbers from pco_contains_proto()
 | 
				
			||||||
 | 
					  * ggsn: const-ify input / read-only arguments of PCO related functions
 | 
				
			||||||
 | 
					  * ggsn: Remove magic numbers from ipcp_contains_option()
 | 
				
			||||||
 | 
					  * ggsn: Fix build_ipcp_pco() in presence of invalid IPCP content
 | 
				
			||||||
 | 
					  * ggsn.c: Refactor PCO processing during PDP activation
 | 
				
			||||||
 | 
					  * ggsn: Add minimalistic PAP support
 | 
				
			||||||
 | 
					  * ggsn: More logging from PCO handling (e.g. in case of malconfiguration)
 | 
				
			||||||
 | 
					  * sgsnemu: Fix format string argument count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * osmo-ggsn: fix VTY command for getting PDP contexts by APN
 | 
				
			||||||
 | 
					  * osmo-ggsn: add VTY command to show PDP context by IPv4
 | 
				
			||||||
 | 
					  * osmo-ggsn: check result of osmo_apn_to_str()
 | 
				
			||||||
 | 
					  * osmo-ggsn: print requested / actual APN in PDP info
 | 
				
			||||||
 | 
					  * osmo-ggsn: properly show subscriber's MSISDN in the VTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * ggsn: Drop unused param force in apn_stop()
 | 
				
			||||||
 | 
					  * gtp: Document spec reasoning drop of Rx DeleteCtxReq
 | 
				
			||||||
 | 
					  * ggsn: Start gtp retrans timer during startup
 | 
				
			||||||
 | 
					  * gtp: Take queue_resp into account to schedule retrans timer
 | 
				
			||||||
 | 
					  * gtp: Fix typo dublicate->duplicate
 | 
				
			||||||
 | 
					  * pdp: Introduce new API pdp_count_secondary
 | 
				
			||||||
 | 
					  * gtp_create_pdp_ind: simplify code by reordering and compacting parsing
 | 
				
			||||||
 | 
					  * gtp: Refactor code to use gtp_freepdp(_teardown) APIs
 | 
				
			||||||
 | 
					  * cosmetic: gtp: Document free pdp ctx in non-teardown scenario
 | 
				
			||||||
 | 
					  * gtp: Re-arrange free pdp ctx code in non-teardown scenario
 | 
				
			||||||
 | 
					  * pdp: Drop unused code for haship
 | 
				
			||||||
 | 
					  * cosmetic: gtp.h: Remove trailing whitespaces
 | 
				
			||||||
 | 
					  * ggsn: Fix undefined behaviour shifting beyond sign bit
 | 
				
			||||||
 | 
					  * gtp: Introduce new pdp APIs (and deprecate old ones) to support multiple GSN
 | 
				
			||||||
 | 
					  * gtp: Make use of new libgtp APIs with multi-gsn support
 | 
				
			||||||
 | 
					  * ggsn_vty_reference.xml: Update from last code changes
 | 
				
			||||||
 | 
					  * ggsn: vty: Require ggsn param in <show pdp-context> cmd
 | 
				
			||||||
 | 
					  * sgsnemu: Replace use of deprecated libgtp API pdp_newpdp with new one
 | 
				
			||||||
 | 
					  * cosmetic: gtp: queue: remove trailing whitespace
 | 
				
			||||||
 | 
					  * gtp: Add missing headers
 | 
				
			||||||
 | 
					  * gtp: queue.c: Document queue APIs
 | 
				
			||||||
 | 
					  * gtp: queue: Add unit test queue_test
 | 
				
			||||||
 | 
					  * ggsn: Avoid unaligned mem access reading PCO proto id
 | 
				
			||||||
 | 
					  * ggsn: Use structures instead of raw arrays when parsing ipcp_hdr
 | 
				
			||||||
 | 
					  * configure.ac: Replace obosolete macro AC_CANONICAL_SYSTEM
 | 
				
			||||||
 | 
					  * configure.ac: Use brackets in AC_INIT params
 | 
				
			||||||
 | 
					  * configure.ac: Use prefered AC_CONFIG_HEADERS over AM_CONFIG_HEADER
 | 
				
			||||||
 | 
					  * configure.ac: some versions of linux/if.h require including sys/socket.h
 | 
				
			||||||
 | 
					  * sgsnemu: Fix unaligned pointer access during ip/icmp checksum
 | 
				
			||||||
 | 
					  * Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
 | 
				
			||||||
 | 
					  * Require libosmocore 1.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * debian: create -doc subpackage with pdf manuals
 | 
				
			||||||
 | 
					  * ggsn: Use gtp_delete_context_req2() everywhere
 | 
				
			||||||
 | 
					  * contrib/jenkins.sh: run "make maintainer-clean"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Daniel Willmann ]
 | 
				
			||||||
 | 
					  * manuals: Add script to regenerate vty/counter documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Wed, 07 Aug 2019 21:28:30 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.3.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * ggsn: ctrl iface: listen on IP configured by VTY
 | 
				
			||||||
 | 
					  * gtp: Log type name of unexpected signalling message
 | 
				
			||||||
 | 
					  * gtp: Allow recv DEL CTX REQ in sgsn and DEL CTX RSP in ggsn
 | 
				
			||||||
 | 
					  * gtp: Log ignore CTX DEL REQ due to no teardown and only 1 ctx active
 | 
				
			||||||
 | 
					  * gtp: Add new API to avoid freeing pdp contexts during DEL CTX REQ
 | 
				
			||||||
 | 
					  * gtp: Add new replacement cb_recovery2 for cb_recovery
 | 
				
			||||||
 | 
					  * Install systemd services with autotools
 | 
				
			||||||
 | 
					  * Install sample cfg file to /etc/osmocom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Stefan Sperling ]
 | 
				
			||||||
 | 
					  * fix unaligned access in build_ipcp_pco()
 | 
				
			||||||
 | 
					  * fix support for multiple IPCP in PDP protocol configuration options
 | 
				
			||||||
 | 
					  * check ioctl() call return value in tun_new()
 | 
				
			||||||
 | 
					  * fix allocation of ippool's hash table
 | 
				
			||||||
 | 
					  * replace bogus memcpy() call in ippool_newip()
 | 
				
			||||||
 | 
					  * initialize local variable addr in ippool_new()
 | 
				
			||||||
 | 
					  * fix format string error in ippool_printaddr()
 | 
				
			||||||
 | 
					  * fix a format string directives in queue_seqset()
 | 
				
			||||||
 | 
					  * properly store IPv6 addresses in struct tun_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * debian/rules: Don't overwrite .tarball-version
 | 
				
			||||||
 | 
					  * osmo-ggsn.cfg: Ensure well-formed config file example
 | 
				
			||||||
 | 
					  * sgsnemu: Fix printing of tun device name
 | 
				
			||||||
 | 
					  * ippool.c: Use "%td" format string for ptrdiff_t
 | 
				
			||||||
 | 
					  * initial version of OsmoGGSN user manual
 | 
				
			||||||
 | 
					  * OsmoGGSN: Add VTY reference manual
 | 
				
			||||||
 | 
					  * GGSN: Document how 'ip tuntap' is used for non-root; call netdev 'apn0'
 | 
				
			||||||
 | 
					  * vty-ref: Update URI of docbook 5.0 schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Alexander Couzens ]
 | 
				
			||||||
 | 
					  * libgtp: implement gtp_clear_queues to clear req/resp queue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * Importing history from osmo-gsm-manuals.git
 | 
				
			||||||
 | 
					  * refactor Makefile build rules, don't use the FORCE
 | 
				
			||||||
 | 
					  * GGSN: don't say 'NITB'
 | 
				
			||||||
 | 
					  * OsmoGGSN: more info on non-root operation / tun creation
 | 
				
			||||||
 | 
					  * OsmoGGSN: multiple instances: mention GTP port
 | 
				
			||||||
 | 
					  * OsmoGGSN: add Routing section for IP forward and masquerading
 | 
				
			||||||
 | 
					  * OsmoGGSN: typo: priveleges
 | 
				
			||||||
 | 
					  * OsmoGGSN VTY ref: prep: convert newlines to unix
 | 
				
			||||||
 | 
					  * OsmoGGSN vty: update VTY reference
 | 
				
			||||||
 | 
					  * OsmoGGSN: fix VTY additions' node IDs
 | 
				
			||||||
 | 
					  * OsmoGGSN: update vty reference
 | 
				
			||||||
 | 
					  * ggsn: update vty reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Max ]
 | 
				
			||||||
 | 
					  * Expand OsmoGGSN manual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * build manuals moved here from osmo-gsm-manuals.git
 | 
				
			||||||
 | 
					  * Fix DISTCHECK_CONFIGURE_FLAGS override
 | 
				
			||||||
 | 
					  * contrib/jenkins.sh: build and publish manuals
 | 
				
			||||||
 | 
					  * contrib: fix makedistcheck with disabled systemd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Harald Welte <laforge@gnumonks.org>  Sun, 20 Jan 2019 21:34:22 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.2.2) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * ggsn_vty.c: fix: use CONFIG_NODE as parent by default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * ggsn: fix misinterpreted length field in ipcp_contains_option()
 | 
				
			||||||
 | 
					  * ggsn: make sure ipcp_option_hdr and and ipcp_hdr are packed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Thu, 31 May 2018 12:44:54 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.2.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * debian/rules: Fix debian packaging after 1.2.0 release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Fri, 04 May 2018 12:19:58 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.2.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * fix compiler warnings: return 0 in main(), in 3 tests
 | 
				
			||||||
 | 
					  * add --enable-sanitize config option
 | 
				
			||||||
 | 
					  * sanitize build: ensure uint16/32 alignment in gtpie_test and in46a_test
 | 
				
			||||||
 | 
					  * configure: add --enable-werror
 | 
				
			||||||
 | 
					  * jenkins.sh: use --enable-werror configure flag, not CFLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * sgsnemu: Don't leak FILE handle in proc_read()
 | 
				
			||||||
 | 
					  * sgsnemu: Fix format string in printing tun-device name
 | 
				
			||||||
 | 
					  * sgsnemu: Make sure buffer has space for terminating-NUL
 | 
				
			||||||
 | 
					  * sgsnemu: Free strings in error path
 | 
				
			||||||
 | 
					  * gtp: Fix buffer overflow in imsi_gtp2str()
 | 
				
			||||||
 | 
					  * gtp: Explicit OSMO_ASSERT to ensure pdp variable is set
 | 
				
			||||||
 | 
					  * tun: Don't copy 16byte IPv6 address to 'struct in_addr'
 | 
				
			||||||
 | 
					  * ippool: Correctly compute size of static pool
 | 
				
			||||||
 | 
					  * remove unused argument to alloc_ippool_blacklist()
 | 
				
			||||||
 | 
					  * factor out netdev_ip_local_get() from tun_ip_local_get()
 | 
				
			||||||
 | 
					  * Properly NULL-out blacklist in alloc_ippool_blacklist()
 | 
				
			||||||
 | 
					  * gtp_kernel: Change gtp_kernel_init() function signature
 | 
				
			||||||
 | 
					  * gtp-kernel: Re-add support for kernel GTP-U acceleration
 | 
				
			||||||
 | 
					  * gtp-kernel: Get rid of hard-coded kernel GTP device name
 | 
				
			||||||
 | 
					  * gtp-kernel: shut down kernel GTP device in apn_down()
 | 
				
			||||||
 | 
					  * gtp-kernel: Align logging for APN start in kernel-gtp case with that of TUN
 | 
				
			||||||
 | 
					  * gtp-kernel: Avoid global state variable
 | 
				
			||||||
 | 
					  * gtp-kernel: Make sure repeated calls to gtp_kernel_init() are safe
 | 
				
			||||||
 | 
					  * gtp-kernel: proper cleanup in error path
 | 
				
			||||||
 | 
					  * gtp-kernel: Get rid of SYS_ERR where not applicable
 | 
				
			||||||
 | 
					  * gtp-kernel: Add function name to pdp_debug() function calls
 | 
				
			||||||
 | 
					  * gtp-kernel: Add device nime in pdp_debug() log statements
 | 
				
			||||||
 | 
					  * contrib/jenkins.sh: Allow jenkins job to specify if kernel GTP is used
 | 
				
			||||||
 | 
					  * ggsn.c: Fix byte order of IPCP IPv4 DNS servers
 | 
				
			||||||
 | 
					  * ggsn: Ignore PCO with length 0, don't abort processing
 | 
				
			||||||
 | 
					  * README.md: Remove misleading sentence on sgsnemu
 | 
				
			||||||
 | 
					  * Add talloc context introspection via VTY
 | 
				
			||||||
 | 
					  * fix segfault in case of kernel gtp-u
 | 
				
			||||||
 | 
					  * lib/tun.c: Generalize tun_sifflags() to netdev_sifflags
 | 
				
			||||||
 | 
					  * lib/tun.c: generalize tun_*route() to netdev_*route()
 | 
				
			||||||
 | 
					  * lib/tun.c: Generalize tun_{set,add}addr*() functions
 | 
				
			||||||
 | 
					  * lib/tun: split generic network device related stuff to lib/netdev
 | 
				
			||||||
 | 
					  * lib/netdev.c: Cosmetic changes (coding style / cleanups)
 | 
				
			||||||
 | 
					  * ggsn: Don't explicitly use tun_setaddr() API anymore
 | 
				
			||||||
 | 
					  * sgsnemu: Convert from tun_setaddr() to tun_addaddr()
 | 
				
			||||||
 | 
					  * lib/tun: Remove tun_setaddr() API, as everyone is using tun_addaddr() now
 | 
				
			||||||
 | 
					  * Move kernel GTP support from ggsn/ to lib/
 | 
				
			||||||
 | 
					  * ggsn: don't use gtp_kernel_tunnel_{add,del}() for userspace tun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * ggsn_vty: Stop using deprecated API vty_install_default
 | 
				
			||||||
 | 
					  * contrib/jenkins.sh: Enable Werror in C(PP)FLAGS
 | 
				
			||||||
 | 
					  * examples: Add secondary ipv6 google DNS to osmo-ggsn.cfg
 | 
				
			||||||
 | 
					  * tun_setaddr6: Fix log typo
 | 
				
			||||||
 | 
					  * cosmetic: Reorder tun_addaddr to get rid of decl of tun_setaddr4
 | 
				
			||||||
 | 
					  * ggsn.c: Print version of unhandled ip packet
 | 
				
			||||||
 | 
					  * Remove unused empty src/Makefile.in
 | 
				
			||||||
 | 
					  * tests: Split ipv6 specific tests into a new test group
 | 
				
			||||||
 | 
					  * Add support for IPv4v6 End User Addresses
 | 
				
			||||||
 | 
					  * contrib: jenkins.sh: Build libgtpnl as dep when building with gtp kernel support
 | 
				
			||||||
 | 
					  * cosmetic: sgsnemu.c: Fix trailing whitespace
 | 
				
			||||||
 | 
					  * ggsn.c: Improve logging info on link-local ipv6 addr not found
 | 
				
			||||||
 | 
					  * tun.c: tun_addaddr: Fix segfault and wrong usage of tun_nlattr
 | 
				
			||||||
 | 
					  * Set tun_addaddr ipv agnostic and add support for ipv6
 | 
				
			||||||
 | 
					  * ggsn: Add 'ipv6 link-local' vty cmd
 | 
				
			||||||
 | 
					  * ggsn_vty.c: Print ipv6 link-local cmd when writing config to file
 | 
				
			||||||
 | 
					  * gtp.c: Fix trailing whitespace
 | 
				
			||||||
 | 
					  * gtp.c: Determine GTP version from header
 | 
				
			||||||
 | 
					  * gtp.c: Log unsupported GTP version number
 | 
				
			||||||
 | 
					  * gtp/pdp: Fix trailing whitespace
 | 
				
			||||||
 | 
					  * gtp/pdp: Remove unused APIs pdp_ntoeua pdp_euaton
 | 
				
			||||||
 | 
					  * gtp.c: gtp_gpdu_ind: Convert ifelse to switch statement
 | 
				
			||||||
 | 
					  * gtp.c: gtp_gpdu_ind: Early return to avoid use of uninitialized var
 | 
				
			||||||
 | 
					  * gtp/gtp.c: Remove unused function char2ul_t
 | 
				
			||||||
 | 
					  * gtp/gtp.c: Mark non exported functions as static
 | 
				
			||||||
 | 
					  * gtp/gtp.c: Use uint8_t for version param in static functions
 | 
				
			||||||
 | 
					  * ggsn: encaps_tun: Avoid forwarding packet if EUA is unassigned, fix crash
 | 
				
			||||||
 | 
					  * ggsn: Validate packet src addr from MS
 | 
				
			||||||
 | 
					  * ggsn: Parse PCO_IPCP
 | 
				
			||||||
 | 
					  * ggsn: Parse PCO_IPCP for IPv4v6 pdp ctx
 | 
				
			||||||
 | 
					  * ggsn: Print all addresses on successful pdp ctx creation
 | 
				
			||||||
 | 
					  * ggsn.c: cb_tun_ind: Convert ifelse to switch statement
 | 
				
			||||||
 | 
					  * ggsn.c: cb_tun_ind: log dst addr of packet without pdp ctx
 | 
				
			||||||
 | 
					  * ggsn.c: cb_tun_ind: Don't drop packets targeting pdp ctx ll addr
 | 
				
			||||||
 | 
					  * sgsnemu: Fix bad ptr during context deallocation
 | 
				
			||||||
 | 
					  * sgsnemu: listen param is a host, not an interface
 | 
				
			||||||
 | 
					  * use osmo_init_logging2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Max ]
 | 
				
			||||||
 | 
					  * Log APN and tun names for packets
 | 
				
			||||||
 | 
					  * Enable sanitize for CI tests
 | 
				
			||||||
 | 
					  * Fix stow-enabled jenkins build failure
 | 
				
			||||||
 | 
					  * Add GTP message names
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Viktor Tsymbalyuk ]
 | 
				
			||||||
 | 
					  * sgsnemu: sgsnemu stopped after recieving "Request accepted" from ggsn
 | 
				
			||||||
 | 
					  * sgsnemu: created "pinghost" and "createif" modes for mutual exclusion
 | 
				
			||||||
 | 
					  * sgsnemu: fix: no outgoing GTP-U in "createif" mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Martin Hauke ]
 | 
				
			||||||
 | 
					  * build: Remove AC_PROG_CXX, C++ is never used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Stefan Sperling ]
 | 
				
			||||||
 | 
					  * remove the -f option from osmo-ggsn.service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Thu, 03 May 2018 16:05:27 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-ggsn (1.1.0) unstable; urgency=medium
 | 
					osmo-ggsn (1.1.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * libgtp: pdp.h: Addition of new tx_gpdu_seq struct member member
 | 
					  * libgtp: pdp.h: Addition of new tx_gpdu_seq struct member member
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
Source: osmo-ggsn
 | 
					Source: osmo-ggsn
 | 
				
			||||||
Maintainer: Harald Welte <laforge@gnumonks.org>
 | 
					Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
				
			||||||
Section: net
 | 
					Section: net
 | 
				
			||||||
Priority: optional
 | 
					Priority: optional
 | 
				
			||||||
Build-Depends: debhelper (>= 9),
 | 
					Build-Depends: debhelper (>= 9),
 | 
				
			||||||
@@ -7,7 +7,9 @@ Build-Depends: debhelper (>= 9),
 | 
				
			|||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               libdpkg-perl, git,
 | 
					               libdpkg-perl, git,
 | 
				
			||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               libosmocore-dev (>= 0.8.0)
 | 
					               libosmocore-dev (>= 1.5.0),
 | 
				
			||||||
 | 
					               osmo-gsm-manuals-dev,
 | 
				
			||||||
 | 
					               libgtpnl-dev (>= 1.2.0)
 | 
				
			||||||
Standards-Version: 3.9.6
 | 
					Standards-Version: 3.9.6
 | 
				
			||||||
Vcs-Browser: http://git.osmocom.org/osmo-ggsn/
 | 
					Vcs-Browser: http://git.osmocom.org/osmo-ggsn/
 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-ggsn
 | 
					Vcs-Git: git://git.osmocom.org/osmo-ggsn
 | 
				
			||||||
@@ -22,7 +24,7 @@ Description: Osmocom Gateway GPRS Support Node (GGSN)
 | 
				
			|||||||
 operators as the interface between the Internet and the rest of the
 | 
					 operators as the interface between the Internet and the rest of the
 | 
				
			||||||
 mobile network infrastructure.
 | 
					 mobile network infrastructure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libgtp2
 | 
					Package: libgtp6
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
@@ -36,12 +38,18 @@ Description: library implementing the GTP protocol between SGSN and GGSN
 | 
				
			|||||||
 This library is part of OsmoGGSN and implements the GTP protocol between
 | 
					 This library is part of OsmoGGSN and implements the GTP protocol between
 | 
				
			||||||
 SGSN (Serving GPRS support node) and GGSN.
 | 
					 SGSN (Serving GPRS support node) and GGSN.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: gtp-echo-responder
 | 
				
			||||||
 | 
					Architecture: any
 | 
				
			||||||
 | 
					Depends: ${shlibs:Depends},
 | 
				
			||||||
 | 
					         ${misc:Depends}
 | 
				
			||||||
 | 
					Description: Small program answering GTP ECHO Request with GTP ECHO Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libgtp-dev
 | 
					Package: libgtp-dev
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Depends: ${misc:Depends},
 | 
					Depends: ${misc:Depends},
 | 
				
			||||||
         libgtp2 (= ${binary:Version})
 | 
					         libgtp6 (= ${binary:Version})
 | 
				
			||||||
Description: Development files for libgtp
 | 
					Description: Development files for libgtp
 | 
				
			||||||
 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
					 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
				
			||||||
 operators as the interface between the Internet and the rest of the
 | 
					 operators as the interface between the Internet and the rest of the
 | 
				
			||||||
@@ -54,18 +62,27 @@ Package: osmo-ggsn-dbg
 | 
				
			|||||||
Section: debug
 | 
					Section: debug
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp2 (= ${binary:Version}), osmo-ggsn (= ${binary:Version})
 | 
					Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp6 (= ${binary:Version}), osmo-ggsn (= ${binary:Version})
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Description: Debug symbols for OsmoGGSN
 | 
					Description: Debug symbols for OsmoGGSN
 | 
				
			||||||
 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
					 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
				
			||||||
 operators as the interface between the Internet and the rest of the
 | 
					 operators as the interface between the Internet and the rest of the
 | 
				
			||||||
 mobile network infrastructure.
 | 
					 mobile network infrastructure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: gtp-echo-responder-dbg
 | 
				
			||||||
 | 
					Section: debug
 | 
				
			||||||
 | 
					Architecture: any
 | 
				
			||||||
 | 
					Priority: extra
 | 
				
			||||||
 | 
					Depends: ${shlibs:Depends}, ${misc:Depends}, gtp-echo-responder (= ${binary:Version})
 | 
				
			||||||
 | 
					Multi-Arch: same
 | 
				
			||||||
 | 
					Description: Debug symbols for gtp-echo-responder
 | 
				
			||||||
 | 
					 Small program answering GTP ECHO Request with GTP ECHO Response.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libgtp-dbg
 | 
					Package: libgtp-dbg
 | 
				
			||||||
Section: debug
 | 
					Section: debug
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp2 (= ${binary:Version})
 | 
					Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp6 (= ${binary:Version})
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Description: Debug symbols for OsmoGGSN
 | 
					Description: Debug symbols for OsmoGGSN
 | 
				
			||||||
 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
					 OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
				
			||||||
@@ -74,3 +91,12 @@ Description: Debug symbols for OsmoGGSN
 | 
				
			|||||||
 .
 | 
					 .
 | 
				
			||||||
 The library libgtp implements the GTP protocol between SGSN and GGSN
 | 
					 The library libgtp implements the GTP protocol between SGSN and GGSN
 | 
				
			||||||
 and this package contains the development files for this library.
 | 
					 and this package contains the development files for this library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: osmo-ggsn-doc
 | 
				
			||||||
 | 
					Architecture: all
 | 
				
			||||||
 | 
					Section: doc
 | 
				
			||||||
 | 
					Priority: optional
 | 
				
			||||||
 | 
					Depends: ${misc:Depends}
 | 
				
			||||||
 | 
					Description: ${misc:Package} PDF documentation
 | 
				
			||||||
 | 
					 Various manuals: user manual, VTY reference manual and/or
 | 
				
			||||||
 | 
					 protocol/interface manuals.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -16,6 +16,11 @@ Files: lib/getopt.c
 | 
				
			|||||||
Copyright: 1987-2001 Free Software Foundation, Inc.
 | 
					Copyright: 1987-2001 Free Software Foundation, Inc.
 | 
				
			||||||
License: LGPL-2.1+
 | 
					License: LGPL-2.1+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: utils/gtp_echo_responder.c
 | 
				
			||||||
 | 
					       utils/gtp_echo_responder_test.py
 | 
				
			||||||
 | 
					Copyright: 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					License: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: debian/*
 | 
					Files: debian/*
 | 
				
			||||||
Copyright: 2010-2017  Harald Welte <laforge@gnumonks.org>
 | 
					Copyright: 2010-2017  Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
           2016       Ruben Undheim <ruben.undheim@gmail.com>
 | 
					           2016       Ruben Undheim <ruben.undheim@gmail.com>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/gtp-echo-responder.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/gtp-echo-responder.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/usr/bin/gtp-echo-responder
 | 
				
			||||||
							
								
								
									
										1
									
								
								debian/osmo-ggsn-doc.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-ggsn-doc.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					usr/share/doc/osmo-ggsn-doc/*.pdf
 | 
				
			||||||
							
								
								
									
										1
									
								
								debian/osmo-ggsn.examples
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-ggsn.examples
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,3 @@
 | 
				
			|||||||
doc/examples/osmo-ggsn.cfg
 | 
					doc/examples/osmo-ggsn.cfg
 | 
				
			||||||
 | 
					doc/examples/osmo-ggsn-kernel-gtp.cfg
 | 
				
			||||||
doc/examples/sgsnemu.conf
 | 
					doc/examples/sgsnemu.conf
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/osmo-ggsn.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/osmo-ggsn.install
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					/etc/osmocom/osmo-ggsn.cfg
 | 
				
			||||||
 | 
					/lib/systemd/system/osmo-ggsn.service
 | 
				
			||||||
/usr/bin/osmo-ggsn
 | 
					/usr/bin/osmo-ggsn
 | 
				
			||||||
/usr/bin/sgsnemu
 | 
					/usr/bin/sgsnemu
 | 
				
			||||||
/usr/share/man/man8/*
 | 
					/usr/share/man/man8/*
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/osmo-ggsn.service
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-ggsn.service
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
../contrib/osmo-ggsn.service
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -16,8 +16,14 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
override_dh_strip:
 | 
					override_dh_strip:
 | 
				
			||||||
	dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
 | 
						dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
 | 
				
			||||||
	dh_strip -plibgtp2 --dbg-package=libgtp-dbg
 | 
						dh_strip -plibgtp6 --dbg-package=libgtp-dbg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_autoreconf:
 | 
					override_dh_auto_configure:
 | 
				
			||||||
	echo $(VERSION) > .tarball-version
 | 
						dh_auto_configure -- \
 | 
				
			||||||
	dh_autoreconf
 | 
							--enable-gtp-linux \
 | 
				
			||||||
 | 
							--with-systemdsystemunitdir=/lib/systemd/system \
 | 
				
			||||||
 | 
							--enable-manuals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
 | 
				
			||||||
 | 
					override_dh_compress:
 | 
				
			||||||
 | 
						dh_compress -X.pdf
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,5 @@ EXTRA_DIST = $(man_MANS)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
SUBDIRS = \
 | 
					SUBDIRS = \
 | 
				
			||||||
	examples \
 | 
						examples \
 | 
				
			||||||
 | 
						manuals \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,13 @@
 | 
				
			|||||||
CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,'
 | 
					OSMOCONF_FILES = \
 | 
				
			||||||
 | 
						osmo-ggsn.cfg \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmoconfdir = $(sysconfdir)/osmocom
 | 
				
			||||||
 | 
					osmoconf_DATA = $(OSMOCONF_FILES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXTRA_DIST = $(OSMOCONF_FILES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFG_FILES = find $(srcdir) -name '*.cfg' -o -name '*.conf' | sed -e 's,^$(srcdir),,'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dist-hook:
 | 
					dist-hook:
 | 
				
			||||||
	for f in $$($(CFG_FILES)); do \
 | 
						for f in $$($(CFG_FILES)); do \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										51
									
								
								doc/examples/osmo-ggsn-kernel-gtp.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								doc/examples/osmo-ggsn-kernel-gtp.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					!
 | 
				
			||||||
 | 
					! OpenGGSN (0.94.1-adac) configuration saved from vty
 | 
				
			||||||
 | 
					!!
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					log stderr
 | 
				
			||||||
 | 
					 logging filter all 1
 | 
				
			||||||
 | 
					 logging color 1
 | 
				
			||||||
 | 
					 logging print category 0
 | 
				
			||||||
 | 
					 logging timestamp 0
 | 
				
			||||||
 | 
					 logging level ip info
 | 
				
			||||||
 | 
					 logging level tun info
 | 
				
			||||||
 | 
					 logging level ggsn info
 | 
				
			||||||
 | 
					 logging level sgsn notice
 | 
				
			||||||
 | 
					 logging level icmp6 notice
 | 
				
			||||||
 | 
					 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
 | 
				
			||||||
 | 
					 logging level lctrl notice
 | 
				
			||||||
 | 
					 logging level lgtp info
 | 
				
			||||||
 | 
					 logging level lstats notice
 | 
				
			||||||
 | 
					 logging level lgsup notice
 | 
				
			||||||
 | 
					 logging level loap notice
 | 
				
			||||||
 | 
					 logging level lss7 notice
 | 
				
			||||||
 | 
					 logging level lsccp notice
 | 
				
			||||||
 | 
					 logging level lsua notice
 | 
				
			||||||
 | 
					 logging level lm3ua notice
 | 
				
			||||||
 | 
					 logging level lmgcp notice
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					stats interval 5
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					line vty
 | 
				
			||||||
 | 
					 no login
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					ggsn ggsn0
 | 
				
			||||||
 | 
					 gtp state-dir /tmp
 | 
				
			||||||
 | 
					 gtp bind-ip 127.0.0.2
 | 
				
			||||||
 | 
					 apn internet
 | 
				
			||||||
 | 
					  gtpu-mode kernel-gtp
 | 
				
			||||||
 | 
					  tun-device tun4
 | 
				
			||||||
 | 
					  type-support v4
 | 
				
			||||||
 | 
					  ip prefix dynamic 172.16.222.0/24
 | 
				
			||||||
 | 
					  ip dns 0 8.8.8.8
 | 
				
			||||||
 | 
					  ip dns 1 8.8.4.4
 | 
				
			||||||
 | 
					  ip ifconfig 172.16.222.0/24
 | 
				
			||||||
 | 
					  no shutdown
 | 
				
			||||||
 | 
					 default-apn internet
 | 
				
			||||||
 | 
					 no shutdown ggsn
 | 
				
			||||||
@@ -3,32 +3,32 @@
 | 
				
			|||||||
!!
 | 
					!!
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
log stderr
 | 
					log stderr
 | 
				
			||||||
  logging filter all 1
 | 
					 logging filter all 1
 | 
				
			||||||
  logging color 1
 | 
					 logging color 1
 | 
				
			||||||
  logging print category 0
 | 
					 logging print category 0
 | 
				
			||||||
  logging timestamp 0
 | 
					 logging timestamp 0
 | 
				
			||||||
  logging level ip info
 | 
					 logging level ip info
 | 
				
			||||||
  logging level tun info
 | 
					 logging level tun info
 | 
				
			||||||
  logging level ggsn info
 | 
					 logging level ggsn info
 | 
				
			||||||
  logging level sgsn notice
 | 
					 logging level sgsn notice
 | 
				
			||||||
  logging level icmp6 notice
 | 
					 logging level icmp6 notice
 | 
				
			||||||
  logging level lglobal notice
 | 
					 logging level lglobal notice
 | 
				
			||||||
  logging level llapd notice
 | 
					 logging level llapd notice
 | 
				
			||||||
  logging level linp notice
 | 
					 logging level linp notice
 | 
				
			||||||
  logging level lmux notice
 | 
					 logging level lmux notice
 | 
				
			||||||
  logging level lmi notice
 | 
					 logging level lmi notice
 | 
				
			||||||
  logging level lmib notice
 | 
					 logging level lmib notice
 | 
				
			||||||
  logging level lsms notice
 | 
					 logging level lsms notice
 | 
				
			||||||
  logging level lctrl notice
 | 
					 logging level lctrl notice
 | 
				
			||||||
  logging level lgtp info
 | 
					 logging level lgtp info
 | 
				
			||||||
  logging level lstats notice
 | 
					 logging level lstats notice
 | 
				
			||||||
  logging level lgsup notice
 | 
					 logging level lgsup notice
 | 
				
			||||||
  logging level loap notice
 | 
					 logging level loap notice
 | 
				
			||||||
  logging level lss7 notice
 | 
					 logging level lss7 notice
 | 
				
			||||||
  logging level lsccp notice
 | 
					 logging level lsccp notice
 | 
				
			||||||
  logging level lsua notice
 | 
					 logging level lsua notice
 | 
				
			||||||
  logging level lm3ua notice
 | 
					 logging level lm3ua notice
 | 
				
			||||||
  logging level lmgcp notice
 | 
					 logging level lmgcp notice
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
stats interval 5
 | 
					stats interval 5
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
@@ -37,15 +37,15 @@ line vty
 | 
				
			|||||||
!
 | 
					!
 | 
				
			||||||
ggsn ggsn0
 | 
					ggsn ggsn0
 | 
				
			||||||
 gtp state-dir /tmp
 | 
					 gtp state-dir /tmp
 | 
				
			||||||
 gtp bind-ip 127.0.0.6
 | 
					 gtp bind-ip 127.0.0.2
 | 
				
			||||||
 apn internet
 | 
					 apn internet
 | 
				
			||||||
  gtpu-mode tun
 | 
					  gtpu-mode tun
 | 
				
			||||||
  tun-device tun4
 | 
					  tun-device tun4
 | 
				
			||||||
  type-support v4
 | 
					  type-support v4
 | 
				
			||||||
  ip prefix dynamic 176.16.222.0/24
 | 
					  ip prefix dynamic 172.16.222.0/24
 | 
				
			||||||
  ip dns 0 192.168.100.1
 | 
					  ip dns 0 8.8.8.8
 | 
				
			||||||
  ip dns 1 8.8.8.8
 | 
					  ip dns 1 8.8.4.4
 | 
				
			||||||
  ip ifconfig 176.16.222.0/24
 | 
					  ip ifconfig 172.16.222.0/24
 | 
				
			||||||
  no shutdown
 | 
					  no shutdown
 | 
				
			||||||
 apn inet6
 | 
					 apn inet6
 | 
				
			||||||
  gtpu-mode tun
 | 
					  gtpu-mode tun
 | 
				
			||||||
@@ -60,10 +60,10 @@ ggsn ggsn0
 | 
				
			|||||||
  gtpu-mode tun
 | 
					  gtpu-mode tun
 | 
				
			||||||
  tun-device tun46
 | 
					  tun-device tun46
 | 
				
			||||||
  type-support v4v6
 | 
					  type-support v4v6
 | 
				
			||||||
  ip prefix dynamic 176.16.46.0/24
 | 
					  ip prefix dynamic 172.16.46.0/24
 | 
				
			||||||
  ip dns 0 192.168.100.1
 | 
					  ip dns 0 8.8.8.8
 | 
				
			||||||
  ip dns 1 8.8.8.8
 | 
					  ip dns 1 8.8.4.4
 | 
				
			||||||
  ip ifconfig 176.16.46.0/24
 | 
					  ip ifconfig 172.16.46.0/24
 | 
				
			||||||
  ipv6 prefix dynamic 2001:780:44:2100:0:0:0:0/56
 | 
					  ipv6 prefix dynamic 2001:780:44:2100:0:0:0:0/56
 | 
				
			||||||
  ipv6 dns 0 2001:4860:4860::8888
 | 
					  ipv6 dns 0 2001:4860:4860::8888
 | 
				
			||||||
  ipv6 dns 1 2001:4860:4860::8844
 | 
					  ipv6 dns 1 2001:4860:4860::8844
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								doc/manuals/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								doc/manuals/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					EXTRA_DIST = osmoggsn-usermanual.adoc \
 | 
				
			||||||
 | 
					    osmoggsn-usermanual-docinfo.xml \
 | 
				
			||||||
 | 
					    osmoggsn-vty-reference.xml \
 | 
				
			||||||
 | 
					    regen_doc.sh \
 | 
				
			||||||
 | 
					    chapters \
 | 
				
			||||||
 | 
					    vty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if BUILD_MANUALS
 | 
				
			||||||
 | 
					  ASCIIDOC = osmoggsn-usermanual.adoc
 | 
				
			||||||
 | 
					  ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
 | 
				
			||||||
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  VTY_REFERENCE = osmoggsn-vty-reference.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BUILT_REFERENCE_XML = $(builddir)/vty/ggsn_vty_reference.xml
 | 
				
			||||||
 | 
					  $(builddir)/vty/ggsn_vty_reference.xml: $(top_builddir)/ggsn/osmo-ggsn
 | 
				
			||||||
 | 
						mkdir -p $(builddir)/vty
 | 
				
			||||||
 | 
						$(top_builddir)/ggsn/osmo-ggsn --vty-ref-xml > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OSMO_REPOSITORY=osmo-ggsn
 | 
				
			||||||
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										335
									
								
								doc/manuals/chapters/configuration.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								doc/manuals/chapters/configuration.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
				
			|||||||
 | 
					== Configuring OsmoGGSN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All configuration of OsmoGGSN is performed using the VTY. For more
 | 
				
			||||||
 | 
					general information on the VTY interface, see <<vty>>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Configuring a virtual GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoGGSN can run multiple GGSN instances inside one program/process.
 | 
				
			||||||
 | 
					Each GGSN instance binds to its own transport-layer GTP IP address and
 | 
				
			||||||
 | 
					has its own set of APNs and associated IP address pools + tun/gtp
 | 
				
			||||||
 | 
					devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In most usage cases, yo will only have a single GGSN instance inside
 | 
				
			||||||
 | 
					your configuration file, like in below example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Single GGSN configuration section
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					ggsn ggsn0
 | 
				
			||||||
 | 
					 gtp state-dir /tmp
 | 
				
			||||||
 | 
					 gtp bind-ip 127.0.0.6
 | 
				
			||||||
 | 
					 apn internet
 | 
				
			||||||
 | 
					  gtpu-mode tun
 | 
				
			||||||
 | 
					  tun-device tun4
 | 
				
			||||||
 | 
					  type-support v4
 | 
				
			||||||
 | 
					  ip prefix dynamic 176.16.222.0/24
 | 
				
			||||||
 | 
					  ip dns 0 192.168.100.1
 | 
				
			||||||
 | 
					  ip dns 1 8.8.8.8
 | 
				
			||||||
 | 
					  ip ifconfig 176.16.222.0/24
 | 
				
			||||||
 | 
					  no shutdown
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Creating/Editing a GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creating/Editing a GGSN instance can be done by the following sequence
 | 
				
			||||||
 | 
					of VTY commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# <4>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Create or edit the GGSN instance `ggsn0`. The name can be any ASCII
 | 
				
			||||||
 | 
					    string, its significance is only to the local user.
 | 
				
			||||||
 | 
					<4> Your prompt is now in the `ggsn` config node, where you can
 | 
				
			||||||
 | 
					    configure the properties of this GGSN instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NOTE:: After creating a new GGSN instance, it is in `shutdown` mode. See
 | 
				
			||||||
 | 
					<<unshutdown_apn>> to take it out of shutdown, but make sure to configure it fully
 | 
				
			||||||
 | 
					before taking it out of shutdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Configuring a GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following two mandatory configuration statements have to be given
 | 
				
			||||||
 | 
					for every GGSN instance:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# gtp state-dir /var/lib/ggsn/ggsn0 <1>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# gtp bind-ip 127.0.0.6 <2>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Store the GSN restart state in the specified directory
 | 
				
			||||||
 | 
					<2> Bind the GGSN instance to the specified local IPv4 address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are some further configuration statements that can be used at the
 | 
				
			||||||
 | 
					GGSN node, some examples are given below.  For a full list, see the
 | 
				
			||||||
 | 
					_OsmoGGSN VTY reference manual_ <<vty-ref-osmoggsn>>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# default-apn foobar <1>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Configure a default APN to be used if the user-requested APN is not
 | 
				
			||||||
 | 
					    found.  The named APN must previously be configured
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Deleting a GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A GGSN instance can be removed like this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Deleting a GGSN instance
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# no ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Delete the GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Taking a GGSN instance out of shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Taking a GGSN instance out of shutdown
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# no shutdown ggsn <4>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config ndoe of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Take the GGSN instance out of shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Shutting a GGSN instance down
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you would like to take a GGSN instance out of service, you can
 | 
				
			||||||
 | 
					put it into shutdown mode.  This will make the entire GGSN unavailable
 | 
				
			||||||
 | 
					to user traffic and permit you to e.g. reconfigure it before taking it
 | 
				
			||||||
 | 
					out of shutdown again.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Shutting down a GGSN instance
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# shutdown ggsn <4>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config ndoe of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Shut down the GGSN instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Configuring an Access Point Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An Access Point Name (APN) represents a connection to an external packet
 | 
				
			||||||
 | 
					data network, such as the public Internet or private corporate networsk.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					APNs are selected by terminals (MS/UE) when establishing PDP contexts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each OsmoGGSN GGSN instance can have any number of APNs configured.
 | 
				
			||||||
 | 
					Each APN is identified by a string name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Creating/Editing an APN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Creating a new APN
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# apn internet <4>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# <5>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config node of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Create or Edit an APN called `internet`
 | 
				
			||||||
 | 
					<5> Your prompt is now in the `ggsn` config node, where you can
 | 
				
			||||||
 | 
					    configure the properties of this GGSN instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NOTE:: The newly-create APN is created in `shutdown` mode. See <<unshutdown_apn>> to take it
 | 
				
			||||||
 | 
					out of shutdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Configuring an APN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Configuring an APN
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# gtpu-mode tun <1>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# type-support v4 <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# ip prefix dynamic 176.16.222.0/24 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# ip dns 0 192.168.100.1 <4>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# ip dns 1 8.8.8.8 <5>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# ip ifconfig 176.16.222.0/24 <6>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Use the userspace GTP-U handling using a TUN device
 | 
				
			||||||
 | 
					<2> Support (only) IPv4 Addresses
 | 
				
			||||||
 | 
					<3> Specify the pool of dynamic IPv4 addresses to be allocated to PDP
 | 
				
			||||||
 | 
					    contexts
 | 
				
			||||||
 | 
					<4> Specify the primary DNS server to be provided using IPCP/PCO
 | 
				
			||||||
 | 
					<5> Specify the secondary DNS server to be provided using IPCP/PCO
 | 
				
			||||||
 | 
					<6> Request OsmoGGSN to configure the `tun4` device network/netmask
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NOTE:: If you use the optional `ip ifconfig` command to set the network
 | 
				
			||||||
 | 
					device address/mask, OsmoGGSN must run with root or `CAP_NET_ADMIN`
 | 
				
			||||||
 | 
					support.  It might be better to configure related tun devices at system
 | 
				
			||||||
 | 
					startup and run OsmoGGSN as non-privileged user.  See <<ggsn_no_root>> for more
 | 
				
			||||||
 | 
					details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Deleting an APN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An APN configuration can be removed like this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Deleting an APN
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# no apn internet <4>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config node of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Delete the APN `internet`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[unshutdown_apn]]
 | 
				
			||||||
 | 
					==== Taking an APN out of shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to bring a deactived APN in `shutdown` state into active
 | 
				
			||||||
 | 
					operation, use the `no shutdown` command at the APN node as explained in
 | 
				
			||||||
 | 
					the following example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Taking an APN out of shutdown
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# apn internet <4>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# no shutdown <5>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config ndoe of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Enter the config ndoe of the APN `internet`
 | 
				
			||||||
 | 
					<5> Take the APN out of shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Shutting an APN down
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you would like to take an APN instance out of service, you can
 | 
				
			||||||
 | 
					put it into shutdown mode.  This will make the APN unavailable
 | 
				
			||||||
 | 
					to user traffic and permit you to e.g. reconfigure it before taking it
 | 
				
			||||||
 | 
					out of shutdown again.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Shutting down an APN
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					OsmoGGSN> enable <1>
 | 
				
			||||||
 | 
					OsmoGGSN# configure terminal <2>
 | 
				
			||||||
 | 
					OsmoGGSN(config)# ggsn ggsn0 <3>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn)# apn internet <4>
 | 
				
			||||||
 | 
					OsmoGGSN(config-ggsn-apn)# shutdown <5>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> Change into privileged mode
 | 
				
			||||||
 | 
					<2> Enter the interactive configuration mode
 | 
				
			||||||
 | 
					<3> Enter the config ndoe of the GGSN instance `ggsn0`
 | 
				
			||||||
 | 
					<4> Enter the config ndoe of the APN `internet`
 | 
				
			||||||
 | 
					<5> Shut down the APN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[ggsn_no_root]]
 | 
				
			||||||
 | 
					=== Configuring for running without root privileges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It's possible to run OsmoGGSN without root privileges if the tun devices are already configured.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The interface creation + configuration must then happen before osmo-ggsn starting up.  This can be
 | 
				
			||||||
 | 
					achieved by means such as
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* a custom shell script run as root before starting osmo-ggsn (e.g. as init script)
 | 
				
			||||||
 | 
					* systemd .netdev and .network files, if your system is using systemd-networkd (see `networkctl status`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Manual TUN device creation / configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you chose to go for custom shell/init scripts, you may use the `ip` program which is the standard
 | 
				
			||||||
 | 
					tool for network interface configuration on Linux, part of the `iproute2` package.  In order to
 | 
				
			||||||
 | 
					create a tun device, you must call it like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: iproute2 command to create a tun device
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					# ip tuntap add dev apn0 mode tun user username group groupname
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Where _username_ and _groupname_ correspond to the User and Group that will have ownership over the
 | 
				
			||||||
 | 
					device, i.e. the privileges which you intend to run osmo-ggsn under, and _apn0_ will be the
 | 
				
			||||||
 | 
					name of the network device created.  After creating the interface, you can configure its addresses
 | 
				
			||||||
 | 
					using standard means like `ip addr add` or your distribution-specific utilities/tools
 | 
				
			||||||
 | 
					to match the `ip prefix dynamic` config item, and activate the link, for example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					# ip addr add 192.168.7.1/24 dev apn0
 | 
				
			||||||
 | 
					# ip link set apn0 up
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== systemd based TUN device creation+configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to have systemd take care of creating and configuring a tun device for you,
 | 
				
			||||||
 | 
					you can use the below example config files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: device config via systemd-networkd using apn0.netdev
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					[NetDev]
 | 
				
			||||||
 | 
					Name=apn0 <1>
 | 
				
			||||||
 | 
					Kind=tun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Tun]
 | 
				
			||||||
 | 
					User=username <2>
 | 
				
			||||||
 | 
					Group=username <3>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> The network interface name of the newly-created device
 | 
				
			||||||
 | 
					<2> The username under which you will run OsmoGGSN
 | 
				
			||||||
 | 
					<3> The group name under which you will run OsmoGGSN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: network settings via systemd-networkd using ggsn.network
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					[Match]
 | 
				
			||||||
 | 
					Name=apn0 <1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Network]
 | 
				
			||||||
 | 
					Address=192.168.7.1/24 <2>
 | 
				
			||||||
 | 
					IPMasquerade=yes <3>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> The netowrk device name, which must match the one in the apn0.netdev unit file above
 | 
				
			||||||
 | 
					<2> The local IP address configured on the device
 | 
				
			||||||
 | 
					<3> Requesting systemd to configure IP masquerading for this interface.  Depending on your needs,
 | 
				
			||||||
 | 
					    You may not want this if you have proper end-to-end routing set up, and want to have transparent
 | 
				
			||||||
 | 
					    inbound IP access to your GPRS-attached devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== Config Changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With the tun device pre-configured in one of the ways outlined above, the main
 | 
				
			||||||
 | 
					changes in your osmo-ggsn.cfg file are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* remove `ip ifconfig` directive,
 | 
				
			||||||
 | 
					* make sure that `no shutdown` is present in the `apn` section as well as
 | 
				
			||||||
 | 
					  `no shutdown ggsn` in the `ggsn` section.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: using externally configured tun device `apn0` as non-root
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					ggsn ggsn0
 | 
				
			||||||
 | 
					 gtp state-dir /tmp
 | 
				
			||||||
 | 
					 gtp bind-ip 127.0.0.6
 | 
				
			||||||
 | 
					 apn internet
 | 
				
			||||||
 | 
					  gtpu-mode tun
 | 
				
			||||||
 | 
					  tun-device apn0
 | 
				
			||||||
 | 
					  type-support v4
 | 
				
			||||||
 | 
					  ip prefix dynamic 192.168.7.0/24
 | 
				
			||||||
 | 
					  ip dns 0 192.168.100.1
 | 
				
			||||||
 | 
					  ip dns 1 8.8.8.8
 | 
				
			||||||
 | 
					  no shutdown
 | 
				
			||||||
 | 
					 default-apn internet
 | 
				
			||||||
 | 
					 no shutdown ggsn
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
							
								
								
									
										145
									
								
								doc/manuals/chapters/overview.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								doc/manuals/chapters/overview.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					[[chapter_introduction]]
 | 
				
			||||||
 | 
					== Overview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[intro_overview]]
 | 
				
			||||||
 | 
					=== About OsmoGGSN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoGGSN is a Free / Open Source Software implementation of the GPRS
 | 
				
			||||||
 | 
					GGSN (Gateway GPRS support node) element in side the packet switched
 | 
				
			||||||
 | 
					core network of 2G and 3G cellular networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The GGSN function is the tunnel endpoint on the core network side,
 | 
				
			||||||
 | 
					from where the external (IP) packet data network 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Software Components
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== GTP Implementation (libgtp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The OsmoGGSN source code includes a shared library implementation of
 | 
				
			||||||
 | 
					the GTP protocol used on the GGSN-SGSN interface.  This library
 | 
				
			||||||
 | 
					and associated header files are installed system-wide and are
 | 
				
			||||||
 | 
					available to other programs/applications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In fact, libgtp is what the OsmoSGSN also uses for its use of GTP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== sgsnemu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to test OsmoGGSN without running a SGSN and other elements
 | 
				
			||||||
 | 
					of a cellular network, there is a small command-line utility called
 | 
				
			||||||
 | 
					*sgsnemu* which is able to simulate the customary operations of a SGSN
 | 
				
			||||||
 | 
					towards the GGSN, such as a PDP Context Activation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*sgsnemu* can even be used for testing against other GGSNs, as the GTP
 | 
				
			||||||
 | 
					protocol is standardized across implementations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== osmo-ggsn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*osmo-ggsn* is the actual name of the OsmoGGSN executable program.  It
 | 
				
			||||||
 | 
					implements the GGSN functionality.  All parameters are set using the
 | 
				
			||||||
 | 
					configuration file, by default located in *./osmo-ggsn.cfg*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== systemd service file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In *contrib/osmo-ggsn.service* you can find a sample service file for
 | 
				
			||||||
 | 
					OsmoGGSN which can be used with systemd.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== init script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In *contrib/osmo-ggsn.init* you can find a sample init script to be used
 | 
				
			||||||
 | 
					on systems with classic init process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Limitations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoGGSN supports both GTP0 (GSM 09.60) and GTP1 (3GPP 29.060). In the
 | 
				
			||||||
 | 
					following tables the support of each individual message type is
 | 
				
			||||||
 | 
					detailed. The numbers before each feature indicates the relevant
 | 
				
			||||||
 | 
					section in the standard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== GSM 09.60 (GTPv0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[options="header",cols="50%,15%,15%,15%,5%"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					| Feature                | gtplib      | osmo-ggsn   | sgsnemu     | notes
 | 
				
			||||||
 | 
					5+<|*7.4 Path Management Messages*
 | 
				
			||||||
 | 
					|7.4.1 Echo Request      |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.4.2 Echo Response     |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.4.3 Version Not Supported      |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					5+<| *7.5 Tunnel Management Messages*
 | 
				
			||||||
 | 
					|7.5.1 Create PDP Context Request|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.5.2 Create PDP Context Response|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.5.3 Update PDP Context Request|Supported   |Supported   |Not         |
 | 
				
			||||||
 | 
					|7.5.4 Update PDP Context Response|Supported   |Supported   |Not         |
 | 
				
			||||||
 | 
					|7.5.5 Delete PDP Context Request|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.5.6 Delete PDP Context Response|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.5.7 Create AA PDP Context Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.8 Create AA PDP Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.9 Delete AA PDP Context Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.10 Delete AA PDP Context Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.11 Error Indication |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.5.12 PDU Notification Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.13 PDU Notification Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.14 PDU Notification Reject Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.5.15 PDU Notification Reject Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					5+<| *7.6 Location Management Messages*
 | 
				
			||||||
 | 
					|7.6.1 Send Routeing Information for GPRS Request|Unsupported |Unsupported |Not applicable  |
 | 
				
			||||||
 | 
					|7.6.2 Send Routeing Information for GPRS Response|Unsupported |Unsupported |Not applicable  |
 | 
				
			||||||
 | 
					|7.6.3 Failure Report Request|Unsupported |Unsupported |Not applicable |
 | 
				
			||||||
 | 
					|7.6.3 Failure Report Response|Unsupported |Unsupported |Not applicable |
 | 
				
			||||||
 | 
					|7.6.5 Note MS GPRS Present Request|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					|7.6.6 Note MS GPRS Present Response|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					5+<| *7.5 Mobility Management Messages*
 | 
				
			||||||
 | 
					|7.5.1 Identification Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.2 Identification Response|Unsupported |Not applicable|Not applicable |
 | 
				
			||||||
 | 
					|7.5.3 SGSN Context Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.4 SGSN Context Response|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.5 SGSN Context Acknowledge|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					==== 3GPP 29.060 (GTPv1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[options="header",cols="50%,15%,15%,15%,5%"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					|Feature                 |gtplib      |osmo-ggsn   |sgsnemu     |notes
 | 
				
			||||||
 | 
					5+<|*7.2 Path Management Messages*
 | 
				
			||||||
 | 
					|7.2.1 Echo Request      |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.2.2 Echo Response     |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.2.3 Version Not Supported|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.2.4 Extension Headers Notification|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					5+<|*7.3 Tunnel Management Messages*
 | 
				
			||||||
 | 
					|7.3.1 Create PDP Context Request|Supported   |Supported   |Supported   |1
 | 
				
			||||||
 | 
					|7.3.2 Create PDP Context Response|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.3.3 Update PDP Context Request|Supported   |Supported   |Not applicable|1
 | 
				
			||||||
 | 
					|7.3.4 Update PDP Context Response|Supported   |Supported   |Not applicable|
 | 
				
			||||||
 | 
					|7.3.5 Delete PDP Context Request|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.3.6 Delete PDP Context Response|Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.3.7 Error Indication  |Supported   |Supported   |Supported   |
 | 
				
			||||||
 | 
					|7.3.8 PDU Notification Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.3.9 PDU Notification Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.3.10 PDU Notification Reject Request|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					|7.3.10 PDU Notification Reject Response|Unsupported |Unsupported |Unsupported |
 | 
				
			||||||
 | 
					5+<|*7.4 Location Management Messages*
 | 
				
			||||||
 | 
					|7.4.1 Send Routeing Information for GPRS Request|Unsupported |Unsupported |Not applicable  |
 | 
				
			||||||
 | 
					|7.4.2 Send Routeing Information for GPRS Response|Unsupported |Unsupported |Not applicable  |
 | 
				
			||||||
 | 
					|7.4.3 Failure Report Request|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					|7.4.3 Failure Report Response|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					|7.4.5 Note MS GPRS Present Request|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					|7.4.6 Note MS GPRS Present Response|Unsupported |Unsupported |Not applicable|
 | 
				
			||||||
 | 
					5+<|*7.5 Mobility Management Messages*
 | 
				
			||||||
 | 
					|7.5.1 Identification Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.2 Identification Response|Unsupported |Not applicable |Not applicable|
 | 
				
			||||||
 | 
					|7.5.3 SGSN Context Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.4 SGSN Context Response|Unsupported |Not applicable |Not applicable|
 | 
				
			||||||
 | 
					|7.5.5 SGSN Context Acknowledge|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.6 Forward Relocation Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.7 Forward Relocation Response|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.8 Forward Relocation Complete|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.9 Relocation Cancel Request|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.10 Relocation Cancel Response|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.11 Forward Relocation Complete     |Unsupported |Not applicable |Not applicable  |
 | 
				
			||||||
 | 
					|7.5.12 Forward SRNS Context Acknowledge|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|7.5.13 Forward SRNS Context|Unsupported |Not applicable|Not applicable|
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) The "Secondary PDP Context Activation Procedure" is not supported.
 | 
				
			||||||
							
								
								
									
										126
									
								
								doc/manuals/chapters/running.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								doc/manuals/chapters/running.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					== Running OsmoGGSN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The OsmoGGSN executable (`osmo-ggsn`) offers the following command-line
 | 
				
			||||||
 | 
					arguments:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== SYNOPSIS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*osmo-ggsn* [-h|-V] [-D] [-c 'CONFIGFILE']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== OPTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*-h, --help*::
 | 
				
			||||||
 | 
						Print a short help message about the supported options
 | 
				
			||||||
 | 
					*-V, --version*::
 | 
				
			||||||
 | 
						Print the compile-time version number of the program
 | 
				
			||||||
 | 
					*-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-ggsn.cfg` in the current
 | 
				
			||||||
 | 
						working directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Routing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Operating the OpenGGSN tun device naturally creates a network setup with
 | 
				
			||||||
 | 
					multiple interfaces. Consider:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Typical Linux setups prevent forwarding of packets between separate
 | 
				
			||||||
 | 
					  interfaces by default. To let subscribers reach the internet uplink from the
 | 
				
			||||||
 | 
					  tun device, it may be required to enable IP forwarding.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Having a locally defined address range assigned to the tun device requires
 | 
				
			||||||
 | 
					  either sensible routing for this address range, or that masquerading is
 | 
				
			||||||
 | 
					  enabled to allow your single uplink IP address to "proxy" for the tun.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These are decisions to be made on a network administration level.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In a trivial case where you have a single box serving GPRS to few subscribers
 | 
				
			||||||
 | 
					on an arbitrary IP address range not known in the larger network, the easiest
 | 
				
			||||||
 | 
					way to enable GPRS uplink would be to enable IP forwarding and masquerading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To manually enable IPv4 forwarding and masquerading ad-hoc, you can do:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
 | 
				
			||||||
 | 
					iptables -t nat -A POSTROUTING -o '*' -j MASQUERADE
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(You may want to replace `*` with the network device name, like `-o eth0`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are various ways to enable these settings persistently, please refer to
 | 
				
			||||||
 | 
					your distribution's documentation -- e.g. look for @net.ipv4.ip_forward=1@ in
 | 
				
			||||||
 | 
					@/etc/sysctl.d/@, and https://wiki.debian.org/iptables for masquerading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Multiple instances
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Running multiple instances of `osmo-ggsn` is possible if all GGSN instances
 | 
				
			||||||
 | 
					are binding to different local IP addresse and all other interfaces (VTY,
 | 
				
			||||||
 | 
					OML) are separated using the appropriate configuration options. The IP based
 | 
				
			||||||
 | 
					interfaces are binding to local host by default. In order to separate the
 | 
				
			||||||
 | 
					processes, the user has to bind those services to specific but different
 | 
				
			||||||
 | 
					IP addresses.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The VTY and the control interface can be bound to IP addresses from the loopback
 | 
				
			||||||
 | 
					address range.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: Binding VTY and control interface to a specific ip-address
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					line vty
 | 
				
			||||||
 | 
					 bind 127.0.0.2
 | 
				
			||||||
 | 
					ctrl
 | 
				
			||||||
 | 
					 bind 127.0.0.2
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also make sure to place each instance's GTP bind on a separate IP address (GTP
 | 
				
			||||||
 | 
					uses a port number that is fixed in the GTP specifications, so it will not be
 | 
				
			||||||
 | 
					possible to pick differing ports on the same IP address), like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					ggsn ggsn0
 | 
				
			||||||
 | 
					 gtp bind-ip 127.0.0.2
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== GTP-U kernel module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WARNING: As of writing, the kernel module does not support IPv6.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoGGSN has support to use the Linux kernel GTP-U tunnel driver to accelerate
 | 
				
			||||||
 | 
					the data/user plane while still implementing the control plane (GTP-C) in
 | 
				
			||||||
 | 
					userspace in OsmoGGSN. The kernel module is included in Linux 4.7.0 and higher.
 | 
				
			||||||
 | 
					Notably the Debian GNU/Linux distribution has it enabled by default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to use this feature, make sure that your Linux kernel was configured
 | 
				
			||||||
 | 
					to support it (`CONFIG_GTP=m` or `=y`). Furthermore, `osmo-ggsn` must have been
 | 
				
			||||||
 | 
					built with `./configure` argument `--enable-gtp-linux` (which requires libgtpnl
 | 
				
			||||||
 | 
					to be installed).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Load the kernel module with:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					$ sudo modprobe gtp
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then start OsmoGGSN with a configuration file that uses `gtpu-mode kernel-gtp`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A full example configuration is in `osmo-ggsn-kernel-gtp.cfg`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					$ sudo osmo-ggsn -c /usr/share/doc/osmo-ggsn/examples/osmo-ggsn-kernel-gtp.cfg
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example: APN with kernel-gtp
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					ggsn ggsn0
 | 
				
			||||||
 | 
					 gtp state-dir /tmp
 | 
				
			||||||
 | 
					 gtp bind-ip 127.0.0.2
 | 
				
			||||||
 | 
					 apn internet
 | 
				
			||||||
 | 
					  gtpu-mode kernel-gtp
 | 
				
			||||||
 | 
					  tun-device tun4
 | 
				
			||||||
 | 
					  type-support v4
 | 
				
			||||||
 | 
					  ip prefix dynamic 172.16.222.0/24
 | 
				
			||||||
 | 
					  ip dns 0 8.8.8.8
 | 
				
			||||||
 | 
					  ip dns 1 8.8.4.4
 | 
				
			||||||
 | 
					  ip ifconfig 172.16.222.0/24
 | 
				
			||||||
 | 
					  no shutdown
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
							
								
								
									
										46
									
								
								doc/manuals/osmoggsn-usermanual-docinfo.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								doc/manuals/osmoggsn-usermanual-docinfo.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					<revhistory>
 | 
				
			||||||
 | 
					  <revision>
 | 
				
			||||||
 | 
					    <revnumber>1</revnumber>
 | 
				
			||||||
 | 
					    <date>August 2017</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-2017</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="http://git.osmocom.org/osmo-gsm-manuals/">
 | 
				
			||||||
 | 
							http://git.osmocom.org/osmo-gsm-manuals/
 | 
				
			||||||
 | 
						</ulink>
 | 
				
			||||||
 | 
					  </para>
 | 
				
			||||||
 | 
					</legalnotice>
 | 
				
			||||||
							
								
								
									
										31
									
								
								doc/manuals/osmoggsn-usermanual.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								doc/manuals/osmoggsn-usermanual.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					OsmoGGSN User Manual
 | 
				
			||||||
 | 
					====================
 | 
				
			||||||
 | 
					Harald Welte <hwelte@sysmocom.de>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/preface.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::{srcdir}/chapters/overview.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::{srcdir}/chapters/running.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//include::{srcdir}/chapters/control.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/vty.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/logging.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::{srcdir}/chapters/configuration.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/control_if.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/vty_cpu_sched.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/port_numbers.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/bibliography.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/glossary.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/gfdl.adoc[]
 | 
				
			||||||
							
								
								
									
										38
									
								
								doc/manuals/osmoggsn-vty-reference.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								doc/manuals/osmoggsn-vty-reference.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					<?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_vty.xml"  >
 | 
				
			||||||
 | 
					]>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<book>
 | 
				
			||||||
 | 
					  <info>
 | 
				
			||||||
 | 
					    <revhistory>
 | 
				
			||||||
 | 
					        <revision>
 | 
				
			||||||
 | 
					            <revnumber>v1</revnumber>
 | 
				
			||||||
 | 
					            <date>06th September 2017</date>
 | 
				
			||||||
 | 
					            <authorinitials>hw</authorinitials>
 | 
				
			||||||
 | 
					            <revremark>Initial version as of OsmoGGSN v1.0.0</revremark>
 | 
				
			||||||
 | 
					        </revision>
 | 
				
			||||||
 | 
					    </revhistory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <title>OsmoGGSN VTY Reference</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <copyright>
 | 
				
			||||||
 | 
					      <year>2017</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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								doc/manuals/regen_doc.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								doc/manuals/regen_doc.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					#!/bin/sh -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -z "$DOCKER_PLAYGROUND" ]; then
 | 
				
			||||||
 | 
						echo "You need to set DOCKER_PLAYGROUND"
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SCRIPT=$(realpath "$0")
 | 
				
			||||||
 | 
					MANUAL_DIR=$(dirname "$SCRIPT")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd "$DOCKER_PLAYGROUND/scripts" || exit 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OSMO_GGSN_BRANCH=$COMMIT ./regen_doc.sh osmo-ggsn 4260 \
 | 
				
			||||||
 | 
						"$MANUAL_DIR/chapters/counters_generated.adoc" \
 | 
				
			||||||
 | 
						"$MANUAL_DIR/vty/ggsn_vty_reference.xml"
 | 
				
			||||||
							
								
								
									
										30
									
								
								doc/manuals/vty/ggsn_vty_additions.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								doc/manuals/vty/ggsn_vty_additions.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
 | 
				
			||||||
 | 
						<node id='config-line'>
 | 
				
			||||||
 | 
							<child_of nodeid='config' />
 | 
				
			||||||
 | 
							<name>Telnet/VTY Configuration Node</name>
 | 
				
			||||||
 | 
							<description>
 | 
				
			||||||
 | 
								Configure parameters of the Telnet/VTY Interface, such as to which IP address it should bind/listen to.
 | 
				
			||||||
 | 
							</description>
 | 
				
			||||||
 | 
						</node>
 | 
				
			||||||
 | 
						<node id='config-ctrl'>
 | 
				
			||||||
 | 
							<child_of nodeid='config' />
 | 
				
			||||||
 | 
							<name>CTRL Configuration Node</name>
 | 
				
			||||||
 | 
							<description>
 | 
				
			||||||
 | 
								Configure parameters of the CTRL Interface, such as to which IP address it should bind/listen to.
 | 
				
			||||||
 | 
							</description>
 | 
				
			||||||
 | 
						</node>
 | 
				
			||||||
 | 
						<node id='config-ggsn'>
 | 
				
			||||||
 | 
							<child_of nodeid='config' />
 | 
				
			||||||
 | 
							<name>GGSN Instance Configuration Node</name>
 | 
				
			||||||
 | 
							<description>
 | 
				
			||||||
 | 
								Configure an Instance of a (virtual) GGSN
 | 
				
			||||||
 | 
							</description>
 | 
				
			||||||
 | 
						</node>
 | 
				
			||||||
 | 
						<node id='config-ggsn-apn'>
 | 
				
			||||||
 | 
							<child_of nodeid='config-ggsn' />
 | 
				
			||||||
 | 
							<name>APN Configuration Node</name>
 | 
				
			||||||
 | 
							<description>
 | 
				
			||||||
 | 
								Configure an Access Point Name (APN) inside a GGSN Instance
 | 
				
			||||||
 | 
							</description>
 | 
				
			||||||
 | 
						</node>
 | 
				
			||||||
 | 
					</vtydoc>
 | 
				
			||||||
@@ -7,13 +7,9 @@ AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb
 | 
				
			|||||||
osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
 | 
					osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ENABLE_GTP_KERNEL
 | 
					if ENABLE_GTP_KERNEL
 | 
				
			||||||
AM_CFLAGS += -DGTP_KERNEL
 | 
					AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
 | 
				
			||||||
osmo_ggsn_LDADD += -lgtpnl
 | 
					osmo_ggsn_LDADD += $(LIBGTPNL_LIBS)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo_ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
 | 
					osmo_ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
 | 
				
			||||||
osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h
 | 
					osmo_ggsn_SOURCES = ggsn_main.c ggsn_vty.c ggsn.c ggsn.h sgsn.c sgsn.h pco.c pco.h
 | 
				
			||||||
 | 
					 | 
				
			||||||
if ENABLE_GTP_KERNEL
 | 
					 | 
				
			||||||
osmo_ggsn_SOURCES += gtp-kernel.c
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										845
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							
							
						
						
									
										845
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										35
									
								
								ggsn/ggsn.h
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								ggsn/ggsn.h
									
									
									
									
									
								
							@@ -6,6 +6,7 @@
 | 
				
			|||||||
#include <osmocom/core/linuxlist.h>
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
#include <osmocom/core/select.h>
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../lib/tun.h"
 | 
					#include "../lib/tun.h"
 | 
				
			||||||
#include "../lib/ippool.h"
 | 
					#include "../lib/ippool.h"
 | 
				
			||||||
@@ -13,6 +14,8 @@
 | 
				
			|||||||
#include "../lib/in46_addr.h"
 | 
					#include "../lib/in46_addr.h"
 | 
				
			||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "sgsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define APN_TYPE_IPv4	0x01	/* v4-only */
 | 
					#define APN_TYPE_IPv4	0x01	/* v4-only */
 | 
				
			||||||
#define APN_TYPE_IPv6	0x02	/* v6-only */
 | 
					#define APN_TYPE_IPv6	0x02	/* v6-only */
 | 
				
			||||||
#define APN_TYPE_IPv4v6	0x04	/* v4v6 dual-stack */
 | 
					#define APN_TYPE_IPv4v6	0x04	/* v4v6 dual-stack */
 | 
				
			||||||
@@ -22,6 +25,7 @@ struct ggsn_ctx;
 | 
				
			|||||||
struct apn_ctx_ip {
 | 
					struct apn_ctx_ip {
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct in46_prefix ifconfig_prefix;
 | 
							struct in46_prefix ifconfig_prefix;
 | 
				
			||||||
 | 
							struct in46_prefix ll_prefix;
 | 
				
			||||||
		struct in46_prefix static_prefix;
 | 
							struct in46_prefix static_prefix;
 | 
				
			||||||
		struct in46_prefix dynamic_prefix;
 | 
							struct in46_prefix dynamic_prefix;
 | 
				
			||||||
		/* v4 DNS server names */
 | 
							/* v4 DNS server names */
 | 
				
			||||||
@@ -87,6 +91,14 @@ struct apn_ctx {
 | 
				
			|||||||
	struct apn_ctx_ip v6;
 | 
						struct apn_ctx_ip v6;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pdp_priv_t {
 | 
				
			||||||
 | 
						struct pdp_t *lib; /* pointer to libgtp associated pdp_t instance */
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
 | 
						struct llist_head entry; /* to be included into sgsn_peer */
 | 
				
			||||||
 | 
						/* struct ggsn_ctx can be reached through lib->gsn->priv, or through sgsn->ggsn */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ggsn_ctx {
 | 
					struct ggsn_ctx {
 | 
				
			||||||
	/* global list of GGSNs */
 | 
						/* global list of GGSNs */
 | 
				
			||||||
	struct llist_head list;
 | 
						struct llist_head list;
 | 
				
			||||||
@@ -94,6 +106,9 @@ struct ggsn_ctx {
 | 
				
			|||||||
	/* list of APNs in this GGSN */
 | 
						/* list of APNs in this GGSN */
 | 
				
			||||||
	struct llist_head apn_list;
 | 
						struct llist_head apn_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* list of SGSN peers (struct sgsn_peer) in this GGSN. TODO: hash table with key <ip+port>? */
 | 
				
			||||||
 | 
						struct llist_head sgsn_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool started;
 | 
						bool started;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
@@ -110,6 +125,8 @@ struct ggsn_ctx {
 | 
				
			|||||||
		struct in46_addr gtpu_addr;
 | 
							struct in46_addr gtpu_addr;
 | 
				
			||||||
		/* directory for state file */
 | 
							/* directory for state file */
 | 
				
			||||||
		char *state_dir;
 | 
							char *state_dir;
 | 
				
			||||||
 | 
							/* Time between Echo requests on each SGSN */
 | 
				
			||||||
 | 
							unsigned int echo_interval;
 | 
				
			||||||
		/* administratively shut-down (true) or not (false) */
 | 
							/* administratively shut-down (true) or not (false) */
 | 
				
			||||||
		bool shutdown;
 | 
							bool shutdown;
 | 
				
			||||||
	} cfg;
 | 
						} cfg;
 | 
				
			||||||
@@ -121,8 +138,6 @@ struct ggsn_ctx {
 | 
				
			|||||||
	struct osmo_fd gtp_fd0;
 | 
						struct osmo_fd gtp_fd0;
 | 
				
			||||||
	struct osmo_fd gtp_fd1c;
 | 
						struct osmo_fd gtp_fd1c;
 | 
				
			||||||
	struct osmo_fd gtp_fd1u;
 | 
						struct osmo_fd gtp_fd1u;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct osmo_timer_list gtp_timer;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ggsn_vty.c */
 | 
					/* ggsn_vty.c */
 | 
				
			||||||
@@ -134,9 +149,21 @@ struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name);
 | 
				
			|||||||
struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name);
 | 
					struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name);
 | 
				
			||||||
struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name);
 | 
					struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ggsn.c */
 | 
					/* ggsn_main.c */
 | 
				
			||||||
 | 
					extern struct ctrl_handle *g_ctrlh;
 | 
				
			||||||
extern void *tall_ggsn_ctx;
 | 
					extern void *tall_ggsn_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ggsn.c */
 | 
				
			||||||
extern int ggsn_start(struct ggsn_ctx *ggsn);
 | 
					extern int ggsn_start(struct ggsn_ctx *ggsn);
 | 
				
			||||||
extern int ggsn_stop(struct ggsn_ctx *ggsn);
 | 
					extern int ggsn_stop(struct ggsn_ctx *ggsn);
 | 
				
			||||||
extern int apn_start(struct apn_ctx *apn);
 | 
					extern int apn_start(struct apn_ctx *apn);
 | 
				
			||||||
extern int apn_stop(struct apn_ctx *apn, bool force);
 | 
					extern int apn_stop(struct apn_ctx *apn);
 | 
				
			||||||
 | 
					void ggsn_close_one_pdp(struct pdp_t *pdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPAPN(level, apn, fmt, args...)			\
 | 
				
			||||||
 | 
						LOGP(DGGSN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPGGSN(level, ggsn, fmt, args...)			\
 | 
				
			||||||
 | 
						LOGP(DGGSN, level, "GGSN(%s): " fmt, (ggsn)->cfg.name, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPPDP(level, pdp, fmt, args...) LOGPDPX(DGGSN, level, pdp, fmt, ## args)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										256
									
								
								ggsn/ggsn_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								ggsn/ggsn_main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,256 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 | 
					 * Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 | 
					 * Copyright (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_STDINT_H
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stats.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_cmd.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_vty.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/ports.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/command.h>
 | 
				
			||||||
 | 
					#include <osmocom/vty/misc.h>
 | 
				
			||||||
 | 
					#include <osmocom/vty/cpu_sched_vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ggsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *tall_ggsn_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int end = 0;
 | 
				
			||||||
 | 
					static int daemonize = 0;
 | 
				
			||||||
 | 
					struct ctrl_handle *g_ctrlh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ul255_t qos;
 | 
				
			||||||
 | 
					struct ul255_t apn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *config_file = "osmo-ggsn.cfg";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
 | 
				
			||||||
 | 
					static void signal_handler(int s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGP(DGGSN, LOGL_NOTICE, "signal %d received\n", s);
 | 
				
			||||||
 | 
						switch (s) {
 | 
				
			||||||
 | 
						case SIGINT:
 | 
				
			||||||
 | 
						case SIGTERM:
 | 
				
			||||||
 | 
							LOGP(DGGSN, LOGL_NOTICE, "SIGINT received, shutting down\n");
 | 
				
			||||||
 | 
							end = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGABRT:
 | 
				
			||||||
 | 
							/* in case of abort, we want to obtain a talloc report and
 | 
				
			||||||
 | 
							 * then run default SIGABRT handler, who will generate coredump
 | 
				
			||||||
 | 
							 * and abort the process. abort() should do this for us after we
 | 
				
			||||||
 | 
							 * return, but program wouldn't exit if an external SIGABRT is
 | 
				
			||||||
 | 
							 * received.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_ggsn_ctx, stderr);
 | 
				
			||||||
 | 
							signal(SIGABRT, SIG_DFL);
 | 
				
			||||||
 | 
							raise(SIGABRT);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGUSR1:
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_ggsn_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGUSR2:
 | 
				
			||||||
 | 
							talloc_report_full(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_usage()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("Usage: osmo-ggsn [-h] [-D] [-c configfile] [-V]\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_help()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf(	"  Some useful help...\n"
 | 
				
			||||||
 | 
							"  -h --help		This help text\n"
 | 
				
			||||||
 | 
							"  -D --daemonize	Fork the process into a background daemon\n"
 | 
				
			||||||
 | 
							"  -c --config-file	filename The config file to use\n"
 | 
				
			||||||
 | 
							"  -V --version		Print the version of OsmoGGSN\n"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("\nVTY reference generation:\n");
 | 
				
			||||||
 | 
						printf("     --vty-ref-mode MODE        VTY reference generation mode (e.g. 'expert').\n");
 | 
				
			||||||
 | 
						printf("     --vty-ref-xml              Generate the VTY reference XML output and exit.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_long_options(const char *prog_name, const int long_option)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (long_option) {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
 | 
				
			||||||
 | 
							if (vty_ref_mode < 0) {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s: Unknown VTY reference generation "
 | 
				
			||||||
 | 
									"mode '%s'\n", prog_name, optarg);
 | 
				
			||||||
 | 
								exit(2);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
 | 
				
			||||||
 | 
								get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
 | 
				
			||||||
 | 
								get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
 | 
				
			||||||
 | 
							vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
 | 
				
			||||||
 | 
							exit(0);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
 | 
				
			||||||
 | 
							exit(2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_options(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							int option_index = 0, c;
 | 
				
			||||||
 | 
							static int long_option = 0;
 | 
				
			||||||
 | 
							static struct option long_options[] = {
 | 
				
			||||||
 | 
								{ "help", 0, 0, 'h' },
 | 
				
			||||||
 | 
								{ "daemonize", 0, 0, 'D' },
 | 
				
			||||||
 | 
								{ "config-file", 1, 0, 'c' },
 | 
				
			||||||
 | 
								{ "version", 0, 0, 'V' },
 | 
				
			||||||
 | 
								{ "vty-ref-mode", 1, &long_option, 1 },
 | 
				
			||||||
 | 
								{ "vty-ref-xml", 0, &long_option, 2 },
 | 
				
			||||||
 | 
								{ 0, 0, 0, 0 }
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c = getopt_long(argc, argv, "hdc:V", long_options, &option_index);
 | 
				
			||||||
 | 
							if (c == -1)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								handle_long_options(argv[0], long_option);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'h':
 | 
				
			||||||
 | 
								print_usage();
 | 
				
			||||||
 | 
								print_help();
 | 
				
			||||||
 | 
								exit(0);
 | 
				
			||||||
 | 
							case 'D':
 | 
				
			||||||
 | 
								daemonize = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'c':
 | 
				
			||||||
 | 
								config_file = optarg;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'V':
 | 
				
			||||||
 | 
								print_version(1);
 | 
				
			||||||
 | 
								exit(0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
 | 
				
			||||||
 | 
						g_vty_info.tall_ctx = tall_ggsn_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle keyboard interrupt SIGINT */
 | 
				
			||||||
 | 
						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_ggsn_ctx, &log_info);
 | 
				
			||||||
 | 
						osmo_stats_init(tall_ggsn_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_init(&g_vty_info);
 | 
				
			||||||
 | 
						logging_vty_add_cmds();
 | 
				
			||||||
 | 
						osmo_talloc_vty_add_cmds();
 | 
				
			||||||
 | 
						osmo_stats_vty_add_cmds();
 | 
				
			||||||
 | 
						ggsn_vty_init();
 | 
				
			||||||
 | 
						ctrl_vty_init(tall_ggsn_ctx);
 | 
				
			||||||
 | 
						osmo_cpu_sched_vty_init(tall_ggsn_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handle_options(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rate_ctr_init(tall_ggsn_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = vty_read_config_file(config_file, NULL);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
 | 
				
			||||||
 | 
							exit(2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
 | 
				
			||||||
 | 
										     OSMO_CTRL_PORT_GGSN, NULL);
 | 
				
			||||||
 | 
						if (!g_ctrlh) {
 | 
				
			||||||
 | 
							LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (daemonize) {
 | 
				
			||||||
 | 
							rc = osmo_daemonize();
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								perror("Error during daemonize");
 | 
				
			||||||
 | 
								exit(1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						/* qos                                                             */
 | 
				
			||||||
 | 
						qos.l = 3;
 | 
				
			||||||
 | 
						qos.v[2] = (args_info.qos_arg) & 0xff;
 | 
				
			||||||
 | 
						qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
 | 
				
			||||||
 | 
						qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Main select loop */
 | 
				
			||||||
 | 
						while (!end) {
 | 
				
			||||||
 | 
							osmo_select_main(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(ggsn, &g_ggsn_list, list)
 | 
				
			||||||
 | 
							ggsn_stop(ggsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										317
									
								
								ggsn/ggsn_vty.c
									
									
									
									
									
								
							
							
						
						
									
										317
									
								
								ggsn/ggsn_vty.c
									
									
									
									
									
								
							@@ -26,6 +26,8 @@
 | 
				
			|||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/apn.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm48_ie.h>
 | 
				
			||||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
					#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/command.h>
 | 
					#include <osmocom/vty/command.h>
 | 
				
			||||||
@@ -35,7 +37,10 @@
 | 
				
			|||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../lib/util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ggsn.h"
 | 
					#include "ggsn.h"
 | 
				
			||||||
 | 
					#include "sgsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PREFIX_STR	"Prefix (Network/Netmask)\n"
 | 
					#define PREFIX_STR	"Prefix (Network/Netmask)\n"
 | 
				
			||||||
#define IFCONFIG_STR	"GGSN-based interface configuration\n"
 | 
					#define IFCONFIG_STR	"GGSN-based interface configuration\n"
 | 
				
			||||||
@@ -75,6 +80,7 @@ struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name)
 | 
				
			|||||||
	ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
 | 
						ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
 | 
				
			||||||
	ggsn->cfg.shutdown = true;
 | 
						ggsn->cfg.shutdown = true;
 | 
				
			||||||
	INIT_LLIST_HEAD(&ggsn->apn_list);
 | 
						INIT_LLIST_HEAD(&ggsn->apn_list);
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&ggsn->sgsn_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_add_tail(&ggsn->list, &g_ggsn_list);
 | 
						llist_add_tail(&ggsn->list, &g_ggsn_list);
 | 
				
			||||||
	return ggsn;
 | 
						return ggsn;
 | 
				
			||||||
@@ -324,6 +330,80 @@ DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void show_one_sgsn(struct vty *vty, const struct sgsn_peer *sgsn, const char* prefix)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[INET_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inet_ntop(AF_INET, &sgsn->addr, buf, sizeof(buf));
 | 
				
			||||||
 | 
						vty_out(vty, "%s(S)GSN %s%s", prefix, buf, VTY_NEWLINE);
 | 
				
			||||||
 | 
						vty_out(vty, "%s Restart Counter: %d%s", prefix, sgsn->remote_restart_ctr, VTY_NEWLINE);
 | 
				
			||||||
 | 
						vty_out(vty, "%s PDP contexts: %d%s", prefix, llist_count(&sgsn->pdp_list), VTY_NEWLINE);
 | 
				
			||||||
 | 
						vty_out(vty, "%s Echo Requests in-flight: %u%s", prefix, sgsn->tx_msgs_queued, VTY_NEWLINE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_ggsn_show_sgsn, cfg_ggsn_show_sgsn_cmd,
 | 
				
			||||||
 | 
						"show sgsn",
 | 
				
			||||||
 | 
						NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry) {
 | 
				
			||||||
 | 
							show_one_sgsn(vty, sgsn, "");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Seee 3GPP TS 29.060 section 7.2.1 */
 | 
				
			||||||
 | 
					DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
 | 
				
			||||||
 | 
						"echo-interval <1-36000>",
 | 
				
			||||||
 | 
						GGSN_STR "GGSN Number\n"
 | 
				
			||||||
 | 
						"Send an echo request to this static GGSN every interval\n"
 | 
				
			||||||
 | 
						"Interval between echo requests in seconds\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
 | 
				
			||||||
 | 
						int prev_interval = ggsn->cfg.echo_interval;
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ggsn->cfg.echo_interval = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ggsn->cfg.echo_interval < 60)
 | 
				
			||||||
 | 
							vty_out(vty, "%% 3GPP TS 29.060 section states interval should " \
 | 
				
			||||||
 | 
								     "not be lower than 60 seconds, use this value for " \
 | 
				
			||||||
 | 
								     "testing purposes only!%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (prev_interval == ggsn->cfg.echo_interval)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Re-enable echo timer for all sgsn */
 | 
				
			||||||
 | 
						llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
 | 
				
			||||||
 | 
							sgsn_echo_timer_start(sgsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
 | 
				
			||||||
 | 
						"no echo-interval",
 | 
				
			||||||
 | 
						GGSN_STR "GGSN Number\n"
 | 
				
			||||||
 | 
						NO_STR "Send an echo request to this static GGSN every interval.\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
 | 
				
			||||||
 | 
						int prev_interval = ggsn->cfg.echo_interval;
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (prev_interval == ggsn->cfg.echo_interval)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ggsn->cfg.echo_interval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable echo timer for all sgsn */
 | 
				
			||||||
 | 
						llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
 | 
				
			||||||
 | 
							sgsn_echo_timer_stop(sgsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* APN Node */
 | 
					/* APN Node */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cmd_node apn_node = {
 | 
					static struct cmd_node apn_node = {
 | 
				
			||||||
@@ -453,9 +533,11 @@ DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
 | 
				
			|||||||
	struct in46_prefix *pfx;
 | 
						struct in46_prefix *pfx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* first update our parsed prefix */
 | 
						/* first update our parsed prefix */
 | 
				
			||||||
	if (!strcmp(argv[0], "static"))
 | 
						if (!strcmp(argv[0], "static")) {
 | 
				
			||||||
		pfx = &apn->v4.cfg.static_prefix;
 | 
							pfx = &apn->v4.cfg.static_prefix;
 | 
				
			||||||
	else
 | 
							vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
		pfx = &apn->v4.cfg.dynamic_prefix;
 | 
							pfx = &apn->v4.cfg.dynamic_prefix;
 | 
				
			||||||
	str2prefix(pfx, argv[1]);
 | 
						str2prefix(pfx, argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -487,9 +569,11 @@ DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
 | 
				
			|||||||
	struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
						struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
				
			||||||
	struct in46_prefix *pfx;
 | 
						struct in46_prefix *pfx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strcmp(argv[0], "static"))
 | 
						if (!strcmp(argv[0], "static")) {
 | 
				
			||||||
		pfx = &apn->v6.cfg.static_prefix;
 | 
							pfx = &apn->v6.cfg.static_prefix;
 | 
				
			||||||
	else
 | 
							vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
		pfx = &apn->v6.cfg.dynamic_prefix;
 | 
							pfx = &apn->v6.cfg.dynamic_prefix;
 | 
				
			||||||
	str2prefix(pfx, argv[1]);
 | 
						str2prefix(pfx, argv[1]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -513,6 +597,24 @@ DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_apn_ipv6_linklocal, cfg_apn_ipv6_linklocal_cmd,
 | 
				
			||||||
 | 
						"ipv6 link-local X:X::X:X/M",
 | 
				
			||||||
 | 
						IP6_STR IFCONFIG_STR "IPv6 Link-local Adress/Prefix-Length\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
				
			||||||
 | 
						str2prefix(&apn->v6.cfg.ll_prefix, argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_apn_no_ipv6_linklocal, cfg_apn_no_ipv6_linklocal_cmd,
 | 
				
			||||||
 | 
						"no ipv6 link-local",
 | 
				
			||||||
 | 
						NO_STR IP6_STR IFCONFIG_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
				
			||||||
 | 
						memset(&apn->v6.cfg.ll_prefix, 0, sizeof(apn->v6.cfg.ll_prefix));
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
 | 
					#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
 | 
					DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
 | 
				
			||||||
@@ -584,7 +686,7 @@ DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
 | 
				
			|||||||
	struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
						struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!apn->cfg.shutdown) {
 | 
						if (!apn->cfg.shutdown) {
 | 
				
			||||||
		if (apn_stop(apn, false)) {
 | 
							if (apn_stop(apn)) {
 | 
				
			||||||
			vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
 | 
								vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
 | 
				
			||||||
			return CMD_WARNING;
 | 
								return CMD_WARNING;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -601,6 +703,10 @@ DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
 | 
				
			|||||||
	struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
						struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (apn->cfg.shutdown) {
 | 
						if (apn->cfg.shutdown) {
 | 
				
			||||||
 | 
							if (!apn->tun.cfg.dev_name) {
 | 
				
			||||||
 | 
								vty_out(vty, "%% Failed to start APN, tun-device is not configured%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
								return CMD_WARNING;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (apn_start(apn) < 0) {
 | 
							if (apn_start(apn) < 0) {
 | 
				
			||||||
			vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
 | 
								vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
 | 
				
			||||||
			return CMD_WARNING;
 | 
								return CMD_WARNING;
 | 
				
			||||||
@@ -634,9 +740,9 @@ static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
 | 
				
			|||||||
		vty_out(vty, "  ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
 | 
							vty_out(vty, "  ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 32; i++) {
 | 
						for (i = 0; i < 32; i++) {
 | 
				
			||||||
		if (!(apn->cfg.apn_type_mask & (1 << i)))
 | 
							if (!(apn->cfg.apn_type_mask & (UINT32_C(1) << i)))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		vty_out(vty, "  type-support %s%s", get_value_string(pdp_type_names, (1 << i)),
 | 
							vty_out(vty, "  type-support %s%s", get_value_string(pdp_type_names, (UINT32_C(1) << i)),
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -668,6 +774,8 @@ static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if (apn->v6.cfg.ifconfig_prefix.addr.len)
 | 
						if (apn->v6.cfg.ifconfig_prefix.addr.len)
 | 
				
			||||||
		vty_dump_prefix(vty, "  ipv6 ifconfig", &apn->v6.cfg.ifconfig_prefix);
 | 
							vty_dump_prefix(vty, "  ipv6 ifconfig", &apn->v6.cfg.ifconfig_prefix);
 | 
				
			||||||
 | 
						if (apn->v6.cfg.ll_prefix.addr.len)
 | 
				
			||||||
 | 
							vty_dump_prefix(vty, "  ipv6 link-local", &apn->v6.cfg.ll_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* must be last */
 | 
						/* must be last */
 | 
				
			||||||
	vty_out(vty, "  %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
 | 
						vty_out(vty, "  %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
@@ -692,6 +800,8 @@ static int config_write_ggsn(struct vty *vty)
 | 
				
			|||||||
			config_write_apn(vty, apn);
 | 
								config_write_apn(vty, apn);
 | 
				
			||||||
		if (ggsn->cfg.default_apn)
 | 
							if (ggsn->cfg.default_apn)
 | 
				
			||||||
			vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
 | 
								vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
 | 
				
			||||||
 | 
							if (ggsn->cfg.echo_interval)
 | 
				
			||||||
 | 
								vty_out(vty, " echo-interval %u%s", ggsn->cfg.echo_interval, VTY_NEWLINE);
 | 
				
			||||||
		/* must be last */
 | 
							/* must be last */
 | 
				
			||||||
		vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
 | 
							vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -710,12 +820,42 @@ static const char *print_gsnaddr(const struct ul16_t *in)
 | 
				
			|||||||
	return in46a_ntoa(&in46);
 | 
						return in46a_ntoa(&in46);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
 | 
					/* Useful for v4v6 APNs, where we first iterate over v4 pool and then over v6
 | 
				
			||||||
 | 
					   pool. param v4only can be used to avoid printing duplicates for pdp context
 | 
				
			||||||
 | 
					   containing both IPv4 and IPv6 addresses. */
 | 
				
			||||||
 | 
					static void show_one_pdp_v4only(struct vty *vty, struct pdp_t *pdp, bool v4only)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in46_addr eua46;
 | 
						struct ippoolm_t *peer4, *peer6;
 | 
				
			||||||
 | 
						char name_buf[256];
 | 
				
			||||||
 | 
						char *apn_name;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						peer4 = pdp_get_peer_ipv(pdp, false);
 | 
				
			||||||
 | 
						peer6 = pdp_get_peer_ipv(pdp, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (v4only && peer6)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Attempt to decode MSISDN */
 | 
				
			||||||
 | 
						rc = gsm48_decode_bcd_number2(name_buf, sizeof(name_buf),
 | 
				
			||||||
 | 
									      pdp->msisdn.v, pdp->msisdn.l, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
 | 
						vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
 | 
				
			||||||
		osmo_hexdump_nospc(pdp->msisdn.v, pdp->msisdn.l), VTY_NEWLINE);
 | 
							rc ? "(NONE)" : name_buf, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_out(vty, " Version: %d", pdp->version);
 | 
				
			||||||
 | 
						if (pdp->version == 1) {
 | 
				
			||||||
 | 
							if (!pdp->secondary) {
 | 
				
			||||||
 | 
								vty_out(vty, ", Primary, Num Secondaries: %d%s%s",
 | 
				
			||||||
 | 
									pdp_count_secondary(pdp) - 1, /* primary included in count */
 | 
				
			||||||
 | 
									pdp->nodata ? ", No User Plane": "",
 | 
				
			||||||
 | 
									VTY_NEWLINE);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								vty_out(vty, ", Secondary%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vty_out(vty, "%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
 | 
						vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
 | 
				
			||||||
	vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
 | 
						vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
 | 
				
			||||||
@@ -723,32 +863,61 @@ static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
 | 
				
			|||||||
	vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
 | 
						vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
 | 
				
			||||||
	vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
 | 
						vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	in46a_from_eua(&pdp->eua, &eua46);
 | 
						apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
 | 
				
			||||||
	vty_out(vty, " End-User Address: %s%s", in46a_ntoa(&eua46), VTY_NEWLINE);
 | 
						vty_out(vty, " APN requested: %s%s", apn_name ? name_buf : "(NONE)", VTY_NEWLINE);
 | 
				
			||||||
 | 
						apn_name = osmo_apn_to_str(name_buf, pdp->apn_use.v, pdp->apn_use.l);
 | 
				
			||||||
 | 
						vty_out(vty, " APN in use: %s%s", apn_name ? name_buf : "(NONE)", VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (peer4)
 | 
				
			||||||
 | 
							vty_out(vty, " End-User Address (IPv4): %s%s",
 | 
				
			||||||
 | 
								in46a_ntop(&peer4->addr, name_buf, sizeof(name_buf)), VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (peer6)
 | 
				
			||||||
 | 
							vty_out(vty, " End-User Address (IPv6): %s%s",
 | 
				
			||||||
 | 
								in46a_ntop(&peer6->addr, name_buf, sizeof(name_buf)), VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " Transmit GTP Sequence Number for G-PDU: %s%s",
 | 
						vty_out(vty, " Transmit GTP Sequence Number for G-PDU: %s%s",
 | 
				
			||||||
		pdp->tx_gpdu_seq ? "Yes" : "No", VTY_NEWLINE);
 | 
							pdp->tx_gpdu_seq ? "Yes" : "No", VTY_NEWLINE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						show_one_pdp_v4only(vty, pdp, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
 | 
					DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
 | 
				
			||||||
	"show pdp-context imsi IMSI [<0-15>]",
 | 
						"show pdp-context ggsn NAME imsi IMSI [<0-15>]",
 | 
				
			||||||
	SHOW_STR "Display information on PDP Context\n"
 | 
						SHOW_STR "Display information on PDP Context\n"
 | 
				
			||||||
 | 
						GGSN_STR "GGSN Name\n"
 | 
				
			||||||
	"PDP contexts for given IMSI\n"
 | 
						"PDP contexts for given IMSI\n"
 | 
				
			||||||
	"PDP context for given NSAPI\n")
 | 
						"PDP context for given NSAPI\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t imsi = strtoull(argv[0], NULL, 10);
 | 
						struct ggsn_ctx *ggsn;
 | 
				
			||||||
 | 
						uint64_t imsi;
 | 
				
			||||||
	unsigned int nsapi;
 | 
						unsigned int nsapi;
 | 
				
			||||||
	struct pdp_t *pdp;
 | 
						struct pdp_t *pdp;
 | 
				
			||||||
	int num_found = 0;
 | 
						int num_found = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (argc > 1) {
 | 
						ggsn = ggsn_find(argv[0]);
 | 
				
			||||||
		nsapi = atoi(argv[1]);
 | 
						if (!ggsn) {
 | 
				
			||||||
		if (pdp_getimsi(&pdp, imsi, nsapi)) {
 | 
							vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strlen(argv[1]) < 6 || strlen(argv[1]) > 15) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% Invalid IMSI '%s'%s", argv[1], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imsi = gtp_imsi_str2gtp(argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argc > 2) {
 | 
				
			||||||
 | 
							nsapi = atoi(argv[2]);
 | 
				
			||||||
 | 
							if (!gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi)) {
 | 
				
			||||||
			show_one_pdp(vty, pdp);
 | 
								show_one_pdp(vty, pdp);
 | 
				
			||||||
			num_found++;
 | 
								num_found++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
 | 
							for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
 | 
				
			||||||
			if (pdp_getimsi(&pdp, imsi, nsapi))
 | 
								if (gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			show_one_pdp(vty, pdp);
 | 
								show_one_pdp(vty, pdp);
 | 
				
			||||||
			num_found++;
 | 
								num_found++;
 | 
				
			||||||
@@ -761,8 +930,49 @@ DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
 | 
				
			|||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(show_pdpctx_ip, show_pdpctx_ip_cmd,
 | 
				
			||||||
 | 
						"show pdp-context ggsn NAME ipv4 A.B.C.D",
 | 
				
			||||||
 | 
						SHOW_STR "Display information on PDP Context\n"
 | 
				
			||||||
 | 
						GGSN_STR "GGSN Name\n" "IPv4 address type\n" "IP address\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn;
 | 
				
			||||||
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ggsn = ggsn_find(argv[0]);
 | 
				
			||||||
 | 
						if (!ggsn) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Iterate over all APNs of a given GGSN */
 | 
				
			||||||
 | 
						llist_for_each_entry(apn, &ggsn->apn_list, list) {
 | 
				
			||||||
 | 
							struct ippool_t *pool = apn->v4.pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* In some rare cases, if GGSN fails to init TUN/TAP interfaces
 | 
				
			||||||
 | 
							 * (e.g. due to insufficient permissions), it will continue to
 | 
				
			||||||
 | 
							 * work in such broken state, and pool would be NULL. */
 | 
				
			||||||
 | 
							if (!pool)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Iterate over all IPv4 pool members */
 | 
				
			||||||
 | 
							for (i = 0; i < pool->listsize; i++) {
 | 
				
			||||||
 | 
								struct ippoolm_t *member = &pool->member[i];
 | 
				
			||||||
 | 
								if (member->inuse == 0)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								if (strcmp(argv[1], in46a_ntoa(&member->addr)) == 0) {
 | 
				
			||||||
 | 
									show_one_pdp(vty, member->peer);
 | 
				
			||||||
 | 
									return CMD_SUCCESS;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_out(vty, "%% No PDP context found for IP '%s'%s", argv[1], VTY_NEWLINE);
 | 
				
			||||||
 | 
						return CMD_WARNING;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* show all (active) PDP contexts within a pool */
 | 
					/* show all (active) PDP contexts within a pool */
 | 
				
			||||||
static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool)
 | 
					static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool, bool pdp_v4only)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -773,21 +983,21 @@ static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool)
 | 
				
			|||||||
		struct ippoolm_t *member = &pool->member[i];
 | 
							struct ippoolm_t *member = &pool->member[i];
 | 
				
			||||||
		if (member->inuse == 0)
 | 
							if (member->inuse == 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		show_one_pdp(vty, member->peer);
 | 
							show_one_pdp_v4only(vty, member->peer, pdp_v4only);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* show all (active) PDP contexts within an APN */
 | 
					/* show all (active) PDP contexts within an APN */
 | 
				
			||||||
static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
 | 
					static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ippool_show_pdp_contexts(vty, apn->v4.pool);
 | 
						ippool_show_pdp_contexts(vty, apn->v4.pool, true);
 | 
				
			||||||
	ippool_show_pdp_contexts(vty, apn->v6.pool);
 | 
						ippool_show_pdp_contexts(vty, apn->v6.pool, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(show_pdpctx, show_pdpctx_cmd,
 | 
					DEFUN(show_pdpctx, show_pdpctx_cmd,
 | 
				
			||||||
	"show pdp-context ggsn NAME [apn APN]",
 | 
						"show pdp-context ggsn NAME",
 | 
				
			||||||
	SHOW_STR "Show PDP Context Information\n"
 | 
						SHOW_STR "Show PDP Context Information\n"
 | 
				
			||||||
	GGSN_STR "GGSN Name\n") // FIXME
 | 
						GGSN_STR "GGSN Name\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ggsn_ctx *ggsn;
 | 
						struct ggsn_ctx *ggsn;
 | 
				
			||||||
	struct apn_ctx *apn;
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
@@ -797,21 +1007,45 @@ DEFUN(show_pdpctx, show_pdpctx_cmd,
 | 
				
			|||||||
		vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (argc < 2) {
 | 
					
 | 
				
			||||||
		llist_for_each_entry(apn, &ggsn->apn_list, list)
 | 
						llist_for_each_entry(apn, &ggsn->apn_list, list)
 | 
				
			||||||
			apn_show_pdp_contexts(vty, apn);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		apn = ggsn_find_apn(ggsn, argv[1]);
 | 
					 | 
				
			||||||
		if (!apn) {
 | 
					 | 
				
			||||||
			vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
 | 
					 | 
				
			||||||
			return CMD_WARNING;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		apn_show_pdp_contexts(vty, apn);
 | 
							apn_show_pdp_contexts(vty, apn);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(show_pdpctx_apn, show_pdpctx_apn_cmd,
 | 
				
			||||||
 | 
						"show pdp-context ggsn NAME apn APN",
 | 
				
			||||||
 | 
						SHOW_STR "Show PDP Context Information\n"
 | 
				
			||||||
 | 
						GGSN_STR "GGSN Name\n" "Filter by APN\n" "APN name\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn;
 | 
				
			||||||
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ggsn = ggsn_find(argv[0]);
 | 
				
			||||||
 | 
						if (!ggsn) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apn = ggsn_find_apn(ggsn, argv[1]);
 | 
				
			||||||
 | 
						if (!apn) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apn_show_pdp_contexts(vty, apn);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Backwards compatibility: the VTY parser is (mis)interpreting
 | 
				
			||||||
 | 
					 * "[apn APN]" as two separate elements: "[apn" and "APN]",
 | 
				
			||||||
 | 
					 * but the first part somehow turns into command "ap". */
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(show_pdpctx_apn, show_deprecated_pdpctx_apn_cmd,
 | 
				
			||||||
 | 
							 "show pdp-context ggsn NAME ap APN",
 | 
				
			||||||
 | 
							 SHOW_STR "Show PDP Context Information\n"
 | 
				
			||||||
 | 
							 GGSN_STR "GGSN Name\n" "Filter by APN\n" "APN name\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void show_apn(struct vty *vty, struct apn_ctx *apn)
 | 
					static void show_apn(struct vty *vty, struct apn_ctx *apn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
 | 
						vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
 | 
				
			||||||
@@ -821,12 +1055,15 @@ static void show_apn(struct vty *vty, struct apn_ctx *apn)
 | 
				
			|||||||
static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
 | 
					static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct apn_ctx *apn;
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
	vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
 | 
						vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
 | 
				
			||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
	/* FIXME */
 | 
						/* FIXME */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(apn, &ggsn->apn_list, list)
 | 
						llist_for_each_entry(apn, &ggsn->apn_list, list)
 | 
				
			||||||
		show_apn(vty, apn);
 | 
							show_apn(vty, apn);
 | 
				
			||||||
 | 
						llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
 | 
				
			||||||
 | 
							show_one_sgsn(vty, sgsn, " ");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(show_ggsn, show_ggsn_cmd,
 | 
					DEFUN(show_ggsn, show_ggsn_cmd,
 | 
				
			||||||
@@ -851,7 +1088,10 @@ DEFUN(show_ggsn, show_ggsn_cmd,
 | 
				
			|||||||
int ggsn_vty_init(void)
 | 
					int ggsn_vty_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	install_element_ve(&show_pdpctx_cmd);
 | 
						install_element_ve(&show_pdpctx_cmd);
 | 
				
			||||||
 | 
						install_element_ve(&show_pdpctx_apn_cmd);
 | 
				
			||||||
 | 
						install_element_ve(&show_deprecated_pdpctx_apn_cmd);
 | 
				
			||||||
	install_element_ve(&show_pdpctx_imsi_cmd);
 | 
						install_element_ve(&show_pdpctx_imsi_cmd);
 | 
				
			||||||
 | 
						install_element_ve(&show_pdpctx_ip_cmd);
 | 
				
			||||||
	install_element_ve(&show_ggsn_cmd);
 | 
						install_element_ve(&show_ggsn_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_element(CONFIG_NODE, &cfg_ggsn_cmd);
 | 
						install_element(CONFIG_NODE, &cfg_ggsn_cmd);
 | 
				
			||||||
@@ -870,6 +1110,9 @@ int ggsn_vty_init(void)
 | 
				
			|||||||
	install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
 | 
						install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
 | 
				
			||||||
	install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
 | 
						install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
 | 
				
			||||||
	install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
 | 
						install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
 | 
				
			||||||
 | 
						install_element(GGSN_NODE, &cfg_ggsn_show_sgsn_cmd);
 | 
				
			||||||
 | 
						install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd);
 | 
				
			||||||
 | 
						install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_node(&apn_node, NULL);
 | 
						install_node(&apn_node, NULL);
 | 
				
			||||||
	install_element(APN_NODE, &cfg_description_cmd);
 | 
						install_element(APN_NODE, &cfg_description_cmd);
 | 
				
			||||||
@@ -893,6 +1136,8 @@ int ggsn_vty_init(void)
 | 
				
			|||||||
	install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
 | 
						install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
 | 
				
			||||||
	install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
 | 
						install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
 | 
				
			||||||
	install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
 | 
						install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
 | 
				
			||||||
 | 
						install_element(APN_NODE, &cfg_apn_ipv6_linklocal_cmd);
 | 
				
			||||||
 | 
						install_element(APN_NODE, &cfg_apn_no_ipv6_linklocal_cmd);
 | 
				
			||||||
	install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd);
 | 
						install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd);
 | 
				
			||||||
	install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd);
 | 
						install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -926,6 +1171,10 @@ static int ggsn_vty_go_parent(struct vty *vty)
 | 
				
			|||||||
			vty->index_sub = &apn->ggsn->cfg.description;
 | 
								vty->index_sub = &apn->ggsn->cfg.description;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							vty->node = CONFIG_NODE;
 | 
				
			||||||
 | 
							vty->index = NULL;
 | 
				
			||||||
 | 
							vty->index_sub = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return vty->node;
 | 
						return vty->node;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "../gtp/gtp.h"
 | 
					 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *own_ll_addr,
 | 
					 | 
				
			||||||
			const uint8_t *pack, unsigned len);
 | 
					 | 
				
			||||||
							
								
								
									
										252
									
								
								ggsn/pco.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								ggsn/pco.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,252 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * PCO parsing related code
 | 
				
			||||||
 | 
					 * Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 | 
					 * Copyright (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/tlv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../lib/util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pco.h"
 | 
				
			||||||
 | 
					#include "ggsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* determine if IPCP contains given option */
 | 
				
			||||||
 | 
					static const uint8_t *ipcp_contains_option(const struct ipcp_hdr *ipcp, size_t ipcp_len,
 | 
				
			||||||
 | 
										   enum ipcp_options opt, size_t opt_minlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint8_t *cur_opt = ipcp->options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* iterate over Options and check if protocol contained */
 | 
				
			||||||
 | 
						while (cur_opt + sizeof(struct ipcp_option_hdr) <= (uint8_t*)ipcp + ipcp_len) {
 | 
				
			||||||
 | 
							const struct ipcp_option_hdr *cur_opt_hdr = (const struct ipcp_option_hdr *)cur_opt;
 | 
				
			||||||
 | 
							/* length value includes 2 bytes type/length */
 | 
				
			||||||
 | 
							if (cur_opt_hdr->len < sizeof(struct ipcp_option_hdr))
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							if (cur_opt_hdr->type == opt &&
 | 
				
			||||||
 | 
							    cur_opt_hdr->len >= sizeof(struct ipcp_option_hdr) + opt_minlen)
 | 
				
			||||||
 | 
								return cur_opt;
 | 
				
			||||||
 | 
							cur_opt += cur_opt_hdr->len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *pap_welcome = "Welcome to OsmoGGSN " PACKAGE_VERSION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handle PAP protocol according to RFC 1334 */
 | 
				
			||||||
 | 
					static void process_pco_element_pap(const struct pco_element *pco_in, struct msgb *resp,
 | 
				
			||||||
 | 
									    const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct pap_element *pap_in = (const struct pap_element *) pco_in->data;
 | 
				
			||||||
 | 
						uint16_t pap_in_len;
 | 
				
			||||||
 | 
						uint8_t peer_id_len;
 | 
				
			||||||
 | 
						const uint8_t *peer_id;
 | 
				
			||||||
 | 
						unsigned int pap_welcome_len;
 | 
				
			||||||
 | 
						uint8_t pap_out_size;
 | 
				
			||||||
 | 
						struct pap_element *pap_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pco_in->length < sizeof(struct pap_element))
 | 
				
			||||||
 | 
							goto ret_broken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pap_in_len = osmo_load16be(&pap_in->len);
 | 
				
			||||||
 | 
						if (pco_in->length < pap_in_len)
 | 
				
			||||||
 | 
							goto ret_broken;
 | 
				
			||||||
 | 
						/* "pco_in->length > pap_in_len" is allowed: RFC1334 2.2 states:
 | 
				
			||||||
 | 
						   "Octets outside the range of the Length field should be treated as
 | 
				
			||||||
 | 
						   Data Link Layer padding and should be ignored on reception."
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (pap_in->code) {
 | 
				
			||||||
 | 
						case PAP_CODE_AUTH_REQ:
 | 
				
			||||||
 | 
							if (pap_in_len < sizeof(struct pap_element) + 1)
 | 
				
			||||||
 | 
								goto ret_broken_auth;
 | 
				
			||||||
 | 
							peer_id_len = pap_in->data[0];
 | 
				
			||||||
 | 
							if (pap_in_len < sizeof(struct pap_element) + 1 + peer_id_len)
 | 
				
			||||||
 | 
								goto ret_broken_auth;
 | 
				
			||||||
 | 
							peer_id = &pap_in->data[1];
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_DEBUG, pdp, "PCO PAP PeerId = %s, ACKing\n",
 | 
				
			||||||
 | 
								osmo_quote_str((const char *)peer_id, peer_id_len));
 | 
				
			||||||
 | 
							/* Password-Length + Password following here, but we don't care */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Prepare response, we ACK all of them: */
 | 
				
			||||||
 | 
							pap_welcome_len = strlen(pap_welcome);
 | 
				
			||||||
 | 
							/* +1: Length field of pap_welcome Message */
 | 
				
			||||||
 | 
							pap_out_size = sizeof(struct pap_element) + 1 + pap_welcome_len;
 | 
				
			||||||
 | 
							pap_out = alloca(pap_out_size);
 | 
				
			||||||
 | 
							pap_out->code = PAP_CODE_AUTH_ACK;
 | 
				
			||||||
 | 
							pap_out->id = pap_in->id;
 | 
				
			||||||
 | 
							pap_out->len = htons(pap_out_size);
 | 
				
			||||||
 | 
							pap_out->data[0] = pap_welcome_len;
 | 
				
			||||||
 | 
							memcpy(pap_out->data+1, pap_welcome, pap_welcome_len);
 | 
				
			||||||
 | 
							msgb_t16lv_put(resp, PCO_P_PAP, pap_out_size, (uint8_t *) pap_out);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PAP_CODE_AUTH_ACK:
 | 
				
			||||||
 | 
						case PAP_CODE_AUTH_NAK:
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_NOTICE, pdp, "Unsupported PAP PCO Code %u, ignoring\n", pap_in->code);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ret_broken_auth:
 | 
				
			||||||
 | 
						LOGPPDP(LOGL_NOTICE, pdp, "Invalid PAP AuthenticateReq: %s, ignoring\n",
 | 
				
			||||||
 | 
							osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ret_broken:
 | 
				
			||||||
 | 
						LOGPPDP(LOGL_NOTICE, pdp, "Invalid PAP PCO Length: %s, ignoring\n",
 | 
				
			||||||
 | 
							osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_pco_element_ipcp(const struct pco_element *pco_elem, struct msgb *resp,
 | 
				
			||||||
 | 
									     const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ippoolm_t *peer_v4 = pdp_get_peer_ipv(pdp, false);
 | 
				
			||||||
 | 
						const struct in46_addr *dns1 = &apn->v4.cfg.dns[0];
 | 
				
			||||||
 | 
						const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
 | 
				
			||||||
 | 
						uint8_t *start = resp->tail;
 | 
				
			||||||
 | 
						const struct ipcp_hdr *ipcp;
 | 
				
			||||||
 | 
						uint16_t ipcp_len;
 | 
				
			||||||
 | 
						uint8_t *len1, *len2;
 | 
				
			||||||
 | 
						unsigned int len_appended;
 | 
				
			||||||
 | 
						ptrdiff_t consumed;
 | 
				
			||||||
 | 
						size_t remain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!peer_v4) {
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_ERROR, pdp, "IPCP but no IPv4 type ?!?\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipcp = (const struct ipcp_hdr *)pco_elem->data;
 | 
				
			||||||
 | 
						consumed = (pco_elem->data - &pdp->pco_req.v[0]);
 | 
				
			||||||
 | 
						remain = sizeof(pdp->pco_req.v) - consumed;
 | 
				
			||||||
 | 
						ipcp_len = osmo_load16be(&ipcp->len);
 | 
				
			||||||
 | 
						if (remain < 0 || remain < ipcp_len) {
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_ERROR, pdp, "Malformed IPCP, ignoring\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Three byte T16L header */
 | 
				
			||||||
 | 
						msgb_put_u16(resp, 0x8021);	/* IPCP */
 | 
				
			||||||
 | 
						len1 = msgb_put(resp, 1);	/* Length of contents: delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_put_u8(resp, 0x02);	/* ACK */
 | 
				
			||||||
 | 
						msgb_put_u8(resp, ipcp->id);	/* ID: Needs to match request */
 | 
				
			||||||
 | 
						msgb_put_u8(resp, 0x00);	/* Length MSB */
 | 
				
			||||||
 | 
						len2 = msgb_put(resp, 1);	/* Length LSB: delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
 | 
				
			||||||
 | 
							msgb_put_u8(resp, 0x81);		/* DNS1 Tag */
 | 
				
			||||||
 | 
							msgb_put_u8(resp, 2 + dns1->len);	/* DNS1 Length, incl. TL */
 | 
				
			||||||
 | 
							msgb_put_u32(resp, ntohl(dns1->v4.s_addr));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
 | 
				
			||||||
 | 
							msgb_put_u8(resp, 0x83);		/* DNS2 Tag */
 | 
				
			||||||
 | 
							msgb_put_u8(resp, 2 + dns2->len);	/* DNS2 Length, incl. TL */
 | 
				
			||||||
 | 
							msgb_put_u32(resp, ntohl(dns2->v4.s_addr));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* patch in length values */
 | 
				
			||||||
 | 
						len_appended = resp->tail - start;
 | 
				
			||||||
 | 
						*len1 = len_appended - 3;
 | 
				
			||||||
 | 
						*len2 = len_appended - 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_pco_element_dns_ipv6(const struct pco_element *pco_elem, struct msgb *resp,
 | 
				
			||||||
 | 
										 const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						const uint8_t *tail = resp->tail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
 | 
				
			||||||
 | 
							const struct in46_addr *i46a = &apn->v6.cfg.dns[i];
 | 
				
			||||||
 | 
							if (i46a->len != 16)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							msgb_t16lv_put(resp, PCO_P_DNS_IPv6_ADDR, i46a->len, i46a->v6.s6_addr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (resp->tail == tail)
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_NOTICE, pdp, "MS requested IPv6 DNS, but APN has none configured\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_pco_element_dns_ipv4(const struct pco_element *pco_elem, struct msgb *resp,
 | 
				
			||||||
 | 
										 const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						const uint8_t *tail = resp->tail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
 | 
				
			||||||
 | 
							const struct in46_addr *i46a = &apn->v4.cfg.dns[i];
 | 
				
			||||||
 | 
							if (i46a->len != 4)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							msgb_t16lv_put(resp, PCO_P_DNS_IPv4_ADDR, i46a->len, (uint8_t *)&i46a->v4);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (resp->tail == tail)
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_NOTICE, pdp, "MS requested IPv4 DNS, but APN has none configured\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_pco_element(const struct pco_element *pco_elem, struct msgb *resp,
 | 
				
			||||||
 | 
									const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint16_t protocol_id = osmo_load16be(&pco_elem->protocol_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPPDP(LOGL_DEBUG, pdp, "PCO Protocol 0x%04x\n", protocol_id);
 | 
				
			||||||
 | 
						switch (protocol_id) {
 | 
				
			||||||
 | 
						case PCO_P_PAP:
 | 
				
			||||||
 | 
							process_pco_element_pap(pco_elem, resp, apn, pdp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PCO_P_IPCP:
 | 
				
			||||||
 | 
							process_pco_element_ipcp(pco_elem, resp, apn, pdp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PCO_P_DNS_IPv6_ADDR:
 | 
				
			||||||
 | 
							process_pco_element_dns_ipv6(pco_elem, resp, apn, pdp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PCO_P_DNS_IPv4_ADDR:
 | 
				
			||||||
 | 
							process_pco_element_dns_ipv4(pco_elem, resp, apn, pdp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGPPDP(LOGL_INFO, pdp, "Unknown/Unimplemented PCO Protocol 0x%04x: %s\n",
 | 
				
			||||||
 | 
								protocol_id, osmo_hexdump_nospc(pco_elem->data, pco_elem->length));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* process one PCO request from a MS/UE, putting together the proper responses */
 | 
				
			||||||
 | 
					void process_pco(const struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *resp = msgb_alloc(256, "PCO.resp");
 | 
				
			||||||
 | 
						const struct ul255_t *pco = &pdp->pco_req;
 | 
				
			||||||
 | 
						const struct pco_element *pco_elem;
 | 
				
			||||||
 | 
						const uint8_t *cur;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* build the header of the PCO response */
 | 
				
			||||||
 | 
						OSMO_ASSERT(resp);
 | 
				
			||||||
 | 
						msgb_put_u8(resp, 0x80); /* ext-bit + configuration protocol byte */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* iterate over the PCO elements in the request; call process_pco_element() for each */
 | 
				
			||||||
 | 
						for (cur = pco->v + 1, pco_elem = (const struct pco_element *) cur;
 | 
				
			||||||
 | 
						     cur + sizeof(struct pco_element) <= pco->v + pco->l;
 | 
				
			||||||
 | 
						     cur += pco_elem->length + sizeof(*pco_elem), pco_elem = (const struct pco_element *) cur) {
 | 
				
			||||||
 | 
							process_pco_element(pco_elem, resp, apn, pdp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy the PCO response msgb and copy its contents over to the PDP context */
 | 
				
			||||||
 | 
						if (msgb_length(resp) > 1) {
 | 
				
			||||||
 | 
							memcpy(pdp->pco_neg.v, msgb_data(resp), msgb_length(resp));
 | 
				
			||||||
 | 
							pdp->pco_neg.l = msgb_length(resp);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							pdp->pco_neg.l = 0;
 | 
				
			||||||
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										81
									
								
								ggsn/pco.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								ggsn/pco.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 3GPP TS 24.008 10.6.5.3 */
 | 
				
			||||||
 | 
					enum pco_protocols {
 | 
				
			||||||
 | 
						PCO_P_LCP		= 0xC021,
 | 
				
			||||||
 | 
						PCO_P_PAP		= 0xC023,
 | 
				
			||||||
 | 
						PCO_P_CHAP		= 0xC223,
 | 
				
			||||||
 | 
						PCO_P_IPCP		= 0x8021,
 | 
				
			||||||
 | 
						PCO_P_PCSCF_ADDR	= 0x0001,
 | 
				
			||||||
 | 
						PCO_P_IM_CN_SS_F	= 0x0002,
 | 
				
			||||||
 | 
						PCO_P_DNS_IPv6_ADDR	= 0x0003,
 | 
				
			||||||
 | 
						PCO_P_POLICY_CTRL_REJ	= 0x0004,	/* only in Network->MS */
 | 
				
			||||||
 | 
						PCO_P_MS_SUP_NETREQ_BCI	= 0x0005,
 | 
				
			||||||
 | 
						/* reserved */
 | 
				
			||||||
 | 
						PCO_P_DSMIPv6_HA_ADDR	= 0x0007,
 | 
				
			||||||
 | 
						PCO_P_DSMIPv6_HN_PREF	= 0x0008,
 | 
				
			||||||
 | 
						PCO_P_DSMIPv6_v4_HA_ADDR= 0x0009,
 | 
				
			||||||
 | 
						PCO_P_IP_ADDR_VIA_NAS	= 0x000a,	/* only MS->Network */
 | 
				
			||||||
 | 
						PCO_P_IPv4_ADDR_VIA_DHCP= 0x000b,	/* only MS->Netowrk */
 | 
				
			||||||
 | 
						PCO_P_PCSCF_IPv4_ADDR	= 0x000c,
 | 
				
			||||||
 | 
						PCO_P_DNS_IPv4_ADDR	= 0x000d,
 | 
				
			||||||
 | 
						PCO_P_MSISDN		= 0x000e,
 | 
				
			||||||
 | 
						PCO_P_IFOM_SUPPORT	= 0x000f,
 | 
				
			||||||
 | 
						PCO_P_IPv4_LINK_MTU	= 0x0010,
 | 
				
			||||||
 | 
						PCO_P_MS_SUPP_LOC_A_TFT	= 0x0011,
 | 
				
			||||||
 | 
						PCO_P_PCSCF_RESEL_SUP	= 0x0012,	/* only MS->Network */
 | 
				
			||||||
 | 
						PCO_P_NBIFOM_REQ	= 0x0013,
 | 
				
			||||||
 | 
						PCO_P_NBIFOM_MODE	= 0x0014,
 | 
				
			||||||
 | 
						PCO_P_NONIP_LINK_MTU	= 0x0015,
 | 
				
			||||||
 | 
						PCO_P_APN_RATE_CTRL_SUP	= 0x0016,
 | 
				
			||||||
 | 
						PCO_P_PS_DATA_OFF_UE	= 0x0017,
 | 
				
			||||||
 | 
						PCO_P_REL_DATA_SVC	= 0x0018,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pco_element {
 | 
				
			||||||
 | 
						uint16_t protocol_id;	/* network byte order */
 | 
				
			||||||
 | 
						uint8_t length;		/* length of data below */
 | 
				
			||||||
 | 
						uint8_t data[0];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC 1332 */
 | 
				
			||||||
 | 
					enum ipcp_options {
 | 
				
			||||||
 | 
						IPCP_OPT_IPADDR = 3,
 | 
				
			||||||
 | 
						IPCP_OPT_PRIMARY_DNS = 129,
 | 
				
			||||||
 | 
						IPCP_OPT_SECONDARY_DNS = 131,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ipcp_option_hdr {
 | 
				
			||||||
 | 
						uint8_t type;
 | 
				
			||||||
 | 
						uint8_t len;
 | 
				
			||||||
 | 
						uint8_t data[0];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ipcp_hdr {
 | 
				
			||||||
 | 
						uint8_t code;
 | 
				
			||||||
 | 
						uint8_t id;
 | 
				
			||||||
 | 
						uint16_t len;
 | 
				
			||||||
 | 
						uint8_t options[0];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC 1334, section 3.2. Packet Format */
 | 
				
			||||||
 | 
					struct pap_element {
 | 
				
			||||||
 | 
						uint8_t code;
 | 
				
			||||||
 | 
						uint8_t id;
 | 
				
			||||||
 | 
						uint16_t len; /* length including header */
 | 
				
			||||||
 | 
						uint8_t data[0];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum pap_code {
 | 
				
			||||||
 | 
						PAP_CODE_AUTH_REQ = 1,
 | 
				
			||||||
 | 
						PAP_CODE_AUTH_ACK = 2,
 | 
				
			||||||
 | 
						PAP_CODE_AUTH_NAK = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct apn_ctx;
 | 
				
			||||||
 | 
					void process_pco(const struct apn_ctx *apn, struct pdp_t *pdp);
 | 
				
			||||||
							
								
								
									
										168
									
								
								ggsn/sgsn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								ggsn/sgsn.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					#include "sgsn.h"
 | 
				
			||||||
 | 
					#include "ggsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool sgsn_peer_attempt_free(struct sgsn_peer *sgsn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* We have to be careful here, since if all pdp ctx for that sgsn were
 | 
				
			||||||
 | 
						   deactivated in-between we sent the Echo Req and receivied the timeout
 | 
				
			||||||
 | 
						   indication, the sgsn (cbp) may be already gone. We need to add some
 | 
				
			||||||
 | 
						   counter reference of echo requets in flight and only free sgsn
 | 
				
			||||||
 | 
						   structures when it goes to zero decreased for all Echo Resp. We do it
 | 
				
			||||||
 | 
						   this way because currently in libgtp there's no understanding of "gsn
 | 
				
			||||||
 | 
						   peer" for which messages are grouped and hence we cannot request
 | 
				
			||||||
 | 
						   libgtp to drop all queued messages for a specific peer. */
 | 
				
			||||||
 | 
						if (sgsn->tx_msgs_queued) {
 | 
				
			||||||
 | 
							LOGSGSN(LOGL_INFO, sgsn, "Delaying delete, still %u echo messages queued\n",
 | 
				
			||||||
 | 
								sgsn->tx_msgs_queued);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						llist_del(&sgsn->entry);
 | 
				
			||||||
 | 
						LOGSGSN(LOGL_INFO, sgsn, "Deleting SGSN\n");
 | 
				
			||||||
 | 
						talloc_free(sgsn);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sgsn_peer_echo_req(struct sgsn_peer *sgsn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn = sgsn->ggsn;
 | 
				
			||||||
 | 
						LOGSGSN(LOGL_INFO, sgsn, "Tx Echo Request\n");
 | 
				
			||||||
 | 
						gtp_echo_req(ggsn->gsn, sgsn->gtp_version, sgsn, &sgsn->addr);
 | 
				
			||||||
 | 
						sgsn->tx_msgs_queued++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_peer_echo_resp(struct sgsn_peer *sgsn, bool timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (timeout) {
 | 
				
			||||||
 | 
							LOGSGSN(LOGL_NOTICE, sgsn, "Rx Echo Request timed out!\n");
 | 
				
			||||||
 | 
							sgsn_peer_drop_all_pdp(sgsn);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGSGSN(LOGL_INFO, sgsn, "Rx Echo Response\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We decrement it here after dropping all pdps to make sure sgsn was
 | 
				
			||||||
 | 
						   not freed upon last pdp ctx deleted and is still alive now */
 | 
				
			||||||
 | 
						sgsn->tx_msgs_queued--;
 | 
				
			||||||
 | 
						if (llist_empty(&sgsn->pdp_list))
 | 
				
			||||||
 | 
							sgsn_peer_attempt_free(sgsn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_echo_timer_start(struct sgsn_peer *sgsn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (sgsn->ggsn->cfg.echo_interval == 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						sgsn_peer_echo_req(sgsn);
 | 
				
			||||||
 | 
						osmo_timer_schedule(&sgsn->echo_timer, sgsn->ggsn->cfg.echo_interval, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_echo_timer_stop(struct sgsn_peer *sgsn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_timer_del(&sgsn->echo_timer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sgsn_echo_timer_cb(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn = (struct sgsn_peer *) data;
 | 
				
			||||||
 | 
						sgsn_echo_timer_start(sgsn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sgsn_peer *sgsn_peer_allocate(struct ggsn_ctx *ggsn, struct in_addr *ia, unsigned int gtp_version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sgsn = talloc_zero_size(ggsn, sizeof(struct sgsn_peer));
 | 
				
			||||||
 | 
						sgsn->ggsn = ggsn;
 | 
				
			||||||
 | 
						sgsn->addr = *ia;
 | 
				
			||||||
 | 
						sgsn->gtp_version = gtp_version;
 | 
				
			||||||
 | 
						sgsn->remote_restart_ctr = -1;
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&sgsn->pdp_list);
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&sgsn->entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_timer_setup(&sgsn->echo_timer, sgsn_echo_timer_cb, sgsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGSGSN(LOGL_INFO, sgsn, "Discovered\n");
 | 
				
			||||||
 | 
						return sgsn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_peer_add_pdp_priv(struct sgsn_peer *sgsn, struct pdp_priv_t *pdp_priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool was_empty = llist_empty(&sgsn->pdp_list);
 | 
				
			||||||
 | 
						pdp_priv->sgsn = sgsn;
 | 
				
			||||||
 | 
						llist_add(&pdp_priv->entry, &sgsn->pdp_list);
 | 
				
			||||||
 | 
						if (was_empty)
 | 
				
			||||||
 | 
							sgsn_echo_timer_start(sgsn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_peer_remove_pdp_priv(struct pdp_priv_t* pdp_priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sgsn_peer *sgsn = pdp_priv->sgsn;
 | 
				
			||||||
 | 
						llist_del(&pdp_priv->entry);
 | 
				
			||||||
 | 
						if (sgsn && llist_empty(&sgsn->pdp_list)) {
 | 
				
			||||||
 | 
							/* No PDP contexts associated to this SGSN, no need to keep it */
 | 
				
			||||||
 | 
							sgsn_echo_timer_stop(sgsn);
 | 
				
			||||||
 | 
							/* sgsn may not be freed if there are some messages still queued
 | 
				
			||||||
 | 
							   in libgtp which could return a pointer to it */
 | 
				
			||||||
 | 
							sgsn_peer_attempt_free(sgsn);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdp_priv->sgsn = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* High-level function to be called in case a GGSN has disappeared or
 | 
				
			||||||
 | 
					 * otherwise lost state (recovery procedure). It will detach all related pdp ctx
 | 
				
			||||||
 | 
					 * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
 | 
				
			||||||
 | 
					 * be kept alive to allow handling later message which contained the Recovery IE. */
 | 
				
			||||||
 | 
					static unsigned int sgsn_peer_drop_all_pdp_except(struct sgsn_peer *sgsn, struct pdp_priv_t *except)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int num = 0;
 | 
				
			||||||
 | 
						char buf[INET_ADDRSTRLEN];
 | 
				
			||||||
 | 
						unsigned int count = llist_count(&sgsn->pdp_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inet_ntop(AF_INET, &sgsn->addr, buf, sizeof(buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pdp_priv_t *pdp, *pdp2;
 | 
				
			||||||
 | 
						llist_for_each_entry_safe(pdp, pdp2, &sgsn->pdp_list, entry) {
 | 
				
			||||||
 | 
							if (pdp == except)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							ggsn_close_one_pdp(pdp->lib);
 | 
				
			||||||
 | 
							num++;
 | 
				
			||||||
 | 
							if (num == count) {
 | 
				
			||||||
 | 
								/* Note: if except is NULL, all pdp contexts are freed and sgsn
 | 
				
			||||||
 | 
								 * is most probably already freed at this point.
 | 
				
			||||||
 | 
								 * As a result, last access to sgsn->pdp_list before exiting
 | 
				
			||||||
 | 
								 * loop would access already freed memory. Avoid it by exiting
 | 
				
			||||||
 | 
								 * the loop without the last check, and make sure sgsn is not
 | 
				
			||||||
 | 
								 * accessed after this loop. */
 | 
				
			||||||
 | 
								 break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DGGSN, LOGL_INFO, "SGSN(%s) Dropped %u PDP contexts\n", buf, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int sgsn_peer_drop_all_pdp(struct sgsn_peer *sgsn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sgsn_peer_drop_all_pdp_except(sgsn, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sgsn_peer_handle_recovery(struct sgsn_peer *sgsn, struct pdp_t *pdp, uint8_t recovery)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_priv_t *pdp_priv = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sgsn->remote_restart_ctr == -1) {
 | 
				
			||||||
 | 
							/* First received ECHO RESPONSE, note the restart ctr */
 | 
				
			||||||
 | 
							sgsn->remote_restart_ctr = recovery;
 | 
				
			||||||
 | 
						} else if (sgsn->remote_restart_ctr != recovery) {
 | 
				
			||||||
 | 
							/* counter has changed (SGSN restart): release all PDP */
 | 
				
			||||||
 | 
							LOGSGSN(LOGL_NOTICE, sgsn, "SGSN recovery (%u->%u) pdp=%p, "
 | 
				
			||||||
 | 
							     "releasing all%s PDP contexts\n",
 | 
				
			||||||
 | 
							     sgsn->remote_restart_ctr, recovery, pdp, pdp ? " other" : "");
 | 
				
			||||||
 | 
							sgsn->remote_restart_ctr = recovery;
 | 
				
			||||||
 | 
							if (pdp)
 | 
				
			||||||
 | 
								pdp_priv = pdp->priv;
 | 
				
			||||||
 | 
							sgsn_peer_drop_all_pdp_except(sgsn, pdp_priv);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								ggsn/sgsn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								ggsn/sgsn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ggsn_ctx;
 | 
				
			||||||
 | 
					struct pdp_priv_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sgsn_peer {
 | 
				
			||||||
 | 
						struct llist_head entry; /* to be included into ggsn_ctx */
 | 
				
			||||||
 | 
						struct ggsn_ctx *ggsn; /* backpointer to ggsn_ctx */
 | 
				
			||||||
 | 
						struct in_addr addr;	/* Addr of the sgsn peer */
 | 
				
			||||||
 | 
						unsigned int gtp_version; /* GTP version */
 | 
				
			||||||
 | 
						int remote_restart_ctr; /* Last received Restart Ctr from sgsn peer, -1 == unknown */
 | 
				
			||||||
 | 
						/* list of pdp contexts associated with this sgsn */
 | 
				
			||||||
 | 
						struct llist_head pdp_list;
 | 
				
			||||||
 | 
						/* Sends echo request towards SGSN on expiration. Echo Resp is received
 | 
				
			||||||
 | 
						   through cb_recovery2(), and echo Req timeout through
 | 
				
			||||||
 | 
						   cb_conf(GTP_ECHO_REQ, EOF, NULL, cbp); */
 | 
				
			||||||
 | 
						struct osmo_timer_list echo_timer;
 | 
				
			||||||
 | 
						/* Number of GTP messages in libgtp transmit queue */
 | 
				
			||||||
 | 
						unsigned int tx_msgs_queued;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sgsn_peer *sgsn_peer_allocate(struct ggsn_ctx *ggsn, struct in_addr *ia, unsigned int gtp_version);
 | 
				
			||||||
 | 
					void sgsn_peer_add_pdp_priv(struct sgsn_peer *sgsn, struct pdp_priv_t *pdp_priv);
 | 
				
			||||||
 | 
					void sgsn_peer_remove_pdp_priv(struct pdp_priv_t *pdp_priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_echo_timer_start(struct sgsn_peer *sgsn);
 | 
				
			||||||
 | 
					void sgsn_echo_timer_stop(struct sgsn_peer *sgsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sgsn_peer_echo_resp(struct sgsn_peer *sgsn, bool timeout);
 | 
				
			||||||
 | 
					unsigned int sgsn_peer_drop_all_pdp(struct sgsn_peer *sgsn);
 | 
				
			||||||
 | 
					int sgsn_peer_handle_recovery(struct sgsn_peer *sgsn, struct pdp_t *pdp, uint8_t recovery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGSGSN(level, sgsn, fmt, args...) { \
 | 
				
			||||||
 | 
						char _buf[INET_ADDRSTRLEN]; \
 | 
				
			||||||
 | 
						LOGP(DGGSN, level, "SGSN(%s): " fmt, inet_ntop(AF_INET, &sgsn->addr, _buf, sizeof(_buf)), ## args); \
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
# This is _NOT_ the library release version, it's an API version.
 | 
					# This is _NOT_ the library release version, it's an API version.
 | 
				
			||||||
# Please read chapter "Library interface versions" of the libtool documentation
 | 
					# Please read chapter "Library interface versions" of the libtool documentation
 | 
				
			||||||
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
 | 
					# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
 | 
				
			||||||
LIBVERSION=2:0:0
 | 
					# If major=current-age is increased, remember to update the dh_strip line in debian/rules!
 | 
				
			||||||
 | 
					LIBVERSION=8:0:2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = libgtp.la
 | 
					lib_LTLIBRARIES = libgtp.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include_HEADERS = gtp.h pdp.h gtpie.h
 | 
					include_HEADERS = gtp.h pdp.h gtpie.h
 | 
				
			||||||
@@ -11,7 +13,3 @@ AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_
 | 
				
			|||||||
libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
 | 
					libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
 | 
				
			||||||
libgtp_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
 | 
					libgtp_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
 | 
				
			||||||
libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS)
 | 
					libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										67
									
								
								gtp/gtp.h
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								gtp/gtp.h
									
									
									
									
									
								
							@@ -1,17 +1,24 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
					 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _GTP_H
 | 
					#ifndef _GTP_H
 | 
				
			||||||
#define _GTP_H
 | 
					#define _GTP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/defs.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gtpie.h"
 | 
				
			||||||
 | 
					#include "pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GTP_MODE_GGSN 1
 | 
					#define GTP_MODE_GGSN 1
 | 
				
			||||||
#define GTP_MODE_SGSN 2
 | 
					#define GTP_MODE_SGSN 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,12 +86,17 @@
 | 
				
			|||||||
#define GTP_FWD_SRNS         58	/* Forward SRNS Context */
 | 
					#define GTP_FWD_SRNS         58	/* Forward SRNS Context */
 | 
				
			||||||
#define GTP_FWD_RELOC_ACK    59	/* Forward Relocation Complete Acknowledge */
 | 
					#define GTP_FWD_RELOC_ACK    59	/* Forward Relocation Complete Acknowledge */
 | 
				
			||||||
#define GTP_FWD_SRNS_ACK     60	/* Forward SRNS Context Acknowledge */
 | 
					#define GTP_FWD_SRNS_ACK     60	/* Forward SRNS Context Acknowledge */
 | 
				
			||||||
 | 
					#define GTP_RAN_INFO_RELAY   70	/* RAN Information Relay */
 | 
				
			||||||
/* 61-239 For future use. */
 | 
					/* 61-239 For future use. */
 | 
				
			||||||
#define GTP_DATA_TRAN_REQ   240	/* Data Record Transfer Request */
 | 
					#define GTP_DATA_TRAN_REQ   240	/* Data Record Transfer Request */
 | 
				
			||||||
#define GTP_DATA_TRAN_RSP   241	/* Data Record Transfer Response */
 | 
					#define GTP_DATA_TRAN_RSP   241	/* Data Record Transfer Response */
 | 
				
			||||||
/* 242-254 For future use. */
 | 
					/* 242-254 For future use. */
 | 
				
			||||||
#define GTP_GPDU            255	/* G-PDU */
 | 
					#define GTP_GPDU            255	/* G-PDU */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string gtp_type_names[];
 | 
				
			||||||
 | 
					static inline const char *gtp_type_name(uint8_t val)
 | 
				
			||||||
 | 
					{ return get_value_string(gtp_type_names, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* GTP information element cause codes from 29.060 v3.9.0 7.7 */
 | 
					/* GTP information element cause codes from 29.060 v3.9.0 7.7 */
 | 
				
			||||||
/*                                                            */
 | 
					/*                                                            */
 | 
				
			||||||
#define GTPCAUSE_REQ_IMSI                   0	/* Request IMSI */
 | 
					#define GTPCAUSE_REQ_IMSI                   0	/* Request IMSI */
 | 
				
			||||||
@@ -135,7 +147,7 @@ struct ul66_t;
 | 
				
			|||||||
struct ul16_t;
 | 
					struct ul16_t;
 | 
				
			||||||
struct pdp_t;
 | 
					struct pdp_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* GTP 0 header. 
 | 
					/* GTP 0 header.
 | 
				
			||||||
 * Explanation to some of the fields:
 | 
					 * Explanation to some of the fields:
 | 
				
			||||||
 * SNDCP NPDU Number flag = 0 except for inter SGSN handover situations
 | 
					 * SNDCP NPDU Number flag = 0 except for inter SGSN handover situations
 | 
				
			||||||
 * SNDCP N-PDU LCC Number 0 = 0xff except for inter SGSN handover situations
 | 
					 * SNDCP N-PDU LCC Number 0 = 0xff except for inter SGSN handover situations
 | 
				
			||||||
@@ -224,13 +236,13 @@ union gtp_packet {
 | 
				
			|||||||
 * Information storage for each gsn instance
 | 
					 * Information storage for each gsn instance
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Normally each instance of the application corresponds to
 | 
					 * Normally each instance of the application corresponds to
 | 
				
			||||||
 * one instance of a gsn. 
 | 
					 * one instance of a gsn.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * In order to avoid global variables in the application, and
 | 
					 * In order to avoid global variables in the application, and
 | 
				
			||||||
 * also in order to allow several instances of a gsn in the same
 | 
					 * also in order to allow several instances of a gsn in the same
 | 
				
			||||||
 * application this struct is provided in order to store all
 | 
					 * application this struct is provided in order to store all
 | 
				
			||||||
 * relevant information related to the gsn.
 | 
					 * relevant information related to the gsn.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * Note that this does not include information storage for '
 | 
					 * Note that this does not include information storage for '
 | 
				
			||||||
 * each pdp context. This is stored in another struct.
 | 
					 * each pdp context. This is stored in another struct.
 | 
				
			||||||
 *************************************************************/
 | 
					 *************************************************************/
 | 
				
			||||||
@@ -256,14 +268,22 @@ struct gsn_t {
 | 
				
			|||||||
	struct queue_t *queue_req;	/* Request queue */
 | 
						struct queue_t *queue_req;	/* Request queue */
 | 
				
			||||||
	struct queue_t *queue_resp;	/* Response queue */
 | 
						struct queue_t *queue_resp;	/* Response queue */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pdp_t pdpa[PDP_MAX];	/* PDP storage */
 | 
				
			||||||
 | 
						struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Call back functions */
 | 
						/* Call back functions */
 | 
				
			||||||
	int (*cb_delete_context) (struct pdp_t *);
 | 
						int (*cb_delete_context) (struct pdp_t *);
 | 
				
			||||||
	int (*cb_create_context_ind) (struct pdp_t *);
 | 
						int (*cb_create_context_ind) (struct pdp_t *);
 | 
				
			||||||
	int (*cb_unsup_ind) (struct sockaddr_in * peer);
 | 
						int (*cb_unsup_ind) (struct sockaddr_in * peer);
 | 
				
			||||||
	int (*cb_extheader_ind) (struct sockaddr_in * peer);
 | 
						int (*cb_extheader_ind) (struct sockaddr_in * peer);
 | 
				
			||||||
 | 
						int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
 | 
				
			||||||
	int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
 | 
						int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
 | 
				
			||||||
	int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
 | 
						int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
 | 
				
			||||||
	int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
 | 
						int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
 | 
				
			||||||
 | 
						int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
 | 
				
			||||||
 | 
						int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Counters */
 | 
						/* Counters */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -299,8 +319,9 @@ extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
 | 
				
			|||||||
extern int gtp_free(struct gsn_t *gsn);
 | 
					extern int gtp_free(struct gsn_t *gsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
 | 
					extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
 | 
				
			||||||
		      uint64_t imsi, uint8_t nsapi);
 | 
							      uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
 | 
				
			||||||
extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
 | 
					extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
 | 
				
			||||||
 | 
					extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
					extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
				  void *cbp);
 | 
									  void *cbp);
 | 
				
			||||||
@@ -317,11 +338,19 @@ extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			|||||||
			      void *cbp, struct in_addr *inetaddr);
 | 
								      void *cbp, struct in_addr *inetaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
					extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
				  void *cbp, int teardown);
 | 
									  void *cbp, int teardown)
 | 
				
			||||||
 | 
							OSMO_DEPRECATED("Use gtp_delete_context_req2() instead, to avoid freeing pdp ctx before reply");
 | 
				
			||||||
 | 
					extern int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
 | 
									   void *cbp, int teardown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
					extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
			void *pack, unsigned len);
 | 
								void *pack, unsigned len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
 | 
				
			||||||
 | 
									  const uint8_t *ran_container, size_t ran_container_len,
 | 
				
			||||||
 | 
									  const uint8_t *rim_route_addr, size_t rim_route_addr_len,
 | 
				
			||||||
 | 
									  uint8_t rim_route_addr_discr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
 | 
					extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
 | 
				
			||||||
			       int (*cb_data_ind) (struct pdp_t * pdp,
 | 
								       int (*cb_data_ind) (struct pdp_t * pdp,
 | 
				
			||||||
						   void *pack, unsigned len));
 | 
											   void *pack, unsigned len));
 | 
				
			||||||
@@ -330,8 +359,8 @@ extern int gtp_fd(struct gsn_t *gsn);
 | 
				
			|||||||
extern int gtp_decaps0(struct gsn_t *gsn);
 | 
					extern int gtp_decaps0(struct gsn_t *gsn);
 | 
				
			||||||
extern int gtp_decaps1c(struct gsn_t *gsn);
 | 
					extern int gtp_decaps1c(struct gsn_t *gsn);
 | 
				
			||||||
extern int gtp_decaps1u(struct gsn_t *gsn);
 | 
					extern int gtp_decaps1u(struct gsn_t *gsn);
 | 
				
			||||||
extern int gtp_retrans(struct gsn_t *gsn);
 | 
					extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");
 | 
				
			||||||
extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout);
 | 
					extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
 | 
					extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
 | 
				
			||||||
				     int (*cb_delete_context) (struct pdp_t *
 | 
									     int (*cb_delete_context) (struct pdp_t *
 | 
				
			||||||
@@ -345,14 +374,29 @@ extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
 | 
				
			|||||||
extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
 | 
					extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
 | 
				
			||||||
				    int (*cb) (struct sockaddr_in * peer));
 | 
									    int (*cb) (struct sockaddr_in * peer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
 | 
				
			||||||
 | 
									    int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_set_cb_conf(struct gsn_t *gsn,
 | 
					extern int gtp_set_cb_conf(struct gsn_t *gsn,
 | 
				
			||||||
			   int (*cb) (int type, int cause, struct pdp_t * pdp,
 | 
								   int (*cb) (int type, int cause, struct pdp_t * pdp,
 | 
				
			||||||
				      void *cbp));
 | 
									      void *cbp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_set_cb_recovery(struct gsn_t *gsn,
 | 
					int gtp_set_cb_recovery(struct gsn_t *gsn,
 | 
				
			||||||
			int (*cb) (struct sockaddr_in * peer,
 | 
								int (*cb) (struct sockaddr_in * peer,
 | 
				
			||||||
 | 
									   uint8_t recovery))
 | 
				
			||||||
 | 
						OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
 | 
				
			||||||
 | 
					int gtp_set_cb_recovery2(struct gsn_t *gsn,
 | 
				
			||||||
 | 
								int (*cb) (struct sockaddr_in * peer,
 | 
				
			||||||
 | 
									   struct pdp_t * pdp,
 | 
				
			||||||
 | 
									   uint8_t recovery))
 | 
				
			||||||
 | 
						OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");;
 | 
				
			||||||
 | 
					int gtp_set_cb_recovery3(struct gsn_t *gsn,
 | 
				
			||||||
 | 
								int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer,
 | 
				
			||||||
 | 
									   struct pdp_t * pdp,
 | 
				
			||||||
				   uint8_t recovery));
 | 
									   uint8_t recovery));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gtp_clear_queues(struct gsn_t *gsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Internal functions (not part of the API */
 | 
					/* Internal functions (not part of the API */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
 | 
					extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
 | 
				
			||||||
@@ -408,5 +452,6 @@ extern int eua2ipv4(struct in_addr *dst, struct ul66_t *eua);
 | 
				
			|||||||
extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna);
 | 
					extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna);
 | 
				
			||||||
extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src);
 | 
					extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src);
 | 
				
			||||||
extern const char *imsi_gtp2str(const uint64_t *imsi);
 | 
					extern const char *imsi_gtp2str(const uint64_t *imsi);
 | 
				
			||||||
 | 
					extern uint64_t gtp_imsi_str2gtp(const char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_GTP_H */
 | 
					#endif /* !_GTP_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								gtp/gtpie.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								gtp/gtpie.c
									
									
									
									
									
								
							@@ -1,17 +1,17 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002 Mondru AB.
 | 
					 *  Copyright (C) 2002 Mondru AB.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * gtpie.c: Contains functions to encapsulate and decapsulate GTP 
 | 
					 * gtpie.c: Contains functions to encapsulate and decapsulate GTP
 | 
				
			||||||
 * information elements 
 | 
					 * information elements
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Encapsulation
 | 
					 * Encapsulation
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										208
									
								
								gtp/pdp.c
									
									
									
									
									
								
							
							
						
						
									
										208
									
								
								gtp/pdp.c
									
									
									
									
									
								
							@@ -1,17 +1,17 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
					 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 *  Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
 | 
					 *  Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * pdp.c: 
 | 
					 * pdp.c:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,30 +31,23 @@
 | 
				
			|||||||
#include "pdp.h"
 | 
					#include "pdp.h"
 | 
				
			||||||
#include "gtp.h"
 | 
					#include "gtp.h"
 | 
				
			||||||
#include "lookupa.h"
 | 
					#include "lookupa.h"
 | 
				
			||||||
 | 
					#include "queue.h"
 | 
				
			||||||
/* ***********************************************************
 | 
					 | 
				
			||||||
 * Global variables TODO: most should be moved to gsn_t
 | 
					 | 
				
			||||||
 *************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pdp_t pdpa[PDP_MAX];	/* PDP storage */
 | 
					 | 
				
			||||||
static struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
					 | 
				
			||||||
/* struct pdp_t* haship[PDP_MAX];  Hash table for IP and network interface */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ***********************************************************
 | 
					/* ***********************************************************
 | 
				
			||||||
 * Functions related to PDP storage
 | 
					 * Functions related to PDP storage
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Lifecycle
 | 
					 * Lifecycle
 | 
				
			||||||
 * For a GGSN pdp context life begins with the reception of a 
 | 
					 * For a GGSN pdp context life begins with the reception of a
 | 
				
			||||||
 * create pdp context request. It normally ends with the reception
 | 
					 * create pdp context request. It normally ends with the reception
 | 
				
			||||||
 * of a delete pdp context request, but will also end with the
 | 
					 * of a delete pdp context request, but will also end with the
 | 
				
			||||||
 * reception of an error indication message. 
 | 
					 * reception of an error indication message.
 | 
				
			||||||
 * Provisions should probably be made for terminating pdp contexts
 | 
					 * Provisions should probably be made for terminating pdp contexts
 | 
				
			||||||
 * based on either idle timeout, or by sending downlink probe 
 | 
					 * based on either idle timeout, or by sending downlink probe
 | 
				
			||||||
 * messages (ping?) to see if the MS is still responding.
 | 
					 * messages (ping?) to see if the MS is still responding.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * For an SGSN pdp context life begins with the application just
 | 
					 * For an SGSN pdp context life begins with the application just
 | 
				
			||||||
 * before sending off a create pdp context request. It normally
 | 
					 * before sending off a create pdp context request. It normally
 | 
				
			||||||
 * ends when a delete pdp context response message is received 
 | 
					 * ends when a delete pdp context response message is received
 | 
				
			||||||
 * from the GGSN, but should also end when with the reception of
 | 
					 * from the GGSN, but should also end when with the reception of
 | 
				
			||||||
 * an error indication message.
 | 
					 * an error indication message.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -64,15 +57,15 @@ static struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
				
			|||||||
 * Downlink packets received in the GGSN are identified only by their
 | 
					 * Downlink packets received in the GGSN are identified only by their
 | 
				
			||||||
 * network interface together with their destination IP address (Two
 | 
					 * network interface together with their destination IP address (Two
 | 
				
			||||||
 * network interfaces can use the same private IP address). Each IMSI
 | 
					 * network interfaces can use the same private IP address). Each IMSI
 | 
				
			||||||
 * (mobile station) can have several PDP contexts using the same IP 
 | 
					 * (mobile station) can have several PDP contexts using the same IP
 | 
				
			||||||
 * address. In this case the traffic flow template (TFT) is used to
 | 
					 * address. In this case the traffic flow template (TFT) is used to
 | 
				
			||||||
 * determine the correct PDP context for a particular IMSI. Also it 
 | 
					 * determine the correct PDP context for a particular IMSI. Also it
 | 
				
			||||||
 * should be possible for each PDP context to use several IP adresses
 | 
					 * should be possible for each PDP context to use several IP adresses
 | 
				
			||||||
 * For fixed wireless access a mobile station might need a full class
 | 
					 * For fixed wireless access a mobile station might need a full class
 | 
				
			||||||
 * C network. Even in the case of several IP adresses the PDP context
 | 
					 * C network. Even in the case of several IP adresses the PDP context
 | 
				
			||||||
 * should be determined on the basis of the network IP address.
 | 
					 * should be determined on the basis of the network IP address.
 | 
				
			||||||
 * Thus we need a hash table based on network interface + IP address.
 | 
					 * Thus we need a hash table based on network interface + IP address.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * Uplink packets are for GTP0 identified by their IMSI and NSAPI, which
 | 
					 * Uplink packets are for GTP0 identified by their IMSI and NSAPI, which
 | 
				
			||||||
 * is collectively called the tunnel identifier. There is also a 16 bit
 | 
					 * is collectively called the tunnel identifier. There is also a 16 bit
 | 
				
			||||||
 * flow label that can be used for identification of uplink packets. This
 | 
					 * flow label that can be used for identification of uplink packets. This
 | 
				
			||||||
@@ -85,7 +78,7 @@ static struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
				
			|||||||
 * Thus we need a hash table based on TID (IMSI and NSAPI). The TEID will
 | 
					 * Thus we need a hash table based on TID (IMSI and NSAPI). The TEID will
 | 
				
			||||||
 * be used for directly addressing the PDP context.
 | 
					 * be used for directly addressing the PDP context.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * pdp_newpdp 
 | 
					 * pdp_newpdp
 | 
				
			||||||
 * Gives you a pdp context with no hash references In some way
 | 
					 * Gives you a pdp context with no hash references In some way
 | 
				
			||||||
 * this should have a limited lifetime.
 | 
					 * this should have a limited lifetime.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -112,11 +105,16 @@ static struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *************************************************************/
 | 
					 *************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_init()
 | 
					static struct gsn_t *g_gsn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pdp_init(struct gsn_t *gsn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	memset(&pdpa, 0, sizeof(pdpa));
 | 
						if (!g_gsn) {
 | 
				
			||||||
	memset(&hashtid, 0, sizeof(hashtid));
 | 
							g_gsn = gsn;
 | 
				
			||||||
	/*  memset(&haship, 0, sizeof(haship)); */
 | 
						} else {
 | 
				
			||||||
 | 
							LOGP(DLGTP, LOGL_FATAL, "This interface is depreacted and doesn't support multiple GGSN!");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -124,6 +122,13 @@ int pdp_init()
 | 
				
			|||||||
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
					int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			||||||
	       struct pdp_t *pdp_old)
 | 
						       struct pdp_t *pdp_old)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return gtp_pdp_newpdp(g_gsn, pdp, imsi, nsapi, pdp_old);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			||||||
 | 
						       struct pdp_t *pdp_old)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t *pdpa = gsn->pdpa;
 | 
				
			||||||
	int n;
 | 
						int n;
 | 
				
			||||||
	for (n = 0; n < PDP_MAX; n++) {	/* TODO: Need to do better than linear search */
 | 
						for (n = 0; n < PDP_MAX; n++) {	/* TODO: Need to do better than linear search */
 | 
				
			||||||
		if (pdpa[n].inuse == 0) {
 | 
							if (pdpa[n].inuse == 0) {
 | 
				
			||||||
@@ -133,6 +138,7 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			|||||||
			else
 | 
								else
 | 
				
			||||||
				memset(*pdp, 0, sizeof(struct pdp_t));
 | 
									memset(*pdp, 0, sizeof(struct pdp_t));
 | 
				
			||||||
			(*pdp)->inuse = 1;
 | 
								(*pdp)->inuse = 1;
 | 
				
			||||||
 | 
								(*pdp)->gsn = gsn;
 | 
				
			||||||
			(*pdp)->imsi = imsi;
 | 
								(*pdp)->imsi = imsi;
 | 
				
			||||||
			(*pdp)->nsapi = nsapi;
 | 
								(*pdp)->nsapi = nsapi;
 | 
				
			||||||
			(*pdp)->fllc = (uint16_t) n + 1;
 | 
								(*pdp)->fllc = (uint16_t) n + 1;
 | 
				
			||||||
@@ -151,7 +157,7 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			/* Default: Generate G-PDU sequence numbers on Tx */
 | 
								/* Default: Generate G-PDU sequence numbers on Tx */
 | 
				
			||||||
			(*pdp)->tx_gpdu_seq = true;
 | 
								(*pdp)->tx_gpdu_seq = true;
 | 
				
			||||||
 | 
								INIT_LLIST_HEAD(&(*pdp)->qmsg_list_req);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -160,6 +166,18 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_freepdp(struct pdp_t *pdp)
 | 
					int pdp_freepdp(struct pdp_t *pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct qmsg_t *qmsg, *qmsg2;
 | 
				
			||||||
 | 
						struct pdp_t *pdpa = pdp->gsn->pdpa;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Remove all enqueued messages belonging to this pdp from req tx transmit
 | 
				
			||||||
 | 
						   queue. queue_freemsg will call llist_del(). */
 | 
				
			||||||
 | 
						llist_for_each_entry_safe(qmsg, qmsg2, &pdp->qmsg_list_req, entry) {
 | 
				
			||||||
 | 
							if ((rc = queue_freemsg(pdp->gsn->queue_req, qmsg)))
 | 
				
			||||||
 | 
								LOGP(DLGTP, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "Failed freeing qmsg from qmsg_list_req during pdp_freepdp()! %d\n", rc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdp_tiddel(pdp);
 | 
						pdp_tiddel(pdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Remove any references in primary context */
 | 
						/* Remove any references in primary context */
 | 
				
			||||||
@@ -174,12 +192,20 @@ int pdp_freepdp(struct pdp_t *pdp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_getpdp(struct pdp_t **pdp)
 | 
					int pdp_getpdp(struct pdp_t **pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	*pdp = &pdpa[0];
 | 
						*pdp = &g_gsn->pdpa[0];
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
 | 
					int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return gtp_pdp_getgtp0(g_gsn, pdp, fl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gtp_pdp_getgtp0(struct gsn_t *gsn, struct pdp_t **pdp, uint16_t fl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t *pdpa = gsn->pdpa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((fl > PDP_MAX) || (fl < 1)) {
 | 
						if ((fl > PDP_MAX) || (fl < 1)) {
 | 
				
			||||||
		return EOF;	/* Not found */
 | 
							return EOF;	/* Not found */
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -194,6 +220,13 @@ int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
 | 
					int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return gtp_pdp_getgtp1(g_gsn, pdp, tei);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gtp_pdp_getgtp1(struct gsn_t *gsn, struct pdp_t **pdp, uint32_t tei)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t *pdpa = gsn->pdpa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((tei > PDP_MAX) || (tei < 1)) {
 | 
						if ((tei > PDP_MAX) || (tei < 1)) {
 | 
				
			||||||
		return EOF;	/* Not found */
 | 
							return EOF;	/* Not found */
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -209,6 +242,12 @@ int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
 | 
				
			|||||||
/* get a PDP based on the *peer* address + TEI-Data.  Used for matching inbound Error Ind */
 | 
					/* get a PDP based on the *peer* address + TEI-Data.  Used for matching inbound Error Ind */
 | 
				
			||||||
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
 | 
					int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return gtp_pdp_getgtp1_peer_d(g_gsn, pdp, peer, teid_gn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gtp_pdp_getgtp1_peer_d(struct gsn_t *gsn, struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t *pdpa = gsn->pdpa;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* this is O(n) but we don't have (nor want) another hash... */
 | 
						/* this is O(n) but we don't have (nor want) another hash... */
 | 
				
			||||||
@@ -231,6 +270,7 @@ int pdp_tidhash(uint64_t tid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
 | 
					int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t **hashtid = pdp->gsn->hashtid;
 | 
				
			||||||
	int hash = pdp_tidhash(tid);
 | 
						int hash = pdp_tidhash(tid);
 | 
				
			||||||
	struct pdp_t *pdp2;
 | 
						struct pdp_t *pdp2;
 | 
				
			||||||
	struct pdp_t *pdp_prev = NULL;
 | 
						struct pdp_t *pdp_prev = NULL;
 | 
				
			||||||
@@ -249,6 +289,7 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_tiddel(struct pdp_t *pdp)
 | 
					int pdp_tiddel(struct pdp_t *pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t **hashtid = pdp->gsn->hashtid;
 | 
				
			||||||
	int hash = pdp_tidhash(pdp->tid);
 | 
						int hash = pdp_tidhash(pdp->tid);
 | 
				
			||||||
	struct pdp_t *pdp2;
 | 
						struct pdp_t *pdp2;
 | 
				
			||||||
	struct pdp_t *pdp_prev = NULL;
 | 
						struct pdp_t *pdp_prev = NULL;
 | 
				
			||||||
@@ -270,6 +311,12 @@ int pdp_tiddel(struct pdp_t *pdp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
 | 
					int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return gtp_pdp_tidget(g_gsn, pdp, tid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gtp_pdp_tidget(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t tid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t **hashtid = gsn->hashtid;
 | 
				
			||||||
	int hash = pdp_tidhash(tid);
 | 
						int hash = pdp_tidhash(tid);
 | 
				
			||||||
	struct pdp_t *pdp2;
 | 
						struct pdp_t *pdp2;
 | 
				
			||||||
	DEBUGP(DLGTP, "Begin pdp_tidget tid = %"PRIx64"\n", tid);
 | 
						DEBUGP(DLGTP, "Begin pdp_tidget tid = %"PRIx64"\n", tid);
 | 
				
			||||||
@@ -286,102 +333,17 @@ int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
 | 
					int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return pdp_tidget(pdp,
 | 
						return gtp_pdp_getimsi(g_gsn, pdp, imsi, nsapi);
 | 
				
			||||||
			  (imsi & 0x0fffffffffffffffull) +
 | 
					 | 
				
			||||||
			  ((uint64_t) nsapi << 60));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					int gtp_pdp_getimsi(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
 | 
				
			||||||
int pdp_iphash(void* ipif, struct ul66_t *eua) {
 | 
					{
 | 
				
			||||||
  /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
 | 
						return gtp_pdp_tidget(gsn, pdp, pdp_gettid(imsi, nsapi));
 | 
				
			||||||
  return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
 | 
					 | 
				
			||||||
  int hash;
 | 
					 | 
				
			||||||
  struct pdp_t *pdp2;
 | 
					 | 
				
			||||||
  struct pdp_t *pdp_prev = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
 | 
					 | 
				
			||||||
			(unsigned) ipif, eua->l,
 | 
					 | 
				
			||||||
			eua->v[2], eua->v[3], 
 | 
					 | 
				
			||||||
			eua->v[4], eua->v[5]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pdp->ipnext = NULL;
 | 
					 | 
				
			||||||
  pdp->ipif = ipif;
 | 
					 | 
				
			||||||
  pdp->eua.l = eua->l;
 | 
					 | 
				
			||||||
  memcpy(pdp->eua.v, eua->v, eua->l);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  hash = pdp_iphash(pdp->ipif, &pdp->eua);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
 | 
					 | 
				
			||||||
    pdp_prev = pdp2;
 | 
					 | 
				
			||||||
  if (!pdp_prev) 
 | 
					 | 
				
			||||||
    haship[hash] = pdp;
 | 
					 | 
				
			||||||
  else 
 | 
					 | 
				
			||||||
    pdp_prev->ipnext = pdp;
 | 
					 | 
				
			||||||
  if (PDP_DEBUG) printf("End pdp_ipset\n");
 | 
					 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_ipdel(struct pdp_t *pdp) {
 | 
					 | 
				
			||||||
  int hash = pdp_iphash(pdp->ipif, &pdp->eua);
 | 
					 | 
				
			||||||
  struct pdp_t *pdp2;
 | 
					 | 
				
			||||||
  struct pdp_t *pdp_prev = NULL;
 | 
					 | 
				
			||||||
  if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
 | 
					 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
					 | 
				
			||||||
    if (pdp2 == pdp) {
 | 
					 | 
				
			||||||
      if (!pdp_prev) 
 | 
					 | 
				
			||||||
	haship[hash] = pdp2->ipnext;
 | 
					 | 
				
			||||||
      else 
 | 
					 | 
				
			||||||
	pdp_prev->ipnext = pdp2->ipnext;
 | 
					 | 
				
			||||||
      if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pdp_prev = pdp2;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
 | 
					 | 
				
			||||||
  return EOF; /# End of linked list and not found #/
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
 | 
					 | 
				
			||||||
  int hash = pdp_iphash(ipif, eua);
 | 
					 | 
				
			||||||
  struct pdp_t *pdp2;
 | 
					 | 
				
			||||||
  /#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l, 
 | 
					 | 
				
			||||||
    eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
 | 
					 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
					 | 
				
			||||||
    if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) && 
 | 
					 | 
				
			||||||
	(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
 | 
					 | 
				
			||||||
      *pdp = pdp2;
 | 
					 | 
				
			||||||
      /#printf("End pdp_ipget. Found\n");#/
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n", 
 | 
					 | 
				
			||||||
	 (unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
 | 
					 | 
				
			||||||
  return EOF; /# End of linked list and not found #/
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
/* Various conversion functions */
 | 
					/* Various conversion functions */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	eua->l = 6;
 | 
					 | 
				
			||||||
	eua->v[0] = PDP_EUA_ORG_IETF;
 | 
					 | 
				
			||||||
	eua->v[1] = PDP_EUA_TYPE_v4;
 | 
					 | 
				
			||||||
	memcpy(&eua->v[2], src, 4);	/* Copy a 4 byte address */
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int pdp_euaton(struct ul66_t *eua, struct in_addr *dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if ((eua->l != 6) || (eua->v[0] != PDP_EUA_ORG_IETF) || (eua->v[1] != PDP_EUA_TYPE_v4)) {
 | 
					 | 
				
			||||||
		return EOF;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	memcpy(dst, &eua->v[2], 4);	/* Copy a 4 byte address */
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi)
 | 
					uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60);
 | 
						return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60);
 | 
				
			||||||
@@ -392,3 +354,17 @@ void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid)
 | 
				
			|||||||
	pdp->imsi = teid & 0x0fffffffffffffffull;
 | 
						pdp->imsi = teid & 0x0fffffffffffffffull;
 | 
				
			||||||
	pdp->nsapi = (teid & 0xf000000000000000ull) >> 60;
 | 
						pdp->nsapi = (teid & 0xf000000000000000ull) >> 60;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Count amount of secondary PDP contexts linked to this primary PDP context
 | 
				
			||||||
 | 
					 * (itself included). Must be called on a primary PDP context. */
 | 
				
			||||||
 | 
					unsigned int pdp_count_secondary(const struct pdp_t *pdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int n;
 | 
				
			||||||
 | 
						unsigned int count = 0;
 | 
				
			||||||
 | 
						OSMO_ASSERT(!pdp->secondary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (n = 0; n < PDP_MAXNSAPI; n++)
 | 
				
			||||||
 | 
							if (pdp->secondary_tei[n])
 | 
				
			||||||
 | 
								count++;
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										67
									
								
								gtp/pdp.h
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								gtp/pdp.h
									
									
									
									
									
								
							@@ -1,19 +1,23 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002, 2003 Mondru AB.
 | 
					 *  Copyright (C) 2002, 2003 Mondru AB.
 | 
				
			||||||
 *  Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
 | 
					 *  Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _PDP_H
 | 
					#ifndef _PDP_H
 | 
				
			||||||
#define _PDP_H
 | 
					#define _PDP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/defs.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gsn_t;
 | 
					struct gsn_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +30,7 @@ struct gsn_t;
 | 
				
			|||||||
#define PDP_EUA_ORG_IETF	0xF1
 | 
					#define PDP_EUA_ORG_IETF	0xF1
 | 
				
			||||||
#define PDP_EUA_TYPE_v4		0x21
 | 
					#define PDP_EUA_TYPE_v4		0x21
 | 
				
			||||||
#define PDP_EUA_TYPE_v6		0x57
 | 
					#define PDP_EUA_TYPE_v6		0x57
 | 
				
			||||||
 | 
					#define PDP_EUA_TYPE_v4v6	0x8D
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */
 | 
					/* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */
 | 
				
			||||||
/* Also covers version 0. Note that version 0 6: QOS Profile was superceded *
 | 
					/* Also covers version 0. Note that version 0 6: QOS Profile was superceded *
 | 
				
			||||||
@@ -71,16 +76,16 @@ struct ul255_t {
 | 
				
			|||||||
 * and 09.60.
 | 
					 * and 09.60.
 | 
				
			||||||
 * 31 * 4 + 15 structs +  = 120 + 15 structs ~ 2k / context
 | 
					 * 31 * 4 + 15 structs +  = 120 + 15 structs ~ 2k / context
 | 
				
			||||||
 * Structs: IP address 16+4 bytes (6), APN 255 bytes (2)
 | 
					 * Structs: IP address 16+4 bytes (6), APN 255 bytes (2)
 | 
				
			||||||
 * QOS: 255 bytes (3), msisdn 16 bytes (1), 
 | 
					 * QOS: 255 bytes (3), msisdn 16 bytes (1),
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * TODO: We need to consider who manages the pdp_t hash tables
 | 
					 * TODO: We need to consider who manages the pdp_t hash tables
 | 
				
			||||||
 * Is it gtp_lib, or is it the application?
 | 
					 * Is it gtp_lib, or is it the application?
 | 
				
			||||||
 * I suppose that it will be gtp_lib. 
 | 
					 * I suppose that it will be gtp_lib.
 | 
				
			||||||
 * SGSN will ask gtplib for new pdp_t. Fill out the fields,
 | 
					 * SGSN will ask gtplib for new pdp_t. Fill out the fields,
 | 
				
			||||||
 * and pass it on to gtp_create_pdp_req.
 | 
					 * and pass it on to gtp_create_pdp_req.
 | 
				
			||||||
 * GGSN will receive gtp_create_pdp_ind, create new pdp_t and
 | 
					 * GGSN will receive gtp_create_pdp_ind, create new pdp_t and
 | 
				
			||||||
 * send responce to SGSN.
 | 
					 * send responce to SGSN.
 | 
				
			||||||
 * SGSN will receive response and gtplib will find the 
 | 
					 * SGSN will receive response and gtplib will find the
 | 
				
			||||||
 * original pdp_t corresponding to the request. This will be
 | 
					 * original pdp_t corresponding to the request. This will be
 | 
				
			||||||
 * passed on to the application.
 | 
					 * passed on to the application.
 | 
				
			||||||
 * Eventually the SGSN will close the connection, and the
 | 
					 * Eventually the SGSN will close the connection, and the
 | 
				
			||||||
@@ -88,10 +93,10 @@ struct ul255_t {
 | 
				
			|||||||
 * This means that gtplib need to have functions to
 | 
					 * This means that gtplib need to have functions to
 | 
				
			||||||
 * allocate, free, sort and find pdp_t
 | 
					 * allocate, free, sort and find pdp_t
 | 
				
			||||||
 * (newpdp, freepdp, getpdp)
 | 
					 * (newpdp, freepdp, getpdp)
 | 
				
			||||||
 * Hash tables: TID, IMSI, IP etc.) 
 | 
					 * Hash tables: TID, IMSI, IP etc.)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Secondary PDP Context Activation Procedure 
 | 
					 * Secondary PDP Context Activation Procedure
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * With GTP version 1 it is possible to establish multiple PDP
 | 
					 * With GTP version 1 it is possible to establish multiple PDP
 | 
				
			||||||
 * contexts with the same IP address. With this scheme the first
 | 
					 * contexts with the same IP address. With this scheme the first
 | 
				
			||||||
@@ -121,7 +126,7 @@ struct pdp_t {
 | 
				
			|||||||
	/* Parameters shared by all PDP context belonging to the same MS */
 | 
						/* Parameters shared by all PDP context belonging to the same MS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *ipif;		/* IP network interface */
 | 
						void *ipif;		/* IP network interface */
 | 
				
			||||||
	void *peer;		/* Pointer to peer protocol */
 | 
						void *peer[2];		/* Pointer to peer protocol */
 | 
				
			||||||
	void *asap;		/* Application specific service access point */
 | 
						void *asap;		/* Application specific service access point */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t imsi;		/* International Mobile Subscriber Identity. */
 | 
						uint64_t imsi;		/* International Mobile Subscriber Identity. */
 | 
				
			||||||
@@ -234,40 +239,42 @@ struct pdp_t {
 | 
				
			|||||||
	/* to be used by libgtp callers/users (to attach their own private state) */
 | 
						/* to be used by libgtp callers/users (to attach their own private state) */
 | 
				
			||||||
	void *priv;
 | 
						void *priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct gsn_t *gsn;
 | 
						struct gsn_t *gsn; /* Back pointer to GSN where this pdp ctx belongs to */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool tx_gpdu_seq;		/* Transmit (true) or suppress G-PDU sequence numbers */
 | 
						bool tx_gpdu_seq;		/* Transmit (true) or suppress G-PDU sequence numbers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct llist_head qmsg_list_req; /* list of req qmsg_t in retrans queue belonging this pdp ctx */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* functions related to pdp_t management */
 | 
					/* functions related to pdp_t management */
 | 
				
			||||||
int pdp_init();
 | 
					int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi,
 | 
				
			||||||
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
							   uint8_t nsapi, struct pdp_t *pdp_old);
 | 
				
			||||||
	       struct pdp_t *pdp_old);
 | 
					 | 
				
			||||||
int pdp_freepdp(struct pdp_t *pdp);
 | 
					int pdp_freepdp(struct pdp_t *pdp);
 | 
				
			||||||
int pdp_getpdp(struct pdp_t **pdp);
 | 
					int gtp_pdp_getgtp0(struct gsn_t *gsn, struct pdp_t **pdp, uint16_t fl);
 | 
				
			||||||
 | 
					int gtp_pdp_getgtp1(struct gsn_t *gsn, struct pdp_t **pdp, uint32_t tei);
 | 
				
			||||||
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl);
 | 
					int gtp_pdp_getgtp1_peer_d(struct gsn_t *gsn, struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn);
 | 
				
			||||||
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei);
 | 
					int gtp_pdp_getimsi(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi);
 | 
				
			||||||
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn);
 | 
					int gtp_pdp_tidget(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t tid);
 | 
				
			||||||
 | 
					 | 
				
			||||||
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_tidhash(uint64_t tid);
 | 
					int pdp_tidhash(uint64_t tid);
 | 
				
			||||||
int pdp_tidset(struct pdp_t *pdp, uint64_t tid);
 | 
					int pdp_tidset(struct pdp_t *pdp, uint64_t tid);
 | 
				
			||||||
int pdp_tiddel(struct pdp_t *pdp);
 | 
					int pdp_tiddel(struct pdp_t *pdp);
 | 
				
			||||||
int pdp_tidget(struct pdp_t **pdp, uint64_t tid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
 | 
				
			||||||
void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid);
 | 
					void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					unsigned int pdp_count_secondary(const struct pdp_t *pdp);
 | 
				
			||||||
int pdp_iphash(void* ipif, struct ul66_t *eua);
 | 
					
 | 
				
			||||||
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua);
 | 
					/* Deprecated APIs (support for only 1 GSN per process). Must be used only after first call to gtp_new() and until it is freed. */
 | 
				
			||||||
int pdp_ipdel(struct pdp_t *pdp);
 | 
					int pdp_init(struct gsn_t *gsn); /* Use only allowed inside libgtp to keep compatiblity with deprecated APIs defined here. */
 | 
				
			||||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua);
 | 
					int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
 | 
				
			||||||
*/
 | 
						       struct pdp_t *pdp_old) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
 | 
				
			||||||
 | 
					int pdp_getpdp(struct pdp_t **pdp) OSMO_DEPRECATED("Use gsn_t->pdpa field instead");
 | 
				
			||||||
 | 
					int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl) OSMO_DEPRECATED("Use gtp_pdp_getgtp0() instead");
 | 
				
			||||||
 | 
					int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei) OSMO_DEPRECATED("Use gtp_pdp_getgtp1() instead");
 | 
				
			||||||
 | 
					int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn) OSMO_DEPRECATED("Use gtp_pdp_getgtp1_peer_d() instead");
 | 
				
			||||||
 | 
					int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_getimsi() instead");
 | 
				
			||||||
 | 
					int pdp_tidget(struct pdp_t **pdp, uint64_t tid) OSMO_DEPRECATED("Use gtp_pdp_tidget() instead");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua);
 | 
					 | 
				
			||||||
int pdp_euaton(struct ul66_t *eua, struct in_addr *dst);
 | 
					 | 
				
			||||||
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_PDP_H */
 | 
					#endif /* !_PDP_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										66
									
								
								gtp/queue.c
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								gtp/queue.c
									
									
									
									
									
								
							@@ -1,14 +1,14 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
					 *  Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 *  Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
 | 
					 *  Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 *  Copyright (C) 2016 sysmocom - s.f.m.c. GmbH
 | 
					 *  Copyright (C) 2016 sysmocom - s.f.m.c. GmbH
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -62,7 +62,7 @@ static int queue_seqhash(struct sockaddr_in *peer, uint16_t seq)
 | 
				
			|||||||
	return seq % QUEUE_HASH_SIZE;
 | 
						return seq % QUEUE_HASH_SIZE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Insert a message with given sequence number into the hash
 | 
					/*! \brief Insert a message with given sequence number into the hash.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This function sets the peer and the seq of the qmsg and then inserts
 | 
					 * This function sets the peer and the seq of the qmsg and then inserts
 | 
				
			||||||
 * the qmsg into the queue hash.  To do so, it does a hashtable lookup
 | 
					 * the qmsg into the queue hash.  To do so, it does a hashtable lookup
 | 
				
			||||||
@@ -79,7 +79,7 @@ static int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
 | 
				
			|||||||
	if (QUEUE_DEBUG)
 | 
						if (QUEUE_DEBUG)
 | 
				
			||||||
		printf("Begin queue_seqset seq = %d\n", (int)seq);
 | 
							printf("Begin queue_seqset seq = %d\n", (int)seq);
 | 
				
			||||||
	if (QUEUE_DEBUG)
 | 
						if (QUEUE_DEBUG)
 | 
				
			||||||
		printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer),
 | 
							printf("SIZEOF PEER %zu, *PEER %zu\n", sizeof(peer),
 | 
				
			||||||
		       sizeof(*peer));
 | 
							       sizeof(*peer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qmsg->seq = seq;
 | 
						qmsg->seq = seq;
 | 
				
			||||||
@@ -121,7 +121,10 @@ static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
				
			|||||||
	return EOF;		/* End of linked list and not found */
 | 
						return EOF;		/* End of linked list and not found */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Allocates and initialises new queue structure */
 | 
					/*! Allocates and initialises new queue structure.
 | 
				
			||||||
 | 
					 *  \param[out] queue pointer where to store the allocated object. Must be freed with queue_free
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_new(struct queue_t **queue)
 | 
					int queue_new(struct queue_t **queue)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (QUEUE_DEBUG)
 | 
						if (QUEUE_DEBUG)
 | 
				
			||||||
@@ -138,7 +141,10 @@ int queue_new(struct queue_t **queue)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Deallocates queue structure */
 | 
					/*! Deallocates queue structure.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_free(struct queue_t *queue)
 | 
					int queue_free(struct queue_t *queue)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (QUEUE_DEBUG)
 | 
						if (QUEUE_DEBUG)
 | 
				
			||||||
@@ -149,7 +155,13 @@ int queue_free(struct queue_t *queue)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Add a new message to the queue */
 | 
					/*! Add a new message to the queue.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[out] qmsg first message from the queue (if succeeds)
 | 
				
			||||||
 | 
					 *  \param[in] peer who sent the message to add
 | 
				
			||||||
 | 
					 *  \param[in] seq sequence number of the message to add
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
					int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
				
			||||||
		 struct sockaddr_in *peer, uint16_t seq)
 | 
							 struct sockaddr_in *peer, uint16_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -160,6 +172,7 @@ int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		*qmsg = &queue->qmsga[queue->next];
 | 
							*qmsg = &queue->qmsga[queue->next];
 | 
				
			||||||
		queue_seqset(queue, *qmsg, peer, seq);
 | 
							queue_seqset(queue, *qmsg, peer, seq);
 | 
				
			||||||
 | 
							INIT_LLIST_HEAD(&(*qmsg)->entry);
 | 
				
			||||||
		(*qmsg)->state = 1;	/* Space taken */
 | 
							(*qmsg)->state = 1;	/* Space taken */
 | 
				
			||||||
		(*qmsg)->this = queue->next;
 | 
							(*qmsg)->this = queue->next;
 | 
				
			||||||
		(*qmsg)->next = -1;	/* End of the queue */
 | 
							(*qmsg)->next = -1;	/* End of the queue */
 | 
				
			||||||
@@ -176,7 +189,11 @@ int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Simply remoev a given qmsg_t from the queue
 | 
					
 | 
				
			||||||
 | 
					/*! Remove an element from the queue.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[in] qmsg message to free
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Internally, we first delete the entry from the queue, and then update
 | 
					 * Internally, we first delete the entry from the queue, and then update
 | 
				
			||||||
 * up our global queue->first / queue->last pointers.  Finally,
 | 
					 * up our global queue->first / queue->last pointers.  Finally,
 | 
				
			||||||
@@ -190,6 +207,8 @@ int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
				
			|||||||
		return EOF;	/* Not in queue */
 | 
							return EOF;	/* Not in queue */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_del(&qmsg->entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	queue_seqdel(queue, qmsg);
 | 
						queue_seqdel(queue, qmsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (qmsg->next == -1)	/* Are we the last in queue? */
 | 
						if (qmsg->next == -1)	/* Are we the last in queue? */
 | 
				
			||||||
@@ -210,7 +229,11 @@ int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Move a given qmsg_t to the end of the queue ?!? */
 | 
					/*! Move a given qmsg_t to the end of the queue.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[in] qmsg message to move to the end of the queue
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
					int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (QUEUE_DEBUG)
 | 
						if (QUEUE_DEBUG)
 | 
				
			||||||
@@ -236,7 +259,11 @@ int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Get the first element in the entire queue */
 | 
					/*! Get the first element in the entire queue.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[out] qmsg first message from the queue (if succeeds)
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
 | 
					int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*printf("queue_getfirst\n"); */
 | 
						/*printf("queue_getfirst\n"); */
 | 
				
			||||||
@@ -250,7 +277,13 @@ int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief Get a queue entry for a given peer + seq */
 | 
					/*! Get a queue entry for a given peer + seq.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[out] qmsg first message from the queue (if succeeds)
 | 
				
			||||||
 | 
					 *  \param[in] peer who sent the message to retrieve
 | 
				
			||||||
 | 
					 *  \param[in] seq sequence number of the message to retrive
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
					int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
				
			||||||
		 struct sockaddr_in *peer, uint16_t seq)
 | 
							 struct sockaddr_in *peer, uint16_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -272,7 +305,14 @@ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
 | 
				
			|||||||
	return EOF;		/* End of linked list and not found */
 | 
						return EOF;		/* End of linked list and not found */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief look-up a given seq/peer, return cbp + type and free entry */
 | 
					/*! look-up a given seq/peer, return cbp + type and free entry.
 | 
				
			||||||
 | 
					 *  \param[in] queue pointer previously allocated by queue_new
 | 
				
			||||||
 | 
					 *  \param[in] peer who sent the message to retrieve
 | 
				
			||||||
 | 
					 *  \param[in] seq sequence number of the message to retrive
 | 
				
			||||||
 | 
					 *  \param[out] type GTP message type
 | 
				
			||||||
 | 
					 *  \param[out] type callback pointer of the message
 | 
				
			||||||
 | 
					 *  \returns zero on success, non-zero on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
 | 
					int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
 | 
				
			||||||
		      uint16_t seq, uint8_t * type, void **cbp)
 | 
							      uint16_t seq, uint8_t * type, void **cbp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								gtp/queue.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								gtp/queue.h
									
									
									
									
									
								
							@@ -1,12 +1,12 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
					 *  OsmoGGSN - Gateway GPRS Support Node
 | 
				
			||||||
 *  Copyright (C) 2002 Mondru AB.
 | 
					 *  Copyright (C) 2002 Mondru AB.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  The contents of this file may be used under the terms of the GNU
 | 
					 *  The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 *  General Public License Version 2, provided that the above copyright
 | 
					 *  General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 *  notice and this permission notice is included in all copies or
 | 
					 *  notice and this permission notice is included in all copies or
 | 
				
			||||||
 *  substantial portions of the software.
 | 
					 *  substantial portions of the software.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -17,6 +17,10 @@
 | 
				
			|||||||
#ifndef _QUEUE_H
 | 
					#ifndef _QUEUE_H
 | 
				
			||||||
#define _QUEUE_H
 | 
					#define _QUEUE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gtp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QUEUE_DEBUG 0		/* Print debug information */
 | 
					#define QUEUE_DEBUG 0		/* Print debug information */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QUEUE_SIZE 1024		/* Size of retransmission queue */
 | 
					#define QUEUE_SIZE 1024		/* Size of retransmission queue */
 | 
				
			||||||
@@ -37,6 +41,7 @@ struct qmsg_t {			/* Holder for queued packets */
 | 
				
			|||||||
	int this;		/* Pointer to myself */
 | 
						int this;		/* Pointer to myself */
 | 
				
			||||||
	time_t timeout;		/* When do we retransmit this packet? */
 | 
						time_t timeout;		/* When do we retransmit this packet? */
 | 
				
			||||||
	int retrans;		/* How many times did we retransmit this? */
 | 
						int retrans;		/* How many times did we retransmit this? */
 | 
				
			||||||
 | 
						struct llist_head entry; /* Listed with other qmsg_t belonging to a pdp_t->qmsg_list_req */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct queue_t {
 | 
					struct queue_t {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,12 @@
 | 
				
			|||||||
noinst_LIBRARIES = libmisc.a
 | 
					noinst_LIBRARIES = libmisc.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h
 | 
					noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.h netns.h util.h icmpv6.h checksum.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
 | 
					AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c
 | 
					libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c netdev.c netns.c util.c icmpv6.c checksum.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ENABLE_GTP_KERNEL
 | 
				
			||||||
 | 
					AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
 | 
				
			||||||
 | 
					libmisc_a_SOURCES += gtp-kernel.c
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,12 +24,12 @@ static const struct log_info_cat default_categories[] = {
 | 
				
			|||||||
	[DSGSN] = {
 | 
						[DSGSN] = {
 | 
				
			||||||
		.name = "DSGSN",
 | 
							.name = "DSGSN",
 | 
				
			||||||
		.description = "SGSN Emulator",
 | 
							.description = "SGSN Emulator",
 | 
				
			||||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
							.enabled = 1, .loglevel = LOGL_INFO,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	[DICMP6] = {
 | 
						[DICMP6] = {
 | 
				
			||||||
		.name = "DICMP6",
 | 
							.name = "DICMP6",
 | 
				
			||||||
		.description = "ICMPv6",
 | 
							.description = "ICMPv6",
 | 
				
			||||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
							.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libgtpnl/gtp.h>
 | 
					#include <libgtpnl/gtp.h>
 | 
				
			||||||
#include <libgtpnl/gtpnl.h>
 | 
					#include <libgtpnl/gtpnl.h>
 | 
				
			||||||
#include <libmnl/libmnl.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,27 +25,32 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "../lib/tun.h"
 | 
					#include "../lib/tun.h"
 | 
				
			||||||
#include "../lib/syserr.h"
 | 
					#include "../lib/syserr.h"
 | 
				
			||||||
 | 
					#include "../lib/util.h"
 | 
				
			||||||
 | 
					#include "../lib/ippool.h"
 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libgtpnl/gtp.h>
 | 
					 | 
				
			||||||
#include <libgtpnl/gtpnl.h>
 | 
					 | 
				
			||||||
#include <libmnl/libmnl.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "gtp-kernel.h"
 | 
					#include "gtp-kernel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
 | 
					static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in46_addr ia46;
 | 
						char buf4[INET_ADDRSTRLEN], buf6[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct ippoolm_t *peer;
 | 
				
			||||||
	struct in_addr ia;
 | 
						struct in_addr ia;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	in46a_from_eua(&pdp->eua, &ia46);
 | 
						buf4[0] = '\0';
 | 
				
			||||||
 | 
						if ((peer = pdp_get_peer_ipv(pdp, false)))
 | 
				
			||||||
 | 
							in46a_ntop(&peer->addr, buf4, sizeof(buf4));
 | 
				
			||||||
 | 
						buf6[0] = '\0';
 | 
				
			||||||
 | 
						if ((peer = pdp_get_peer_ipv(pdp, true)))
 | 
				
			||||||
 | 
							in46a_ntop(&peer->addr, buf6, sizeof(buf6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gsna2in_addr(&ia, &pdp->gsnrc);
 | 
						gsna2in_addr(&ia, &pdp->gsnrc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=%s SGSN=%s\n", prefix,
 | 
						LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=(%s,%s) SGSN=%s\n", prefix,
 | 
				
			||||||
		devname, pdp->version,
 | 
							devname, pdp->version,
 | 
				
			||||||
		pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
 | 
							pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
 | 
				
			||||||
		in46a_ntoa(&ia46), inet_ntoa(ia));
 | 
							buf4, buf6, inet_ntoa(ia));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct {
 | 
					static struct {
 | 
				
			||||||
@@ -77,56 +81,20 @@ static int gtp_kernel_init_once(void)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup)
 | 
					int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in_addr net;
 | 
						if (gtp_kernel_init_once() < 0)
 | 
				
			||||||
	const char *net_arg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!gtp_nl.nl)
 | 
					 | 
				
			||||||
		gtp_kernel_init_once();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (prefix->addr.len != 4) {
 | 
					 | 
				
			||||||
		LOGP(DGGSN, LOGL_ERROR, "we only support IPv4 in this path :/");
 | 
					 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	net = prefix->addr.v4;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gtp_dev_create(-1, devname, gsn->fd0, gsn->fd1u) < 0) {
 | 
						return gtp_dev_create(dest_ns, devname, fd0, fd1u);
 | 
				
			||||||
		LOGP(DGGSN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n",
 | 
					}
 | 
				
			||||||
			strerror(errno));
 | 
					
 | 
				
			||||||
 | 
					int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (gtp_kernel_init_once() < 0)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	net_arg = in46p_ntoa(prefix);
 | 
						return gtp_dev_create_sgsn(dest_ns, devname, fd0, fd1u);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	DEBUGP(DGGSN, "Setting route to reach %s via %s\n", net_arg, devname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (gtp_dev_config(devname, &net, prefix->prefixlen) < 0) {
 | 
					 | 
				
			||||||
		LOGP(DGGSN, LOGL_ERROR, "Cannot add route to reach network %s\n", net_arg);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* launch script if it is set to bring up the route to reach
 | 
					 | 
				
			||||||
	 * the MS, eg. ip ro add 10.0.0.0/8 dev gtp0. Better add this
 | 
					 | 
				
			||||||
	 * using native rtnetlink interface given that we know the
 | 
					 | 
				
			||||||
	 * MS network mask, later.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (ipup) {
 | 
					 | 
				
			||||||
		char cmd[1024];
 | 
					 | 
				
			||||||
		int err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* eg. /home/ggsn/ipup gtp0 10.0.0.0/8 */
 | 
					 | 
				
			||||||
		snprintf(cmd, sizeof(cmd), "%s %s %s", ipup, devname, net_arg);
 | 
					 | 
				
			||||||
		cmd[sizeof(cmd)-1] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		err = system(cmd);
 | 
					 | 
				
			||||||
		if (err < 0) {
 | 
					 | 
				
			||||||
			LOGP(DGGSN, LOGL_ERROR, "Failed to launch script `%s'\n", ipup);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	LOGP(DGGSN, LOGL_NOTICE, "GTP kernel configured\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gtp_kernel_stop(const char *devname)
 | 
					void gtp_kernel_stop(const char *devname)
 | 
				
			||||||
@@ -7,18 +7,20 @@ extern int debug;
 | 
				
			|||||||
extern char *ipup;
 | 
					extern char *ipup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef GTP_KERNEL
 | 
					#ifdef GTP_KERNEL
 | 
				
			||||||
int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup);
 | 
					int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u);
 | 
				
			||||||
 | 
					int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u);
 | 
				
			||||||
void gtp_kernel_stop(const char *devname);
 | 
					void gtp_kernel_stop(const char *devname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname);
 | 
					int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname);
 | 
				
			||||||
int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname);
 | 
					int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup)
 | 
					static inline int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n");
 | 
						SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n");
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#define gtp_kernel_create_sgsn gtp_kernel_create
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void gtp_kernel_stop(const char *devname) {}
 | 
					static inline void gtp_kernel_stop(const char *devname) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/* Minimal ICMPv6 code for generating router advertisements as required by
 | 
					/* Minimal ICMPv6 code for generating router advertisements as required by
 | 
				
			||||||
 * relevant 3GPP specs for a GGSN with IPv6 PDP contexts */
 | 
					 * relevant 3GPP specs for a GGSN with IPv6 PDP contexts */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* (C) 2017 by Harald Welte <laforge@gnumonks.org> 
 | 
					/* (C) 2017 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The contents of this file may be used under the terms of the GNU
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 * General Public License Version 2, provided that the above copyright
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
@@ -25,8 +25,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
#include "../lib/ippool.h"
 | 
					#include "ippool.h"
 | 
				
			||||||
#include "../lib/syserr.h"
 | 
					#include "syserr.h"
 | 
				
			||||||
 | 
					#include "icmpv6.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 29.061 11.2.1.3.4 IPv6 Router Configuration Variables in GGSN */
 | 
					/* 29.061 11.2.1.3.4 IPv6 Router Configuration Variables in GGSN */
 | 
				
			||||||
@@ -35,78 +36,68 @@
 | 
				
			|||||||
#define GGSN_AdvValidLifetime	0xffffffff	/* infinite */
 | 
					#define GGSN_AdvValidLifetime	0xffffffff	/* infinite */
 | 
				
			||||||
#define GGSN_AdvPreferredLifetime 0xffffffff	/* infinite */
 | 
					#define GGSN_AdvPreferredLifetime 0xffffffff	/* infinite */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct icmpv6_hdr {
 | 
					/* RFC3307 link-local scope multicast address */
 | 
				
			||||||
	uint8_t type;
 | 
					const struct in6_addr all_router_mcast_addr = {
 | 
				
			||||||
	uint8_t code;
 | 
						.s6_addr = { 0xff,0x02,0,0,  0,0,0,0, 0,0,0,0,  0,0,0,2 }
 | 
				
			||||||
	uint16_t csum;
 | 
					};
 | 
				
			||||||
} __attribute__ ((packed));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RFC4861 Section 4.2 */
 | 
					/* Prepends the ipv6 header and returns checksum content */
 | 
				
			||||||
struct icmpv6_radv_hdr {
 | 
					uint16_t icmpv6_prepend_ip6hdr(struct msgb *msg, const struct in6_addr *saddr,
 | 
				
			||||||
	struct icmpv6_hdr hdr;
 | 
									  const struct in6_addr *daddr)
 | 
				
			||||||
	uint8_t cur_ho_limit;
 | 
					{
 | 
				
			||||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
						uint32_t len;
 | 
				
			||||||
	uint8_t res:6,
 | 
						uint16_t skb_csum;
 | 
				
			||||||
		m:1,
 | 
						struct ip6_hdr *i6h;
 | 
				
			||||||
		o:1;
 | 
					 | 
				
			||||||
#elif BYTE_ORDER == BIG_ENDIAN
 | 
					 | 
				
			||||||
	uint8_t m:1,
 | 
					 | 
				
			||||||
		o:1,
 | 
					 | 
				
			||||||
		res:6;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# error	"Please fix <bits/endian.h>"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	uint16_t router_lifetime;
 | 
					 | 
				
			||||||
	uint32_t reachable_time;
 | 
					 | 
				
			||||||
	uint32_t retrans_timer;
 | 
					 | 
				
			||||||
	uint8_t options[0];
 | 
					 | 
				
			||||||
} __attribute__ ((packed));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RFC4861 Section 4.6 */
 | 
						/* checksum */
 | 
				
			||||||
struct icmpv6_opt_hdr {
 | 
						skb_csum = csum_partial(msgb_data(msg), msgb_length(msg), 0);
 | 
				
			||||||
	uint8_t type;
 | 
						len = msgb_length(msg);
 | 
				
			||||||
	/* length in units of 8 octets, including type+len! */
 | 
						skb_csum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, skb_csum);
 | 
				
			||||||
	uint8_t len;
 | 
					 | 
				
			||||||
	uint8_t data[0];
 | 
					 | 
				
			||||||
} __attribute__ ((packed));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RFC4861 Section 4.6.2 */
 | 
						/* Push IPv6 header in front of ICMPv6 packet */
 | 
				
			||||||
struct icmpv6_opt_prefix {
 | 
						i6h = (struct ip6_hdr *) msgb_push(msg, sizeof(*i6h));
 | 
				
			||||||
	struct icmpv6_opt_hdr hdr;
 | 
						/* 4 bits version, 8 bits TC, 20 bits flow-ID */
 | 
				
			||||||
	uint8_t prefix_len;
 | 
						i6h->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
 | 
				
			||||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
						i6h->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(len);
 | 
				
			||||||
	uint8_t res:6,
 | 
						i6h->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_ICMPV6;
 | 
				
			||||||
		a:1,
 | 
						i6h->ip6_ctlun.ip6_un1.ip6_un1_hlim = 255;
 | 
				
			||||||
		l:1;
 | 
						i6h->ip6_src = *saddr;
 | 
				
			||||||
#elif BYTE_ORDER == BIG_ENDIAN
 | 
						i6h->ip6_dst = *daddr;
 | 
				
			||||||
	uint8_t l:1,
 | 
						return skb_csum;
 | 
				
			||||||
		a:1,
 | 
					}
 | 
				
			||||||
		res:6;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# error	"Please fix <bits/endian.h>"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	uint32_t valid_lifetime;
 | 
					 | 
				
			||||||
	uint32_t preferred_lifetime;
 | 
					 | 
				
			||||||
	uint32_t res2;
 | 
					 | 
				
			||||||
	uint8_t prefix[16];
 | 
					 | 
				
			||||||
} __attribute__ ((packed));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! construct a RFC4861 compliant ICMPv6 router soliciation
 | 
				
			||||||
 | 
					 *  \param[in] saddr Source IPv6 address for router advertisement
 | 
				
			||||||
 | 
					 *  \param[in] daddr Destination IPv6 address for router advertisement IPv6 header
 | 
				
			||||||
 | 
					 *  \param[in] prefix The single prefix to be advertised (/64 implied!)
 | 
				
			||||||
 | 
					 *  \returns callee-allocated message buffer containing router advertisement */
 | 
				
			||||||
 | 
					struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RS");
 | 
				
			||||||
 | 
						struct icmpv6_rsol_hdr *rs;
 | 
				
			||||||
 | 
						OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
						rs = (struct icmpv6_rsol_hdr *) msgb_put(msg, sizeof(*rs));
 | 
				
			||||||
 | 
						rs->hdr.type = 133;	/* see RFC4861 4.1 */
 | 
				
			||||||
 | 
						rs->hdr.code = 0;	/* see RFC4861 4.1 */
 | 
				
			||||||
 | 
						rs->hdr.csum = 0;	/* updated below */
 | 
				
			||||||
 | 
						rs->reserved = 0;	/* see RFC4861 4.1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rs->hdr.csum = icmpv6_prepend_ip6hdr(msg, saddr, &all_router_mcast_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return msg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
/*! construct a 3GPP 29.061 compliant router advertisement for a given prefix
 | 
					/*! construct a 3GPP 29.061 compliant router advertisement for a given prefix
 | 
				
			||||||
 *  \param[in] saddr Source IPv6 address for router advertisement
 | 
					 *  \param[in] saddr Source IPv6 address for router advertisement
 | 
				
			||||||
 *  \param[in] daddr Destination IPv6 address for router advertisement IPv6 header
 | 
					 *  \param[in] daddr Destination IPv6 address for router advertisement IPv6 header
 | 
				
			||||||
 *  \param[in] prefix The single prefix to be advertised (/64 implied!)i
 | 
					 *  \param[in] prefix The single prefix to be advertised (/64 implied!)
 | 
				
			||||||
 *  \returns callee-allocated message buffer containing router advertisement */
 | 
					 *  \returns callee-allocated message buffer containing router advertisement */
 | 
				
			||||||
struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr,
 | 
					static struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr,
 | 
				
			||||||
				 const struct in6_addr *daddr,
 | 
									 const struct in6_addr *daddr,
 | 
				
			||||||
				 const struct in6_addr *prefix)
 | 
									 const struct in6_addr *prefix)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RA");
 | 
						struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RA");
 | 
				
			||||||
	struct icmpv6_radv_hdr *ra;
 | 
						struct icmpv6_radv_hdr *ra;
 | 
				
			||||||
	struct icmpv6_opt_prefix *ra_opt_pref;
 | 
						struct icmpv6_opt_prefix *ra_opt_pref;
 | 
				
			||||||
	struct ip6_hdr *i6h;
 | 
					 | 
				
			||||||
	uint32_t len;
 | 
					 | 
				
			||||||
	uint16_t skb_csum;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(msg);
 | 
						OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,24 +135,12 @@ struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr,
 | 
				
			|||||||
	memcpy(ra_opt_pref->prefix, prefix, sizeof(ra_opt_pref->prefix));
 | 
						memcpy(ra_opt_pref->prefix, prefix, sizeof(ra_opt_pref->prefix));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* checksum */
 | 
						/* checksum */
 | 
				
			||||||
	skb_csum = csum_partial(msgb_data(msg), msgb_length(msg), 0);
 | 
						ra->hdr.csum = icmpv6_prepend_ip6hdr(msg, saddr, daddr);
 | 
				
			||||||
	len = msgb_length(msg);
 | 
					 | 
				
			||||||
	ra->hdr.csum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, skb_csum);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Push IPv6 header in front of ICMPv6 packet */
 | 
					 | 
				
			||||||
	i6h = (struct ip6_hdr *) msgb_push(msg, sizeof(*i6h));
 | 
					 | 
				
			||||||
	/* 4 bits version, 8 bits TC, 20 bits flow-ID */
 | 
					 | 
				
			||||||
	i6h->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
 | 
					 | 
				
			||||||
	i6h->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(len);
 | 
					 | 
				
			||||||
	i6h->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_ICMPV6;
 | 
					 | 
				
			||||||
	i6h->ip6_ctlun.ip6_un1.ip6_un1_hlim = 255;
 | 
					 | 
				
			||||||
	i6h->ip6_src = *saddr;
 | 
					 | 
				
			||||||
	i6h->ip6_dst = *daddr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Walidate an ICMPv6 router solicitation according to RFC4861 6.1.1 */
 | 
					/* Validate an ICMPv6 router solicitation according to RFC4861 6.1.1 */
 | 
				
			||||||
static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
 | 
					static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
						const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
				
			||||||
@@ -179,18 +158,47 @@ static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Validate an ICMPv6 router advertisement according to RFC4861 6.1.2.
 | 
				
			||||||
 | 
					   Returns pointer packet header on success, NULL otherwise. */
 | 
				
			||||||
 | 
					struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
				
			||||||
 | 
						const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ICMP length (derived from IP length) is 16 or more octets */
 | 
				
			||||||
 | 
						if (len < sizeof(*ip6h) + 16)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ic6h->type != 134) /* router advertismenet type */
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*Routers must use their link-local address */
 | 
				
			||||||
 | 
						if (!IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						/* Hop limit field must have 255 */
 | 
				
			||||||
 | 
						if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_hlim != 255)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						/* ICMP Code is 0 */
 | 
				
			||||||
 | 
						if (ic6h->code != 0)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						/* ICMP length (derived from IP length) is 16 or more octets */
 | 
				
			||||||
 | 
						if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_plen < 16)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						/* FIXME: All included options have a length > 0 */
 | 
				
			||||||
 | 
						/* FIXME: If IP source is unspecified, no source link-layer addr option */
 | 
				
			||||||
 | 
						return (struct icmpv6_radv_hdr *)ic6h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* handle incoming packets to the all-routers multicast address */
 | 
					/* handle incoming packets to the all-routers multicast address */
 | 
				
			||||||
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *own_ll_addr,
 | 
					int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
 | 
								const struct in6_addr *pdp_prefix,
 | 
				
			||||||
 | 
								const struct in6_addr *own_ll_addr,
 | 
				
			||||||
			const uint8_t *pack, unsigned len)
 | 
								const uint8_t *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ippoolm_t *member = pdp->peer;
 | 
					 | 
				
			||||||
	const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
						const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
				
			||||||
	const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
 | 
						const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(pdp);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(member);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (len < sizeof(*ip6h)) {
 | 
						if (len < sizeof(*ip6h)) {
 | 
				
			||||||
		LOGP(DICMP6, LOGL_NOTICE, "Packet too short: %u bytes\n", len);
 | 
							LOGP(DICMP6, LOGL_NOTICE, "Packet too short: %u bytes\n", len);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -221,7 +229,7 @@ int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_a
 | 
				
			|||||||
		/* Send router advertisement from GGSN link-local
 | 
							/* Send router advertisement from GGSN link-local
 | 
				
			||||||
		 * address to MS link-local address, including prefix
 | 
							 * address to MS link-local address, including prefix
 | 
				
			||||||
		 * allocated to this PDP context */
 | 
							 * allocated to this PDP context */
 | 
				
			||||||
		msg = icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, &member->addr.v6);
 | 
							msg = icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, pdp_prefix);
 | 
				
			||||||
		/* Send the constructed RA to the MS */
 | 
							/* Send the constructed RA to the MS */
 | 
				
			||||||
		gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
 | 
							gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
							
								
								
									
										100
									
								
								lib/icmpv6.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								lib/icmpv6.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/endian.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ICMPv6_OPT_TYPE_PREFIX_INFO 0x03
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define foreach_icmpv6_opt(icmpv6_pkt, icmpv6_len, opt_hdr) \
 | 
				
			||||||
 | 
							for (opt_hdr = (struct icmpv6_opt_hdr *)(icmpv6_pkt)->options; \
 | 
				
			||||||
 | 
							     (uint8_t*)(opt_hdr) + sizeof(struct icmpv6_opt_hdr) <= (((uint8_t*)(icmpv6_pkt)) + (icmpv6_len)); \
 | 
				
			||||||
 | 
							     opt_hdr = (struct icmpv6_opt_hdr*)((uint8_t*)(opt_hdr) + (opt_hdr)->len) \
 | 
				
			||||||
 | 
							    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct icmpv6_hdr {
 | 
				
			||||||
 | 
						uint8_t type;
 | 
				
			||||||
 | 
						uint8_t code;
 | 
				
			||||||
 | 
						uint16_t csum;
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct icmpv6_echo_hdr {
 | 
				
			||||||
 | 
						struct icmpv6_hdr hdr;
 | 
				
			||||||
 | 
						uint16_t ident;		/* Identifier */
 | 
				
			||||||
 | 
						uint16_t seq;		/* Sequence number */
 | 
				
			||||||
 | 
						uint8_t data[0];	/* Data */
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC4861 Section 4.1 */
 | 
				
			||||||
 | 
					struct icmpv6_rsol_hdr {
 | 
				
			||||||
 | 
						struct icmpv6_hdr hdr;
 | 
				
			||||||
 | 
						uint32_t reserved;
 | 
				
			||||||
 | 
						uint8_t options[0];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC4861 Section 4.2 */
 | 
				
			||||||
 | 
					struct icmpv6_radv_hdr {
 | 
				
			||||||
 | 
						struct icmpv6_hdr hdr;
 | 
				
			||||||
 | 
						uint8_t cur_ho_limit;
 | 
				
			||||||
 | 
					#if OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t res:6,
 | 
				
			||||||
 | 
							m:1,
 | 
				
			||||||
 | 
							o:1;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						uint8_t m:1,
 | 
				
			||||||
 | 
							o:1,
 | 
				
			||||||
 | 
							res:6;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						uint16_t router_lifetime;
 | 
				
			||||||
 | 
						uint32_t reachable_time;
 | 
				
			||||||
 | 
						uint32_t retrans_timer;
 | 
				
			||||||
 | 
						uint8_t options[0];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC4861 Section 4.6 */
 | 
				
			||||||
 | 
					struct icmpv6_opt_hdr {
 | 
				
			||||||
 | 
						uint8_t type;
 | 
				
			||||||
 | 
						/* length in units of 8 octets, including type+len! */
 | 
				
			||||||
 | 
						uint8_t len;
 | 
				
			||||||
 | 
						uint8_t data[0];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC4861 Section 4.6.2 */
 | 
				
			||||||
 | 
					struct icmpv6_opt_prefix {
 | 
				
			||||||
 | 
						struct icmpv6_opt_hdr hdr;
 | 
				
			||||||
 | 
						uint8_t prefix_len;
 | 
				
			||||||
 | 
					#if OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t res:6,
 | 
				
			||||||
 | 
							a:1,
 | 
				
			||||||
 | 
							l:1;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						uint8_t l:1,
 | 
				
			||||||
 | 
							a:1,
 | 
				
			||||||
 | 
							res:6;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						uint32_t valid_lifetime;
 | 
				
			||||||
 | 
						uint32_t preferred_lifetime;
 | 
				
			||||||
 | 
						uint32_t res2;
 | 
				
			||||||
 | 
						uint8_t prefix[16];
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t icmpv6_prepend_ip6hdr(struct msgb *msg, const struct in6_addr *saddr,
 | 
				
			||||||
 | 
									  const struct in6_addr *daddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
 | 
								const struct in6_addr *pdp_prefix,
 | 
				
			||||||
 | 
								const struct in6_addr *own_ll_addr,
 | 
				
			||||||
 | 
								const uint8_t *pack, unsigned len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RFC3307 link-local scope multicast address */
 | 
				
			||||||
 | 
					extern const struct in6_addr all_router_mcast_addr;
 | 
				
			||||||
							
								
								
									
										115
									
								
								lib/in46_addr.c
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								lib/in46_addr.c
									
									
									
									
									
								
							@@ -60,7 +60,11 @@ int in46a_to_sas(struct sockaddr_storage *out, const struct in46_addr *in)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Convenience wrapper around inet_ntop() for \ref in46_addr */
 | 
					/*! Convenience wrapper around inet_ntop() for in46_addr.
 | 
				
			||||||
 | 
					 *  \param[in] in the in46_addr to print
 | 
				
			||||||
 | 
					 *  \param[out] dst destination buffer where string representation of the address is stored
 | 
				
			||||||
 | 
					 *  \param[out] dst_size size dst. Usually it should be at least INET6_ADDRSTRLEN.
 | 
				
			||||||
 | 
					 *  \return address of dst on success, NULL on error */
 | 
				
			||||||
const char *in46a_ntop(const struct in46_addr *in, char *dst, socklen_t dst_size)
 | 
					const char *in46a_ntop(const struct in46_addr *in, char *dst, socklen_t dst_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int af;
 | 
						int af;
 | 
				
			||||||
@@ -253,33 +257,66 @@ unsigned int in46a_netmasklen(const struct in46_addr *netmask)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Convert given PDP End User Address to in46_addr
 | 
					/*! Convert given array of in46_addr to PDP End User Address
 | 
				
			||||||
 *  \returns 0 on success; negative on error */
 | 
					 *  \param[in] src Array containing 1 or 2 in46_addr
 | 
				
			||||||
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua)
 | 
					 *  \param[out] eua End User Address structure to fill
 | 
				
			||||||
 | 
					 *  \returns 0 on success; negative on error
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In case size is 2, this function expects to find exactly one IPv4 and one
 | 
				
			||||||
 | 
					 * IPv6 addresses in src. */
 | 
				
			||||||
 | 
					int in46a_to_eua(const struct in46_addr *src, unsigned int size, struct ul66_t *eua)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (src->len) {
 | 
						const struct in46_addr *src_v4, *src_v6;
 | 
				
			||||||
	case 4:
 | 
						if (size == 1) {
 | 
				
			||||||
		eua->l = 6;
 | 
							switch (src->len) {
 | 
				
			||||||
		eua->v[0] = PDP_EUA_ORG_IETF;
 | 
							case 4:
 | 
				
			||||||
		eua->v[1] = PDP_EUA_TYPE_v4;
 | 
								eua->l = 6;
 | 
				
			||||||
		memcpy(&eua->v[2], &src->v4, 4);	/* Copy a 4 byte address */
 | 
								eua->v[0] = PDP_EUA_ORG_IETF;
 | 
				
			||||||
		break;
 | 
								eua->v[1] = PDP_EUA_TYPE_v4;
 | 
				
			||||||
	case 8:
 | 
								memcpy(&eua->v[2], &src->v4, 4);	/* Copy a 4 byte address */
 | 
				
			||||||
	case 16:
 | 
								break;
 | 
				
			||||||
		eua->l = 18;
 | 
							case 8:
 | 
				
			||||||
		eua->v[0] = PDP_EUA_ORG_IETF;
 | 
							case 16:
 | 
				
			||||||
		eua->v[1] = PDP_EUA_TYPE_v6;
 | 
								eua->l = 18;
 | 
				
			||||||
		memcpy(&eua->v[2], &src->v6, 16);	/* Copy a 16 byte address */
 | 
								eua->v[0] = PDP_EUA_ORG_IETF;
 | 
				
			||||||
		break;
 | 
								eua->v[1] = PDP_EUA_TYPE_v6;
 | 
				
			||||||
	default:
 | 
								memcpy(&eua->v[2], &src->v6, 16);	/* Copy a 16 byte address */
 | 
				
			||||||
		OSMO_ASSERT(0);
 | 
								break;
 | 
				
			||||||
		return -1;
 | 
							default:
 | 
				
			||||||
 | 
								OSMO_ASSERT(0);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (src[0].len == src[1].len)
 | 
				
			||||||
 | 
							return -1; /* we should have a v4 and a v6 address */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						src_v4 = (src[0].len == 4) ? &src[0] : &src[1];
 | 
				
			||||||
 | 
						src_v6 = (src[0].len == 4) ? &src[1] : &src[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						eua->l = 22;
 | 
				
			||||||
 | 
						eua->v[0] = PDP_EUA_ORG_IETF;
 | 
				
			||||||
 | 
						eua->v[1] = PDP_EUA_TYPE_v4v6;
 | 
				
			||||||
 | 
						memcpy(&eua->v[2], &src_v4->v4, 4);
 | 
				
			||||||
 | 
						memcpy(&eua->v[6], &src_v6->v6, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Convert given in46_addr to PDP End User Address
 | 
					/*! Convert given PDP End User Address to an array of in46_addr
 | 
				
			||||||
 *  \returns 0 on success; negative on error */
 | 
					 *  \param[in] eua End User Address structure to parse
 | 
				
			||||||
 | 
					 *  \param[out] dst Array containing 2 in46_addr
 | 
				
			||||||
 | 
					 *  \returns number of parsed addresses (1 or 2) on success; negative on error
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function expects to receive an End User Address struct together with an
 | 
				
			||||||
 | 
					 * array of 2 zeroed in46_addr structs. The in46_addr structs are filled in
 | 
				
			||||||
 | 
					 * order, hence if the function returns 1 the parsed address will be stored in
 | 
				
			||||||
 | 
					 * the first struct and the second one will be left intact. If 2 is returned, it
 | 
				
			||||||
 | 
					 * is guaranteed that one of them is an IPv4 and the other one is an IPv6, but
 | 
				
			||||||
 | 
					 * the order in which they are presented is not specified and must be
 | 
				
			||||||
 | 
					 * discovered for instance by checking the len field of each address.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
 | 
					int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (eua->l < 2)
 | 
						if (eua->l < 2)
 | 
				
			||||||
@@ -295,22 +332,46 @@ int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
 | 
				
			|||||||
			memcpy(&dst->v4, &eua->v[2], 4);	/* Copy a 4 byte address */
 | 
								memcpy(&dst->v4, &eua->v[2], 4);	/* Copy a 4 byte address */
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			dst->v4.s_addr = 0;
 | 
								dst->v4.s_addr = 0;
 | 
				
			||||||
		break;
 | 
							return 1;
 | 
				
			||||||
	case PDP_EUA_TYPE_v6:
 | 
						case PDP_EUA_TYPE_v6:
 | 
				
			||||||
		dst->len = 16;
 | 
							dst->len = 16;
 | 
				
			||||||
		if (eua->l >= 18)
 | 
							if (eua->l >= 18)
 | 
				
			||||||
			memcpy(&dst->v6, &eua->v[2], 16);	/* Copy a 16 byte address */
 | 
								memcpy(&dst->v6, &eua->v[2], 16);	/* Copy a 16 byte address */
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			memset(&dst->v6, 0, 16);
 | 
								memset(&dst->v6, 0, 16);
 | 
				
			||||||
		break;
 | 
							return 1;
 | 
				
			||||||
 | 
						case PDP_EUA_TYPE_v4v6:
 | 
				
			||||||
 | 
							/* 3GPP TS 29.060, section 7.7.27 */
 | 
				
			||||||
 | 
							switch (eua->l) {
 | 
				
			||||||
 | 
								case 2: /* v4 & v6 dynamic */
 | 
				
			||||||
 | 
									dst[0].v4.s_addr = 0;
 | 
				
			||||||
 | 
									memset(&dst[1].v6, 0, 16);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 6: /* v4 static, v6 dynamic */
 | 
				
			||||||
 | 
									memcpy(&dst[0].v4, &eua->v[2], 4);
 | 
				
			||||||
 | 
									memset(&dst[1].v6, 0, 16);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 18: /* v4 dynamic, v6 static */
 | 
				
			||||||
 | 
									dst[0].v4.s_addr = 0;
 | 
				
			||||||
 | 
									memcpy(&dst[1].v6, &eua->v[2], 16);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 22:  /* v4 & v6 static */
 | 
				
			||||||
 | 
									memcpy(&dst[0].v4, &eua->v[2], 4);
 | 
				
			||||||
 | 
									memcpy(&dst[1].v6, &eua->v[6], 16);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dst[0].len = 4;
 | 
				
			||||||
 | 
							dst[1].len = 16;
 | 
				
			||||||
 | 
							return 2;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
default_to_dyn_v4:
 | 
					default_to_dyn_v4:
 | 
				
			||||||
	/* assume dynamic IPv4 by default */
 | 
						/* assume dynamic IPv4 by default */
 | 
				
			||||||
	dst->len = 4;
 | 
						dst->len = 4;
 | 
				
			||||||
	dst->v4.s_addr = 0;
 | 
						dst->v4.s_addr = 0;
 | 
				
			||||||
	return 0;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,5 +29,13 @@ extern int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr
 | 
				
			|||||||
extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen);
 | 
					extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen);
 | 
				
			||||||
unsigned int in46a_netmasklen(const struct in46_addr *netmask);
 | 
					unsigned int in46a_netmasklen(const struct in46_addr *netmask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua);
 | 
					int in46a_to_eua(const struct in46_addr *src, unsigned int size, struct ul66_t *eua);
 | 
				
			||||||
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
 | 
					int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool in46a_is_v6(const struct in46_addr *addr) {
 | 
				
			||||||
 | 
						return addr->len == 8 || addr->len == 16;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool in46a_is_v4(const struct in46_addr *addr) {
 | 
				
			||||||
 | 
						return addr->len == sizeof(struct in_addr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								lib/ippool.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								lib/ippool.c
									
									
									
									
									
								
							@@ -26,16 +26,16 @@ int ippool_printaddr(struct ippool_t *this)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int n;
 | 
						unsigned int n;
 | 
				
			||||||
	printf("ippool_printaddr\n");
 | 
						printf("ippool_printaddr\n");
 | 
				
			||||||
	printf("Firstdyn %d\n", this->firstdyn - this->member);
 | 
						printf("Firstdyn %td\n", this->firstdyn - this->member);
 | 
				
			||||||
	printf("Lastdyn %d\n", this->lastdyn - this->member);
 | 
						printf("Lastdyn %td\n", this->lastdyn - this->member);
 | 
				
			||||||
	printf("Firststat %d\n", this->firststat - this->member);
 | 
						printf("Firststat %td\n", this->firststat - this->member);
 | 
				
			||||||
	printf("Laststat %d\n", this->laststat - this->member);
 | 
						printf("Laststat %td\n", this->laststat - this->member);
 | 
				
			||||||
	printf("Listsize %d\n", this->listsize);
 | 
						printf("Listsize %u\n", this->listsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (n = 0; n < this->listsize; n++) {
 | 
						for (n = 0; n < this->listsize; n++) {
 | 
				
			||||||
		char s[256];
 | 
							char s[256];
 | 
				
			||||||
		in46a_ntop(&this->member[n].addr, s, sizeof(s));
 | 
							in46a_ntop(&this->member[n].addr, s, sizeof(s));
 | 
				
			||||||
		printf("Unit %d inuse %d prev %d next %d addr %s\n",
 | 
							printf("Unit %d inuse %d prev %td next %td addr %s\n",
 | 
				
			||||||
		       n,
 | 
							       n,
 | 
				
			||||||
		       this->member[n].inuse,
 | 
							       this->member[n].inuse,
 | 
				
			||||||
		       this->member[n].prev - this->member,
 | 
							       this->member[n].prev - this->member,
 | 
				
			||||||
@@ -202,7 +202,7 @@ int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const stru
 | 
				
			|||||||
	/* Parse only first instance of pool for now */
 | 
						/* Parse only first instance of pool for now */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct in46_addr addr;
 | 
						struct in46_addr addr = { 0 };
 | 
				
			||||||
	size_t addrprefixlen;
 | 
						size_t addrprefixlen;
 | 
				
			||||||
	struct in46_addr stataddr;
 | 
						struct in46_addr stataddr;
 | 
				
			||||||
	size_t stataddrprefixlen;
 | 
						size_t stataddrprefixlen;
 | 
				
			||||||
@@ -276,9 +276,8 @@ int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const stru
 | 
				
			|||||||
	(*this)->hashmask = (*this)->hashsize - 1;
 | 
						(*this)->hashmask = (*this)->hashsize - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate hash table */
 | 
						/* Allocate hash table */
 | 
				
			||||||
	if (!
 | 
						(*this)->hash = calloc((*this)->hashsize, sizeof(struct ippoolm_t *));
 | 
				
			||||||
	    ((*this)->hash =
 | 
						if (!(*this)->hash) {
 | 
				
			||||||
	     calloc(sizeof(struct ippoolm_t), (*this)->hashsize))) {
 | 
					 | 
				
			||||||
		SYS_ERR(DIP, LOGL_ERROR, 0,
 | 
							SYS_ERR(DIP, LOGL_ERROR, 0,
 | 
				
			||||||
			"Failed to allocate memory for hash members in ippool");
 | 
								"Failed to allocate memory for hash members in ippool");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -513,7 +512,15 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
 | 
				
			|||||||
		p2->next = NULL;
 | 
							p2->next = NULL;
 | 
				
			||||||
		p2->prev = NULL;
 | 
							p2->prev = NULL;
 | 
				
			||||||
		p2->inuse = 2;	/* Static address in use */
 | 
							p2->inuse = 2;	/* Static address in use */
 | 
				
			||||||
		memcpy(&p2->addr, addr, sizeof(addr));
 | 
							/* p2->addr.len and addr->len already match (see above). */
 | 
				
			||||||
 | 
							if (p2->addr.len == sizeof(struct in_addr))
 | 
				
			||||||
 | 
								p2->addr.v4 = addr->v4;
 | 
				
			||||||
 | 
							else if (p2->addr.len == sizeof(struct in6_addr))
 | 
				
			||||||
 | 
								p2->addr.v6 = addr->v6;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
 | 
				
			||||||
 | 
								return -GTPCAUSE_UNKNOWN_PDP;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		*member = p2;
 | 
							*member = p2;
 | 
				
			||||||
		(void)ippool_hashadd(this, *member);
 | 
							(void)ippool_hashadd(this, *member);
 | 
				
			||||||
		if (0)
 | 
							if (0)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										792
									
								
								lib/netdev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										792
									
								
								lib/netdev.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,792 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * TUN interface functions.
 | 
				
			||||||
 | 
					 * Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 | 
					 * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * netdev.c: Contains generic network device related functionality.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <net/route.h>
 | 
				
			||||||
 | 
					#include <net/if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					#include <linux/netlink.h>
 | 
				
			||||||
 | 
					#include <linux/rtnetlink.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined (__FreeBSD__)
 | 
				
			||||||
 | 
					#include <net/if_var.h>
 | 
				
			||||||
 | 
					#include <netinet/in_var.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined (__APPLE__)
 | 
				
			||||||
 | 
					#include <net/if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#error  "Unknown platform!"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "netdev.h"
 | 
				
			||||||
 | 
					#include "syserr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/ipv6.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int netdev_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = RTA_LENGTH(dlen);
 | 
				
			||||||
 | 
						int alen = NLMSG_ALIGN(n->nlmsg_len);
 | 
				
			||||||
 | 
						struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
 | 
				
			||||||
 | 
						if (alen + len > nsize)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						rta->rta_len = len;
 | 
				
			||||||
 | 
						rta->rta_type = type;
 | 
				
			||||||
 | 
						memcpy(RTA_DATA(rta), d, dlen);
 | 
				
			||||||
 | 
						n->nlmsg_len = alen + len;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int netdev_sifflags(const char *devname, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ifreq ifr;
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&ifr, '\0', sizeof(ifr));
 | 
				
			||||||
 | 
						ifr.ifr_flags = flags;
 | 
				
			||||||
 | 
						strncpy(ifr.ifr_name, devname, IFNAMSIZ);
 | 
				
			||||||
 | 
						ifr.ifr_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
								"ioctl(SIOCSIFFLAGS) failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_setaddr4(const char *devname, struct in_addr *addr,
 | 
				
			||||||
 | 
							    struct in_addr *dstaddr, struct in_addr *netmask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ifreq ifr;
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&ifr, '\0', sizeof(ifr));
 | 
				
			||||||
 | 
						ifr.ifr_addr.sa_family = AF_INET;
 | 
				
			||||||
 | 
						ifr.ifr_dstaddr.sa_family = AF_INET;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						ifr.ifr_netmask.sa_family = AF_INET;
 | 
				
			||||||
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
 | 
				
			||||||
 | 
						    sizeof(struct sockaddr_in);
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
 | 
				
			||||||
 | 
						    sizeof(struct sockaddr_in);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(ifr.ifr_name, devname, IFNAMSIZ);
 | 
				
			||||||
 | 
						ifr.ifr_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel. */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (addr) {		/* Set the interface address */
 | 
				
			||||||
 | 
							memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
 | 
				
			||||||
 | 
							       sizeof(*addr));
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
 | 
				
			||||||
 | 
								if (errno != EEXIST) {
 | 
				
			||||||
 | 
									SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
										"ioctl(SIOCSIFADDR) failed");
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									SYS_ERR(DTUN, LOGL_NOTICE, errno,
 | 
				
			||||||
 | 
										"ioctl(SIOCSIFADDR): Address already exists");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dstaddr) {		/* Set the destination address */
 | 
				
			||||||
 | 
							memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
 | 
				
			||||||
 | 
							       dstaddr, sizeof(*dstaddr));
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCSIFDSTADDR) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (netmask) {		/* Set the netmask */
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
							memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
 | 
				
			||||||
 | 
							       netmask, sizeof(*netmask));
 | 
				
			||||||
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
							((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
 | 
				
			||||||
 | 
							    netmask->s_addr;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCSIFNETMASK) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* On linux the route to the interface is set automatically
 | 
				
			||||||
 | 
						   on FreeBSD we have to do this manually */
 | 
				
			||||||
 | 
					#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						netdev_addroute4(dstaddr, addr, &this->netmask);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
 | 
				
			||||||
 | 
							    size_t prefixlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in6_ifreq ifr;
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&ifr, 0, sizeof(ifr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						ifr.ifr6_prefixlen = prefixlen;
 | 
				
			||||||
 | 
						ifr.ifr6_ifindex = if_nametoindex(devname);
 | 
				
			||||||
 | 
						if (ifr.ifr6_ifindex == 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", devname);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						strncpy(ifr.ifr_name, devname, IFNAMSIZ);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						if (addr) {
 | 
				
			||||||
 | 
							memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
 | 
				
			||||||
 | 
								if (errno != EEXIST) {
 | 
				
			||||||
 | 
									SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						/* FIXME: looks like this is not possible/necessary for IPv6? */
 | 
				
			||||||
 | 
						if (dstaddr) {
 | 
				
			||||||
 | 
							memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						if (addr)
 | 
				
			||||||
 | 
							memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
 | 
				
			||||||
 | 
						if (dstaddr)
 | 
				
			||||||
 | 
							memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* On linux the route to the interface is set automatically
 | 
				
			||||||
 | 
						   on FreeBSD we have to do this manually */
 | 
				
			||||||
 | 
					#if 0	/* FIXME */
 | 
				
			||||||
 | 
					//#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						netdev_addroute6(dstaddr, addr, prefixlen);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_addaddr4(const char *devname, struct in_addr *addr,
 | 
				
			||||||
 | 
							    struct in_addr *dstaddr, struct in_addr *netmask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct nlmsghdr n;
 | 
				
			||||||
 | 
							struct ifaddrmsg i;
 | 
				
			||||||
 | 
							char buf[TUN_NLBUFSIZE];
 | 
				
			||||||
 | 
						} req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sockaddr_nl local;
 | 
				
			||||||
 | 
						socklen_t addr_len;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sockaddr_nl nladdr;
 | 
				
			||||||
 | 
						struct iovec iov;
 | 
				
			||||||
 | 
						struct msghdr msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&req, 0, sizeof(req));
 | 
				
			||||||
 | 
						req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 | 
				
			||||||
 | 
						req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
 | 
				
			||||||
 | 
						req.n.nlmsg_type = RTM_NEWADDR;
 | 
				
			||||||
 | 
						req.i.ifa_family = AF_INET;
 | 
				
			||||||
 | 
						req.i.ifa_prefixlen = 32;	/* 32 FOR IPv4 */
 | 
				
			||||||
 | 
						req.i.ifa_flags = 0;
 | 
				
			||||||
 | 
						req.i.ifa_scope = RT_SCOPE_HOST;	/* TODO or 0 */
 | 
				
			||||||
 | 
						req.i.ifa_index = if_nametoindex(devname);
 | 
				
			||||||
 | 
						if (!req.i.ifa_index) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
 | 
				
			||||||
 | 
						if (dstaddr)
 | 
				
			||||||
 | 
							netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&local, 0, sizeof(local));
 | 
				
			||||||
 | 
						local.nl_family = AF_NETLINK;
 | 
				
			||||||
 | 
						local.nl_groups = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr_len = sizeof(local);
 | 
				
			||||||
 | 
						if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
								"getsockname() failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (addr_len != sizeof(local)) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
				
			||||||
 | 
								"Wrong address length %d", addr_len);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (local.nl_family != AF_NETLINK) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
				
			||||||
 | 
								"Wrong address family %d", local.nl_family);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iov.iov_base = (void *)&req.n;
 | 
				
			||||||
 | 
						iov.iov_len = req.n.nlmsg_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg.msg_name = (void *)&nladdr;
 | 
				
			||||||
 | 
						msg.msg_namelen = sizeof(nladdr);
 | 
				
			||||||
 | 
						msg.msg_iov = &iov;
 | 
				
			||||||
 | 
						msg.msg_iovlen = 1;
 | 
				
			||||||
 | 
						msg.msg_control = NULL;
 | 
				
			||||||
 | 
						msg.msg_controllen = 0;
 | 
				
			||||||
 | 
						msg.msg_flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&nladdr, 0, sizeof(nladdr));
 | 
				
			||||||
 | 
						nladdr.nl_family = AF_NETLINK;
 | 
				
			||||||
 | 
						nladdr.nl_pid = 0;
 | 
				
			||||||
 | 
						nladdr.nl_groups = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.n.nlmsg_seq = 0;
 | 
				
			||||||
 | 
						req.n.nlmsg_flags |= NLM_F_ACK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = sendmsg(fd, &msg, 0);
 | 
				
			||||||
 | 
						if (status != req.n.nlmsg_len) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
 | 
				
			||||||
 | 
						if (status == -1) {
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#elif defined (__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						struct ifaliasreq areq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&areq, 0, sizeof(areq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up interface name */
 | 
				
			||||||
 | 
						strncpy(areq.ifra_name, devname, IFNAMSIZ);
 | 
				
			||||||
 | 
						areq.ifra_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
 | 
				
			||||||
 | 
						    sizeof(areq.ifra_addr);
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
 | 
				
			||||||
 | 
						    sizeof(areq.ifra_mask);
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
 | 
				
			||||||
 | 
						    netmask->s_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
 | 
				
			||||||
 | 
						    sizeof(areq.ifra_broadaddr);
 | 
				
			||||||
 | 
						((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
 | 
				
			||||||
 | 
						    dstaddr->s_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel. */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
								"ioctl(SIOCAIFADDR) failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_addaddr6(const char *devname, struct in6_addr *addr,
 | 
				
			||||||
 | 
							    struct in6_addr *dstaddr, int prefixlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct nlmsghdr n;
 | 
				
			||||||
 | 
							struct ifaddrmsg i;
 | 
				
			||||||
 | 
							char buf[TUN_NLBUFSIZE];
 | 
				
			||||||
 | 
						} req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sockaddr_nl local;
 | 
				
			||||||
 | 
						socklen_t addr_len;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sockaddr_nl nladdr;
 | 
				
			||||||
 | 
						struct iovec iov;
 | 
				
			||||||
 | 
						struct msghdr msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&req, 0, sizeof(req));
 | 
				
			||||||
 | 
						req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 | 
				
			||||||
 | 
						req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
 | 
				
			||||||
 | 
						req.n.nlmsg_type = RTM_NEWADDR;
 | 
				
			||||||
 | 
						req.i.ifa_family = AF_INET6;
 | 
				
			||||||
 | 
						req.i.ifa_prefixlen = prefixlen;	/* 64 FOR IPv6 */
 | 
				
			||||||
 | 
						req.i.ifa_flags = 0;
 | 
				
			||||||
 | 
						req.i.ifa_scope = RT_SCOPE_HOST;	/* TODO or 0 */
 | 
				
			||||||
 | 
						req.i.ifa_index = if_nametoindex(devname);
 | 
				
			||||||
 | 
						if (!req.i.ifa_index) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
 | 
				
			||||||
 | 
						if (dstaddr)
 | 
				
			||||||
 | 
							netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&local, 0, sizeof(local));
 | 
				
			||||||
 | 
						local.nl_family = AF_NETLINK;
 | 
				
			||||||
 | 
						local.nl_groups = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr_len = sizeof(local);
 | 
				
			||||||
 | 
						if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
								"getsockname() failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (addr_len != sizeof(local)) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
				
			||||||
 | 
								"Wrong address length %d", addr_len);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (local.nl_family != AF_NETLINK) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
				
			||||||
 | 
								"Wrong address family %d", local.nl_family);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iov.iov_base = (void *)&req.n;
 | 
				
			||||||
 | 
						iov.iov_len = req.n.nlmsg_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg.msg_name = (void *)&nladdr;
 | 
				
			||||||
 | 
						msg.msg_namelen = sizeof(nladdr);
 | 
				
			||||||
 | 
						msg.msg_iov = &iov;
 | 
				
			||||||
 | 
						msg.msg_iovlen = 1;
 | 
				
			||||||
 | 
						msg.msg_control = NULL;
 | 
				
			||||||
 | 
						msg.msg_controllen = 0;
 | 
				
			||||||
 | 
						msg.msg_flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&nladdr, 0, sizeof(nladdr));
 | 
				
			||||||
 | 
						nladdr.nl_family = AF_NETLINK;
 | 
				
			||||||
 | 
						nladdr.nl_pid = 0;
 | 
				
			||||||
 | 
						nladdr.nl_groups = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.n.nlmsg_seq = 0;
 | 
				
			||||||
 | 
						req.n.nlmsg_flags |= NLM_F_ACK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = sendmsg(fd, &msg, 0);
 | 
				
			||||||
 | 
						if (status != req.n.nlmsg_len) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
 | 
				
			||||||
 | 
						if (status == -1) {
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#elif defined (__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						struct ifaliasreq areq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&areq, 0, sizeof(areq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up interface name */
 | 
				
			||||||
 | 
						strncpy(areq.ifra_name, devname, IFNAMSIZ);
 | 
				
			||||||
 | 
						areq.ifra_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_family = AF_INET6;
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_len = sizeof(areq.ifra_addr);
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_addr.s6_addr = addr->s6_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_family = AF_INET6;
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_len = sizeof(areq.ifra_mask);
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_addr.s6_addr = netmask->s6_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_family = AF_INET6;
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_len = sizeof(areq.ifra_broadaddr);
 | 
				
			||||||
 | 
						((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_addr.s6_addr = dstaddr->s6_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel. */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
								"ioctl(SIOCAIFADDR) failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int netdev_route4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask, int delete)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						struct rtentry r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&r, '\0', sizeof(r));
 | 
				
			||||||
 | 
						r.rt_flags = RTF_UP | RTF_GATEWAY;	/* RTF_HOST not set */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel. */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.rt_dst.sa_family = AF_INET;
 | 
				
			||||||
 | 
						r.rt_gateway.sa_family = AF_INET;
 | 
				
			||||||
 | 
						r.rt_genmask.sa_family = AF_INET;
 | 
				
			||||||
 | 
						memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
 | 
				
			||||||
 | 
						memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
 | 
				
			||||||
 | 
						       sizeof(*gateway));
 | 
				
			||||||
 | 
						memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
 | 
				
			||||||
 | 
						       sizeof(*mask));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (delete) {
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCDELRT) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCADDRT) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct rt_msghdr rt;
 | 
				
			||||||
 | 
							struct sockaddr_in dst;
 | 
				
			||||||
 | 
							struct sockaddr_in gate;
 | 
				
			||||||
 | 
							struct sockaddr_in mask;
 | 
				
			||||||
 | 
						} req;
 | 
				
			||||||
 | 
						struct rt_msghdr *rtm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&req, 0x00, sizeof(req));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtm = &req.rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtm->rtm_msglen = sizeof(req);
 | 
				
			||||||
 | 
						rtm->rtm_version = RTM_VERSION;
 | 
				
			||||||
 | 
						if (delete) {
 | 
				
			||||||
 | 
							rtm->rtm_type = RTM_DELETE;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rtm->rtm_type = RTM_ADD;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;	/* TODO */
 | 
				
			||||||
 | 
						rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 | 
				
			||||||
 | 
						rtm->rtm_pid = getpid();
 | 
				
			||||||
 | 
						rtm->rtm_seq = 0044;	/* TODO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.dst.sin_family = AF_INET;
 | 
				
			||||||
 | 
						req.dst.sin_len = sizeof(req.dst);
 | 
				
			||||||
 | 
						req.mask.sin_family = AF_INET;
 | 
				
			||||||
 | 
						req.mask.sin_len = sizeof(req.mask);
 | 
				
			||||||
 | 
						req.gate.sin_family = AF_INET;
 | 
				
			||||||
 | 
						req.gate.sin_len = sizeof(req.gate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.dst.sin_addr.s_addr = dst->s_addr;
 | 
				
			||||||
 | 
						req.mask.sin_addr.s_addr = mask->s_addr;
 | 
				
			||||||
 | 
						req.gate.sin_addr.s_addr = gateway->s_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (write(fd, rtm, rtm->rtm_msglen) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int netdev_route6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface, int delete)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
						struct in6_rtmsg r;
 | 
				
			||||||
 | 
						struct ifreq ifr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&r, 0, sizeof(r));
 | 
				
			||||||
 | 
						r.rtmsg_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
 | 
				
			||||||
 | 
						r.rtmsg_metric = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a channel to the NET kernel. */
 | 
				
			||||||
 | 
						if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gw_iface) {
 | 
				
			||||||
 | 
							strncpy(ifr.ifr_name, gw_iface, IFNAMSIZ);
 | 
				
			||||||
 | 
							ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCGIFINDEX) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							r.rtmsg_ifindex = ifr.ifr_ifindex;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&r.rtmsg_dst, dst->s6_addr, sizeof(struct in6_addr));
 | 
				
			||||||
 | 
						memcpy(&r.rtmsg_gateway, gateway->s6_addr, sizeof(struct in6_addr));
 | 
				
			||||||
 | 
						r.rtmsg_dst_len = prefixlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (delete) {
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCDELRT) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
				
			||||||
 | 
									"ioctl(SIOCADDRT) failed");
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_addroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route4(dst, gateway, mask, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_delroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route4(dst, gateway, mask, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_addroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route6(dst, gateway, prefixlen, gw_iface, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_delroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route6(dst, gateway, prefixlen, gw_iface, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ifaddrs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Obtain the local address of a network device
 | 
				
			||||||
 | 
					 *  \param[in] devname Target device owning the IP
 | 
				
			||||||
 | 
					 *  \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
 | 
				
			||||||
 | 
					 *  \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
 | 
				
			||||||
 | 
					 *  \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
 | 
				
			||||||
 | 
					 *  \returns The number of ips found following the criteria specified by flags, -1 on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will fill prefix_list with up to prefix_size IPs following the
 | 
				
			||||||
 | 
					 * criteria specified by flags parameter. It returns the number of IPs matching
 | 
				
			||||||
 | 
					 * the criteria. As a result, the number returned can be bigger than
 | 
				
			||||||
 | 
					 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
 | 
				
			||||||
 | 
					 * needed for prefix_list.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
 | 
				
			||||||
 | 
						struct ifaddrs *ifaddr, *ifa;
 | 
				
			||||||
 | 
						struct in46_addr netmask;
 | 
				
			||||||
 | 
						size_t count = 0;
 | 
				
			||||||
 | 
						bool is_ipv6_ll;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (getifaddrs(&ifaddr) == -1) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
 | 
				
			||||||
 | 
							if (ifa->ifa_addr == NULL)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(ifa->ifa_name, devname))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ifa->ifa_addr->sa_family == AF_INET && (flags & IP_TYPE_IPv4)) {
 | 
				
			||||||
 | 
								struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
 | 
				
			||||||
 | 
								struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (count < prefix_size) {
 | 
				
			||||||
 | 
									netmask.len = sizeof(netmask4->sin_addr);
 | 
				
			||||||
 | 
									netmask.v4 = netmask4->sin_addr;
 | 
				
			||||||
 | 
									prefix_list[count].addr.len = sizeof(sin4->sin_addr);
 | 
				
			||||||
 | 
									prefix_list[count].addr.v4 = sin4->sin_addr;
 | 
				
			||||||
 | 
									prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								count++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) {
 | 
				
			||||||
 | 
								struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
 | 
				
			||||||
 | 
								struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								is_ipv6_ll = !memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix));
 | 
				
			||||||
 | 
								if ((flags & IP_TYPE_IPv6_NONLINK) && is_ipv6_ll)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (count < prefix_size) {
 | 
				
			||||||
 | 
									netmask.len = sizeof(netmask6->sin6_addr);
 | 
				
			||||||
 | 
									netmask.v6 = netmask6->sin6_addr;
 | 
				
			||||||
 | 
									prefix_list[count].addr.len = sizeof(sin6->sin6_addr);
 | 
				
			||||||
 | 
									prefix_list[count].addr.v6 = sin6->sin6_addr;
 | 
				
			||||||
 | 
									prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								count++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						freeifaddrs(ifaddr);
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										74
									
								
								lib/netdev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/netdev.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * TUN interface functions.
 | 
				
			||||||
 | 
					 * Copyright (C) 2002, 2003 Mondru AB.
 | 
				
			||||||
 | 
					 * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../lib/in46_addr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUN_NLBUFSIZE   1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ipv6 ip type flags for tun_ipv6_local_get() */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						IP_TYPE_IPv4 = 1,
 | 
				
			||||||
 | 
						IP_TYPE_IPv6_LINK = 2,
 | 
				
			||||||
 | 
						IP_TYPE_IPv6_NONLINK = 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#define IP_TYPE_IPv6 (IP_TYPE_IPv6_LINK | IP_TYPE_IPv6_NONLINK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef HAVE_IPHDR
 | 
				
			||||||
 | 
					struct iphdr
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					#if __BYTE_ORDER == __LITTLE_ENDIAN
 | 
				
			||||||
 | 
					    unsigned int ihl:4;
 | 
				
			||||||
 | 
					    unsigned int version:4;
 | 
				
			||||||
 | 
					#elif __BYTE_ORDER == __BIG_ENDIAN
 | 
				
			||||||
 | 
					    unsigned int version:4;
 | 
				
			||||||
 | 
					    unsigned int ihl:4;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					# error	"Please fix <bits/endian.h>"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    u_int8_t tos;
 | 
				
			||||||
 | 
					    u_int16_t tot_len;
 | 
				
			||||||
 | 
					    u_int16_t id;
 | 
				
			||||||
 | 
					    u_int16_t frag_off;
 | 
				
			||||||
 | 
					    u_int8_t ttl;
 | 
				
			||||||
 | 
					    u_int8_t protocol;
 | 
				
			||||||
 | 
					    u_int16_t check;
 | 
				
			||||||
 | 
					    u_int32_t saddr;
 | 
				
			||||||
 | 
					    u_int32_t daddr;
 | 
				
			||||||
 | 
					    /*The options start here. */
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					#endif /* !HAVE_IPHDR */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_setaddr4(const char *devname, struct in_addr *addr,
 | 
				
			||||||
 | 
								   struct in_addr *dstaddr, struct in_addr *netmask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
 | 
				
			||||||
 | 
								   size_t prefixlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_addaddr4(const char *devname, struct in_addr *addr,
 | 
				
			||||||
 | 
								   struct in_addr *dstaddr, struct in_addr *netmask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_addaddr6(const char *devname, struct in6_addr *addr,
 | 
				
			||||||
 | 
								   struct in6_addr *dstaddr, int prefixlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_addroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
 | 
				
			||||||
 | 
					extern int netdev_delroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
 | 
				
			||||||
 | 
					extern int netdev_addroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface);
 | 
				
			||||||
 | 
					extern int netdev_delroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list,
 | 
				
			||||||
 | 
									size_t prefix_size, int flags);
 | 
				
			||||||
							
								
								
									
										272
									
								
								lib/netns.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								lib/netns.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2014-2017, Travelping GmbH <info@travelping.com>
 | 
				
			||||||
 | 
					 * Copyright (C) 2020, Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					# include "config.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _GNU_SOURCE
 | 
				
			||||||
 | 
					# define _GNU_SOURCE
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/mount.h>
 | 
				
			||||||
 | 
					#include <sys/param.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NETNS_PATH "/var/run/netns"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! default namespace of the GGSN process */
 | 
				
			||||||
 | 
					static int default_nsfd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! switch to a (non-default) namespace, store existing signal mask in oldmask.
 | 
				
			||||||
 | 
					 *  \param[in] nsfd file descriptor representing the namespace to whch we shall switch
 | 
				
			||||||
 | 
					 *  \param[out] oldmask caller-provided memory location to which old signal mask is stored
 | 
				
			||||||
 | 
					 *  \ returns 0 on success or negative (errno) in case of error */
 | 
				
			||||||
 | 
					int switch_ns(int nsfd, sigset_t *oldmask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sigset_t intmask;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(default_nsfd >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sigfillset(&intmask) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_BLOCK, &intmask, oldmask)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (setns(nsfd, CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							/* restore old mask if we couldn't switch the netns */
 | 
				
			||||||
 | 
							sigprocmask(SIG_SETMASK, oldmask, NULL);
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! switch back to the default namespace, restoring signal mask.
 | 
				
			||||||
 | 
					 *  \param[in] oldmask signal mask to restore after returning to default namespace
 | 
				
			||||||
 | 
					 *  \returns 0 on successs; negative errno value in case of error */
 | 
				
			||||||
 | 
					int restore_ns(sigset_t *oldmask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(default_nsfd >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						if (setns(default_nsfd, CLONE_NEWNET) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_SETMASK, oldmask, NULL)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! open a file from within specified network namespace */
 | 
				
			||||||
 | 
					int open_ns(int nsfd, const char *pathname, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sigset_t intmask, oldmask;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int fd = -1;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(default_nsfd >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mask off all signals, store old signal mask */
 | 
				
			||||||
 | 
						if (sigfillset(&intmask) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* associate the calling thread with namespace file descriptor */
 | 
				
			||||||
 | 
						if (setns(nsfd, CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto restore_sigmask;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* open the requested file/path */
 | 
				
			||||||
 | 
						if ((fd = open(pathname, flags)) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto restore_defaultns;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restore_defaultns:
 | 
				
			||||||
 | 
						/* return back to default namespace */
 | 
				
			||||||
 | 
						if (setns(default_nsfd, CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							if (fd >= 0)
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restore_sigmask:
 | 
				
			||||||
 | 
						/* restore process mask */
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
 | 
				
			||||||
 | 
							if (fd >= 0)
 | 
				
			||||||
 | 
								close(fd);
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! create a socket in another namespace.
 | 
				
			||||||
 | 
					 *  Switches temporarily to namespace indicated by nsfd, creates a socket in
 | 
				
			||||||
 | 
					 *  that namespace and then returns to the default namespace.
 | 
				
			||||||
 | 
					 *  \param[in] nsfd File descriptor of the namspace in which to create socket
 | 
				
			||||||
 | 
					 *  \param[in] domain Domain of the socket (AF_INET, ...)
 | 
				
			||||||
 | 
					 *  \param[in] type Type of the socket (SOCK_STREAM, ...)
 | 
				
			||||||
 | 
					 *  \param[in] protocol Protocol of the socket (IPPROTO_TCP, ...)
 | 
				
			||||||
 | 
					 *  \returns 0 on success; negative errno in case of error */
 | 
				
			||||||
 | 
					int socket_ns(int nsfd, int domain, int type, int protocol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sigset_t intmask, oldmask;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int sk = -1;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(default_nsfd >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mask off all signals, store old signal mask */
 | 
				
			||||||
 | 
						if (sigfillset(&intmask) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* associate the calling thread with namespace file descriptor */
 | 
				
			||||||
 | 
						if (setns(nsfd, CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto restore_sigmask;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create socket of requested domain/type/proto */
 | 
				
			||||||
 | 
						if ((sk = socket(domain, type, protocol)) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto restore_defaultns;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = sk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restore_defaultns:
 | 
				
			||||||
 | 
						/* return back to default namespace */
 | 
				
			||||||
 | 
						if (setns(default_nsfd, CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							if (sk >= 0)
 | 
				
			||||||
 | 
								close(sk);
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restore_sigmask:
 | 
				
			||||||
 | 
						/* restore process mask */
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
 | 
				
			||||||
 | 
							if (sk >= 0)
 | 
				
			||||||
 | 
								close(sk);
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! initialize this network namespace helper module.
 | 
				
			||||||
 | 
					 *  Must be called before using any other functions of this file.
 | 
				
			||||||
 | 
					 *  \returns 0 on success; negative errno in case of error */
 | 
				
			||||||
 | 
					int init_netns()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* store the default namespace for later reference */
 | 
				
			||||||
 | 
						if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! create obtain file descriptor for network namespace of give name.
 | 
				
			||||||
 | 
					 *  Creates /var/run/netns  if it doesn't exist already.
 | 
				
			||||||
 | 
					 *  \param[in] name Name of the network namespace (in /var/run/netns/)
 | 
				
			||||||
 | 
					 *  \returns File descriptor of network namespace; negative errno in case of error */
 | 
				
			||||||
 | 
					int get_nsfd(const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						sigset_t intmask, oldmask;
 | 
				
			||||||
 | 
						char path[MAXPATHLEN] = NETNS_PATH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(default_nsfd >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create /var/run/netns, if it doesn't exist already */
 | 
				
			||||||
 | 
						rc = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
 | 
				
			||||||
 | 
						if (rc < 0 && errno != EEXIST)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create /var/run/netns/[name], if it doesn't exist already */
 | 
				
			||||||
 | 
						snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name);
 | 
				
			||||||
 | 
						fd = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							if (errno == EEXIST) {
 | 
				
			||||||
 | 
								if ((fd = open(path, O_RDONLY)) < 0)
 | 
				
			||||||
 | 
									return -errno;
 | 
				
			||||||
 | 
								return fd;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (close(fd) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mask off all signals, store old signal mask */
 | 
				
			||||||
 | 
						if (sigfillset(&intmask) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create a new network namespace */
 | 
				
			||||||
 | 
						if (unshare(CLONE_NEWNET) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto restore_sigmask;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (mount("/proc/self/ns/net", path, "none", MS_BIND, NULL) < 0)
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* switch back to default namespace */
 | 
				
			||||||
 | 
						if (setns(default_nsfd, CLONE_NEWNET) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restore_sigmask:
 | 
				
			||||||
 | 
						/* restore process mask */
 | 
				
			||||||
 | 
						if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0)
 | 
				
			||||||
 | 
							return -rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* might have been set above in case mount fails */
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* finally, open the created namespace file descriptor from default ns */
 | 
				
			||||||
 | 
						if ((fd = open(path, O_RDONLY)) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										35
									
								
								lib/netns.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/netns.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2014-2017, Travelping GmbH <info@travelping.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __NETNS_H
 | 
				
			||||||
 | 
					#define __NETNS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int init_netns(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int switch_ns(int nsfd, sigset_t *oldmask);
 | 
				
			||||||
 | 
					int restore_ns(sigset_t *oldmask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int open_ns(int nsfd, const char *pathname, int flags);
 | 
				
			||||||
 | 
					int socket_ns(int nsfd, int domain, int type, int protocol);
 | 
				
			||||||
 | 
					int get_nsfd(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										690
									
								
								lib/tun.c
									
									
									
									
									
								
							
							
						
						
									
										690
									
								
								lib/tun.c
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * TUN interface functions.
 | 
					 * TUN interface functions.
 | 
				
			||||||
 * Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
					 * Copyright (C) 2002, 2003, 2004 Mondru AB.
 | 
				
			||||||
 * Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
 | 
					 * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The contents of this file may be used under the terms of the GNU
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 * General Public License Version 2, provided that the above copyright
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
@@ -42,8 +43,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__)
 | 
					#if defined(__linux__)
 | 
				
			||||||
#include <linux/if_tun.h>
 | 
					#include <linux/if_tun.h>
 | 
				
			||||||
#include <linux/netlink.h>
 | 
					 | 
				
			||||||
#include <linux/rtnetlink.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined (__FreeBSD__)
 | 
					#elif defined (__FreeBSD__)
 | 
				
			||||||
#include <net/if_tun.h>
 | 
					#include <net/if_tun.h>
 | 
				
			||||||
@@ -59,527 +58,104 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "tun.h"
 | 
					#include "tun.h"
 | 
				
			||||||
#include "syserr.h"
 | 
					#include "syserr.h"
 | 
				
			||||||
 | 
					#include "gtp-kernel.h"
 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/ipv6.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int len = RTA_LENGTH(dlen);
 | 
					 | 
				
			||||||
	int alen = NLMSG_ALIGN(n->nlmsg_len);
 | 
					 | 
				
			||||||
	struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
 | 
					 | 
				
			||||||
	if (alen + len > nsize)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	rta->rta_len = len;
 | 
					 | 
				
			||||||
	rta->rta_type = type;
 | 
					 | 
				
			||||||
	memcpy(RTA_DATA(rta), d, dlen);
 | 
					 | 
				
			||||||
	n->nlmsg_len = alen + len;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int tun_sifflags(struct tun_t *this, int flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ifreq ifr;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&ifr, '\0', sizeof(ifr));
 | 
					 | 
				
			||||||
	ifr.ifr_flags = flags;
 | 
					 | 
				
			||||||
	strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
 | 
					 | 
				
			||||||
	ifr.ifr_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
			"ioctl(SIOCSIFFLAGS) failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
 | 
					static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
 | 
				
			||||||
			struct in_addr *dstaddr, struct in_addr *netmask)
 | 
								struct in_addr *dstaddr, struct in_addr *netmask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ifreq ifr;
 | 
						int rc;
 | 
				
			||||||
	int fd;
 | 
						rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&ifr, '\0', sizeof(ifr));
 | 
						if (addr) {
 | 
				
			||||||
	ifr.ifr_addr.sa_family = AF_INET;
 | 
							this->addr.len = sizeof(struct in_addr);
 | 
				
			||||||
	ifr.ifr_dstaddr.sa_family = AF_INET;
 | 
							this->addr.v4.s_addr = addr->s_addr;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
	ifr.ifr_netmask.sa_family = AF_INET;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
 | 
					 | 
				
			||||||
	    sizeof(struct sockaddr_in);
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
 | 
					 | 
				
			||||||
	    sizeof(struct sockaddr_in);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
 | 
					 | 
				
			||||||
	ifr.ifr_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create a channel to the NET kernel. */
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (dstaddr) {
 | 
				
			||||||
	if (addr) {		/* Set the interface address */
 | 
							this->dstaddr.len = sizeof(struct in_addr);
 | 
				
			||||||
		this->addr.s_addr = addr->s_addr;
 | 
							this->dstaddr.v4.s_addr = dstaddr->s_addr;
 | 
				
			||||||
		memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
 | 
					 | 
				
			||||||
		       sizeof(*addr));
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
 | 
					 | 
				
			||||||
			if (errno != EEXIST) {
 | 
					 | 
				
			||||||
				SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
					"ioctl(SIOCSIFADDR) failed");
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				SYS_ERR(DTUN, LOGL_NOTICE, errno,
 | 
					 | 
				
			||||||
					"ioctl(SIOCSIFADDR): Address already exists");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (netmask)
 | 
				
			||||||
	if (dstaddr) {		/* Set the destination address */
 | 
					 | 
				
			||||||
		this->dstaddr.s_addr = dstaddr->s_addr;
 | 
					 | 
				
			||||||
		memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
 | 
					 | 
				
			||||||
		       dstaddr, sizeof(*dstaddr));
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
 | 
					 | 
				
			||||||
			SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
				"ioctl(SIOCSIFDSTADDR) failed");
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (netmask) {		/* Set the netmask */
 | 
					 | 
				
			||||||
		this->netmask.s_addr = netmask->s_addr;
 | 
							this->netmask.s_addr = netmask->s_addr;
 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
		memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
 | 
					 | 
				
			||||||
		       netmask, sizeof(*netmask));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
		((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
 | 
					 | 
				
			||||||
		    netmask->s_addr;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
 | 
					 | 
				
			||||||
			SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
				"ioctl(SIOCSIFNETMASK) failed");
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	this->addrs++;
 | 
						this->addrs++;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* On linux the route to the interface is set automatically
 | 
					 | 
				
			||||||
	   on FreeBSD we have to do this manually */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO: How does it work on Solaris? */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tun_sifflags(this, IFF_UP | IFF_RUNNING);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
					#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
	tun_addroute(this, dstaddr, addr, &this->netmask);
 | 
					 | 
				
			||||||
	this->routes = 1;
 | 
						this->routes = 1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
 | 
					static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
 | 
				
			||||||
			size_t prefixlen)
 | 
								size_t prefixlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in6_ifreq ifr;
 | 
						int rc;
 | 
				
			||||||
	int fd;
 | 
						rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
	memset(&ifr, 0, sizeof(ifr));
 | 
							return rc;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
	ifr.ifr6_prefixlen = prefixlen;
 | 
					 | 
				
			||||||
	ifr.ifr6_ifindex = if_nametoindex(this->devname);
 | 
					 | 
				
			||||||
	if (ifr.ifr6_ifindex == 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", this->devname);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
	strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create a channel to the NET kernel */
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
	if (addr) {
 | 
					 | 
				
			||||||
		memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
 | 
					 | 
				
			||||||
			if (errno != EEXIST) {
 | 
					 | 
				
			||||||
				SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	/* FIXME: looks like this is not possible/necessary for IPv6? */
 | 
					 | 
				
			||||||
	if (dstaddr) {
 | 
						if (dstaddr) {
 | 
				
			||||||
		memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr));
 | 
							this->dstaddr.len = sizeof(*dstaddr);
 | 
				
			||||||
		memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
 | 
							memcpy(&this->dstaddr.v6, dstaddr, sizeof(*dstaddr));
 | 
				
			||||||
		if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
 | 
					 | 
				
			||||||
			SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
	if (addr)
 | 
					 | 
				
			||||||
		memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
 | 
					 | 
				
			||||||
	if (dstaddr)
 | 
					 | 
				
			||||||
		memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	this->addrs++;
 | 
						this->addrs++;
 | 
				
			||||||
 | 
					#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
	/* On linux the route to the interface is set automatically
 | 
					 | 
				
			||||||
	   on FreeBSD we have to do this manually */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO: How does it work on Solaris? */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tun_sifflags(this, IFF_UP | IFF_RUNNING);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0	/* FIXME */
 | 
					 | 
				
			||||||
//#if defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
	tun_addroute6(this, dstaddr, addr, prefixlen);
 | 
					 | 
				
			||||||
	this->routes = 1;
 | 
						this->routes = 1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
 | 
					static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
 | 
				
			||||||
 | 
								struct in_addr *dstaddr, struct in_addr *netmask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in_addr netmask;
 | 
						int rc;
 | 
				
			||||||
	switch (addr->len) {
 | 
					 | 
				
			||||||
	case 4:
 | 
					 | 
				
			||||||
		netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
 | 
					 | 
				
			||||||
		return tun_setaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
 | 
					 | 
				
			||||||
	case 16:
 | 
					 | 
				
			||||||
		return tun_setaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tun_addaddr(struct tun_t *this,
 | 
					 | 
				
			||||||
		struct in_addr *addr,
 | 
					 | 
				
			||||||
		struct in_addr *dstaddr, struct in_addr *netmask)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		struct nlmsghdr n;
 | 
					 | 
				
			||||||
		struct ifaddrmsg i;
 | 
					 | 
				
			||||||
		char buf[TUN_NLBUFSIZE];
 | 
					 | 
				
			||||||
	} req;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct sockaddr_nl local;
 | 
					 | 
				
			||||||
	socklen_t addr_len;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	int status;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct sockaddr_nl nladdr;
 | 
					 | 
				
			||||||
	struct iovec iov;
 | 
					 | 
				
			||||||
	struct msghdr msg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!this->addrs)	/* Use ioctl for first addr to make ping work */
 | 
					 | 
				
			||||||
		return tun_setaddr4(this, addr, dstaddr, netmask);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&req, 0, sizeof(req));
 | 
					 | 
				
			||||||
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 | 
					 | 
				
			||||||
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
 | 
					 | 
				
			||||||
	req.n.nlmsg_type = RTM_NEWADDR;
 | 
					 | 
				
			||||||
	req.i.ifa_family = AF_INET;
 | 
					 | 
				
			||||||
	req.i.ifa_prefixlen = 32;	/* 32 FOR IPv4 */
 | 
					 | 
				
			||||||
	req.i.ifa_flags = 0;
 | 
					 | 
				
			||||||
	req.i.ifa_scope = RT_SCOPE_HOST;	/* TODO or 0 */
 | 
					 | 
				
			||||||
	req.i.ifa_index = if_nametoindex(this->devname);
 | 
					 | 
				
			||||||
	if (!req.i.ifa_index) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", this->devname);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
 | 
					 | 
				
			||||||
	tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&local, 0, sizeof(local));
 | 
					 | 
				
			||||||
	local.nl_family = AF_NETLINK;
 | 
					 | 
				
			||||||
	local.nl_groups = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	addr_len = sizeof(local);
 | 
					 | 
				
			||||||
	if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
			"getsockname() failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (addr_len != sizeof(local)) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
					 | 
				
			||||||
			"Wrong address length %d", addr_len);
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (local.nl_family != AF_NETLINK) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, 0,
 | 
					 | 
				
			||||||
			"Wrong address family %d", local.nl_family);
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	iov.iov_base = (void *)&req.n;
 | 
					 | 
				
			||||||
	iov.iov_len = req.n.nlmsg_len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg.msg_name = (void *)&nladdr;
 | 
					 | 
				
			||||||
	msg.msg_namelen = sizeof(nladdr);
 | 
					 | 
				
			||||||
	msg.msg_iov = &iov;
 | 
					 | 
				
			||||||
	msg.msg_iovlen = 1;
 | 
					 | 
				
			||||||
	msg.msg_control = NULL;
 | 
					 | 
				
			||||||
	msg.msg_controllen = 0;
 | 
					 | 
				
			||||||
	msg.msg_flags = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&nladdr, 0, sizeof(nladdr));
 | 
					 | 
				
			||||||
	nladdr.nl_family = AF_NETLINK;
 | 
					 | 
				
			||||||
	nladdr.nl_pid = 0;
 | 
					 | 
				
			||||||
	nladdr.nl_groups = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req.n.nlmsg_seq = 0;
 | 
					 | 
				
			||||||
	req.n.nlmsg_flags |= NLM_F_ACK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	status = sendmsg(fd, &msg, 0);
 | 
					 | 
				
			||||||
	if (status != req.n.nlmsg_len) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	status = tun_sifflags(this, IFF_UP | IFF_RUNNING);
 | 
					 | 
				
			||||||
	if (status == -1) {
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	this->addrs++;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	struct ifaliasreq areq;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Is this needed on FreeBSD? */
 | 
						/* TODO: Is this needed on FreeBSD? */
 | 
				
			||||||
	if (!this->addrs)	/* Use ioctl for first addr to make ping work */
 | 
						if (!this->addrs)	/* Use ioctl for first addr to make ping work */
 | 
				
			||||||
		return tun_setaddr4(this, addr, dstaddr, netmask);	/* TODO dstaddr */
 | 
							return tun_setaddr4(this, addr, dstaddr, netmask);	/* TODO dstaddr */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&areq, 0, sizeof(areq));
 | 
						rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set up interface name */
 | 
					 | 
				
			||||||
	strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
 | 
					 | 
				
			||||||
	areq.ifra_name[IFNAMSIZ - 1] = 0;	/* Make sure to terminate */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
 | 
					 | 
				
			||||||
	    sizeof(areq.ifra_addr);
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
 | 
					 | 
				
			||||||
	    sizeof(areq.ifra_mask);
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
 | 
					 | 
				
			||||||
	    netmask->s_addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
 | 
					 | 
				
			||||||
	    sizeof(areq.ifra_broadaddr);
 | 
					 | 
				
			||||||
	((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
 | 
					 | 
				
			||||||
	    dstaddr->s_addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create a channel to the NET kernel. */
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
			"ioctl(SIOCAIFADDR) failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	this->addrs++;
 | 
						this->addrs++;
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tun_route(struct tun_t *this,
 | 
					static int tun_addaddr6(struct tun_t *this,
 | 
				
			||||||
	      struct in_addr *dst,
 | 
							struct in6_addr *addr,
 | 
				
			||||||
	      struct in_addr *gateway, struct in_addr *mask, int delete)
 | 
							struct in6_addr *dstaddr, int prefixlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__)
 | 
						if (!this->addrs)	/* Use ioctl for first addr to make ping work */
 | 
				
			||||||
 | 
							return tun_setaddr6(this, addr, dstaddr, prefixlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rtentry r;
 | 
						rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
 | 
				
			||||||
	int fd;
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&r, '\0', sizeof(r));
 | 
						this->addrs++;
 | 
				
			||||||
	r.rt_flags = RTF_UP | RTF_GATEWAY;	/* RTF_HOST not set */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Create a channel to the NET kernel. */
 | 
						return rc;
 | 
				
			||||||
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
					}
 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					
 | 
				
			||||||
 | 
					int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in_addr netmask;
 | 
				
			||||||
 | 
						switch (addr->len) {
 | 
				
			||||||
 | 
						case 4:
 | 
				
			||||||
 | 
							netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
 | 
				
			||||||
 | 
							return tun_addaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
 | 
				
			||||||
 | 
						case 16:
 | 
				
			||||||
 | 
							return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	r.rt_dst.sa_family = AF_INET;
 | 
					 | 
				
			||||||
	r.rt_gateway.sa_family = AF_INET;
 | 
					 | 
				
			||||||
	r.rt_genmask.sa_family = AF_INET;
 | 
					 | 
				
			||||||
	memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
 | 
					 | 
				
			||||||
	memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
 | 
					 | 
				
			||||||
	       sizeof(*gateway));
 | 
					 | 
				
			||||||
	memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
 | 
					 | 
				
			||||||
	       sizeof(*mask));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (delete) {
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
 | 
					 | 
				
			||||||
			SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
				"ioctl(SIOCDELRT) failed");
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
 | 
					 | 
				
			||||||
			SYS_ERR(DTUN, LOGL_ERROR, errno,
 | 
					 | 
				
			||||||
				"ioctl(SIOCADDRT) failed");
 | 
					 | 
				
			||||||
			close(fd);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		struct rt_msghdr rt;
 | 
					 | 
				
			||||||
		struct sockaddr_in dst;
 | 
					 | 
				
			||||||
		struct sockaddr_in gate;
 | 
					 | 
				
			||||||
		struct sockaddr_in mask;
 | 
					 | 
				
			||||||
	} req;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	struct rt_msghdr *rtm;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&req, 0x00, sizeof(req));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtm = &req.rt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtm->rtm_msglen = sizeof(req);
 | 
					 | 
				
			||||||
	rtm->rtm_version = RTM_VERSION;
 | 
					 | 
				
			||||||
	if (delete) {
 | 
					 | 
				
			||||||
		rtm->rtm_type = RTM_DELETE;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		rtm->rtm_type = RTM_ADD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;	/* TODO */
 | 
					 | 
				
			||||||
	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 | 
					 | 
				
			||||||
	rtm->rtm_pid = getpid();
 | 
					 | 
				
			||||||
	rtm->rtm_seq = 0044;	/* TODO */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req.dst.sin_family = AF_INET;
 | 
					 | 
				
			||||||
	req.dst.sin_len = sizeof(req.dst);
 | 
					 | 
				
			||||||
	req.mask.sin_family = AF_INET;
 | 
					 | 
				
			||||||
	req.mask.sin_len = sizeof(req.mask);
 | 
					 | 
				
			||||||
	req.gate.sin_family = AF_INET;
 | 
					 | 
				
			||||||
	req.gate.sin_len = sizeof(req.gate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req.dst.sin_addr.s_addr = dst->s_addr;
 | 
					 | 
				
			||||||
	req.mask.sin_addr.s_addr = mask->s_addr;
 | 
					 | 
				
			||||||
	req.gate.sin_addr.s_addr = gateway->s_addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (write(fd, rtm, rtm->rtm_msglen) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
 | 
					 | 
				
			||||||
		close(fd);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tun_addroute(struct tun_t *this,
 | 
					int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u)
 | 
				
			||||||
		 struct in_addr *dst,
 | 
					 | 
				
			||||||
		 struct in_addr *gateway, struct in_addr *mask)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return tun_route(this, dst, gateway, mask, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tun_delroute(struct tun_t *this,
 | 
					 | 
				
			||||||
		 struct in_addr *dst,
 | 
					 | 
				
			||||||
		 struct in_addr *gateway, struct in_addr *mask)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return tun_route(this, dst, gateway, mask, 1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tun_new(struct tun_t **tun, const char *dev_name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__)
 | 
					#if defined(__linux__)
 | 
				
			||||||
@@ -602,31 +178,53 @@ int tun_new(struct tun_t **tun, const char *dev_name)
 | 
				
			|||||||
	(*tun)->routes = 0;
 | 
						(*tun)->routes = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__)
 | 
					#if defined(__linux__)
 | 
				
			||||||
	/* Open the actual tun device */
 | 
						if (!use_kernel) {
 | 
				
			||||||
	if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
 | 
							/* Open the actual tun device */
 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
 | 
							if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
 | 
				
			||||||
		goto err_free;
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
 | 
				
			||||||
 | 
								goto err_free;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Set device flags. For some weird reason this is also the method
 | 
				
			||||||
 | 
							   used to obtain the network interface name */
 | 
				
			||||||
 | 
							memset(&ifr, 0, sizeof(ifr));
 | 
				
			||||||
 | 
							if (dev_name)
 | 
				
			||||||
 | 
								strcpy(ifr.ifr_name, dev_name);
 | 
				
			||||||
 | 
							ifr.ifr_flags = IFF_TUN | IFF_NO_PI;	/* Tun device, no packet info */
 | 
				
			||||||
 | 
							if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
 | 
				
			||||||
 | 
								goto err_close;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
 | 
				
			||||||
 | 
							(*tun)->devname[IFNAMSIZ - 1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Disable checksums */
 | 
				
			||||||
 | 
							if (ioctl((*tun)->fd, TUNSETNOCSUM, 1) < 0) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable checksum on %s", (*tun)->devname);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							strncpy((*tun)->devname, dev_name, IFNAMSIZ);
 | 
				
			||||||
 | 
							(*tun)->devname[IFNAMSIZ - 1] = 0;
 | 
				
			||||||
 | 
							(*tun)->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) {
 | 
				
			||||||
 | 
								LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n",
 | 
				
			||||||
 | 
									strerror(errno));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set device flags. For some weird reason this is also the method
 | 
					 | 
				
			||||||
	   used to obtain the network interface name */
 | 
					 | 
				
			||||||
	memset(&ifr, 0, sizeof(ifr));
 | 
					 | 
				
			||||||
	if (dev_name)
 | 
					 | 
				
			||||||
		strcpy(ifr.ifr_name, dev_name);
 | 
					 | 
				
			||||||
	ifr.ifr_flags = IFF_TUN | IFF_NO_PI;	/* Tun device, no packet info */
 | 
					 | 
				
			||||||
	if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
 | 
					 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
 | 
					 | 
				
			||||||
		goto err_close;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
 | 
					 | 
				
			||||||
	(*tun)->devname[IFNAMSIZ - 1] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ioctl((*tun)->fd, TUNSETNOCSUM, 1);	/* Disable checksums */
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
					#elif defined(__FreeBSD__) || defined (__APPLE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (use_kernel) {
 | 
				
			||||||
 | 
							LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find suitable device */
 | 
						/* Find suitable device */
 | 
				
			||||||
	for (devnum = 0; devnum < 255; devnum++) {	/* TODO 255 */
 | 
						for (devnum = 0; devnum < 255; devnum++) {	/* TODO 255 */
 | 
				
			||||||
		snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
 | 
							snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
 | 
				
			||||||
@@ -678,13 +276,17 @@ int tun_free(struct tun_t *tun)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tun->routes) {
 | 
						if (tun->routes) {
 | 
				
			||||||
		tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
 | 
							netdev_delroute4(&tun->dstaddr.v4, &tun->addr.v4, &tun->netmask);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (close(tun->fd)) {
 | 
						if (tun->fd >= 0) {
 | 
				
			||||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
 | 
							if (close(tun->fd)) {
 | 
				
			||||||
 | 
								SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gtp_kernel_stop(tun->devname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: For solaris we need to unlink streams */
 | 
						/* TODO: For solaris we need to unlink streams */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(tun);
 | 
						free(tun);
 | 
				
			||||||
@@ -716,7 +318,14 @@ int tun_decaps(struct tun_t *this)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
 | 
					int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return write(tun->fd, pack, len);
 | 
						int rc;
 | 
				
			||||||
 | 
						rc = write(tun->fd, pack, len);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							SYS_ERR(DTUN, LOGL_ERROR, errno, "TUN(%s): write() failed", tun->devname);
 | 
				
			||||||
 | 
						} else if (rc < len) {
 | 
				
			||||||
 | 
							LOGTUN(LOGL_ERROR, tun, "short write() %d < %u\n", rc, len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tun_runscript(struct tun_t *tun, char *script)
 | 
					int tun_runscript(struct tun_t *tun, char *script)
 | 
				
			||||||
@@ -727,7 +336,7 @@ int tun_runscript(struct tun_t *tun, char *script)
 | 
				
			|||||||
	char smask[TUN_ADDRSIZE];
 | 
						char smask[TUN_ADDRSIZE];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
 | 
						strncpy(snet, inet_ntoa(tun->addr.v4), sizeof(snet));
 | 
				
			||||||
	snet[sizeof(snet) - 1] = 0;
 | 
						snet[sizeof(snet) - 1] = 0;
 | 
				
			||||||
	strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
 | 
						strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
 | 
				
			||||||
	smask[sizeof(smask) - 1] = 0;
 | 
						smask[sizeof(smask) - 1] = 0;
 | 
				
			||||||
@@ -745,79 +354,6 @@ int tun_runscript(struct tun_t *tun, char *script)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ifaddrs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Obtain the local address of a network device
 | 
					 | 
				
			||||||
 *  \param[in] devname Target device owning the IP
 | 
					 | 
				
			||||||
 *  \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
 | 
					 | 
				
			||||||
 *  \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
 | 
					 | 
				
			||||||
 *  \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
 | 
					 | 
				
			||||||
 *  \returns The number of ips found following the criteria specified by flags, -1 on error.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This function will fill prefix_list with up to prefix_size IPs following the
 | 
					 | 
				
			||||||
 * criteria specified by flags parameter. It returns the number of IPs matching
 | 
					 | 
				
			||||||
 * the criteria. As a result, the number returned can be bigger than
 | 
					 | 
				
			||||||
 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
 | 
					 | 
				
			||||||
 * needed for prefix_list.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
 | 
					 | 
				
			||||||
	struct ifaddrs *ifaddr, *ifa;
 | 
					 | 
				
			||||||
	struct in46_addr netmask;
 | 
					 | 
				
			||||||
	size_t count = 0;
 | 
					 | 
				
			||||||
	bool is_ipv6_ll;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (getifaddrs(&ifaddr) == -1) {
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
 | 
					 | 
				
			||||||
		if (ifa->ifa_addr == NULL)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (strcmp(ifa->ifa_name, devname))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ifa->ifa_addr->sa_family == AF_INET && (flags & IP_TYPE_IPv4)) {
 | 
					 | 
				
			||||||
			struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
 | 
					 | 
				
			||||||
			struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (count < prefix_size) {
 | 
					 | 
				
			||||||
				netmask.len = sizeof(netmask4->sin_addr);
 | 
					 | 
				
			||||||
				netmask.v4 = netmask4->sin_addr;
 | 
					 | 
				
			||||||
				prefix_list[count].addr.len = sizeof(sin4->sin_addr);
 | 
					 | 
				
			||||||
				prefix_list[count].addr.v4 = sin4->sin_addr;
 | 
					 | 
				
			||||||
				prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			count++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) {
 | 
					 | 
				
			||||||
			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
 | 
					 | 
				
			||||||
			struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			is_ipv6_ll = !memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix));
 | 
					 | 
				
			||||||
			if ((flags & IP_TYPE_IPv6_NONLINK) && is_ipv6_ll)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (count < prefix_size) {
 | 
					 | 
				
			||||||
				netmask.len = sizeof(netmask6->sin6_addr);
 | 
					 | 
				
			||||||
				netmask.v6 = netmask6->sin6_addr;
 | 
					 | 
				
			||||||
				prefix_list[count].addr.len = sizeof(sin6->sin6_addr);
 | 
					 | 
				
			||||||
				prefix_list[count].addr.v6 = sin6->sin6_addr;
 | 
					 | 
				
			||||||
				prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			count++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	freeifaddrs(ifaddr);
 | 
					 | 
				
			||||||
	return count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Obtain the local address of the tun device.
 | 
					/*! Obtain the local address of the tun device.
 | 
				
			||||||
 *  \param[in] tun Target device owning the IP
 | 
					 *  \param[in] tun Target device owning the IP
 | 
				
			||||||
 *  \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
 | 
					 *  \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										61
									
								
								lib/tun.h
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								lib/tun.h
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * TUN interface functions.
 | 
					 * TUN interface functions.
 | 
				
			||||||
 * Copyright (C) 2002, 2003 Mondru AB.
 | 
					 * Copyright (C) 2002, 2003 Mondru AB.
 | 
				
			||||||
 * Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
 | 
					 * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The contents of this file may be used under the terms of the GNU
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 * General Public License Version 2, provided that the above copyright
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
@@ -13,6 +13,7 @@
 | 
				
			|||||||
#ifndef _TUN_H
 | 
					#ifndef _TUN_H
 | 
				
			||||||
#define _TUN_H
 | 
					#define _TUN_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <net/if.h>
 | 
					#include <net/if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../lib/in46_addr.h"
 | 
					#include "../lib/in46_addr.h"
 | 
				
			||||||
@@ -20,43 +21,9 @@
 | 
				
			|||||||
#define PACKET_MAX      8196	/* Maximum packet size we receive */
 | 
					#define PACKET_MAX      8196	/* Maximum packet size we receive */
 | 
				
			||||||
#define TUN_SCRIPTSIZE   256
 | 
					#define TUN_SCRIPTSIZE   256
 | 
				
			||||||
#define TUN_ADDRSIZE     128
 | 
					#define TUN_ADDRSIZE     128
 | 
				
			||||||
#define TUN_NLBUFSIZE   1024
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#include "netdev.h"
 | 
				
			||||||
/* ipv6 ip type flags for tun_ipv6_local_get() */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	IP_TYPE_IPv4 = 1,
 | 
					 | 
				
			||||||
	IP_TYPE_IPv6_LINK = 2,
 | 
					 | 
				
			||||||
	IP_TYPE_IPv6_NONLINK = 4,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
#define IP_TYPE_IPv6 (IP_TYPE_IPv6_LINK | IP_TYPE_IPv6_NONLINK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef HAVE_IPHDR
 | 
					 | 
				
			||||||
struct iphdr
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
 | 
					 | 
				
			||||||
    unsigned int ihl:4;
 | 
					 | 
				
			||||||
    unsigned int version:4;
 | 
					 | 
				
			||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
 | 
					 | 
				
			||||||
    unsigned int version:4;
 | 
					 | 
				
			||||||
    unsigned int ihl:4;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# error	"Please fix <bits/endian.h>"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    u_int8_t tos;
 | 
					 | 
				
			||||||
    u_int16_t tot_len;
 | 
					 | 
				
			||||||
    u_int16_t id;
 | 
					 | 
				
			||||||
    u_int16_t frag_off;
 | 
					 | 
				
			||||||
    u_int8_t ttl;
 | 
					 | 
				
			||||||
    u_int8_t protocol;
 | 
					 | 
				
			||||||
    u_int16_t check;
 | 
					 | 
				
			||||||
    u_int32_t saddr;
 | 
					 | 
				
			||||||
    u_int32_t daddr;
 | 
					 | 
				
			||||||
    /*The options start here. */
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
#endif /* !HAVE_IPHDR */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ***********************************************************
 | 
					/* ***********************************************************
 | 
				
			||||||
 * Information storage for each tun instance
 | 
					 * Information storage for each tun instance
 | 
				
			||||||
@@ -64,8 +31,8 @@ struct iphdr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct tun_t {
 | 
					struct tun_t {
 | 
				
			||||||
	int fd;			/* File descriptor to tun interface */
 | 
						int fd;			/* File descriptor to tun interface */
 | 
				
			||||||
	struct in_addr addr;
 | 
						struct in46_addr addr;
 | 
				
			||||||
	struct in_addr dstaddr;
 | 
						struct in46_addr dstaddr;
 | 
				
			||||||
	struct in_addr netmask;
 | 
						struct in_addr netmask;
 | 
				
			||||||
	int addrs;		/* Number of allocated IP addresses */
 | 
						int addrs;		/* Number of allocated IP addresses */
 | 
				
			||||||
	int routes;		/* One if we allocated an automatic route */
 | 
						int routes;		/* One if we allocated an automatic route */
 | 
				
			||||||
@@ -75,19 +42,13 @@ struct tun_t {
 | 
				
			|||||||
	void *priv;
 | 
						void *priv;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int tun_new(struct tun_t **tun, const char *dev_name);
 | 
					extern int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u);
 | 
				
			||||||
extern int tun_free(struct tun_t *tun);
 | 
					extern int tun_free(struct tun_t *tun);
 | 
				
			||||||
extern int tun_decaps(struct tun_t *this);
 | 
					extern int tun_decaps(struct tun_t *this);
 | 
				
			||||||
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
 | 
					extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
 | 
					extern int tun_addaddr(struct tun_t *this, struct in46_addr *addr,
 | 
				
			||||||
		       struct in_addr *dstaddr, struct in_addr *netmask);
 | 
							       struct in46_addr *dstaddr, size_t prefixlen);
 | 
				
			||||||
 | 
					 | 
				
			||||||
extern int tun_setaddr(struct tun_t *this, struct in46_addr *our_adr,
 | 
					 | 
				
			||||||
		       struct in46_addr *his_adr, size_t prefixlen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tun_addroute(struct tun_t *this, struct in_addr *dst,
 | 
					 | 
				
			||||||
		 struct in_addr *gateway, struct in_addr *mask);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int tun_set_cb_ind(struct tun_t *this,
 | 
					extern int tun_set_cb_ind(struct tun_t *this,
 | 
				
			||||||
			  int (*cb_ind) (struct tun_t * tun, void *pack,
 | 
								  int (*cb_ind) (struct tun_t * tun, void *pack,
 | 
				
			||||||
@@ -95,10 +56,10 @@ extern int tun_set_cb_ind(struct tun_t *this,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern int tun_runscript(struct tun_t *tun, char *script);
 | 
					extern int tun_runscript(struct tun_t *tun, char *script);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list,
 | 
					 | 
				
			||||||
			size_t prefix_size, int flags);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list,
 | 
					int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list,
 | 
				
			||||||
		     size_t prefix_size, int flags);
 | 
							     size_t prefix_size, int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGTUN(level, tun, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DTUN, level, "TUN(%s): " fmt, (tun)->devname, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_TUN_H */
 | 
					#endif /* !_TUN_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								lib/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/util.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * misc helpers
 | 
				
			||||||
 | 
					 * Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ippool.h"
 | 
				
			||||||
 | 
					#include "in46_addr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get the peer of pdp based on IP version used.
 | 
				
			||||||
 | 
					*  \param[in] pdp PDP context to select the peer from.
 | 
				
			||||||
 | 
					*  \param[in] v4v6 IP version to select. Valid values are 4 and 6.
 | 
				
			||||||
 | 
					*  \returns The selected peer matching the given IP version. NULL if not present.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
 | 
				
			||||||
 | 
						uint8_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
							struct ippoolm_t * ippool = pdp->peer[i];
 | 
				
			||||||
 | 
							if (!ippool)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (is_ipv6 && in46a_is_v6(&ippool->addr))
 | 
				
			||||||
 | 
								return ippool;
 | 
				
			||||||
 | 
							else if (!is_ipv6 && in46a_is_v4(&ippool->addr))
 | 
				
			||||||
 | 
								return ippool;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								lib/util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/util.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * misc helpers
 | 
				
			||||||
 | 
					 * Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The contents of this file may be used under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License Version 2, provided that the above copyright
 | 
				
			||||||
 | 
					 * notice and this permission notice is included in all copies or
 | 
				
			||||||
 | 
					 * substantial portions of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ippoolm_t;
 | 
				
			||||||
 | 
					struct pdp_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6);
 | 
				
			||||||
@@ -1,90 +0,0 @@
 | 
				
			|||||||
Summary:   Osmocom Gateway GPRS Support Node (GGSN)
 | 
					 | 
				
			||||||
Name:      @PACKAGE@
 | 
					 | 
				
			||||||
Version:   @VERSION@
 | 
					 | 
				
			||||||
Release:   1
 | 
					 | 
				
			||||||
URL:       https://osmocom.org/projects/openggsn
 | 
					 | 
				
			||||||
Source0:   http://prdownloads.sourceforge.net/ggsn/%{name}-%{version}.tar.gz
 | 
					 | 
				
			||||||
License:   GPL
 | 
					 | 
				
			||||||
Group:     System Environment/Daemons
 | 
					 | 
				
			||||||
BuildRoot: %{_tmppath}/%{name}-root
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description 
 | 
					 | 
				
			||||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
 | 
					 | 
				
			||||||
operators as the interface between the Internet and the rest of the
 | 
					 | 
				
			||||||
mobile network infrastructure. The project also provides an SGSN
 | 
					 | 
				
			||||||
emulator suitable for GPRS core network testing.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%prep
 | 
					 | 
				
			||||||
%setup -q
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
./configure --prefix=/usr --enable-static-exec
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make install prefix=$RPM_BUILD_ROOT/usr
 | 
					 | 
				
			||||||
strip $RPM_BUILD_ROOT/usr/bin/osmo-ggsn
 | 
					 | 
				
			||||||
strip $RPM_BUILD_ROOT/usr/bin/sgsnemu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Copy osmo-ggsn init script in place
 | 
					 | 
				
			||||||
mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
 | 
					 | 
				
			||||||
install -m755 examples/osmo-ggsn.init \
 | 
					 | 
				
			||||||
	$RPM_BUILD_ROOT/etc/rc.d/init.d/osmo-ggsn
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Copy osmo-ggsn.conf in place
 | 
					 | 
				
			||||||
install -m755 examples/osmo-ggsn.cfg \
 | 
					 | 
				
			||||||
	$RPM_BUILD_ROOT/etc/osmo-ggsn.cfg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Copy gsn_restart file in place
 | 
					 | 
				
			||||||
mkdir -p $RPM_BUILD_ROOT/var/lib/osmo-ggsn
 | 
					 | 
				
			||||||
echo "0" > $RPM_BUILD_ROOT/var/lib/osmo-ggsn/gsn_restart
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Clean up unwanted library files
 | 
					 | 
				
			||||||
rm -rf $RPM_BUILD_ROOT/usr/include/*
 | 
					 | 
				
			||||||
rm -rf $RPM_BUILD_ROOT/usr/lib/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%clean
 | 
					 | 
				
			||||||
rm -rf $RPM_BUILD_ROOT
 | 
					 | 
				
			||||||
make clean
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%post
 | 
					 | 
				
			||||||
/sbin/chkconfig --add osmo-ggsn
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files
 | 
					 | 
				
			||||||
%defattr(-,root,root)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/usr/bin/osmo-ggsn
 | 
					 | 
				
			||||||
/usr/bin/sgsnemu
 | 
					 | 
				
			||||||
/etc/rc.d/init.d/osmo-ggsn
 | 
					 | 
				
			||||||
%dir /var/lib/osmo-ggsn
 | 
					 | 
				
			||||||
/var/lib/osmo-ggsn/gsn_restart
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%doc AUTHORS COPYING INSTALL NEWS README.md
 | 
					 | 
				
			||||||
%doc examples/osmo-ggsn.conf
 | 
					 | 
				
			||||||
%doc examples/sgsnemu.conf
 | 
					 | 
				
			||||||
%doc examples/osmo-ggsn.init
 | 
					 | 
				
			||||||
%doc examples/firewall
 | 
					 | 
				
			||||||
%doc /usr/man/man8/osmo-ggsn.8.gz
 | 
					 | 
				
			||||||
%doc /usr/man/man8/sgsnemu.8.gz
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%config /etc/osmo-ggsn.cfg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#/usr/lib/libgtp.a
 | 
					 | 
				
			||||||
#/usr/lib/libgtp.la
 | 
					 | 
				
			||||||
#/usr/lib/libgtp.so
 | 
					 | 
				
			||||||
#/usr/lib/libgtp.so.0
 | 
					 | 
				
			||||||
#/usr/lib/libgtp.so.0.0.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%changelog
 | 
					 | 
				
			||||||
* Mon Jun 30 2017  <laforge@gnumonks.org>
 | 
					 | 
				
			||||||
- Update to OsmoGGSN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* Mon Jun 30 2003  <jj@openggsn.org>
 | 
					 | 
				
			||||||
- Initial build.
 | 
					 | 
				
			||||||
@@ -5,5 +5,11 @@ AM_LDFLAGS = @EXEC_LDFLAGS@
 | 
				
			|||||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
 | 
					AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
 | 
					sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ENABLE_GTP_KERNEL
 | 
				
			||||||
 | 
					AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
 | 
				
			||||||
 | 
					sgsnemu_LDADD += $(LIBGTPNL_LIBS)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sgsnemu_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
 | 
					sgsnemu_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
 | 
				
			||||||
sgsnemu_SOURCES = sgsnemu.c cmdline.c cmdline.h
 | 
					sgsnemu_SOURCES = sgsnemu.c cmdline.c cmdline.h
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ const char *gengetopt_args_info_help[] = {
 | 
				
			|||||||
	"      --pidfile=STRING          Filename of process id file\n                                  (default=`./sgsnemu.pid')",
 | 
						"      --pidfile=STRING          Filename of process id file\n                                  (default=`./sgsnemu.pid')",
 | 
				
			||||||
	"      --statedir=STRING         Directory of nonvolatile data  (default=`./')",
 | 
						"      --statedir=STRING         Directory of nonvolatile data  (default=`./')",
 | 
				
			||||||
	"      --dns=STRING              DNS Server to use",
 | 
						"      --dns=STRING              DNS Server to use",
 | 
				
			||||||
	"  -l, --listen=STRING           Local interface",
 | 
						"  -l, --listen=STRING           Local host",
 | 
				
			||||||
	"  -r, --remote=STRING           Remote host",
 | 
						"  -r, --remote=STRING           Remote host",
 | 
				
			||||||
	"      --contexts=INT            Number of contexts  (default=`1')",
 | 
						"      --contexts=INT            Number of contexts  (default=`1')",
 | 
				
			||||||
	"      --timelimit=INT           Exit after timelimit seconds  (default=`0')",
 | 
						"      --timelimit=INT           Exit after timelimit seconds  (default=`0')",
 | 
				
			||||||
@@ -65,12 +65,15 @@ const char *gengetopt_args_info_help[] = {
 | 
				
			|||||||
	"      --charging=INT            Charging characteristics  (default=`0x0800')",
 | 
						"      --charging=INT            Charging characteristics  (default=`0x0800')",
 | 
				
			||||||
	"  -u, --uid=STRING              Login user ID  (default=`mig')",
 | 
						"  -u, --uid=STRING              Login user ID  (default=`mig')",
 | 
				
			||||||
	"  -p, --pwd=STRING              Login password  (default=`hemmelig')",
 | 
						"  -p, --pwd=STRING              Login password  (default=`hemmelig')",
 | 
				
			||||||
 | 
						"\n Mode: createif\n  any option of this mode is related to tun interface, all payload going in and\n  out  via tunN interface",
 | 
				
			||||||
	"      --createif                Create local network interface  (default=off)",
 | 
						"      --createif                Create local network interface  (default=off)",
 | 
				
			||||||
	"  -n, --net=STRING              Network address for local interface",
 | 
						"  -n, --net=STRING              Network address for local interface",
 | 
				
			||||||
	"      --defaultroute            Create default route  (default=off)",
 | 
						"      --defaultroute            Create default route  (default=off)",
 | 
				
			||||||
	"      --ipup=STRING             Script to run after link-up",
 | 
						"      --ipup=STRING             Script to run after link-up",
 | 
				
			||||||
	"      --ipdown=STRING           Script to run after link-down",
 | 
						"      --ipdown=STRING           Script to run after link-down",
 | 
				
			||||||
	"      --tun-device=STRING       Name of the local network interface",
 | 
						"      --tun-device=STRING       Name of the local network interface",
 | 
				
			||||||
 | 
						"      --netns=STRING            Network namespace to use",
 | 
				
			||||||
 | 
						"\n Mode: pinghost\n  generate ICMP payload inside G-PDU without setting up tun interface",
 | 
				
			||||||
	"      --pinghost=STRING         Ping remote host",
 | 
						"      --pinghost=STRING         Ping remote host",
 | 
				
			||||||
	"      --pingrate=INT            Number of ping req per second  (default=`1')",
 | 
						"      --pingrate=INT            Number of ping req per second  (default=`1')",
 | 
				
			||||||
	"      --pingsize=INT            Number of ping data bytes  (default=`56')",
 | 
						"      --pingsize=INT            Number of ping data bytes  (default=`56')",
 | 
				
			||||||
@@ -161,6 +164,7 @@ void clear_given(struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	args_info->ipup_given = 0;
 | 
						args_info->ipup_given = 0;
 | 
				
			||||||
	args_info->ipdown_given = 0;
 | 
						args_info->ipdown_given = 0;
 | 
				
			||||||
	args_info->tun_device_given = 0;
 | 
						args_info->tun_device_given = 0;
 | 
				
			||||||
 | 
						args_info->netns_given = 0;
 | 
				
			||||||
	args_info->pinghost_given = 0;
 | 
						args_info->pinghost_given = 0;
 | 
				
			||||||
	args_info->pingrate_given = 0;
 | 
						args_info->pingrate_given = 0;
 | 
				
			||||||
	args_info->pingsize_given = 0;
 | 
						args_info->pingsize_given = 0;
 | 
				
			||||||
@@ -168,6 +172,8 @@ void clear_given(struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	args_info->pingquiet_given = 0;
 | 
						args_info->pingquiet_given = 0;
 | 
				
			||||||
	args_info->no_tx_gpdu_seq_given = 0;
 | 
						args_info->no_tx_gpdu_seq_given = 0;
 | 
				
			||||||
	args_info->pdp_type_given = 0;
 | 
						args_info->pdp_type_given = 0;
 | 
				
			||||||
 | 
						args_info->createif_mode_counter = 0;
 | 
				
			||||||
 | 
						args_info->pinghost_mode_counter = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
@@ -240,6 +246,8 @@ void clear_args(struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	args_info->ipdown_orig = NULL;
 | 
						args_info->ipdown_orig = NULL;
 | 
				
			||||||
	args_info->tun_device_arg = NULL;
 | 
						args_info->tun_device_arg = NULL;
 | 
				
			||||||
	args_info->tun_device_orig = NULL;
 | 
						args_info->tun_device_orig = NULL;
 | 
				
			||||||
 | 
						args_info->netns_arg = NULL;
 | 
				
			||||||
 | 
						args_info->netns_orig = NULL;
 | 
				
			||||||
	args_info->pinghost_arg = NULL;
 | 
						args_info->pinghost_arg = NULL;
 | 
				
			||||||
	args_info->pinghost_orig = NULL;
 | 
						args_info->pinghost_orig = NULL;
 | 
				
			||||||
	args_info->pingrate_arg = 1;
 | 
						args_info->pingrate_arg = 1;
 | 
				
			||||||
@@ -290,19 +298,20 @@ void init_args_info(struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	args_info->charging_help = gengetopt_args_info_help[28];
 | 
						args_info->charging_help = gengetopt_args_info_help[28];
 | 
				
			||||||
	args_info->uid_help = gengetopt_args_info_help[29];
 | 
						args_info->uid_help = gengetopt_args_info_help[29];
 | 
				
			||||||
	args_info->pwd_help = gengetopt_args_info_help[30];
 | 
						args_info->pwd_help = gengetopt_args_info_help[30];
 | 
				
			||||||
	args_info->createif_help = gengetopt_args_info_help[31];
 | 
						args_info->createif_help = gengetopt_args_info_help[32];
 | 
				
			||||||
	args_info->net_help = gengetopt_args_info_help[32];
 | 
						args_info->net_help = gengetopt_args_info_help[33];
 | 
				
			||||||
	args_info->defaultroute_help = gengetopt_args_info_help[33];
 | 
						args_info->defaultroute_help = gengetopt_args_info_help[34];
 | 
				
			||||||
	args_info->ipup_help = gengetopt_args_info_help[34];
 | 
						args_info->ipup_help = gengetopt_args_info_help[35];
 | 
				
			||||||
	args_info->ipdown_help = gengetopt_args_info_help[35];
 | 
						args_info->ipdown_help = gengetopt_args_info_help[36];
 | 
				
			||||||
	args_info->tun_device_help = gengetopt_args_info_help[36];
 | 
						args_info->tun_device_help = gengetopt_args_info_help[37];
 | 
				
			||||||
	args_info->pinghost_help = gengetopt_args_info_help[37];
 | 
						args_info->netns_help = gengetopt_args_info_help[38];
 | 
				
			||||||
	args_info->pingrate_help = gengetopt_args_info_help[38];
 | 
						args_info->pinghost_help = gengetopt_args_info_help[40];
 | 
				
			||||||
	args_info->pingsize_help = gengetopt_args_info_help[39];
 | 
						args_info->pingrate_help = gengetopt_args_info_help[41];
 | 
				
			||||||
	args_info->pingcount_help = gengetopt_args_info_help[40];
 | 
						args_info->pingsize_help = gengetopt_args_info_help[42];
 | 
				
			||||||
	args_info->pingquiet_help = gengetopt_args_info_help[41];
 | 
						args_info->pingcount_help = gengetopt_args_info_help[43];
 | 
				
			||||||
	args_info->no_tx_gpdu_seq_help = gengetopt_args_info_help[42];
 | 
						args_info->pingquiet_help = gengetopt_args_info_help[44];
 | 
				
			||||||
	args_info->pdp_type_help = gengetopt_args_info_help[43];
 | 
						args_info->no_tx_gpdu_seq_help = gengetopt_args_info_help[45];
 | 
				
			||||||
 | 
						args_info->pdp_type_help = gengetopt_args_info_help[46];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,15 +368,6 @@ void cmdline_parser_params_init(struct cmdline_parser_params *params)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmdline_parser_params *cmdline_parser_params_create(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct cmdline_parser_params *params =
 | 
					 | 
				
			||||||
	    (struct cmdline_parser_params *)
 | 
					 | 
				
			||||||
	    malloc(sizeof(struct cmdline_parser_params));
 | 
					 | 
				
			||||||
	cmdline_parser_params_init(params);
 | 
					 | 
				
			||||||
	return params;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void free_string_field(char **s)
 | 
					static void free_string_field(char **s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (*s) {
 | 
						if (*s) {
 | 
				
			||||||
@@ -429,6 +429,8 @@ static void cmdline_parser_release(struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	free_string_field(&(args_info->ipdown_orig));
 | 
						free_string_field(&(args_info->ipdown_orig));
 | 
				
			||||||
	free_string_field(&(args_info->tun_device_arg));
 | 
						free_string_field(&(args_info->tun_device_arg));
 | 
				
			||||||
	free_string_field(&(args_info->tun_device_orig));
 | 
						free_string_field(&(args_info->tun_device_orig));
 | 
				
			||||||
 | 
						free_string_field(&(args_info->netns_arg));
 | 
				
			||||||
 | 
						free_string_field(&(args_info->netns_orig));
 | 
				
			||||||
	free_string_field(&(args_info->pinghost_arg));
 | 
						free_string_field(&(args_info->pinghost_arg));
 | 
				
			||||||
	free_string_field(&(args_info->pinghost_orig));
 | 
						free_string_field(&(args_info->pinghost_orig));
 | 
				
			||||||
	free_string_field(&(args_info->pingrate_orig));
 | 
						free_string_field(&(args_info->pingrate_orig));
 | 
				
			||||||
@@ -542,6 +544,8 @@ int cmdline_parser_dump(FILE * outfile, struct gengetopt_args_info *args_info)
 | 
				
			|||||||
	if (args_info->tun_device_given)
 | 
						if (args_info->tun_device_given)
 | 
				
			||||||
		write_into_file(outfile, "tun-device",
 | 
							write_into_file(outfile, "tun-device",
 | 
				
			||||||
				args_info->tun_device_orig, 0);
 | 
									args_info->tun_device_orig, 0);
 | 
				
			||||||
 | 
						if (args_info->netns_given)
 | 
				
			||||||
 | 
							write_into_file(outfile, "netns", args_info->netns_orig, 0);
 | 
				
			||||||
	if (args_info->pinghost_given)
 | 
						if (args_info->pinghost_given)
 | 
				
			||||||
		write_into_file(outfile, "pinghost", args_info->pinghost_orig,
 | 
							write_into_file(outfile, "pinghost", args_info->pinghost_orig,
 | 
				
			||||||
				0);
 | 
									0);
 | 
				
			||||||
@@ -706,6 +710,12 @@ cmdline_parser_required2(struct gengetopt_args_info *args_info,
 | 
				
			|||||||
			prog_name, (additional_error ? additional_error : ""));
 | 
								prog_name, (additional_error ? additional_error : ""));
 | 
				
			||||||
		error_occurred = 1;
 | 
							error_occurred = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (args_info->netns_given && !args_info->createif_given) {
 | 
				
			||||||
 | 
							fprintf(stderr,
 | 
				
			||||||
 | 
								"%s: '--netns' option depends on option 'createif'%s\n",
 | 
				
			||||||
 | 
								prog_name, (additional_error ? additional_error : ""));
 | 
				
			||||||
 | 
							error_occurred = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (args_info->pingrate_given && !args_info->pinghost_given) {
 | 
						if (args_info->pingrate_given && !args_info->pinghost_given) {
 | 
				
			||||||
		fprintf(stderr,
 | 
							fprintf(stderr,
 | 
				
			||||||
			"%s: '--pingrate' option depends on option 'pinghost'%s\n",
 | 
								"%s: '--pingrate' option depends on option 'pinghost'%s\n",
 | 
				
			||||||
@@ -853,6 +863,30 @@ int update_arg(void *field, char **orig_field,
 | 
				
			|||||||
	return 0;		/* OK */
 | 
						return 0;		/* OK */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int check_modes(int given1[], const char *options1[],
 | 
				
			||||||
 | 
							       int given2[], const char *options2[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i = 0, j = 0, errors = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (given1[i] >= 0) {
 | 
				
			||||||
 | 
							if (given1[i]) {
 | 
				
			||||||
 | 
								while (given2[j] >= 0) {
 | 
				
			||||||
 | 
									if (given2[j]) {
 | 
				
			||||||
 | 
										++errors;
 | 
				
			||||||
 | 
										fprintf(stderr,
 | 
				
			||||||
 | 
											"%s: option %s conflicts with option %s\n",
 | 
				
			||||||
 | 
											package_name, options1[i],
 | 
				
			||||||
 | 
											options2[j]);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									++j;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							++i;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return errors;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
cmdline_parser_internal(int argc, char **argv,
 | 
					cmdline_parser_internal(int argc, char **argv,
 | 
				
			||||||
			struct gengetopt_args_info *args_info,
 | 
								struct gengetopt_args_info *args_info,
 | 
				
			||||||
@@ -927,6 +961,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			{"ipup", 1, NULL, 0},
 | 
								{"ipup", 1, NULL, 0},
 | 
				
			||||||
			{"ipdown", 1, NULL, 0},
 | 
								{"ipdown", 1, NULL, 0},
 | 
				
			||||||
			{"tun-device", 1, NULL, 0},
 | 
								{"tun-device", 1, NULL, 0},
 | 
				
			||||||
 | 
								{"netns", 1, NULL, 0},
 | 
				
			||||||
			{"pinghost", 1, NULL, 0},
 | 
								{"pinghost", 1, NULL, 0},
 | 
				
			||||||
			{"pingrate", 1, NULL, 0},
 | 
								{"pingrate", 1, NULL, 0},
 | 
				
			||||||
			{"pingsize", 1, NULL, 0},
 | 
								{"pingsize", 1, NULL, 0},
 | 
				
			||||||
@@ -976,7 +1011,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
				goto failure;
 | 
									goto failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'l':	/* Local interface.  */
 | 
							case 'l':	/* Local host.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (update_arg((void *)&(args_info->listen_arg),
 | 
								if (update_arg((void *)&(args_info->listen_arg),
 | 
				
			||||||
				       &(args_info->listen_orig),
 | 
									       &(args_info->listen_orig),
 | 
				
			||||||
@@ -1073,6 +1108,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'n':	/* Network address for local interface.  */
 | 
							case 'n':	/* Network address for local interface.  */
 | 
				
			||||||
 | 
								args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (update_arg((void *)&(args_info->net_arg),
 | 
								if (update_arg((void *)&(args_info->net_arg),
 | 
				
			||||||
				       &(args_info->net_orig),
 | 
									       &(args_info->net_orig),
 | 
				
			||||||
@@ -1391,6 +1427,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "createif") == 0) {
 | 
									  "createif") == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->createif_flag), 0,
 | 
									    ((void *)&(args_info->createif_flag), 0,
 | 
				
			||||||
@@ -1405,6 +1442,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "defaultroute") == 0) {
 | 
									  "defaultroute") == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->defaultroute_flag), 0,
 | 
									    ((void *)&(args_info->defaultroute_flag), 0,
 | 
				
			||||||
@@ -1419,6 +1457,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			/* Script to run after link-up.  */
 | 
								/* Script to run after link-up.  */
 | 
				
			||||||
			else if (strcmp(long_options[option_index].name, "ipup")
 | 
								else if (strcmp(long_options[option_index].name, "ipup")
 | 
				
			||||||
				 == 0) {
 | 
									 == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg((void *)&(args_info->ipup_arg),
 | 
									if (update_arg((void *)&(args_info->ipup_arg),
 | 
				
			||||||
					       &(args_info->ipup_orig),
 | 
										       &(args_info->ipup_orig),
 | 
				
			||||||
@@ -1434,6 +1473,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "ipdown") == 0) {
 | 
									  "ipdown") == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg((void *)&(args_info->ipdown_arg),
 | 
									if (update_arg((void *)&(args_info->ipdown_arg),
 | 
				
			||||||
					       &(args_info->ipdown_orig),
 | 
										       &(args_info->ipdown_orig),
 | 
				
			||||||
@@ -1449,6 +1489,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "tun-device") == 0) {
 | 
									  "tun-device") == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->tun_device_arg),
 | 
									    ((void *)&(args_info->tun_device_arg),
 | 
				
			||||||
@@ -1460,11 +1501,28 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
				     additional_error))
 | 
									     additional_error))
 | 
				
			||||||
					goto failure;
 | 
										goto failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* Network namespace to use.  */
 | 
				
			||||||
 | 
								else if (strcmp
 | 
				
			||||||
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
 | 
									  "netns") == 0) {
 | 
				
			||||||
 | 
									args_info->createif_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (update_arg((void *)&(args_info->netns_arg),
 | 
				
			||||||
 | 
										       &(args_info->netns_orig),
 | 
				
			||||||
 | 
										       &(args_info->netns_given),
 | 
				
			||||||
 | 
										       &(local_args_info.netns_given),
 | 
				
			||||||
 | 
										       optarg, 0, 0, ARG_STRING,
 | 
				
			||||||
 | 
										       check_ambiguity, override, 0, 0,
 | 
				
			||||||
 | 
										       "netns", '-', additional_error))
 | 
				
			||||||
 | 
										goto failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/* Ping remote host.  */
 | 
								/* Ping remote host.  */
 | 
				
			||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "pinghost") == 0) {
 | 
									  "pinghost") == 0) {
 | 
				
			||||||
 | 
									args_info->pinghost_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->pinghost_arg),
 | 
									    ((void *)&(args_info->pinghost_arg),
 | 
				
			||||||
@@ -1481,6 +1539,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "pingrate") == 0) {
 | 
									  "pingrate") == 0) {
 | 
				
			||||||
 | 
									args_info->pinghost_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->pingrate_arg),
 | 
									    ((void *)&(args_info->pingrate_arg),
 | 
				
			||||||
@@ -1496,6 +1555,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "pingsize") == 0) {
 | 
									  "pingsize") == 0) {
 | 
				
			||||||
 | 
									args_info->pinghost_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->pingsize_arg),
 | 
									    ((void *)&(args_info->pingsize_arg),
 | 
				
			||||||
@@ -1512,6 +1572,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "pingcount") == 0) {
 | 
									  "pingcount") == 0) {
 | 
				
			||||||
 | 
									args_info->pinghost_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->pingcount_arg),
 | 
									    ((void *)&(args_info->pingcount_arg),
 | 
				
			||||||
@@ -1527,6 +1588,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			else if (strcmp
 | 
								else if (strcmp
 | 
				
			||||||
				 (long_options[option_index].name,
 | 
									 (long_options[option_index].name,
 | 
				
			||||||
				  "pingquiet") == 0) {
 | 
									  "pingquiet") == 0) {
 | 
				
			||||||
 | 
									args_info->pinghost_mode_counter += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (update_arg
 | 
									if (update_arg
 | 
				
			||||||
				    ((void *)&(args_info->pingquiet_flag), 0,
 | 
									    ((void *)&(args_info->pingquiet_flag), 0,
 | 
				
			||||||
@@ -1566,6 +1628,32 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
		}		/* switch */
 | 
							}		/* switch */
 | 
				
			||||||
	}			/* while */
 | 
						}			/* while */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (args_info->createif_mode_counter
 | 
				
			||||||
 | 
						    && args_info->pinghost_mode_counter) {
 | 
				
			||||||
 | 
							int createif_given[] =
 | 
				
			||||||
 | 
							    { args_info->createif_given, args_info->net_given,
 | 
				
			||||||
 | 
								args_info->defaultroute_given, args_info->ipup_given,
 | 
				
			||||||
 | 
								args_info->ipdown_given, args_info->tun_device_given,
 | 
				
			||||||
 | 
								args_info->netns_given, -1
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							const char *createif_desc[] =
 | 
				
			||||||
 | 
							    { "--createif", "--net", "--defaultroute", "--ipup",
 | 
				
			||||||
 | 
								"--ipdown", "--tun-device", "--netns", 0
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							int pinghost_given[] =
 | 
				
			||||||
 | 
							    { args_info->pinghost_given, args_info->pingrate_given,
 | 
				
			||||||
 | 
								args_info->pingsize_given, args_info->pingcount_given,
 | 
				
			||||||
 | 
								args_info->pingquiet_given, -1
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							const char *pinghost_desc[] =
 | 
				
			||||||
 | 
							    { "--pinghost", "--pingrate", "--pingsize", "--pingcount",
 | 
				
			||||||
 | 
								"--pingquiet", 0
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							error_occurred +=
 | 
				
			||||||
 | 
							    check_modes(createif_given, createif_desc, pinghost_given,
 | 
				
			||||||
 | 
									pinghost_desc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (check_required) {
 | 
						if (check_required) {
 | 
				
			||||||
		error_occurred +=
 | 
							error_occurred +=
 | 
				
			||||||
		    cmdline_parser_required2(args_info, argv[0],
 | 
							    cmdline_parser_required2(args_info, argv[0],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package "sgsnemu"
 | 
					package "sgsnemu"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defmode "createif"  modedesc="any option of this mode is related to tun interface, \
 | 
				
			||||||
 | 
					all payload going in and out  via tunN interface"
 | 
				
			||||||
 | 
					defmode "pinghost"  modedesc="generate ICMP payload inside G-PDU without setting up tun interface"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "debug"        d "Run in debug mode"              flag   off
 | 
					option  "debug"        d "Run in debug mode"              flag   off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "conf"         c "Read configuration file"        string no
 | 
					option  "conf"         c "Read configuration file"        string no
 | 
				
			||||||
@@ -22,7 +26,7 @@ option  "pidfile"      - "Filename of process id file"    string default="./sgsn
 | 
				
			|||||||
option  "statedir"     - "Directory of nonvolatile data"  string default="./" no
 | 
					option  "statedir"     - "Directory of nonvolatile data"  string default="./" no
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "dns"          - "DNS Server to use"              string no
 | 
					option  "dns"          - "DNS Server to use"              string no
 | 
				
			||||||
option  "listen"       l "Local interface"                string no
 | 
					option  "listen"       l "Local host"                     string no
 | 
				
			||||||
option  "remote"       r "Remote host"                    string no
 | 
					option  "remote"       r "Remote host"                    string no
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "contexts"     - "Number of contexts"             int    default="1" no
 | 
					option  "contexts"     - "Number of contexts"             int    default="1" no
 | 
				
			||||||
@@ -49,18 +53,19 @@ option  "charging"     - "Charging characteristics"       int    default="0x0800
 | 
				
			|||||||
option  "uid"          u "Login user ID"                  string default="mig" no
 | 
					option  "uid"          u "Login user ID"                  string default="mig" no
 | 
				
			||||||
option  "pwd"          p "Login password"                 string default="hemmelig" no
 | 
					option  "pwd"          p "Login password"                 string default="hemmelig" no
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "createif"     - "Create local network interface" flag   off
 | 
					modeoption   "createif"     - "Create local network interface" flag   off                           mode="createif"
 | 
				
			||||||
option  "net"          n "Network address for local interface" string dependon="createif" no
 | 
					modeoption   "net"          n "Network address for local interface" string dependon="createif" no   mode="createif"
 | 
				
			||||||
option  "defaultroute" - "Create default route"           flag   dependon="createif" off
 | 
					modeoption   "defaultroute" - "Create default route"           flag   dependon="createif" off       mode="createif"
 | 
				
			||||||
option  "ipup"         - "Script to run after link-up"    string dependon="createif" no
 | 
					modeoption   "ipup"         - "Script to run after link-up"    string dependon="createif" no        mode="createif"
 | 
				
			||||||
option  "ipdown"       - "Script to run after link-down"  string dependon="createif" no
 | 
					modeoption   "ipdown"       - "Script to run after link-down"  string dependon="createif" no        mode="createif"
 | 
				
			||||||
option  "tun-device"   - "Name of the local network interface" string dependon="createif" no
 | 
					modeoption   "tun-device"   - "Name of the local network interface" string dependon="createif" no   mode="createif"
 | 
				
			||||||
 | 
					modeoption   "netns"        - "Network namespace to use"       string dependon="createif" no        mode="createif"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "pinghost"     - "Ping remote host"               string no
 | 
					modeoption   "pinghost"     - "Ping remote host"               string no                                mode="pinghost"
 | 
				
			||||||
option  "pingrate"     - "Number of ping req per second"  int default="1" dependon="pinghost" no
 | 
					modeoption   "pingrate"     - "Number of ping req per second"  int default="1" dependon="pinghost" no   mode="pinghost"
 | 
				
			||||||
option  "pingsize"     - "Number of ping data bytes"      int default="56" dependon="pinghost" no
 | 
					modeoption   "pingsize"     - "Number of ping data bytes"      int default="56" dependon="pinghost" no  mode="pinghost"
 | 
				
			||||||
option  "pingcount"    - "Number of ping req to send"     int default="0" dependon="pinghost" no
 | 
					modeoption   "pingcount"    - "Number of ping req to send"     int default="0" dependon="pinghost" no   mode="pinghost"
 | 
				
			||||||
option  "pingquiet"    - "Do not print ping packet info"  flag dependon="pinghost" off
 | 
					modeoption   "pingquiet"    - "Do not print ping packet info"  flag dependon="pinghost" off             mode="pinghost"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option  "no-tx-gpdu-seq" - "Don't transmit G-PDU sequence nums"   flag    off
 | 
					option  "no-tx-gpdu-seq" - "Don't transmit G-PDU sequence nums"   flag    off
 | 
				
			||||||
option  "pdp-type"     t "PDP Type"                       string default="v4" no typestr="(v4|v6)"
 | 
					option  "pdp-type"     t "PDP Type"                       string default="v4" no typestr="(v4|v6)"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,11 +69,11 @@ extern "C" {
 | 
				
			|||||||
		const char *dns_help;
 | 
							const char *dns_help;
 | 
				
			||||||
			/**< @brief DNS Server to use help description.  */
 | 
								/**< @brief DNS Server to use help description.  */
 | 
				
			||||||
		char *listen_arg;
 | 
							char *listen_arg;
 | 
				
			||||||
			/**< @brief Local interface.  */
 | 
								/**< @brief Local host.  */
 | 
				
			||||||
		char *listen_orig;
 | 
							char *listen_orig;
 | 
				
			||||||
			/**< @brief Local interface original value given at command line.  */
 | 
								/**< @brief Local host original value given at command line.  */
 | 
				
			||||||
		const char *listen_help;
 | 
							const char *listen_help;
 | 
				
			||||||
			   /**< @brief Local interface help description.  */
 | 
								   /**< @brief Local host help description.  */
 | 
				
			||||||
		char *remote_arg;
 | 
							char *remote_arg;
 | 
				
			||||||
			/**< @brief Remote host.  */
 | 
								/**< @brief Remote host.  */
 | 
				
			||||||
		char *remote_orig;
 | 
							char *remote_orig;
 | 
				
			||||||
@@ -242,6 +242,12 @@ extern "C" {
 | 
				
			|||||||
				/**< @brief Name of the local network interface original value given at command line.  */
 | 
									/**< @brief Name of the local network interface original value given at command line.  */
 | 
				
			||||||
		const char *tun_device_help;
 | 
							const char *tun_device_help;
 | 
				
			||||||
			       /**< @brief Name of the local network interface help description.  */
 | 
								       /**< @brief Name of the local network interface help description.  */
 | 
				
			||||||
 | 
							char *netns_arg;
 | 
				
			||||||
 | 
								/**< @brief Network namespace to use.  */
 | 
				
			||||||
 | 
							char *netns_orig;
 | 
				
			||||||
 | 
								/**< @brief Network namespace to use original value given at command line.  */
 | 
				
			||||||
 | 
							const char *netns_help;
 | 
				
			||||||
 | 
								  /**< @brief Network namespace to use help description.  */
 | 
				
			||||||
		char *pinghost_arg;
 | 
							char *pinghost_arg;
 | 
				
			||||||
			/**< @brief Ping remote host.  */
 | 
								/**< @brief Ping remote host.  */
 | 
				
			||||||
		char *pinghost_orig;
 | 
							char *pinghost_orig;
 | 
				
			||||||
@@ -355,6 +361,8 @@ extern "C" {
 | 
				
			|||||||
				/**< @brief Whether ipdown was given.  */
 | 
									/**< @brief Whether ipdown was given.  */
 | 
				
			||||||
		unsigned int tun_device_given;
 | 
							unsigned int tun_device_given;
 | 
				
			||||||
					/**< @brief Whether tun-device was given.  */
 | 
										/**< @brief Whether tun-device was given.  */
 | 
				
			||||||
 | 
							unsigned int netns_given;
 | 
				
			||||||
 | 
									/**< @brief Whether netns was given.  */
 | 
				
			||||||
		unsigned int pinghost_given;
 | 
							unsigned int pinghost_given;
 | 
				
			||||||
				/**< @brief Whether pinghost was given.  */
 | 
									/**< @brief Whether pinghost was given.  */
 | 
				
			||||||
		unsigned int pingrate_given;
 | 
							unsigned int pingrate_given;
 | 
				
			||||||
@@ -370,6 +378,10 @@ extern "C" {
 | 
				
			|||||||
		unsigned int pdp_type_given;
 | 
							unsigned int pdp_type_given;
 | 
				
			||||||
				/**< @brief Whether pdp-type was given.  */
 | 
									/**< @brief Whether pdp-type was given.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int createif_mode_counter;
 | 
				
			||||||
 | 
								     /**< @brief Counter for mode createif */
 | 
				
			||||||
 | 
							int pinghost_mode_counter;
 | 
				
			||||||
 | 
								     /**< @brief Counter for mode pinghost */
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @brief The additional parameters to pass to parser functions */
 | 
					/** @brief The additional parameters to pass to parser functions */
 | 
				
			||||||
@@ -467,13 +479,6 @@ extern "C" {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
	void cmdline_parser_params_init(struct cmdline_parser_params *params);
 | 
						void cmdline_parser_params_init(struct cmdline_parser_params *params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Allocates dynamically a cmdline_parser_params structure and initializes
 | 
					 | 
				
			||||||
 * all its fields to their default values
 | 
					 | 
				
			||||||
 * @return the created and initialized cmdline_parser_params structure
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
	struct cmdline_parser_params *cmdline_parser_params_create(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Initializes the passed gengetopt_args_info structure's fields
 | 
					 * Initializes the passed gengetopt_args_info structure's fields
 | 
				
			||||||
 * (also set default values for options that have a default)
 | 
					 * (also set default values for options that have a default)
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,18 +2,30 @@ AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
	gtpie_test.ok \
 | 
						gtpie_test.ok \
 | 
				
			||||||
 | 
						queue_test.ok \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = \
 | 
					noinst_PROGRAMS = \
 | 
				
			||||||
	gtpie_test \
 | 
						gtpie_test \
 | 
				
			||||||
 | 
						queue_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gtpie_test_SOURCES = \
 | 
					gtpie_test_SOURCES = \
 | 
				
			||||||
	gtpie_test.c \
 | 
						gtpie_test.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					queue_test_SOURCES = \
 | 
				
			||||||
 | 
						queue_test.c \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gtpie_test_LDADD = \
 | 
					gtpie_test_LDADD = \
 | 
				
			||||||
	$(top_builddir)/lib/debug.o \
 | 
						$(top_builddir)/lib/debug.o \
 | 
				
			||||||
	$(top_builddir)/gtp/libgtp.la \
 | 
						$(top_builddir)/gtp/libgtp.la \
 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					queue_test_LDADD = \
 | 
				
			||||||
 | 
						$(top_builddir)/lib/debug.o \
 | 
				
			||||||
 | 
						$(top_builddir)/gtp/libgtp.la \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/bits.h>
 | 
					#include <osmocom/core/bits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../lib/syserr.h"
 | 
					#include "../../lib/syserr.h"
 | 
				
			||||||
@@ -108,9 +109,11 @@ static void test_gtpie_tv8()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_init_logging(&log_info);
 | 
						void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(tall_ctx, &log_info);
 | 
				
			||||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
						log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
						log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srand(time(NULL));
 | 
						srand(time(NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										233
									
								
								tests/gtp/queue_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								tests/gtp/queue_test.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,233 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/bits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../lib/syserr.h"
 | 
				
			||||||
 | 
					#include "../../gtp/queue.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct qmsg_t qmsg_zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void queue_print(struct queue_t *queue, char* str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int n;
 | 
				
			||||||
 | 
						printf("=== [Queue %s] Next: %d First: %d Last: %d\n", str,
 | 
				
			||||||
 | 
							queue->next, queue->first, queue->last);
 | 
				
			||||||
 | 
						printf("#\tseq\tnext\tprev\ttimeout\tretrans\ttype\tcbp\n");
 | 
				
			||||||
 | 
						for (n = 0; n < QUEUE_SIZE; n++) {
 | 
				
			||||||
 | 
							if (queue->qmsga[n].state == 0) {
 | 
				
			||||||
 | 
								/* Nothing there, validate everything is zeroed */
 | 
				
			||||||
 | 
								OSMO_ASSERT(memcmp(&qmsg_zero, &queue->qmsga[n], sizeof(qmsg_zero)) == 0);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							printf("%d\t%d\t%d\t%d\t%d\t%d\t%u\t%" PRIuPTR "\n",
 | 
				
			||||||
 | 
							       n,
 | 
				
			||||||
 | 
							       queue->qmsga[n].seq,
 | 
				
			||||||
 | 
							       queue->qmsga[n].next,
 | 
				
			||||||
 | 
							       queue->qmsga[n].prev,
 | 
				
			||||||
 | 
							       (int)queue->qmsga[n].timeout,
 | 
				
			||||||
 | 
							       queue->qmsga[n].retrans,
 | 
				
			||||||
 | 
							       queue->qmsga[n].type,
 | 
				
			||||||
 | 
							       (uintptr_t)queue->qmsga[n].cbp
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("======================================================\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_queue_empty()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("***** Testing %s()\n", __func__);
 | 
				
			||||||
 | 
						struct queue_t *queue = NULL;
 | 
				
			||||||
 | 
						struct qmsg_t *qmsg = NULL;
 | 
				
			||||||
 | 
						uint16_t seq = 23;
 | 
				
			||||||
 | 
						uint8_t type = 0;
 | 
				
			||||||
 | 
						void *cbp = NULL;
 | 
				
			||||||
 | 
						struct sockaddr_in peer;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_new(&queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "created");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_getfirst(queue, &qmsg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						rc = queue_seqget(queue, &qmsg, &peer, seq);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						rc = queue_freemsg_seq(queue, &peer, seq, &type, &cbp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc==EOF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue_print(queue, "pre-delete");
 | 
				
			||||||
 | 
						rc = queue_free(queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_queue_one()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("***** Testing %s()\n", __func__);
 | 
				
			||||||
 | 
						struct queue_t *queue = NULL;
 | 
				
			||||||
 | 
						struct qmsg_t *qmsg = NULL, *qmsg2 = NULL;;
 | 
				
			||||||
 | 
						uint16_t seq = 23;
 | 
				
			||||||
 | 
						uint8_t type = 0;
 | 
				
			||||||
 | 
						void *cbp = NULL;
 | 
				
			||||||
 | 
						struct sockaddr_in peer, peer2;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						rc = inet_pton(AF_INET, "127.0.0.2", &(peer2.sin_addr));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_new(&queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "created");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_newmsg(queue, &qmsg, &peer, seq);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "first added");
 | 
				
			||||||
 | 
						qmsg->type = GTP_ECHO_REQ;
 | 
				
			||||||
 | 
						qmsg->cbp = (void*) 0x13243546;
 | 
				
			||||||
 | 
						qmsg->seq = seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_getfirst(queue, &qmsg2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(qmsg == qmsg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_seqget(queue, &qmsg2, &peer, seq);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(qmsg == qmsg2);
 | 
				
			||||||
 | 
						rc = queue_seqget(queue, &qmsg, &peer2, seq);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						rc = queue_seqget(queue, &qmsg, &peer, seq + 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						queue_print(queue, "after-get");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_back(queue, qmsg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "after-back");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_freemsg_seq(queue, &peer2, seq, &type, &cbp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						rc = queue_freemsg_seq(queue, &peer, seq + 1, &type, &cbp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						queue_print(queue, "pree-freemsg");
 | 
				
			||||||
 | 
						rc = queue_freemsg_seq(queue, &peer, seq, &type, &cbp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(type == GTP_ECHO_REQ);
 | 
				
			||||||
 | 
						OSMO_ASSERT(cbp == (void*)0x13243546);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue_print(queue, "pre-delete");
 | 
				
			||||||
 | 
						rc = queue_free(queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define newmsg_fill(queue, qmsg_ptr, peer_ptr, seq) \
 | 
				
			||||||
 | 
						do { \
 | 
				
			||||||
 | 
							int rc = queue_newmsg(queue, &(qmsg_ptr), peer_ptr, seq); \
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc == 0); \
 | 
				
			||||||
 | 
							OSMO_ASSERT(qmsg_ptr); \
 | 
				
			||||||
 | 
							qmsg_ptr->type = GTP_CREATE_PDP_REQ; \
 | 
				
			||||||
 | 
							qmsg_ptr->cbp = (void*)(uintptr_t)seq; \
 | 
				
			||||||
 | 
						} while (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define freemsg_verify(seq, type, cbp) \
 | 
				
			||||||
 | 
						do { \
 | 
				
			||||||
 | 
							OSMO_ASSERT(type == GTP_CREATE_PDP_REQ); \
 | 
				
			||||||
 | 
							OSMO_ASSERT(cbp == (void*)(uintptr_t)seq); \
 | 
				
			||||||
 | 
						} while (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_queue_full()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* queue_newmsg until we receive EOF. Try moving back then. */
 | 
				
			||||||
 | 
						printf("***** Testing %s()\n", __func__);
 | 
				
			||||||
 | 
						struct queue_t *queue = NULL;
 | 
				
			||||||
 | 
						struct qmsg_t *qmsg = NULL;
 | 
				
			||||||
 | 
						uint8_t type = 0;
 | 
				
			||||||
 | 
						void *cbp = NULL;
 | 
				
			||||||
 | 
						struct sockaddr_in peer;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_new(&queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "created");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < QUEUE_SIZE - 1; i++) {
 | 
				
			||||||
 | 
							newmsg_fill(queue, qmsg, &peer, i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						queue_print(queue, "after-fill");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* There's one slot left at the end, let's use first()->back() */
 | 
				
			||||||
 | 
						rc = queue_getfirst(queue, &qmsg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = queue_back(queue, qmsg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						queue_print(queue, "after-back");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now let's fill last empty slot */
 | 
				
			||||||
 | 
						newmsg_fill(queue, qmsg, &peer, QUEUE_SIZE - 1);
 | 
				
			||||||
 | 
						queue_print(queue, "after-full");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* queue is now full, it should fail */
 | 
				
			||||||
 | 
						rc = queue_newmsg(queue, &qmsg, &peer, QUEUE_SIZE);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == EOF);
 | 
				
			||||||
 | 
						queue_print(queue, "after-failing-full");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Remove 1before-last msg (the one moved back) and make sure we can
 | 
				
			||||||
 | 
						   re-add it at the end of the list */
 | 
				
			||||||
 | 
						rc = queue_seqget(queue, &qmsg, &peer, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = queue_freemsg(queue, qmsg);
 | 
				
			||||||
 | 
						queue_print(queue, "after-freeing-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						/* Now let's fill last empty slot which should be at the end */
 | 
				
			||||||
 | 
						newmsg_fill(queue, qmsg, &peer, 0);
 | 
				
			||||||
 | 
						queue_print(queue, "after-refilling-0");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now free first half seq set in increasing order */
 | 
				
			||||||
 | 
						for (i = 0; i < QUEUE_SIZE / 2; i++) {
 | 
				
			||||||
 | 
							rc = queue_freemsg_seq(queue, &peer, i, &type, &cbp);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
							freemsg_verify(i, type, cbp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						queue_print(queue, "after-first-half-free");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now free second half seq set in decreasing order */
 | 
				
			||||||
 | 
						for (i = QUEUE_SIZE - 1; i >= QUEUE_SIZE / 2; i--) {
 | 
				
			||||||
 | 
							rc = queue_freemsg_seq(queue, &peer, i, &type, &cbp);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
							freemsg_verify(i, type, cbp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						queue_print(queue, "after-second-half-free");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = queue_free(queue);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(tall_ctx, &log_info);
 | 
				
			||||||
 | 
						log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
						log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_queue_empty();
 | 
				
			||||||
 | 
						test_queue_one();
 | 
				
			||||||
 | 
						test_queue_full();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6711
									
								
								tests/gtp/queue_test.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6711
									
								
								tests/gtp/queue_test.ok
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,7 +1,11 @@
 | 
				
			|||||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
 | 
					AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = ippool_test.ok ippool_test.err \
 | 
					EXTRA_DIST = ippool_test.ok \
 | 
				
			||||||
	     in46a_test.ok
 | 
						     ippool_test.err \
 | 
				
			||||||
 | 
						     ippool_v6_test.ok \
 | 
				
			||||||
 | 
						     ippool_v6_test.err \
 | 
				
			||||||
 | 
						     in46a_test.ok \
 | 
				
			||||||
 | 
						     in46a_v6_test.ok
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = ippool_test in46a_test
 | 
					noinst_PROGRAMS = ippool_test in46a_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/bits.h>
 | 
					#include <osmocom/core/bits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../lib/in46_addr.h"
 | 
					#include "../../lib/in46_addr.h"
 | 
				
			||||||
@@ -20,41 +21,24 @@ static const struct in46_addr g_ia4 = {
 | 
				
			|||||||
	.v4.s_addr = 0x0d0c0b0a,
 | 
						.v4.s_addr = 0x0d0c0b0a,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct in46_addr g_ia6 = {
 | 
					 | 
				
			||||||
	.len = 16,
 | 
					 | 
				
			||||||
	.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void test_in46a_to_af(void)
 | 
					static void test_in46a_to_af(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in46_addr ia;
 | 
						printf("Testing in46a_to_af() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					 | 
				
			||||||
	printf("Testing in46a_to_af()\n");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(in46a_to_af(&g_ia4) == AF_INET);
 | 
						OSMO_ASSERT(in46a_to_af(&g_ia4) == AF_INET);
 | 
				
			||||||
	OSMO_ASSERT(in46a_to_af(&g_ia6) == AF_INET6);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ia.len = 8;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_to_af(&ia) == AF_INET6);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_in46a_to_sas(void)
 | 
					static void test_in46a_to_sas(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr_storage ss;
 | 
						struct sockaddr_storage ss;
 | 
				
			||||||
	struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
 | 
						struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
 | 
				
			||||||
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing in46a_to_sas()\n");
 | 
						printf("Testing in46a_to_sas() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&ss, 0, sizeof(ss));
 | 
						memset(&ss, 0, sizeof(ss));
 | 
				
			||||||
	OSMO_ASSERT(in46a_to_sas(&ss, &g_ia4) == 0);
 | 
						OSMO_ASSERT(in46a_to_sas(&ss, &g_ia4) == 0);
 | 
				
			||||||
	OSMO_ASSERT(sin->sin_family == AF_INET);
 | 
						OSMO_ASSERT(sin->sin_family == AF_INET);
 | 
				
			||||||
	OSMO_ASSERT(sin->sin_addr.s_addr == g_ia4.v4.s_addr);
 | 
						OSMO_ASSERT(sin->sin_addr.s_addr == g_ia4.v4.s_addr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&ss, 0, sizeof(ss));
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_to_sas(&ss, &g_ia6) == 0);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(sin6->sin6_family == AF_INET6);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(!memcmp(&sin6->sin6_addr, &g_ia6.v6, sizeof(sin6->sin6_addr)));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_in46a_ntop(void)
 | 
					static void test_in46a_ntop(void)
 | 
				
			||||||
@@ -63,7 +47,7 @@ static void test_in46a_ntop(void)
 | 
				
			|||||||
	char buf[256];
 | 
						char buf[256];
 | 
				
			||||||
	const char *res;
 | 
						const char *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing in46a_ntop()\n");
 | 
						printf("Testing in46a_ntop() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = in46a_ntop(NULL, buf, sizeof(buf));
 | 
						res = in46a_ntop(NULL, buf, sizeof(buf));
 | 
				
			||||||
	OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
 | 
						OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
 | 
				
			||||||
@@ -79,10 +63,6 @@ static void test_in46a_ntop(void)
 | 
				
			|||||||
	res = in46a_ntop(&ia, buf, sizeof(buf));
 | 
						res = in46a_ntop(&ia, buf, sizeof(buf));
 | 
				
			||||||
	OSMO_ASSERT(res && !strcmp(res, "1.2.3.4"));
 | 
						OSMO_ASSERT(res && !strcmp(res, "1.2.3.4"));
 | 
				
			||||||
	printf("res = %s\n", res);
 | 
						printf("res = %s\n", res);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = in46a_ntop(&g_ia6, buf, sizeof(buf));
 | 
					 | 
				
			||||||
	OSMO_ASSERT(res && !strcmp(res, "102:304:506:708:90a:b0c:d0e:f10"));
 | 
					 | 
				
			||||||
	printf("res = %s\n", res);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_in46p_ntoa(void)
 | 
					static void test_in46p_ntoa(void)
 | 
				
			||||||
@@ -101,21 +81,14 @@ static void test_in46a_equal(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct in46_addr b;
 | 
						struct in46_addr b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing in46a_equal()\n");
 | 
						printf("Testing in46a_equal() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&b, 0xff, sizeof(b));
 | 
						memset(&b, 0xff, sizeof(b));
 | 
				
			||||||
	b.len = g_ia4.len;
 | 
						b.len = g_ia4.len;
 | 
				
			||||||
	b.v4.s_addr = g_ia4.v4.s_addr;
 | 
						b.v4.s_addr = g_ia4.v4.s_addr;
 | 
				
			||||||
	OSMO_ASSERT(in46a_equal(&g_ia4, &b));
 | 
						OSMO_ASSERT(in46a_equal(&g_ia4, &b));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&b, 0xff, sizeof(b));
 | 
					 | 
				
			||||||
	b.len = g_ia6.len;
 | 
					 | 
				
			||||||
	b.v6 = g_ia6.v6;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_equal(&g_ia6, &b));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static int log_in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
 | 
					static int log_in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
 | 
				
			||||||
				 size_t prefixlen)
 | 
									 size_t prefixlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -134,7 +107,7 @@ static void test_in46a_within_mask(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct in46_addr addr, mask;
 | 
						struct in46_addr addr, mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing in46a_within_mask()\n");
 | 
						printf("Testing in46a_within_mask() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = g_ia4;
 | 
						addr = g_ia4;
 | 
				
			||||||
	mask = g_ia4;
 | 
						mask = g_ia4;
 | 
				
			||||||
@@ -155,13 +128,9 @@ static void test_in46a_within_mask(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void test_in46a_to_eua(void)
 | 
					static void test_in46a_to_eua(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct in46_addr ia_v6_8 = {
 | 
					 | 
				
			||||||
		.len = 8,
 | 
					 | 
				
			||||||
		.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	struct ul66_t eua;
 | 
						struct ul66_t eua;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("testing in46a_to_eua()\n");
 | 
						printf("testing in46a_to_eua() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0	/* triggers assert in current implementation */
 | 
					#if 0	/* triggers assert in current implementation */
 | 
				
			||||||
	const struct in46_addr ia_invalid = { .len = 3, };
 | 
						const struct in46_addr ia_invalid = { .len = 3, };
 | 
				
			||||||
@@ -169,22 +138,10 @@ static void test_in46a_to_eua(void)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* IPv4 address */
 | 
						/* IPv4 address */
 | 
				
			||||||
	OSMO_ASSERT(in46a_to_eua(&g_ia4, &eua) == 0);
 | 
						OSMO_ASSERT(in46a_to_eua(&g_ia4, 1, &eua) == 0);
 | 
				
			||||||
	OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
						OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
				
			||||||
	OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4);
 | 
						OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4);
 | 
				
			||||||
	OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
 | 
						OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* IPv6 address */
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_to_eua(&g_ia6, &eua) == 0);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(!memcmp(&eua.v[2], &g_ia6.v6, 16));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* IPv6 address with prefix / length 8 */
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_to_eua(&ia_v6_8, &eua) == 0);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_in46a_from_eua(void)
 | 
					static void test_in46a_from_eua(void)
 | 
				
			||||||
@@ -193,16 +150,12 @@ static void test_in46a_from_eua(void)
 | 
				
			|||||||
	struct ul66_t eua;
 | 
						struct ul66_t eua;
 | 
				
			||||||
	const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 };
 | 
						const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 };
 | 
				
			||||||
	const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 };
 | 
						const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 };
 | 
				
			||||||
	const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 };
 | 
					 | 
				
			||||||
	const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6,
 | 
					 | 
				
			||||||
				    1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&eua, 0, sizeof(eua));
 | 
						memset(&eua, 0, sizeof(eua));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing in46a_from_eua()\n");
 | 
						printf("Testing in46a_from_eua() with IPv4 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* default: v4 unspec */
 | 
						/* default: v4 unspec */
 | 
				
			||||||
	OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
 | 
				
			||||||
	OSMO_ASSERT(ia.len == 4);
 | 
						OSMO_ASSERT(ia.len == 4);
 | 
				
			||||||
	OSMO_ASSERT(ia.v4.s_addr == 0);
 | 
						OSMO_ASSERT(ia.v4.s_addr == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,30 +174,16 @@ static void test_in46a_from_eua(void)
 | 
				
			|||||||
	/* unspecified V4 */
 | 
						/* unspecified V4 */
 | 
				
			||||||
	memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
 | 
						memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
 | 
				
			||||||
	eua.l = sizeof(v4_unspec);
 | 
						eua.l = sizeof(v4_unspec);
 | 
				
			||||||
	OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
 | 
				
			||||||
	OSMO_ASSERT(ia.len == 4);
 | 
						OSMO_ASSERT(ia.len == 4);
 | 
				
			||||||
	OSMO_ASSERT(ia.v4.s_addr == 0);
 | 
						OSMO_ASSERT(ia.v4.s_addr == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* specified V4 */
 | 
						/* specified V4 */
 | 
				
			||||||
	memcpy(eua.v, v4_spec, sizeof(v4_spec));
 | 
						memcpy(eua.v, v4_spec, sizeof(v4_spec));
 | 
				
			||||||
	eua.l = sizeof(v4_spec);
 | 
						eua.l = sizeof(v4_spec);
 | 
				
			||||||
	OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
 | 
				
			||||||
	OSMO_ASSERT(ia.len == 4);
 | 
						OSMO_ASSERT(ia.len == 4);
 | 
				
			||||||
	OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
 | 
						OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* unspecified V6 */
 | 
					 | 
				
			||||||
	memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
 | 
					 | 
				
			||||||
	eua.l = sizeof(v6_unspec);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(ia.len == 16);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* specified V6 */
 | 
					 | 
				
			||||||
	memcpy(eua.v, v6_spec, sizeof(v6_spec));
 | 
					 | 
				
			||||||
	eua.l = sizeof(v6_spec);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(ia.len == 16);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_in46a_netmasklen(void)
 | 
					static void test_in46a_netmasklen(void)
 | 
				
			||||||
@@ -274,7 +213,188 @@ static void test_in46a_netmasklen(void)
 | 
				
			|||||||
	netmask.v4.s_addr = 0x00000000;
 | 
						netmask.v4.s_addr = 0x00000000;
 | 
				
			||||||
	len = in46a_netmasklen(&netmask);
 | 
						len = in46a_netmasklen(&netmask);
 | 
				
			||||||
	OSMO_ASSERT(len == 0);
 | 
						OSMO_ASSERT(len == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* IPv6 specific tests */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct in46_addr g_ia6 = {
 | 
				
			||||||
 | 
						.len = 16,
 | 
				
			||||||
 | 
						.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_to_af_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in46_addr ia;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_to_af() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_af(&g_ia6) == AF_INET6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ia.len = 8;
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_af(&ia) == AF_INET6);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_to_sas_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sockaddr_storage ss;
 | 
				
			||||||
 | 
						struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_to_sas() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&ss, 0, sizeof(ss));
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_sas(&ss, &g_ia6) == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(sin6->sin6_family == AF_INET6);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&sin6->sin6_addr, &g_ia6.v6, sizeof(sin6->sin6_addr)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_ntop_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[256];
 | 
				
			||||||
 | 
						const char *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_ntop() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = in46a_ntop(&g_ia6, buf, sizeof(buf));
 | 
				
			||||||
 | 
						OSMO_ASSERT(res && !strcmp(res, "102:304:506:708:90a:b0c:d0e:f10"));
 | 
				
			||||||
 | 
						printf("res = %s\n", res);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_equal_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in46_addr b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_equal() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&b, 0xff, sizeof(b));
 | 
				
			||||||
 | 
						b.len = g_ia6.len;
 | 
				
			||||||
 | 
						b.v6 = g_ia6.v6;
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_equal(&g_ia6, &b));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_to_eua_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct in46_addr ia_v6_8 = {
 | 
				
			||||||
 | 
							.len = 8,
 | 
				
			||||||
 | 
							.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct ul66_t eua;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_to_eua() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* IPv6 address */
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_eua(&g_ia6, 1, &eua) == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&eua.v[2], &g_ia6.v6, 16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* IPv6 address with prefix / length 8 */
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_eua(&ia_v6_8, 1, &eua) == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_to_eua_v4v6() {
 | 
				
			||||||
 | 
						const struct in46_addr ia_v4v6[2] = {
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							.len = 16,
 | 
				
			||||||
 | 
							.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							.len = 4,
 | 
				
			||||||
 | 
							.v4.s_addr = 0x0d0c0b0a,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct ul66_t eua;
 | 
				
			||||||
 | 
						printf("Testing in46a_to_eua() with IPv4v6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* IPv4 address */
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_to_eua(ia_v4v6, 2, &eua) == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
 | 
				
			||||||
 | 
						OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4v6);
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&eua.v[6], &g_ia6.v6, 16));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_from_eua_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in46_addr ia;
 | 
				
			||||||
 | 
						struct ul66_t eua;
 | 
				
			||||||
 | 
						const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 };
 | 
				
			||||||
 | 
						const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6,
 | 
				
			||||||
 | 
									    1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&eua, 0, sizeof(eua));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_from_eua() with IPv6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* unspecified V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v6_unspec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia.len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* specified V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v6_spec, sizeof(v6_spec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v6_spec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia.len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_from_eua_v4v6(void) {
 | 
				
			||||||
 | 
						struct in46_addr ia[2];
 | 
				
			||||||
 | 
						struct ul66_t eua;
 | 
				
			||||||
 | 
						const uint8_t v4_unspec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6 };
 | 
				
			||||||
 | 
						const uint8_t v4_spec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4 };
 | 
				
			||||||
 | 
						const uint8_t v4_unspec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
 | 
				
			||||||
 | 
						const uint8_t v4_spec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&eua, 0, sizeof(eua));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Testing in46a_from_eua() with IPv4v6 addresses\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* unspecified V4 & V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v4_unspec_v6_unspec, sizeof(v4_unspec_v6_unspec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v4_unspec_v6_unspec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].len == 4);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[1].len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].v4.s_addr == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* specified V4, unspecified V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v4_spec_v6_unspec, sizeof(v4_spec_v6_unspec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v4_spec_v6_unspec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].len == 4);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[1].len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
 | 
				
			||||||
 | 
						OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* unspecified V4, specified V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v4_unspec_v6_spec, sizeof(v4_unspec_v6_spec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v4_unspec_v6_spec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].len == 4);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[1].len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].v4.s_addr == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&ia[1].v6, v4_unspec_v6_spec+2, ia[1].len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* specified V4, specified V6 */
 | 
				
			||||||
 | 
						memcpy(eua.v, v4_spec_v6_spec, sizeof(v4_spec_v6_spec));
 | 
				
			||||||
 | 
						eua.l = sizeof(v4_spec_v6_spec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].len == 4);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[1].len == 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
 | 
				
			||||||
 | 
						OSMO_ASSERT(!memcmp(&ia[1].v6, v4_spec_v6_spec+6, ia[1].len));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_in46a_netmasklen_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int len;
 | 
				
			||||||
	printf("Testing in46a_netmasklen() with IPv6 addresses\n");
 | 
						printf("Testing in46a_netmasklen() with IPv6 addresses\n");
 | 
				
			||||||
	const struct in46_addr netmaskA = {
 | 
						const struct in46_addr netmaskA = {
 | 
				
			||||||
		.len = 16,
 | 
							.len = 16,
 | 
				
			||||||
@@ -307,20 +427,34 @@ static void test_in46a_netmasklen(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_init_logging(&log_info);
 | 
						void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(tall_ctx, &log_info);
 | 
				
			||||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
						log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
						log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srand(time(NULL));
 | 
						srand(time(NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test_in46a_to_af();
 | 
						if (argc < 2 || strcmp(argv[1], "-v6")) {
 | 
				
			||||||
	test_in46a_to_sas();
 | 
							test_in46a_to_af();
 | 
				
			||||||
	test_in46a_ntop();
 | 
							test_in46a_to_sas();
 | 
				
			||||||
	test_in46p_ntoa();
 | 
							test_in46a_ntop();
 | 
				
			||||||
	test_in46a_equal();
 | 
							test_in46p_ntoa();
 | 
				
			||||||
	test_in46a_within_mask();
 | 
							test_in46a_equal();
 | 
				
			||||||
	test_in46a_to_eua();
 | 
							test_in46a_within_mask();
 | 
				
			||||||
	test_in46a_from_eua();
 | 
							test_in46a_to_eua();
 | 
				
			||||||
	test_in46a_netmasklen();
 | 
							test_in46a_from_eua();
 | 
				
			||||||
 | 
							test_in46a_netmasklen();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							test_in46a_to_af_v6();
 | 
				
			||||||
 | 
							test_in46a_to_sas_v6();
 | 
				
			||||||
 | 
							test_in46a_ntop_v6();
 | 
				
			||||||
 | 
							test_in46a_equal_v6();
 | 
				
			||||||
 | 
							test_in46a_to_eua_v6();
 | 
				
			||||||
 | 
							test_in46a_from_eua_v6();
 | 
				
			||||||
 | 
							test_in46a_to_eua_v4v6();
 | 
				
			||||||
 | 
							test_in46a_from_eua_v4v6();
 | 
				
			||||||
 | 
							test_in46a_netmasklen_v6();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,17 @@
 | 
				
			|||||||
Testing in46a_to_af()
 | 
					Testing in46a_to_af() with IPv4 addresses
 | 
				
			||||||
Testing in46a_to_sas()
 | 
					Testing in46a_to_sas() with IPv4 addresses
 | 
				
			||||||
Testing in46a_ntop()
 | 
					Testing in46a_ntop() with IPv4 addresses
 | 
				
			||||||
res = UNDEFINED
 | 
					res = UNDEFINED
 | 
				
			||||||
res = UNDEFINED
 | 
					res = UNDEFINED
 | 
				
			||||||
res = 1.2.3.4
 | 
					res = 1.2.3.4
 | 
				
			||||||
res = 102:304:506:708:90a:b0c:d0e:f10
 | 
					 | 
				
			||||||
in46p_ntoa() returns 16.32.48.0/24
 | 
					in46p_ntoa() returns 16.32.48.0/24
 | 
				
			||||||
Testing in46a_equal()
 | 
					Testing in46a_equal() with IPv4 addresses
 | 
				
			||||||
Testing in46a_within_mask()
 | 
					Testing in46a_within_mask() with IPv4 addresses
 | 
				
			||||||
in46a_within_mask(10.11.12.13, 10.11.12.13, 32) = 1
 | 
					in46a_within_mask(10.11.12.13, 10.11.12.13, 32) = 1
 | 
				
			||||||
in46a_within_mask(10.11.12.13, 10.11.12.12, 30) = 1
 | 
					in46a_within_mask(10.11.12.13, 10.11.12.12, 30) = 1
 | 
				
			||||||
in46a_within_mask(10.11.12.13, 10.8.0.0, 13) = 1
 | 
					in46a_within_mask(10.11.12.13, 10.8.0.0, 13) = 1
 | 
				
			||||||
in46a_within_mask(10.11.12.14, 10.11.12.13, 32) = 0
 | 
					in46a_within_mask(10.11.12.14, 10.11.12.13, 32) = 0
 | 
				
			||||||
in46a_within_mask(10.11.12.14, 10.11.12.12, 30) = 1
 | 
					in46a_within_mask(10.11.12.14, 10.11.12.12, 30) = 1
 | 
				
			||||||
testing in46a_to_eua()
 | 
					testing in46a_to_eua() with IPv4 addresses
 | 
				
			||||||
Testing in46a_from_eua()
 | 
					Testing in46a_from_eua() with IPv4 addresses
 | 
				
			||||||
Testing in46a_netmasklen() with IPv4 addresses
 | 
					Testing in46a_netmasklen() with IPv4 addresses
 | 
				
			||||||
Testing in46a_netmasklen() with IPv6 addresses
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								tests/lib/in46a_v6_test.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/lib/in46a_v6_test.ok
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					Testing in46a_to_af() with IPv6 addresses
 | 
				
			||||||
 | 
					Testing in46a_to_sas() with IPv6 addresses
 | 
				
			||||||
 | 
					Testing in46a_ntop() with IPv6 addresses
 | 
				
			||||||
 | 
					res = 102:304:506:708:90a:b0c:d0e:f10
 | 
				
			||||||
 | 
					Testing in46a_equal() with IPv6 addresses
 | 
				
			||||||
 | 
					Testing in46a_to_eua() with IPv6 addresses
 | 
				
			||||||
 | 
					Testing in46a_from_eua() with IPv6 addresses
 | 
				
			||||||
 | 
					Testing in46a_to_eua() with IPv4v6 addresses
 | 
				
			||||||
 | 
					Testing in46a_from_eua() with IPv4v6 addresses
 | 
				
			||||||
 | 
					Testing in46a_netmasklen() with IPv6 addresses
 | 
				
			||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../lib/in46_addr.h"
 | 
					#include "../../lib/in46_addr.h"
 | 
				
			||||||
#include "../../lib/ippool.h"
 | 
					#include "../../lib/ippool.h"
 | 
				
			||||||
@@ -113,22 +114,33 @@ static void test_pool_sizes(void)
 | 
				
			|||||||
	/* 65534 addresses [0.1..255.254] */
 | 
						/* 65534 addresses [0.1..255.254] */
 | 
				
			||||||
	test_pool_size("192.168.0.0/16", IPPOOL_NONETWORK | IPPOOL_NOBROADCAST, NULL, 0, 65534);
 | 
						test_pool_size("192.168.0.0/16", IPPOOL_NONETWORK | IPPOOL_NOBROADCAST, NULL, 0, 65534);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 256 prefixes of /64 each */
 | 
					 | 
				
			||||||
	test_pool_size("2001:DB8::/56", 0, NULL, 0, 256);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* 253 addresses [1..254] & exclude 192.168.23.1/24 */
 | 
						/* 253 addresses [1..254] & exclude 192.168.23.1/24 */
 | 
				
			||||||
	char *blacklist[] = {"176.16.222.10/24", "192.168.23.1/24", "192.168.38.2/24"};
 | 
						char *blacklist[] = {"176.16.222.10/24", "192.168.23.1/24", "192.168.38.2/24"};
 | 
				
			||||||
	test_pool_size("192.168.23.0/24", IPPOOL_NONETWORK | IPPOOL_NOBROADCAST, blacklist, 3, 253);
 | 
						test_pool_size("192.168.23.0/24", IPPOOL_NONETWORK | IPPOOL_NOBROADCAST, blacklist, 3, 253);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_pool_sizes_v6(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* 256 prefixes of /64 each */
 | 
				
			||||||
 | 
						test_pool_size("2001:DB8::/56", 0, NULL, 0, 256);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_init_logging(&log_info);
 | 
						void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(tall_ctx, &log_info);
 | 
				
			||||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
						log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
						log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
				
			||||||
 | 
						log_set_print_category(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
						log_set_print_category_hex(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srand(time(NULL));
 | 
						srand(time(NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test_pool_sizes();
 | 
						if (argc < 2 || strcmp(argv[1], "-v6")) {
 | 
				
			||||||
 | 
							test_pool_sizes();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							test_pool_sizes_v6();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,5 +8,3 @@ No more IP addresses available
 | 
				
			|||||||
No more IP addresses available
 | 
					No more IP addresses available
 | 
				
			||||||
No more IP addresses available
 | 
					No more IP addresses available
 | 
				
			||||||
No more IP addresses available
 | 
					No more IP addresses available
 | 
				
			||||||
No more IP addresses available
 | 
					 | 
				
			||||||
No more IP addresses available
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66301,263 +66301,6 @@ allocated address 192.168.255.251
 | 
				
			|||||||
allocated address 192.168.255.252
 | 
					allocated address 192.168.255.252
 | 
				
			||||||
allocated address 192.168.255.253
 | 
					allocated address 192.168.255.253
 | 
				
			||||||
allocated address 192.168.255.254
 | 
					allocated address 192.168.255.254
 | 
				
			||||||
testing pool for prefix 2001:DB8::/56, flags=0x0, blacklist_size=0, expected_size=256
 | 
					 | 
				
			||||||
allocated address 2001:db8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:10::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:11::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:12::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:13::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:14::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:15::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:16::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:17::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:18::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:19::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:1f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:20::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:21::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:22::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:23::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:24::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:25::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:26::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:27::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:28::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:29::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:2f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:30::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:31::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:32::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:33::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:34::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:35::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:36::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:37::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:38::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:39::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:3f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:40::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:41::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:42::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:43::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:44::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:45::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:46::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:47::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:48::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:49::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:4f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:50::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:51::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:52::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:53::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:54::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:55::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:56::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:57::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:58::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:59::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:5f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:60::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:61::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:62::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:63::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:64::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:65::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:66::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:67::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:68::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:69::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:6f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:70::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:71::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:72::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:73::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:74::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:75::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:76::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:77::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:78::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:79::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:7f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:80::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:81::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:82::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:83::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:84::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:85::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:86::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:87::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:88::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:89::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:8f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:90::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:91::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:92::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:93::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:94::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:95::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:96::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:97::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:98::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:99::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9a::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9b::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9c::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9d::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9e::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:9f::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:a9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:aa::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ab::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ac::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ad::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ae::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:af::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:b9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ba::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:bb::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:bc::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:bd::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:be::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:bf::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:c9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ca::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:cb::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:cc::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:cd::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ce::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:cf::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:d9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:da::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:db::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:dc::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:dd::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:de::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:df::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:e9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ea::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:eb::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ec::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ed::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ee::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ef::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f0::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f1::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f2::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f3::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f4::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f5::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f6::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f7::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f8::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:f9::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:fa::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:fb::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:fc::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:fd::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:fe::
 | 
					 | 
				
			||||||
allocated address 2001:db8:0:ff::
 | 
					 | 
				
			||||||
testing pool for prefix 192.168.23.0/24, flags=0x3, blacklist_size=3, expected_size=253
 | 
					testing pool for prefix 192.168.23.0/24, flags=0x3, blacklist_size=3, expected_size=253
 | 
				
			||||||
allocated address 192.168.23.2
 | 
					allocated address 192.168.23.2
 | 
				
			||||||
allocated address 192.168.23.3
 | 
					allocated address 192.168.23.3
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								tests/lib/ippool_v6_test.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/lib/ippool_v6_test.err
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					No more IP addresses available
 | 
				
			||||||
 | 
					No more IP addresses available
 | 
				
			||||||
							
								
								
									
										257
									
								
								tests/lib/ippool_v6_test.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								tests/lib/ippool_v6_test.ok
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
				
			|||||||
 | 
					testing pool for prefix 2001:DB8::/56, flags=0x0, blacklist_size=0, expected_size=256
 | 
				
			||||||
 | 
					allocated address 2001:db8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:10::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:11::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:12::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:13::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:14::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:15::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:16::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:17::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:18::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:19::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:1f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:20::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:21::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:22::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:23::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:24::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:25::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:26::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:27::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:28::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:29::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:2f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:30::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:31::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:32::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:33::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:34::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:35::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:36::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:37::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:38::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:39::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:3f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:40::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:41::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:42::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:43::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:44::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:45::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:46::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:47::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:48::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:49::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:4f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:50::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:51::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:52::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:53::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:54::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:55::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:56::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:57::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:58::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:59::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:5f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:60::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:61::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:62::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:63::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:64::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:65::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:66::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:67::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:68::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:69::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:6f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:70::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:71::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:72::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:73::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:74::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:75::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:76::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:77::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:78::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:79::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:7f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:80::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:81::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:82::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:83::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:84::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:85::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:86::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:87::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:88::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:89::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:8f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:90::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:91::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:92::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:93::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:94::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:95::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:96::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:97::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:98::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:99::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9a::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9b::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9c::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9d::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9e::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:9f::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:a9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:aa::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ab::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ac::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ad::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ae::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:af::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:b9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ba::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:bb::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:bc::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:bd::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:be::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:bf::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:c9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ca::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:cb::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:cc::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:cd::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ce::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:cf::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:d9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:da::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:db::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:dc::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:dd::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:de::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:df::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:e9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ea::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:eb::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ec::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ed::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ee::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ef::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f0::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f1::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f2::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f3::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f4::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f5::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f6::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f7::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f8::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:f9::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:fa::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:fb::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:fc::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:fd::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:fe::
 | 
				
			||||||
 | 
					allocated address 2001:db8:0:ff::
 | 
				
			||||||
@@ -8,14 +8,33 @@ cat $abs_srcdir/lib/ippool_test.err > experr
 | 
				
			|||||||
AT_CHECK([$abs_top_builddir/tests/lib/ippool_test], [], [expout], [experr])
 | 
					AT_CHECK([$abs_top_builddir/tests/lib/ippool_test], [], [expout], [experr])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AT_SETUP([ippool_v6])
 | 
				
			||||||
 | 
					AT_KEYWORDS([ippool_v6])
 | 
				
			||||||
 | 
					cat $abs_srcdir/lib/ippool_v6_test.ok > expout
 | 
				
			||||||
 | 
					cat $abs_srcdir/lib/ippool_v6_test.err > experr
 | 
				
			||||||
 | 
					AT_CHECK([$abs_top_builddir/tests/lib/ippool_test -v6], [], [expout], [experr])
 | 
				
			||||||
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AT_SETUP([in46a])
 | 
					AT_SETUP([in46a])
 | 
				
			||||||
AT_KEYWORDS([in46a])
 | 
					AT_KEYWORDS([in46a])
 | 
				
			||||||
cat $abs_srcdir/lib/in46a_test.ok > expout
 | 
					cat $abs_srcdir/lib/in46a_test.ok > expout
 | 
				
			||||||
AT_CHECK([$abs_top_builddir/tests/lib/in46a_test], [], [expout], [])
 | 
					AT_CHECK([$abs_top_builddir/tests/lib/in46a_test], [], [expout], [])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AT_SETUP([in46a_v6])
 | 
				
			||||||
 | 
					AT_KEYWORDS([in46a_v6])
 | 
				
			||||||
 | 
					cat $abs_srcdir/lib/in46a_v6_test.ok > expout
 | 
				
			||||||
 | 
					AT_CHECK([$abs_top_builddir/tests/lib/in46a_test -v6], [], [expout], [])
 | 
				
			||||||
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AT_SETUP([gtpie])
 | 
					AT_SETUP([gtpie])
 | 
				
			||||||
AT_KEYWORDS([gtpie])
 | 
					AT_KEYWORDS([gtpie])
 | 
				
			||||||
cat $abs_srcdir/gtp/gtpie_test.ok > expout
 | 
					cat $abs_srcdir/gtp/gtpie_test.ok > expout
 | 
				
			||||||
AT_CHECK([$abs_top_builddir/tests/gtp/gtpie_test], [], [expout], [])
 | 
					AT_CHECK([$abs_top_builddir/tests/gtp/gtpie_test], [], [expout], [])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AT_SETUP([queue])
 | 
				
			||||||
 | 
					AT_KEYWORDS([queue])
 | 
				
			||||||
 | 
					cat $abs_srcdir/gtp/queue_test.ok > expout
 | 
				
			||||||
 | 
					AT_CHECK([$abs_top_builddir/tests/gtp/queue_test], [], [expout], [])
 | 
				
			||||||
 | 
					AT_CLEANUP
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								utils/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								utils/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					bin_PROGRAMS = gtp-echo-responder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gtp_echo_responder_SOURCES = gtp_echo_responder.c
 | 
				
			||||||
							
								
								
									
										470
									
								
								utils/gtp_echo_responder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										470
									
								
								utils/gtp_echo_responder.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,470 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MIT License
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					 * of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					 * in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					 * copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					 * furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					 * paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					 * Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					 * SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For more info see:
 | 
				
			||||||
 | 
					 * 3GPP TS 29.060 (GTPv1 and GTPv0)
 | 
				
			||||||
 | 
					 * 3GPP TS 29.274 (GTPv2C)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <sys/select.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GTP1C_PORT	2123
 | 
				
			||||||
 | 
					#define GTP_MSGTYPE_ECHO_REQ	1
 | 
				
			||||||
 | 
					#define GTP_MSGTYPE_ECHO_RSP	2
 | 
				
			||||||
 | 
					#define GTP1C_IE_RECOVERY 14
 | 
				
			||||||
 | 
					#define GTP2C_IE_RECOVERY 3
 | 
				
			||||||
 | 
					#define GTP2C_IE_NODE_FEATURES 152
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gtp1_hdr {
 | 
				
			||||||
 | 
					#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
				
			||||||
 | 
						uint8_t pn:1, s:1, e:1, spare:1, pt:1, version:3;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						uint8_t version:3, pt:1, spare:1, e:1, s:1, pn:1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						uint8_t type;
 | 
				
			||||||
 | 
						uint16_t length;
 | 
				
			||||||
 | 
						uint32_t tei;
 | 
				
			||||||
 | 
						uint16_t seq;
 | 
				
			||||||
 | 
						uint8_t npdu;
 | 
				
			||||||
 | 
						uint8_t next;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gtp2_hdr {
 | 
				
			||||||
 | 
					#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
				
			||||||
 | 
						uint8_t reserved:3, t:1, p:1, version:3;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						uint8_t version:3, p:1, t:1, reserved:1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						uint8_t type;
 | 
				
			||||||
 | 
						uint16_t length;
 | 
				
			||||||
 | 
					#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
				
			||||||
 | 
						uint32_t reserved2:8, seq:24;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						uint8_t seq:24, reserved2:1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gtp_echo_resp_state {
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							char laddr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
							uint8_t recovery_ctr;
 | 
				
			||||||
 | 
							uint8_t node_features;
 | 
				
			||||||
 | 
						} cfg;
 | 
				
			||||||
 | 
						struct sockaddr_storage laddr_gtpc;
 | 
				
			||||||
 | 
						int fd_gtpc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gtp_echo_resp_state *g_st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_usage(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("Usage: gtp-echo-responder [-h] [-V] [-l listen_addr]\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_help(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("  Some useful help...\n"
 | 
				
			||||||
 | 
						       "  -h --help		This help text\n"
 | 
				
			||||||
 | 
						       "  -V --version		Print the version of gtp-echo-responder\n"
 | 
				
			||||||
 | 
						       "  -l --listen-addr	Listend address for GTPCv1 and GTPCv2\n"
 | 
				
			||||||
 | 
						       "  -R --recovery-counter GTP Recovery Counter to transmit in GTP Echo Response message\n"
 | 
				
			||||||
 | 
						       "  -n --node-features	GTPCv2 Node Features bitmask to transmit in GTP Echo Response message\n"
 | 
				
			||||||
 | 
						       );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_version(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("gtp-echo-responder version %s\n", PACKAGE_VERSION);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t parse_node_features_mask(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long res;
 | 
				
			||||||
 | 
						char *end;
 | 
				
			||||||
 | 
						errno = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = strtoul(arg, &end, 0);
 | 
				
			||||||
 | 
						if ((errno == ERANGE && res == ULONG_MAX) || (errno && !res) ||
 | 
				
			||||||
 | 
						    arg == end || *end != '\0') {
 | 
				
			||||||
 | 
							fprintf(stderr, "Failed parsing Node Features bitmask: '%s'\n", arg);
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (res > 0xff) {
 | 
				
			||||||
 | 
							fprintf(stderr, "Failed parsing Node Features bitmask: '%s' > 0xFF\n", arg);
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return (uint8_t)res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void handle_options(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							int option_index = 0, c;
 | 
				
			||||||
 | 
							static struct option long_options[] = {
 | 
				
			||||||
 | 
								{ "help", 0, 0, 'h' },
 | 
				
			||||||
 | 
								{ "version", 0, 0, 'V' },
 | 
				
			||||||
 | 
								{ "listen-addr", 1, 0, 'l'},
 | 
				
			||||||
 | 
								{ "recovery-counter", 1, 0, 'R'},
 | 
				
			||||||
 | 
								{ "node-features", 1, 0, 'N'},
 | 
				
			||||||
 | 
								{ 0, 0, 0, 0 }
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c = getopt_long(argc, argv, "hVl:R:N:", long_options, &option_index);
 | 
				
			||||||
 | 
							if (c == -1)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 'h':
 | 
				
			||||||
 | 
								print_usage();
 | 
				
			||||||
 | 
								print_help();
 | 
				
			||||||
 | 
								exit(0);
 | 
				
			||||||
 | 
							case 'V':
 | 
				
			||||||
 | 
								print_version();
 | 
				
			||||||
 | 
								exit(0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'l':
 | 
				
			||||||
 | 
								strncpy(&g_st->cfg.laddr[0], optarg, sizeof(g_st->cfg.laddr));
 | 
				
			||||||
 | 
								g_st->cfg.laddr[sizeof(g_st->cfg.laddr) - 1] = '\0';
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'R':
 | 
				
			||||||
 | 
								g_st->cfg.recovery_ctr = (uint8_t)atoi(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'N':
 | 
				
			||||||
 | 
								g_st->cfg.node_features = parse_node_features_mask(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int init_socket(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in_addr addr;
 | 
				
			||||||
 | 
						struct in6_addr addr6;
 | 
				
			||||||
 | 
						struct sockaddr_in *saddr;
 | 
				
			||||||
 | 
						struct sockaddr_in6 *saddr6;
 | 
				
			||||||
 | 
						int family;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (inet_pton(AF_INET6, g_st->cfg.laddr, &addr6) == 1) {
 | 
				
			||||||
 | 
							family = AF_INET6;
 | 
				
			||||||
 | 
							saddr6 = (struct sockaddr_in6 *)&g_st->laddr_gtpc;
 | 
				
			||||||
 | 
							saddr6->sin6_family = family;
 | 
				
			||||||
 | 
							saddr6->sin6_port = htons(GTP1C_PORT);
 | 
				
			||||||
 | 
							memcpy(&saddr6->sin6_addr, &addr6, sizeof(addr6));
 | 
				
			||||||
 | 
						} else if (inet_pton(AF_INET, g_st->cfg.laddr, &addr) == 1) {
 | 
				
			||||||
 | 
							family = AF_INET;
 | 
				
			||||||
 | 
							saddr = (struct sockaddr_in *)&g_st->laddr_gtpc;
 | 
				
			||||||
 | 
							saddr->sin_family = family;
 | 
				
			||||||
 | 
							saddr->sin_port = htons(GTP1C_PORT);
 | 
				
			||||||
 | 
							memcpy(&saddr->sin_addr, &addr, sizeof(addr));
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							fprintf(stderr, "Failed parsing address %s\n", g_st->cfg.laddr);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((g_st->fd_gtpc = socket(family, SOCK_DGRAM, 0)) < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "socket() failed: %s\n", strerror(errno));
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bind(g_st->fd_gtpc, (struct sockaddr *)&g_st->laddr_gtpc, sizeof(g_st->laddr_gtpc)) < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "bind() failed: %s\n", strerror(errno));
 | 
				
			||||||
 | 
							return -3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *sockaddr2str(const struct sockaddr *saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char _rem_addr_str[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct sockaddr_in *saddr4;
 | 
				
			||||||
 | 
						struct sockaddr_in6 *saddr6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (saddr->sa_family) {
 | 
				
			||||||
 | 
						case AF_INET6:
 | 
				
			||||||
 | 
							saddr6 = (struct sockaddr_in6 *)saddr;
 | 
				
			||||||
 | 
							if (!inet_ntop(saddr6->sin6_family, &saddr6->sin6_addr, _rem_addr_str, sizeof(_rem_addr_str)))
 | 
				
			||||||
 | 
								strcpy(_rem_addr_str, "unknown");
 | 
				
			||||||
 | 
							return _rem_addr_str;
 | 
				
			||||||
 | 
						case AF_INET:
 | 
				
			||||||
 | 
							saddr4 = (struct sockaddr_in *)saddr;
 | 
				
			||||||
 | 
							if (!inet_ntop(saddr4->sin_family, &saddr4->sin_addr, _rem_addr_str, sizeof(_rem_addr_str)))
 | 
				
			||||||
 | 
								strcpy(_rem_addr_str, "unknown");
 | 
				
			||||||
 | 
							return _rem_addr_str;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							strcpy(_rem_addr_str, "unknown-family");
 | 
				
			||||||
 | 
							return _rem_addr_str;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int write_cb(int fd, const uint8_t *buf, size_t buf_len, const struct sockaddr *rem_saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ssize_t rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = sendto(fd, buf, buf_len, 0, rem_saddr, sizeof(struct sockaddr_storage));
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "sendto() failed: %s\n", strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rc != buf_len) {
 | 
				
			||||||
 | 
							fprintf(stderr, "sendto() short write: %zd vs exp %zu\n", rc, buf_len);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gen_gtpc1_echo_rsp(uint8_t *buf, struct gtp1_hdr *echo_req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int offset = 0;
 | 
				
			||||||
 | 
						struct gtp1_hdr *echo_rsp = (struct gtp1_hdr *)buf;
 | 
				
			||||||
 | 
						unsigned exp_hdr_len = (echo_req->s || echo_req->pn || echo_req->e) ? 12 : 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(echo_rsp, echo_req, exp_hdr_len);
 | 
				
			||||||
 | 
						echo_rsp->type = GTP_MSGTYPE_ECHO_RSP;
 | 
				
			||||||
 | 
						offset = exp_hdr_len;
 | 
				
			||||||
 | 
						buf[offset++] = GTP1C_IE_RECOVERY;
 | 
				
			||||||
 | 
						buf[offset++] = g_st->cfg.recovery_ctr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update Length */
 | 
				
			||||||
 | 
						echo_rsp->length = htons(offset - 8);
 | 
				
			||||||
 | 
						return offset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gen_gtpc2_echo_rsp(uint8_t *buf, struct gtp2_hdr *echo_req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int offset = 0;
 | 
				
			||||||
 | 
						struct gtp1_hdr *echo_rsp = (struct gtp1_hdr *)buf;
 | 
				
			||||||
 | 
						unsigned exp_hdr_len = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(echo_rsp, echo_req, exp_hdr_len);
 | 
				
			||||||
 | 
						echo_rsp->type = GTP_MSGTYPE_ECHO_RSP;
 | 
				
			||||||
 | 
						offset = exp_hdr_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 3GPP TS 29.274 sec 8.5 Recovery (Restart Counter) */
 | 
				
			||||||
 | 
						buf[offset++] = GTP2C_IE_RECOVERY;
 | 
				
			||||||
 | 
						buf[offset++] = 0; /* IE Length (high) */
 | 
				
			||||||
 | 
						buf[offset++] = 1; /* IE Length (low) */
 | 
				
			||||||
 | 
						buf[offset++] = 0; /* Spare=0 | Instance=0 (Table 7.1.1-1) */
 | 
				
			||||||
 | 
						buf[offset++] = g_st->cfg.recovery_ctr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 3GPP TS 29.274 sec 8.83 Node Features */
 | 
				
			||||||
 | 
						if (g_st->cfg.node_features > 0) {
 | 
				
			||||||
 | 
							buf[offset++] = GTP2C_IE_NODE_FEATURES;
 | 
				
			||||||
 | 
							buf[offset++] = 0; /* IE Length (high) */
 | 
				
			||||||
 | 
							buf[offset++] = 1; /* IE Length (low) */
 | 
				
			||||||
 | 
							buf[offset++] = 0; /* Spare=0 | Instance=0 (Table 7.1.1-1) */
 | 
				
			||||||
 | 
							buf[offset++] = g_st->cfg.node_features;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update Length */
 | 
				
			||||||
 | 
						echo_rsp->length = htons(offset - 4);
 | 
				
			||||||
 | 
						return offset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_gtpc1_echo_req(struct gtp1_hdr *echo_req, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						const size_t tx_buf_len = buf_len + 128; /* Leave some extra room */
 | 
				
			||||||
 | 
						uint8_t *tx_buf = alloca(tx_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Rx GTPCv1_ECHO_REQ from %s, Tx GTPCv1_ECHO_RSP\n", sockaddr2str(rem_saddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(tx_buf, 0, tx_buf_len);
 | 
				
			||||||
 | 
						rc = gen_gtpc1_echo_rsp(tx_buf, echo_req);
 | 
				
			||||||
 | 
						return write_cb(g_st->fd_gtpc, tx_buf, rc, rem_saddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_gtpc1(struct gtp1_hdr *hdr, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned exp_hdr_len = (hdr->s || hdr->pn || hdr->e) ? 12 : 8;
 | 
				
			||||||
 | 
						unsigned pdu_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buf_len < exp_hdr_len) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv1 packet size smaller than header! %u < exp %u\n", buf_len, exp_hdr_len);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdu_len = ntohs(hdr->length);
 | 
				
			||||||
 | 
						if (buf_len < 8 + pdu_len) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv1 packet size smaller than announced! %u < exp %u\n", buf_len, 8 + pdu_len);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hdr->pt != 1) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv1 Protocol Type GTP' not supported!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (hdr->type) {
 | 
				
			||||||
 | 
						case GTP_MSGTYPE_ECHO_REQ:
 | 
				
			||||||
 | 
							return rx_gtpc1_echo_req(hdr, buf_len, rem_saddr);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "Silently ignoring unexpected packet of type %u\n", hdr->type);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_gtpc2_echo_req(struct gtp2_hdr *echo_req, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						const size_t tx_buf_len = buf_len + 128; /* Leave some extra room */
 | 
				
			||||||
 | 
						uint8_t *tx_buf = alloca(tx_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (echo_req->t) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv2 ECHO message should contain T=0!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Rx GTPCv2_ECHO_REQ from %s, Tx GTPCv2_ECHO_RSP\n", sockaddr2str(rem_saddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(tx_buf, 0, tx_buf_len);
 | 
				
			||||||
 | 
						rc = gen_gtpc2_echo_rsp(tx_buf, echo_req);
 | 
				
			||||||
 | 
						return write_cb(g_st->fd_gtpc, tx_buf, rc, rem_saddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_gtpc2(struct gtp2_hdr *hdr, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned exp_hdr_len = hdr->t ? 12 : 8;
 | 
				
			||||||
 | 
						unsigned pdu_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hdr->p) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv2 piggybacked message not supported!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buf_len < exp_hdr_len) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv2 packet size smaller than header! %u < exp %u\n", buf_len, exp_hdr_len);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdu_len = ntohs(hdr->length);
 | 
				
			||||||
 | 
						/* 3GPP TS 29.274 sec 5.5.1: "Octets 3 to 4 represent the Message Length
 | 
				
			||||||
 | 
						 * field. This field shall indicate the length of the message in octets
 | 
				
			||||||
 | 
						 * excluding the mandatory part of the GTP-C header (the first 4
 | 
				
			||||||
 | 
						 * octets). The TEID (if present) and the Sequence  Number shall be
 | 
				
			||||||
 | 
						 * included in the length count" */
 | 
				
			||||||
 | 
						if (buf_len < 4 + pdu_len) {
 | 
				
			||||||
 | 
							fprintf(stderr, "GTPCv2 packet size smaller than announced! %u < exp %u\n", buf_len, 4 + pdu_len);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (hdr->type) {
 | 
				
			||||||
 | 
						case GTP_MSGTYPE_ECHO_REQ:
 | 
				
			||||||
 | 
							return rx_gtpc2_echo_req(hdr, buf_len, rem_saddr);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "Silently ignoring unexpected packet of type %u\n", hdr->type);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int read_cb(int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ssize_t sz;
 | 
				
			||||||
 | 
						uint8_t buf[4096];
 | 
				
			||||||
 | 
						struct sockaddr_storage rem_saddr;
 | 
				
			||||||
 | 
						socklen_t rem_saddr_len = sizeof(rem_saddr);
 | 
				
			||||||
 | 
						struct gtp1_hdr *hdr1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((sz = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&rem_saddr, &rem_saddr_len)) < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "recvfrom() failed: %s\n", strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (sz == 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "recvfrom() read zero bytes!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr1 = (struct gtp1_hdr *)&buf[0];
 | 
				
			||||||
 | 
						switch (hdr1->version) {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return rx_gtpc1(hdr1, sz, (const struct sockaddr *)&rem_saddr);
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							return rx_gtpc2((struct gtp2_hdr *)&buf[0], sz, (const struct sockaddr *)&rem_saddr);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "Rx GTPv%u: not supported (flags=0x%x)\n", hdr1->version, buf[0]);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int loop(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						fd_set rfds;
 | 
				
			||||||
 | 
						int nfds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							FD_ZERO(&rfds);
 | 
				
			||||||
 | 
							FD_SET(g_st->fd_gtpc, &rfds);
 | 
				
			||||||
 | 
							nfds = g_st->fd_gtpc + 1;
 | 
				
			||||||
 | 
							rc = select(nfds, &rfds, NULL, NULL, NULL);
 | 
				
			||||||
 | 
							if (rc == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								fprintf(stderr, "select() failed: %s\n", strerror(errno));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (FD_ISSET(g_st->fd_gtpc, &rfds))
 | 
				
			||||||
 | 
								read_cb(g_st->fd_gtpc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_st = calloc(1, sizeof(struct gtp_echo_resp_state));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strcpy(g_st->cfg.laddr, "::");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handle_options(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Listening on: %s\n", g_st->cfg.laddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (init_socket() < 0)
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Socket bound successfully, listening for requests...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (loop() < 0)
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										111
									
								
								utils/gtp_echo_responder_test.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										111
									
								
								utils/gtp_echo_responder_test.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					# MIT License
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					# Author: Pau Espin Pedrol <pespin@sysmocom.de>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					# of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					# in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					# copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					# furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					# paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					# Software.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					# SOFTWARE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import struct
 | 
				
			||||||
 | 
					from ipaddress import ip_address, IPv4Address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GTP1C_PORT = 2123
 | 
				
			||||||
 | 
					BUF_SIZE = 4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GTP_HDRv1_FLAG_PN = (1<<0)
 | 
				
			||||||
 | 
					GTP_HDRv1_FLAG_S = (1<<1)
 | 
				
			||||||
 | 
					GTP_HDRv1_FLAG_E = (1<<2)
 | 
				
			||||||
 | 
					GTP_HDRv1_PT_GTP = (1<<4)
 | 
				
			||||||
 | 
					GTP_HDRv1_VER_GTP1 = (1<<5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GTP_HDRv2_FLAG_T = (1<<3)
 | 
				
			||||||
 | 
					GTP_HDRv2_FLAG_P = (1<<4)
 | 
				
			||||||
 | 
					GTP_HDRv2_VER_GTP2 = (2<<5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def gen_gtpc_v1_hdr(flags, type, length, tei, seq=0, npdu=0, next=0):
 | 
				
			||||||
 | 
					    spare = 0
 | 
				
			||||||
 | 
					    if (flags & (GTP_HDRv1_FLAG_PN|GTP_HDRv1_FLAG_S|GTP_HDRv1_FLAG_E)):
 | 
				
			||||||
 | 
					        #long format
 | 
				
			||||||
 | 
					        length += 4
 | 
				
			||||||
 | 
					        d = struct.pack('!BBHIHBB', flags, type, length, tei, seq, npdu, next)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        #short format
 | 
				
			||||||
 | 
					        d = struct.pack('!BBHI', flags, type, length, tei)
 | 
				
			||||||
 | 
					    return d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def gen_gtpc_v2_hdr(flags, type, length, tei=0, seq=0):
 | 
				
			||||||
 | 
					    spare = 0
 | 
				
			||||||
 | 
					    if (flags & (GTP_HDRv2_FLAG_T)):
 | 
				
			||||||
 | 
					        #long format, with TEI
 | 
				
			||||||
 | 
					        length += 4 + 4
 | 
				
			||||||
 | 
					        d = struct.pack('!BBHIHBB', flags, type, length, tei, seq >> 8, seq & 0xff, spare)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        #short format
 | 
				
			||||||
 | 
					        length += 4
 | 
				
			||||||
 | 
					        d = struct.pack('!BBHHBB', flags, type, length, seq >> 8, seq & 0xff, spare)
 | 
				
			||||||
 | 
					    return d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def gen_gtpc_v1_echo_req(tei=0, append_flags=0, seq=0, npdu=0, next=0):
 | 
				
			||||||
 | 
					    return gen_gtpc_v1_hdr(GTP_HDRv1_VER_GTP1 | GTP_HDRv1_PT_GTP | append_flags, 1, 0, tei, seq, npdu, next)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def gen_gtpc_v2_echo_req(append_flags=0, seq=0, recovery=0, node_features=-1):
 | 
				
			||||||
 | 
					    length = 0
 | 
				
			||||||
 | 
					    payload = b''
 | 
				
			||||||
 | 
					    if (recovery > 0):
 | 
				
			||||||
 | 
					        recovery_ie = struct.pack('!BHBB', 3, 1, 0, recovery)
 | 
				
			||||||
 | 
					        payload += recovery_ie
 | 
				
			||||||
 | 
					        length += len(recovery_ie)
 | 
				
			||||||
 | 
					    if (node_features > 0):
 | 
				
			||||||
 | 
					        node_features_ie = struct.pack('!BHBB', 152, 1, 0, node_features)
 | 
				
			||||||
 | 
					        payload += node_features_ie
 | 
				
			||||||
 | 
					        length += len(node_features_ie)
 | 
				
			||||||
 | 
					    return gen_gtpc_v2_hdr(GTP_HDRv2_VER_GTP2 | append_flags, 1, length, 0, seq) + payload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def tx_rx(sk, rem_addr, tx_buf, exp_rx = True):
 | 
				
			||||||
 | 
					    print('Tx ECHO_REQ to %r: %r' % (repr(rem_addr), repr(tx_buf)))
 | 
				
			||||||
 | 
					    sk.sendto(tx_buf, rem_addr)
 | 
				
			||||||
 | 
					    if exp_rx:
 | 
				
			||||||
 | 
					        rx_buf = sk.recvfrom(BUF_SIZE)
 | 
				
			||||||
 | 
					        msg = "Message from Server {}".format(rx_buf)
 | 
				
			||||||
 | 
					        print(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    p = argparse.ArgumentParser(description='Tester for gtp-echo-recorder.')
 | 
				
			||||||
 | 
					    p.add_argument('-l', '--local-address', default='127.0.0.2', help="Local GTP address")
 | 
				
			||||||
 | 
					    p.add_argument('-r', '--remote-address', default='127.0.0.1', help="Remote GTP address")
 | 
				
			||||||
 | 
					    args = p.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print('Binding socket on %r...' % repr((args.local_address, GTP1C_PORT)))
 | 
				
			||||||
 | 
					    family = socket.AF_INET if type(ip_address(args.local_address)) is IPv4Address else socket.AF_INET6
 | 
				
			||||||
 | 
					    sk = socket.socket(family=family, type=socket.SOCK_DGRAM)
 | 
				
			||||||
 | 
					    sk.bind((args.local_address, GTP1C_PORT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rem_addr = (args.remote_address, GTP1C_PORT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req())
 | 
				
			||||||
 | 
					    tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req(1, GTP_HDRv1_FLAG_S, seq=67))
 | 
				
			||||||
 | 
					    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=300, recovery=-1, node_features=-1))
 | 
				
			||||||
 | 
					    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=20, recovery=99, node_features=-1))
 | 
				
			||||||
 | 
					    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=20, recovery=100, node_features=0xbb))
 | 
				
			||||||
		Reference in New Issue
	
	Block a user