mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
				synced 2025-11-03 21:53:25 +00:00 
			
		
		
		
	Compare commits
	
		
			77 Commits
		
	
	
		
			pespin/dis
			...
			daniel/onw
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					24d216c683 | ||
| 
						 | 
					8e97fccc34 | ||
| 
						 | 
					ee44b82b96 | ||
| 
						 | 
					b5f93346df | ||
| 
						 | 
					8e8c7ef3c7 | ||
| 
						 | 
					57238889eb | ||
| 
						 | 
					d70ab97fa4 | ||
| 
						 | 
					d1bd6fce9c | ||
| 
						 | 
					a32e4c4fb8 | ||
| 
						 | 
					3b84e92ab3 | ||
| 
						 | 
					835496d7dd | ||
| 
						 | 
					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 | 
@@ -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.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										30
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								configure.ac
									
									
									
									
									
								
							@@ -18,7 +18,6 @@ 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 check for pkg-config (explained in detail in libosmocore/configure.ac)
 | 
					dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
 | 
				
			||||||
@@ -66,7 +65,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"])
 | 
				
			||||||
@@ -136,9 +135,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 >= 0.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -152,6 +151,27 @@ 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,9 @@ 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]")
 | 
				
			||||||
@@ -35,7 +38,7 @@ set -x
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
cd "$base"
 | 
					cd "$base"
 | 
				
			||||||
autoreconf --install --force
 | 
					autoreconf --install --force
 | 
				
			||||||
./configure CFLAGS="-Werror" CPPFLAGS="-Werror" $GTP
 | 
					./configure --enable-sanitize --enable-werror $GTP
 | 
				
			||||||
$MAKE $PARALLEL_MAKE
 | 
					$MAKE $PARALLEL_MAKE
 | 
				
			||||||
$MAKE distcheck
 | 
					$MAKE distcheck
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										138
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										138
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,141 @@
 | 
				
			|||||||
 | 
					osmo-ggsn (1.2.2+ow2) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Release version for On-Waves
 | 
				
			||||||
 | 
					  * From commit ee44b82b967929eaf8867d967a22428972b58d0a 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Daniel Willmann <dwillmann@sysmocom.de>  Fri, 31 Aug 2018 18:02:47 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-ggsn (1.2.2+ow1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Release new version for On-Waves
 | 
				
			||||||
 | 
					  * commit b673d1c438488fb74abda344e563d733e5ce451a 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Daniel Willmann <dwillmann@sysmocom.de>  Fri, 31 Aug 2018 18:02:02 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -22,7 +22,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: libgtp3
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
@@ -41,7 +41,7 @@ Architecture: any
 | 
				
			|||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Depends: ${misc:Depends},
 | 
					Depends: ${misc:Depends},
 | 
				
			||||||
         libgtp2 (= ${binary:Version})
 | 
					         libgtp3 (= ${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,7 +54,7 @@ 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}, libgtp3 (= ${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
 | 
				
			||||||
@@ -65,7 +65,7 @@ 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}, libgtp3 (= ${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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -16,8 +16,4 @@ 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 -plibgtp3 --dbg-package=libgtp-dbg
 | 
				
			||||||
 | 
					 | 
				
			||||||
override_dh_autoreconf:
 | 
					 | 
				
			||||||
	echo $(VERSION) > .tarball-version
 | 
					 | 
				
			||||||
	dh_autoreconf
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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_vty.c ggsn.c ggsn.h icmpv6.c icmpv6.h checksum.c checksum.h
 | 
				
			||||||
 | 
					 | 
				
			||||||
if ENABLE_GTP_KERNEL
 | 
					 | 
				
			||||||
osmo_ggsn_SOURCES += gtp-kernel.c
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										487
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							
							
						
						
									
										487
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							@@ -56,15 +56,16 @@
 | 
				
			|||||||
#include <osmocom/vty/stats.h>
 | 
					#include <osmocom/vty/stats.h>
 | 
				
			||||||
#include <osmocom/vty/ports.h>
 | 
					#include <osmocom/vty/ports.h>
 | 
				
			||||||
#include <osmocom/vty/command.h>
 | 
					#include <osmocom/vty/command.h>
 | 
				
			||||||
 | 
					#include <osmocom/vty/misc.h>
 | 
				
			||||||
#include <osmocom/gsm/apn.h>
 | 
					#include <osmocom/gsm/apn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../lib/tun.h"
 | 
					#include "../lib/tun.h"
 | 
				
			||||||
#include "../lib/ippool.h"
 | 
					#include "../lib/ippool.h"
 | 
				
			||||||
#include "../lib/syserr.h"
 | 
					#include "../lib/syserr.h"
 | 
				
			||||||
#include "../lib/in46_addr.h"
 | 
					#include "../lib/in46_addr.h"
 | 
				
			||||||
 | 
					#include "../lib/gtp-kernel.h"
 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
#include "gtp-kernel.h"
 | 
					 | 
				
			||||||
#include "icmpv6.h"
 | 
					#include "icmpv6.h"
 | 
				
			||||||
#include "ggsn.h"
 | 
					#include "ggsn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,13 +125,14 @@ int apn_stop(struct apn_ctx *apn, bool force)
 | 
				
			|||||||
			LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
 | 
								LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
 | 
				
			||||||
			tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
 | 
								tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* release tun device */
 | 
							if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
 | 
				
			||||||
		LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
 | 
								/* release tun device */
 | 
				
			||||||
		osmo_fd_unregister(&apn->tun.fd);
 | 
								LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
 | 
				
			||||||
 | 
								osmo_fd_unregister(&apn->tun.fd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		tun_free(apn->tun.tun);
 | 
							tun_free(apn->tun.tun);
 | 
				
			||||||
		apn->tun.tun = NULL;
 | 
							apn->tun.tun = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gtp_kernel_stop(apn->tun.cfg.dev_name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (apn->v4.pool) {
 | 
						if (apn->v4.pool) {
 | 
				
			||||||
		LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
 | 
							LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
 | 
				
			||||||
@@ -194,6 +196,8 @@ int apn_start(struct apn_ctx *apn)
 | 
				
			|||||||
	struct in46_prefix ipv6_tun_linklocal_ip;
 | 
						struct in46_prefix ipv6_tun_linklocal_ip;
 | 
				
			||||||
	struct in46_prefix *blacklist;
 | 
						struct in46_prefix *blacklist;
 | 
				
			||||||
	int blacklist_size;
 | 
						int blacklist_size;
 | 
				
			||||||
 | 
						struct gsn_t *gsn = apn->ggsn->gsn;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (apn->started)
 | 
						if (apn->started)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -202,7 +206,7 @@ int apn_start(struct apn_ctx *apn)
 | 
				
			|||||||
	switch (apn->cfg.gtpu_mode) {
 | 
						switch (apn->cfg.gtpu_mode) {
 | 
				
			||||||
	case APN_GTPU_MODE_TUN:
 | 
						case APN_GTPU_MODE_TUN:
 | 
				
			||||||
		LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
 | 
							LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
 | 
				
			||||||
		if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name)) {
 | 
							if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) {
 | 
				
			||||||
			LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
 | 
								LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -214,50 +218,6 @@ int apn_start(struct apn_ctx *apn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* Set TUN library callback */
 | 
							/* Set TUN library callback */
 | 
				
			||||||
		tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
 | 
							tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (apn->v4.cfg.ifconfig_prefix.addr.len) {
 | 
					 | 
				
			||||||
			LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
 | 
					 | 
				
			||||||
				in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
 | 
					 | 
				
			||||||
			if (tun_setaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
 | 
					 | 
				
			||||||
					apn->v4.cfg.ifconfig_prefix.prefixlen)) {
 | 
					 | 
				
			||||||
				LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
 | 
					 | 
				
			||||||
					in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
 | 
					 | 
				
			||||||
				apn_stop(apn, false);
 | 
					 | 
				
			||||||
				return -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (apn->v6.cfg.ifconfig_prefix.addr.len) {
 | 
					 | 
				
			||||||
			LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
 | 
					 | 
				
			||||||
				in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
 | 
					 | 
				
			||||||
			if (tun_setaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
 | 
					 | 
				
			||||||
					apn->v6.cfg.ifconfig_prefix.prefixlen)) {
 | 
					 | 
				
			||||||
				LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
 | 
					 | 
				
			||||||
					"Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
 | 
					 | 
				
			||||||
					in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
 | 
					 | 
				
			||||||
				apn_stop(apn, false);
 | 
					 | 
				
			||||||
				return -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (apn->tun.cfg.ipup_script) {
 | 
					 | 
				
			||||||
			LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
 | 
					 | 
				
			||||||
				apn->tun.cfg.ipup_script);
 | 
					 | 
				
			||||||
			tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
 | 
					 | 
				
			||||||
			if (tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK) < 1) {
 | 
					 | 
				
			||||||
				LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of "
 | 
					 | 
				
			||||||
					"interface: %s\n", strerror(errno));
 | 
					 | 
				
			||||||
				apn_stop(apn, false);
 | 
					 | 
				
			||||||
				return -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* set back-pointer from TUN device to APN */
 | 
					 | 
				
			||||||
		apn->tun.tun->priv = apn;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case APN_GTPU_MODE_KERNEL_GTP:
 | 
						case APN_GTPU_MODE_KERNEL_GTP:
 | 
				
			||||||
		LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
 | 
							LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
 | 
				
			||||||
@@ -266,9 +226,17 @@ int apn_start(struct apn_ctx *apn)
 | 
				
			|||||||
			apn_stop(apn, false);
 | 
								apn_stop(apn, false);
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (gsn == NULL) {
 | 
				
			||||||
 | 
								/* skip bringing up the APN now if the GSN is not initialized yet.
 | 
				
			||||||
 | 
								 * This happens during initial load of the config file, as the
 | 
				
			||||||
 | 
								 * "no shutdown" in the ggsn node only happens after the "apn" nodes
 | 
				
			||||||
 | 
								 * are brought up */
 | 
				
			||||||
 | 
								LOGPAPN(LOGL_NOTICE, apn, "Skipping APN start\n");
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		/* use GTP kernel module for data packet encapsulation */
 | 
							/* use GTP kernel module for data packet encapsulation */
 | 
				
			||||||
		if (gtp_kernel_init(apn->ggsn->gsn, apn->tun.cfg.dev_name,
 | 
							if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) {
 | 
				
			||||||
				    &apn->v4.cfg.ifconfig_prefix, apn->tun.cfg.ipup_script) < 0) {
 | 
								LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -277,6 +245,68 @@ int apn_start(struct apn_ctx *apn)
 | 
				
			|||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* common initialization below */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set back-pointer from TUN device to APN */
 | 
				
			||||||
 | 
						apn->tun.tun->priv = apn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->v4.cfg.ifconfig_prefix.addr.len) {
 | 
				
			||||||
 | 
							LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
 | 
				
			||||||
 | 
								in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
 | 
				
			||||||
 | 
							if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
 | 
				
			||||||
 | 
									apn->v4.cfg.ifconfig_prefix.prefixlen)) {
 | 
				
			||||||
 | 
								LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
 | 
				
			||||||
 | 
									in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
 | 
				
			||||||
 | 
								apn_stop(apn, false);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->v6.cfg.ifconfig_prefix.addr.len) {
 | 
				
			||||||
 | 
							LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
 | 
				
			||||||
 | 
								in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
 | 
				
			||||||
 | 
							if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
 | 
				
			||||||
 | 
									apn->v6.cfg.ifconfig_prefix.prefixlen)) {
 | 
				
			||||||
 | 
								LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
 | 
				
			||||||
 | 
									"Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
 | 
				
			||||||
 | 
									in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
 | 
				
			||||||
 | 
								apn_stop(apn, false);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->v6.cfg.ll_prefix.addr.len) {
 | 
				
			||||||
 | 
							LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
 | 
				
			||||||
 | 
								in46p_ntoa(&apn->v6.cfg.ll_prefix));
 | 
				
			||||||
 | 
							if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
 | 
				
			||||||
 | 
									apn->v6.cfg.ll_prefix.prefixlen)) {
 | 
				
			||||||
 | 
								LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
 | 
				
			||||||
 | 
									"Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
 | 
				
			||||||
 | 
									in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
 | 
				
			||||||
 | 
								apn_stop(apn, false);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->tun.cfg.ipup_script) {
 | 
				
			||||||
 | 
							LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
 | 
				
			||||||
 | 
								apn->tun.cfg.ipup_script);
 | 
				
			||||||
 | 
							tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
 | 
				
			||||||
 | 
						    apn->v6.cfg.ll_prefix.addr.len == 0) {
 | 
				
			||||||
 | 
							rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
 | 
				
			||||||
 | 
							if (rc < 1) {
 | 
				
			||||||
 | 
								LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
 | 
				
			||||||
 | 
									rc ? strerror(errno) : "tun interface has no link-local IP assigned");
 | 
				
			||||||
 | 
								apn_stop(apn, false);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Create IPv4 pool */
 | 
						/* Create IPv4 pool */
 | 
				
			||||||
	if (apn->v4.cfg.dynamic_prefix.addr.len) {
 | 
						if (apn->v4.cfg.dynamic_prefix.addr.len) {
 | 
				
			||||||
		LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
 | 
							LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
 | 
				
			||||||
@@ -335,21 +365,26 @@ static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const st
 | 
				
			|||||||
static int delete_context(struct pdp_t *pdp)
 | 
					static int delete_context(struct pdp_t *pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gsn_t *gsn = pdp->gsn;
 | 
						struct gsn_t *gsn = pdp->gsn;
 | 
				
			||||||
	struct ippoolm_t *ipp = (struct ippoolm_t *)pdp->peer;
 | 
					 | 
				
			||||||
	struct apn_ctx *apn = pdp->priv;
 | 
						struct apn_ctx *apn = pdp->priv;
 | 
				
			||||||
 | 
						struct ippoolm_t *member;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
 | 
						LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
 | 
				
			||||||
	struct ippoolm_t *member = pdp->peer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pdp->peer) {
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
		send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
 | 
							if (pdp->peer[i]) {
 | 
				
			||||||
		ippool_freeip(ipp->pool, ipp);
 | 
								member = pdp->peer[i];
 | 
				
			||||||
	} else
 | 
								send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
 | 
				
			||||||
		LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
 | 
								ippool_freeip(member->pool, member);
 | 
				
			||||||
 | 
							} else if(i == 0)
 | 
				
			||||||
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
 | 
						if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
 | 
				
			||||||
		LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
 | 
							if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
 | 
				
			||||||
			strerror(errno));
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
 | 
				
			||||||
 | 
									strerror(errno));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -357,6 +392,44 @@ static int delete_context(struct pdp_t *pdp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/gsm/tlv.h>
 | 
					#include <osmocom/gsm/tlv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* determine if IPCP contains given option */
 | 
				
			||||||
 | 
					static uint8_t *ipcp_contains_option(uint8_t *ipcp, size_t ipcp_len, enum ipcp_options opt, size_t opt_minlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *cur_opt = ipcp + sizeof(struct ipcp_hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* iterate over Options and check if protocol contained */
 | 
				
			||||||
 | 
						while (cur_opt + 2 <= ipcp + ipcp_len) {
 | 
				
			||||||
 | 
							uint8_t type = cur_opt[0];
 | 
				
			||||||
 | 
							uint8_t len = cur_opt[1]; /* length value includes 2 bytes type/length */
 | 
				
			||||||
 | 
							if (len < 2)
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							if (type == opt && len >= 2 + opt_minlen)
 | 
				
			||||||
 | 
								return cur_opt;
 | 
				
			||||||
 | 
							cur_opt += len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 3GPP TS 24.008 10.6.5.3 */
 | 
					/* 3GPP TS 24.008 10.6.5.3 */
 | 
				
			||||||
enum pco_protocols {
 | 
					enum pco_protocols {
 | 
				
			||||||
	PCO_P_LCP		= 0xC021,
 | 
						PCO_P_LCP		= 0xC021,
 | 
				
			||||||
@@ -390,85 +463,115 @@ enum pco_protocols {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* determine if PCO contains given protocol */
 | 
					/* determine if PCO contains given protocol */
 | 
				
			||||||
static bool pco_contains_proto(struct ul255_t *pco, uint16_t prot)
 | 
					static uint8_t *pco_contains_proto(struct ul255_t *pco, size_t offset, uint16_t prot, size_t prot_minlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t *cur = pco->v + 1;
 | 
						uint8_t *cur = pco->v + 1 + offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* iterate over PCO and check if protocol contained */
 | 
						/* iterate over PCO and check if protocol contained */
 | 
				
			||||||
	while (cur + 3 <= pco->v + pco->l) {
 | 
						while (cur + 3 <= pco->v + pco->l) {
 | 
				
			||||||
		uint16_t cur_prot = osmo_load16be(cur);
 | 
							uint16_t cur_prot = osmo_load16be(cur);
 | 
				
			||||||
		uint8_t cur_len = cur[2];
 | 
							uint8_t cur_len = cur[2];
 | 
				
			||||||
		if (cur_prot == prot)
 | 
							if (cur_prot == prot && cur_len >= prot_minlen)
 | 
				
			||||||
			return true;
 | 
								return cur;
 | 
				
			||||||
		if (cur_len == 0)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		cur += cur_len + 3;
 | 
							cur += cur_len + 3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* determine if PDP context has IPv6 support */
 | 
					/*! Get the peer of pdp based on IP version used.
 | 
				
			||||||
static bool pdp_has_v4(struct pdp_t *pdp)
 | 
					 *  \param[in] pdp PDP context to select the peer from.
 | 
				
			||||||
{
 | 
					 *  \param[in] v4v6 IP version to select. Valid values are 4 and 6.
 | 
				
			||||||
	if (pdp->eua.l == 4+2)
 | 
					 *  \returns The selected peer matching the given IP version. NULL if not present.
 | 
				
			||||||
		return true;
 | 
					 */
 | 
				
			||||||
	else
 | 
					static struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
 | 
				
			||||||
		return false;
 | 
						uint8_t len1, len2, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_ipv6) {
 | 
				
			||||||
 | 
							len1 = 8;
 | 
				
			||||||
 | 
							len2 = 16;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							len1 = sizeof(struct in_addr);
 | 
				
			||||||
 | 
							len2 = len1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
							struct ippoolm_t * ippool = pdp->peer[i];
 | 
				
			||||||
 | 
							if (ippool && (ippool->addr.len == len1 || ippool->addr.len == len2))
 | 
				
			||||||
 | 
								return ippool;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* construct an IPCP PCO from up to two given DNS addreses */
 | 
					/* construct an IPCP PCO response from request*/
 | 
				
			||||||
static int build_ipcp_pco(struct msgb *msg, uint8_t id, const struct in46_addr *dns1,
 | 
					static void build_ipcp_pco(struct apn_ctx *apn, struct pdp_t *pdp, struct msgb *msg)
 | 
				
			||||||
			  const struct in46_addr *dns2)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t *len1, *len2;
 | 
						const struct in46_addr *dns1 = &apn->v4.cfg.dns[0];
 | 
				
			||||||
	uint8_t *start = msg->tail;
 | 
						const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
 | 
				
			||||||
 | 
						uint8_t *ipcp;
 | 
				
			||||||
 | 
						uint16_t ipcp_len;
 | 
				
			||||||
 | 
						uint8_t *len1, *len2, *pco_ipcp;
 | 
				
			||||||
	unsigned int len_appended;
 | 
						unsigned int len_appended;
 | 
				
			||||||
 | 
						ptrdiff_t consumed;
 | 
				
			||||||
 | 
						size_t remain, offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Three byte T16L header */
 | 
						/* pco_contains_proto() returns a potentially unaligned pointer into pco_req->v (see OS#3194) */
 | 
				
			||||||
	msgb_put_u16(msg, 0x8021);	/* IPCP */
 | 
						pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
 | 
				
			||||||
	len1 = msgb_put(msg, 1);	/* Length of contents: delay */
 | 
						while (pco_ipcp) {
 | 
				
			||||||
 | 
							uint8_t *start = msg->tail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_put_u8(msg, 0x02);		/* ACK */
 | 
							ipcp = (pco_ipcp + 3);  /* 2=type + 1=len */
 | 
				
			||||||
	msgb_put_u8(msg, id);		/* ID: Needs to match request */
 | 
							consumed = (ipcp - &pdp->pco_req.v[0]);
 | 
				
			||||||
	msgb_put_u8(msg, 0x00);		/* Length MSB */
 | 
							remain = sizeof(pdp->pco_req.v) - consumed;
 | 
				
			||||||
	len2 = msgb_put(msg, 1);	/* Length LSB: delay */
 | 
							ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
 | 
				
			||||||
 | 
							if (remain < 0 || remain < ipcp_len)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dns1 && dns1->len == 4) {
 | 
							/* Three byte T16L header */
 | 
				
			||||||
		msgb_put_u8(msg, 0x81);		/* DNS1 Tag */
 | 
							msgb_put_u16(msg, 0x8021);	/* IPCP */
 | 
				
			||||||
		msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
 | 
							len1 = msgb_put(msg, 1);	/* Length of contents: delay */
 | 
				
			||||||
		msgb_put_u32(msg, dns1->v4.s_addr);
 | 
					
 | 
				
			||||||
 | 
							msgb_put_u8(msg, 0x02);		/* ACK */
 | 
				
			||||||
 | 
							msgb_put_u8(msg, ipcp[1]);	/* ID: Needs to match request */
 | 
				
			||||||
 | 
							msgb_put_u8(msg, 0x00);		/* Length MSB */
 | 
				
			||||||
 | 
							len2 = msgb_put(msg, 1);	/* Length LSB: delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
 | 
				
			||||||
 | 
								msgb_put_u8(msg, 0x81);		/* DNS1 Tag */
 | 
				
			||||||
 | 
								msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
 | 
				
			||||||
 | 
								msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
 | 
				
			||||||
 | 
								msgb_put_u8(msg, 0x83);		/* DNS2 Tag */
 | 
				
			||||||
 | 
								msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
 | 
				
			||||||
 | 
								msgb_put_u32(msg, ntohl(dns2->v4.s_addr));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* patch in length values */
 | 
				
			||||||
 | 
							len_appended = msg->tail - start;
 | 
				
			||||||
 | 
							*len1 = len_appended - 3;
 | 
				
			||||||
 | 
							*len2 = len_appended - 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							offset += 3 + ipcp_len;
 | 
				
			||||||
 | 
							pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dns2 && dns2->len == 4) {
 | 
					 | 
				
			||||||
		msgb_put_u8(msg, 0x83);		/* DNS2 Tag */
 | 
					 | 
				
			||||||
		msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
 | 
					 | 
				
			||||||
		msgb_put_u32(msg, dns2->v4.s_addr);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* patch in length values */
 | 
					 | 
				
			||||||
	len_appended = msg->tail - start;
 | 
					 | 
				
			||||||
	*len1 = len_appended - 3;
 | 
					 | 
				
			||||||
	*len2 = len_appended - 3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* process one PCO request from a MS/UE, putting together the proper responses */
 | 
					/* process one PCO request from a MS/UE, putting together the proper responses */
 | 
				
			||||||
static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp)
 | 
					static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = msgb_alloc(256, "PCO");
 | 
						struct msgb *msg = msgb_alloc(256, "PCO");
 | 
				
			||||||
 | 
						struct ippoolm_t *peer_v4 = pdp_get_peer_ipv(pdp, false);
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(msg);
 | 
						OSMO_ASSERT(msg);
 | 
				
			||||||
	msgb_put_u8(msg, 0x80); /* ext-bit + configuration protocol byte */
 | 
						msgb_put_u8(msg, 0x80); /* ext-bit + configuration protocol byte */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: also check if primary / secondary DNS was requested */
 | 
						if (peer_v4)
 | 
				
			||||||
	if (pdp_has_v4(pdp) && pco_contains_proto(&pdp->pco_req, PCO_P_IPCP)) {
 | 
							build_ipcp_pco(apn, pdp, msg);
 | 
				
			||||||
		/* FIXME: properly implement this for IPCP */
 | 
					 | 
				
			||||||
		build_ipcp_pco(msg, 0, &apn->v4.cfg.dns[0], &apn->v4.cfg.dns[1]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv6_ADDR)) {
 | 
						if (pco_contains_proto(&pdp->pco_req, 0, PCO_P_DNS_IPv6_ADDR, 0)) {
 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
 | 
							for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
 | 
				
			||||||
			struct in46_addr *i46a = &apn->v6.cfg.dns[i];
 | 
								struct in46_addr *i46a = &apn->v6.cfg.dns[i];
 | 
				
			||||||
			if (i46a->len != 16)
 | 
								if (i46a->len != 16)
 | 
				
			||||||
@@ -477,7 +580,7 @@ static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv4_ADDR)) {
 | 
						if (pco_contains_proto(&pdp->pco_req, 0, PCO_P_DNS_IPv4_ADDR, 0)) {
 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
 | 
							for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
 | 
				
			||||||
			struct in46_addr *i46a = &apn->v4.cfg.dns[i];
 | 
								struct in46_addr *i46a = &apn->v4.cfg.dns[i];
 | 
				
			||||||
			if (i46a->len != 4)
 | 
								if (i46a->len != 4)
 | 
				
			||||||
@@ -514,10 +617,11 @@ int create_context_ind(struct pdp_t *pdp)
 | 
				
			|||||||
	static char name_buf[256];
 | 
						static char name_buf[256];
 | 
				
			||||||
	struct gsn_t *gsn = pdp->gsn;
 | 
						struct gsn_t *gsn = pdp->gsn;
 | 
				
			||||||
	struct ggsn_ctx *ggsn = gsn->priv;
 | 
						struct ggsn_ctx *ggsn = gsn->priv;
 | 
				
			||||||
	struct in46_addr addr;
 | 
						struct in46_addr addr[2];
 | 
				
			||||||
	struct ippoolm_t *member;
 | 
						struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
 | 
				
			||||||
 | 
						char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
 | 
				
			||||||
	struct apn_ctx *apn;
 | 
						struct apn_ctx *apn;
 | 
				
			||||||
	int rc;
 | 
						int rc, num_addr, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
 | 
						osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -552,56 +656,69 @@ int create_context_ind(struct pdp_t *pdp)
 | 
				
			|||||||
	memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l);	/* TODO */
 | 
						memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l);	/* TODO */
 | 
				
			||||||
	pdp->qos_neg.l = pdp->qos_req.l;
 | 
						pdp->qos_neg.l = pdp->qos_req.l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (in46a_from_eua(&pdp->eua, &addr)) {
 | 
						memset(addr, 0, sizeof(addr));
 | 
				
			||||||
 | 
						if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
 | 
				
			||||||
		LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
 | 
							LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
 | 
				
			||||||
			osmo_hexdump(pdp->eua.v, pdp->eua.l));
 | 
								osmo_hexdump(pdp->eua.v, pdp->eua.l));
 | 
				
			||||||
		gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
 | 
							gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (addr.len == sizeof(struct in_addr)) {
 | 
						/* Allocate dynamic addresses from the pool */
 | 
				
			||||||
		/* does this APN actually have an IPv4 pool? */
 | 
						for (i = 0; i < num_addr; i++) {
 | 
				
			||||||
		if (!apn_supports_ipv4(apn))
 | 
							if (addr[i].len == sizeof(struct in_addr)) {
 | 
				
			||||||
			goto err_wrong_af;
 | 
								/* does this APN actually have an IPv4 pool? */
 | 
				
			||||||
 | 
								if (!apn_supports_ipv4(apn))
 | 
				
			||||||
 | 
									goto err_wrong_af;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc = ippool_newip(apn->v4.pool, &member, &addr, 0);
 | 
								rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
 | 
				
			||||||
		if (rc < 0)
 | 
								if (rc < 0)
 | 
				
			||||||
			goto err_pool_full;
 | 
									goto err_pool_full;
 | 
				
			||||||
		in46a_to_eua(&member->addr, &pdp->eua);
 | 
								/* copy back */
 | 
				
			||||||
 | 
								memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								addrv4 = member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (addr[i].len == sizeof(struct in6_addr)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* does this APN actually have an IPv6 pool? */
 | 
				
			||||||
 | 
								if (!apn_supports_ipv6(apn))
 | 
				
			||||||
 | 
									goto err_wrong_af;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
 | 
				
			||||||
 | 
								if (rc < 0)
 | 
				
			||||||
 | 
									goto err_pool_full;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* IPv6 doesn't really send the real/allocated address at this point, but just
 | 
				
			||||||
 | 
								 * the link-identifier which the MS shall use for router solicitation */
 | 
				
			||||||
 | 
								/* initialize upper 64 bits to prefix, they are discarded by MS anyway */
 | 
				
			||||||
 | 
								memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
 | 
				
			||||||
 | 
								/* use allocated 64bit prefix as lower 64bit, used as link id by MS */
 | 
				
			||||||
 | 
								memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								addrv6 = member;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								OSMO_ASSERT(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pdp->peer[i] = member;
 | 
				
			||||||
 | 
							member->peer = pdp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						in46a_to_eua(addr, num_addr, &pdp->eua);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
 | 
				
			||||||
		/* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
 | 
							/* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
 | 
				
			||||||
		if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
 | 
							if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
 | 
				
			||||||
			LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
 | 
				
			||||||
			gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
 | 
								gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (addr.len == sizeof(struct in6_addr)) {
 | 
						}
 | 
				
			||||||
		struct in46_addr tmp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* does this APN actually have an IPv6 pool? */
 | 
					 | 
				
			||||||
		if (!apn_supports_ipv6(apn))
 | 
					 | 
				
			||||||
			goto err_wrong_af;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rc = ippool_newip(apn->v6.pool, &member, &addr, 0);
 | 
					 | 
				
			||||||
		if (rc < 0)
 | 
					 | 
				
			||||||
			goto err_pool_full;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* IPv6 doesn't really send the real/allocated address at this point, but just
 | 
					 | 
				
			||||||
		 * the link-identifier which the MS shall use for router solicitation */
 | 
					 | 
				
			||||||
		tmp.len = addr.len;
 | 
					 | 
				
			||||||
		/* initialize upper 64 bits to prefix, they are discarded by MS anyway */
 | 
					 | 
				
			||||||
		memcpy(tmp.v6.s6_addr, &member->addr.v6, 8);
 | 
					 | 
				
			||||||
		/* use allocated 64bit prefix as lower 64bit, used as link id by MS */
 | 
					 | 
				
			||||||
		memcpy(tmp.v6.s6_addr+8, &member->addr.v6, 8);
 | 
					 | 
				
			||||||
		in46a_to_eua(&tmp, &pdp->eua);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		OSMO_ASSERT(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pdp->peer = member;
 | 
					 | 
				
			||||||
	pdp->ipif = apn->tun.tun;	/* TODO */
 | 
						pdp->ipif = apn->tun.tun;	/* TODO */
 | 
				
			||||||
	pdp->priv = apn;
 | 
						pdp->priv = apn;
 | 
				
			||||||
	member->peer = pdp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: change trap to send 2 IPs */
 | 
				
			||||||
	if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
 | 
						if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
 | 
				
			||||||
		gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
 | 
							gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -612,8 +729,10 @@ int create_context_ind(struct pdp_t *pdp)
 | 
				
			|||||||
	/* Transmit G-PDU sequence numbers (only) if configured in APN */
 | 
						/* Transmit G-PDU sequence numbers (only) if configured in APN */
 | 
				
			||||||
	pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
 | 
						pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IP=%s\n",
 | 
						LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
 | 
				
			||||||
		name_buf, apn->cfg.name, pdp->teic_own, in46a_ntoa(&member->addr));
 | 
							name_buf, apn->cfg.name, pdp->teic_own,
 | 
				
			||||||
 | 
							addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
 | 
				
			||||||
 | 
							addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
 | 
				
			||||||
	gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
 | 
						gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
 | 
				
			||||||
	return 0;		/* Success */
 | 
						return 0;		/* Success */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -637,23 +756,31 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
 | 
				
			|||||||
	struct iphdr *iph = (struct iphdr *)pack;
 | 
						struct iphdr *iph = (struct iphdr *)pack;
 | 
				
			||||||
	struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
						struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
				
			||||||
	struct ippool_t *pool;
 | 
						struct ippool_t *pool;
 | 
				
			||||||
 | 
						char straddr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						uint8_t pref_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iph->version == 4) {
 | 
						switch (iph->version) {
 | 
				
			||||||
 | 
						case 4:
 | 
				
			||||||
		if (len < sizeof(*iph) || len < 4*iph->ihl)
 | 
							if (len < sizeof(*iph) || len < 4*iph->ihl)
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		dst.len = 4;
 | 
							dst.len = 4;
 | 
				
			||||||
		dst.v4.s_addr = iph->daddr;
 | 
							dst.v4.s_addr = iph->daddr;
 | 
				
			||||||
		pool = apn->v4.pool;
 | 
							pool = apn->v4.pool;
 | 
				
			||||||
	} else if (iph->version == 6) {
 | 
							break;
 | 
				
			||||||
 | 
						case 6:
 | 
				
			||||||
		/* Due to the fact that 3GPP requires an allocation of a
 | 
							/* Due to the fact that 3GPP requires an allocation of a
 | 
				
			||||||
		 * /64 prefix to each MS, we must instruct
 | 
							 * /64 prefix to each MS, we must instruct
 | 
				
			||||||
		 * ippool_getip() below to match only the leading /64
 | 
							 * ippool_getip() below to match only the leading /64
 | 
				
			||||||
		 * prefix, i.e. the first 8 bytes of the address */
 | 
							 * prefix, i.e. the first 8 bytes of the address. If the ll addr
 | 
				
			||||||
 | 
							 * is used, then the match should be done on the trailing 64
 | 
				
			||||||
 | 
							 * bits. */
 | 
				
			||||||
		dst.len = 8;
 | 
							dst.len = 8;
 | 
				
			||||||
		dst.v6 = ip6h->ip6_dst;
 | 
							pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
 | 
				
			||||||
 | 
							memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
 | 
				
			||||||
		pool = apn->v6.pool;
 | 
							pool = apn->v6.pool;
 | 
				
			||||||
	} else {
 | 
							break;
 | 
				
			||||||
		LOGP(DTUN, LOGL_NOTICE, "non-IPv packet received from tun\n");
 | 
						default:
 | 
				
			||||||
 | 
							LOGP(DTUN, LOGL_NOTICE, "non-IPv%u packet received from tun\n", iph->version);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -661,12 +788,15 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
 | 
				
			|||||||
	if (!pool)
 | 
						if (!pool)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DEBUGP(DTUN, "Received packet from tun!\n");
 | 
						DEBUGP(DTUN, "Received packet for APN(%s) from tun %s", apn->cfg.name, tun->devname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ippool_getip(pool, &ipm, &dst)) {
 | 
						if (ippool_getip(pool, &ipm, &dst)) {
 | 
				
			||||||
		DEBUGP(DTUN, "Received packet with no PDP contex!!\n");
 | 
							DEBUGPC(DTUN, " with no PDP contex! (%s)\n", iph->version == 4 ?
 | 
				
			||||||
 | 
								inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
 | 
				
			||||||
 | 
								inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						DEBUGPC(DTUN, "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ipm->peer)		/* Check if a peer protocol is defined */
 | 
						if (ipm->peer)		/* Check if a peer protocol is defined */
 | 
				
			||||||
		gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
 | 
							gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
 | 
				
			||||||
@@ -685,19 +815,53 @@ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
 | 
				
			|||||||
	struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
						struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
				
			||||||
	struct tun_t *tun = (struct tun_t *)pdp->ipif;
 | 
						struct tun_t *tun = (struct tun_t *)pdp->ipif;
 | 
				
			||||||
	struct apn_ctx *apn = tun->priv;
 | 
						struct apn_ctx *apn = tun->priv;
 | 
				
			||||||
 | 
						char straddr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct ippoolm_t *peer;
 | 
				
			||||||
 | 
						uint8_t pref_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(tun);
 | 
						OSMO_ASSERT(tun);
 | 
				
			||||||
	OSMO_ASSERT(apn);
 | 
						OSMO_ASSERT(apn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPPDP(LOGL_DEBUG, pdp, "Packet received: forwarding to tun\n");
 | 
						LOGPPDP(LOGL_DEBUG, pdp, "Packet received on APN(%s): forwarding to tun %s\n", apn->cfg.name, tun->devname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (iph->version) {
 | 
						switch (iph->version) {
 | 
				
			||||||
	case 6:
 | 
						case 6:
 | 
				
			||||||
 | 
							peer = pdp_get_peer_ipv(pdp, true);
 | 
				
			||||||
 | 
							if (!peer) {
 | 
				
			||||||
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
 | 
				
			||||||
 | 
									osmo_hexdump(pack, len));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Validate packet comes from IPaddr assigned to the pdp ctx.
 | 
				
			||||||
 | 
							   If packet is a LL addr, then EUA is in the lower 64 bits,
 | 
				
			||||||
 | 
							   otherwise it's used as the 64 prefix */
 | 
				
			||||||
 | 
							pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
 | 
				
			||||||
 | 
							if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
 | 
				
			||||||
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
 | 
				
			||||||
 | 
									inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* daddr: all-routers multicast addr */
 | 
							/* daddr: all-routers multicast addr */
 | 
				
			||||||
		if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
 | 
							if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
 | 
				
			||||||
			return handle_router_mcast(pdp->gsn, pdp, &apn->v6_lladdr, pack, len);
 | 
								return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
 | 
				
			||||||
 | 
											&apn->v6_lladdr, pack, len);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 4:
 | 
						case 4:
 | 
				
			||||||
 | 
							peer = pdp_get_peer_ipv(pdp, false);
 | 
				
			||||||
 | 
							if (!peer) {
 | 
				
			||||||
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
 | 
				
			||||||
 | 
									osmo_hexdump(pack, len));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Validate packet comes from IPaddr assigned to the pdp ctx */
 | 
				
			||||||
 | 
							if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
 | 
				
			||||||
 | 
								LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
 | 
				
			||||||
 | 
									inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
 | 
							LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
 | 
				
			||||||
@@ -929,6 +1093,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
 | 
						tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
 | 
				
			||||||
	msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
 | 
						msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
 | 
				
			||||||
 | 
						g_vty_info.tall_ctx = tall_ggsn_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Handle keyboard interrupt SIGINT */
 | 
						/* Handle keyboard interrupt SIGINT */
 | 
				
			||||||
	signal(SIGINT, &signal_handler);
 | 
						signal(SIGINT, &signal_handler);
 | 
				
			||||||
@@ -938,11 +1103,12 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	signal(SIGUSR2, &signal_handler);
 | 
						signal(SIGUSR2, &signal_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_init_ignore_signals();
 | 
						osmo_init_ignore_signals();
 | 
				
			||||||
	osmo_init_logging(&log_info);
 | 
						osmo_init_logging2(tall_ggsn_ctx, &log_info);
 | 
				
			||||||
	osmo_stats_init(tall_ggsn_ctx);
 | 
						osmo_stats_init(tall_ggsn_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_init(&g_vty_info);
 | 
						vty_init(&g_vty_info);
 | 
				
			||||||
	logging_vty_add_cmds(NULL);
 | 
						logging_vty_add_cmds(NULL);
 | 
				
			||||||
 | 
						osmo_talloc_vty_add_cmds();
 | 
				
			||||||
	osmo_stats_vty_add_cmds(&log_info);
 | 
						osmo_stats_vty_add_cmds(&log_info);
 | 
				
			||||||
	ggsn_vty_init();
 | 
						ggsn_vty_init();
 | 
				
			||||||
	ctrl_vty_init(tall_ggsn_ctx);
 | 
						ctrl_vty_init(tall_ggsn_ctx);
 | 
				
			||||||
@@ -961,7 +1127,8 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
 | 
						g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
 | 
				
			||||||
 | 
										     OSMO_CTRL_PORT_GGSN, NULL);
 | 
				
			||||||
	if (!g_ctrlh) {
 | 
						if (!g_ctrlh) {
 | 
				
			||||||
		LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
 | 
							LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,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 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -513,6 +513,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,
 | 
				
			||||||
@@ -668,6 +686,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);
 | 
				
			||||||
@@ -893,6 +913,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 +948,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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -180,17 +180,15 @@ static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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 +219,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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,5 +3,7 @@
 | 
				
			|||||||
#include "../gtp/gtp.h"
 | 
					#include "../gtp/gtp.h"
 | 
				
			||||||
#include "../gtp/pdp.h"
 | 
					#include "../gtp/pdp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=3:0:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										381
									
								
								gtp/gtp.c
									
									
									
									
									
								
							
							
						
						
									
										381
									
								
								gtp/gtp.c
									
									
									
									
									
								
							@@ -1,19 +1,19 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  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) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
 | 
					 *  Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 *  Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH
 | 
					 *  Copyright (C) 2015-2017 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.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
 | 
					 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
 | 
				
			||||||
 * tunnels in the same program. 
 | 
					 * tunnels in the same program.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * TODO:
 | 
					 * TODO:
 | 
				
			||||||
 *  - Do we need to handle fragmentation?
 | 
					 *  - Do we need to handle fragmentation?
 | 
				
			||||||
@@ -86,6 +86,51 @@ const char *gtp_version()
 | 
				
			|||||||
	return VERSION;
 | 
						return VERSION;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct value_string gtp_type_names[] = {
 | 
				
			||||||
 | 
						{ GTP_ECHO_REQ,        "Echo Request" },
 | 
				
			||||||
 | 
						{ GTP_ECHO_RSP,        "Echo Response" },
 | 
				
			||||||
 | 
						{ GTP_NOT_SUPPORTED,   "Version Not Supported" },
 | 
				
			||||||
 | 
						{ GTP_ALIVE_REQ,       "Node Alive Request" },
 | 
				
			||||||
 | 
						{ GTP_ALIVE_RSP,       "Node Alive Response" },
 | 
				
			||||||
 | 
						{ GTP_REDIR_REQ,       "Redirection Request" },
 | 
				
			||||||
 | 
						{ GTP_REDIR_RSP,       "Redirection Response" },
 | 
				
			||||||
 | 
						{ GTP_CREATE_PDP_REQ,  "Create PDP Context Request" },
 | 
				
			||||||
 | 
						{ GTP_CREATE_PDP_RSP,  "Create PDP Context Response" },
 | 
				
			||||||
 | 
						{ GTP_UPDATE_PDP_REQ,  "Update PDP Context Request" },
 | 
				
			||||||
 | 
						{ GTP_UPDATE_PDP_RSP,  "Update PDP Context Response" },
 | 
				
			||||||
 | 
						{ GTP_DELETE_PDP_REQ,  "Delete PDP Context Request" },
 | 
				
			||||||
 | 
						{ GTP_DELETE_PDP_RSP,  "Delete PDP Context Response" },
 | 
				
			||||||
 | 
						{ GTP_ERROR,           "Error Indication" },
 | 
				
			||||||
 | 
						{ GTP_PDU_NOT_REQ,     "PDU Notification Request" },
 | 
				
			||||||
 | 
						{ GTP_PDU_NOT_RSP,     "PDU Notification Response" },
 | 
				
			||||||
 | 
						{ GTP_PDU_NOT_REJ_REQ, "PDU Notification Reject Request" },
 | 
				
			||||||
 | 
						{ GTP_PDU_NOT_REJ_RSP, "PDU Notification Reject Response" },
 | 
				
			||||||
 | 
						{ GTP_SUPP_EXT_HEADER, "Supported Extension Headers Notification" },
 | 
				
			||||||
 | 
						{ GTP_SND_ROUTE_REQ,   "Send Routeing Information for GPRS Request" },
 | 
				
			||||||
 | 
						{ GTP_SND_ROUTE_RSP,   "Send Routeing Information for GPRS Response" },
 | 
				
			||||||
 | 
						{ GTP_FAILURE_REQ,     "Failure Report Request" },
 | 
				
			||||||
 | 
						{ GTP_FAILURE_RSP,     "Failure Report Response" },
 | 
				
			||||||
 | 
						{ GTP_MS_PRESENT_REQ,  "Note MS GPRS Present Request" },
 | 
				
			||||||
 | 
						{ GTP_MS_PRESENT_RSP,  "Note MS GPRS Present Response" },
 | 
				
			||||||
 | 
						{ GTP_IDEN_REQ,        "Identification Request" },
 | 
				
			||||||
 | 
						{ GTP_IDEN_RSP,        "Identification Response" },
 | 
				
			||||||
 | 
						{ GTP_SGSN_CONTEXT_REQ,"SGSN Context Request" },
 | 
				
			||||||
 | 
						{ GTP_SGSN_CONTEXT_RSP,"SGSN Context Response" },
 | 
				
			||||||
 | 
						{ GTP_SGSN_CONTEXT_ACK,"SGSN Context Acknowledge" },
 | 
				
			||||||
 | 
						{ GTP_FWD_RELOC_REQ,   "Forward Relocation Request" },
 | 
				
			||||||
 | 
						{ GTP_FWD_RELOC_RSP,   "Forward Relocation Response" },
 | 
				
			||||||
 | 
						{ GTP_FWD_RELOC_COMPL, "Forward Relocation Complete" },
 | 
				
			||||||
 | 
						{ GTP_RELOC_CANCEL_REQ,"Relocation Cancel Request" },
 | 
				
			||||||
 | 
						{ GTP_RELOC_CANCEL_RSP,"Relocation Cancel Response" },
 | 
				
			||||||
 | 
						{ GTP_FWD_SRNS,        "Forward SRNS Context" },
 | 
				
			||||||
 | 
						{ GTP_FWD_RELOC_ACK,   "Forward Relocation Complete Acknowledge" },
 | 
				
			||||||
 | 
						{ GTP_FWD_SRNS_ACK,    "Forward SRNS Context Acknowledge" },
 | 
				
			||||||
 | 
						{ GTP_DATA_TRAN_REQ,   "Data Record Transfer Request" },
 | 
				
			||||||
 | 
						{ GTP_DATA_TRAN_RSP,   "Data Record Transfer Response" },
 | 
				
			||||||
 | 
						{ GTP_GPDU,            "G-PDU" },
 | 
				
			||||||
 | 
						{ 0, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* gtp_new */
 | 
					/* gtp_new */
 | 
				
			||||||
/* gtp_free */
 | 
					/* gtp_free */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,6 +190,15 @@ int gtp_set_cb_conf(struct gsn_t *gsn,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
 | 
				
			||||||
 | 
								     struct pdp_t * pdp, uint8_t recovery)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (gsn->cb_recovery)
 | 
				
			||||||
 | 
							gsn->cb_recovery(peer, recovery);
 | 
				
			||||||
 | 
						if (gsn->cb_recovery2)
 | 
				
			||||||
 | 
							gsn->cb_recovery2(peer, pdp, recovery);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_set_cb_recovery(struct gsn_t *gsn,
 | 
					int gtp_set_cb_recovery(struct gsn_t *gsn,
 | 
				
			||||||
			int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
 | 
								int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -152,7 +206,21 @@ int gtp_set_cb_recovery(struct gsn_t *gsn,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
 | 
					/* cb_recovery()
 | 
				
			||||||
 | 
					 * pdp may be NULL if Recovery IE was received from a message independent
 | 
				
			||||||
 | 
					 * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
 | 
				
			||||||
 | 
					 * local setup. In case pdp is known, caller may want to keep that pdp alive to
 | 
				
			||||||
 | 
					 * handle subsequent msg cb as this specific pdp ctx is still valid according to
 | 
				
			||||||
 | 
					 * specs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int gtp_set_cb_recovery2(struct gsn_t *gsn,
 | 
				
			||||||
 | 
								int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						gsn->cb_recovery2 = cb_recovery2;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -168,7 +236,7 @@ extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
 | 
				
			|||||||
 * to hold the packet header.
 | 
					 * to hold the packet header.
 | 
				
			||||||
 * returns the length of the header. 0 on error.
 | 
					 * returns the length of the header. 0 on error.
 | 
				
			||||||
 **/
 | 
					 **/
 | 
				
			||||||
static unsigned int get_default_gtp(int version, uint8_t type, void *packet)
 | 
					static unsigned int get_default_gtp(uint8_t version, uint8_t type, void *packet)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
 | 
						struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
 | 
				
			||||||
	struct gtp1_header_long *gtp1_default =
 | 
						struct gtp1_header_long *gtp1_default =
 | 
				
			||||||
@@ -281,19 +349,19 @@ static uint32_t get_tei(void *pack)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* ***********************************************************
 | 
					/* ***********************************************************
 | 
				
			||||||
 * Reliable delivery of signalling messages
 | 
					 * Reliable delivery of signalling messages
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * Sequence numbers are used for both signalling messages and
 | 
					 * Sequence numbers are used for both signalling messages and
 | 
				
			||||||
 * data messages.
 | 
					 * data messages.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * For data messages each tunnel maintains a sequence counter,
 | 
					 * For data messages each tunnel maintains a sequence counter,
 | 
				
			||||||
 * which is incremented by one each time a new data message
 | 
					 * which is incremented by one each time a new data message
 | 
				
			||||||
 * is sent. The sequence number starts at (0) zero at tunnel
 | 
					 * is sent. The sequence number starts at (0) zero at tunnel
 | 
				
			||||||
 * establishment, and wraps around at 65535 (29.060 9.3.1.1 
 | 
					 * establishment, and wraps around at 65535 (29.060 9.3.1.1
 | 
				
			||||||
 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
 | 
					 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
 | 
				
			||||||
 * or can be used to check the validity of the message in the
 | 
					 * or can be used to check the validity of the message in the
 | 
				
			||||||
 * receiver, or for reordering af packets.
 | 
					 * receiver, or for reordering af packets.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * For signalling messages the sequence number is used by 
 | 
					 * For signalling messages the sequence number is used by
 | 
				
			||||||
 * signalling messages for which a response is defined. A response
 | 
					 * signalling messages for which a response is defined. A response
 | 
				
			||||||
 * message should copy the sequence from the corresponding request
 | 
					 * message should copy the sequence from the corresponding request
 | 
				
			||||||
 * message. The sequence number "unambiguously" identifies a request
 | 
					 * message. The sequence number "unambiguously" identifies a request
 | 
				
			||||||
@@ -311,7 +379,7 @@ static uint32_t get_tei(void *pack)
 | 
				
			|||||||
 * with path setup and teardown.
 | 
					 * with path setup and teardown.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If a response message is lost, the request will be retransmitted, and
 | 
					 * If a response message is lost, the request will be retransmitted, and
 | 
				
			||||||
 * the receiving GSN will receive a "duplicated" request. The standard 
 | 
					 * the receiving GSN will receive a "duplicated" request. The standard
 | 
				
			||||||
 * requires the receiving GSN to send a response, with the same information
 | 
					 * requires the receiving GSN to send a response, with the same information
 | 
				
			||||||
 * as in the original response. For most messages this happens automatically:
 | 
					 * as in the original response. For most messages this happens automatically:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -326,22 +394,22 @@ static uint32_t get_tei(void *pack)
 | 
				
			|||||||
 *   a nonexist reply message.
 | 
					 *   a nonexist reply message.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The correct solution will be to make a queue containing response messages.
 | 
					 * The correct solution will be to make a queue containing response messages.
 | 
				
			||||||
 * This queue should be checked whenever a request is received. If the 
 | 
					 * This queue should be checked whenever a request is received. If the
 | 
				
			||||||
 * response is allready in the queue that response should be transmitted.
 | 
					 * response is allready in the queue that response should be transmitted.
 | 
				
			||||||
 * It should be possible to find messages in this queue on the basis of
 | 
					 * It should be possible to find messages in this queue on the basis of
 | 
				
			||||||
 * the sequence number and peer GSN IP address (The sequense number is unique
 | 
					 * the sequence number and peer GSN IP address (The sequense number is unique
 | 
				
			||||||
 * within each path). This need to be implemented by a hash table. Furthermore
 | 
					 * within each path). This need to be implemented by a hash table. Furthermore
 | 
				
			||||||
 * it should be possibly to delete messages based on a timeout. This can be
 | 
					 * it should be possibly to delete messages based on a timeout. This can be
 | 
				
			||||||
 * achieved by means of a linked list. The timeout value need to be larger
 | 
					 * achieved by means of a linked list. The timeout value need to be larger
 | 
				
			||||||
 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are 
 | 
					 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
 | 
				
			||||||
 * set in the peer GSN, so there is no way to know these parameters. On the
 | 
					 * set in the peer GSN, so there is no way to know these parameters. On the
 | 
				
			||||||
 * other hand the timeout value need to be so small that we do not receive
 | 
					 * other hand the timeout value need to be so small that we do not receive
 | 
				
			||||||
 * wraparound sequence numbere before the message is deleted. 60 seconds is
 | 
					 * wraparound sequence numbere before the message is deleted. 60 seconds is
 | 
				
			||||||
 * probably not a bad choise.
 | 
					 * probably not a bad choise.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * This queue however is first really needed from gtp1.
 | 
					 * This queue however is first really needed from gtp1.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * gtp_req: 
 | 
					 * gtp_req:
 | 
				
			||||||
 *   Send off a signalling message with appropiate sequence
 | 
					 *   Send off a signalling message with appropiate sequence
 | 
				
			||||||
 *   number. Store packet in queue.
 | 
					 *   number. Store packet in queue.
 | 
				
			||||||
 * gtp_conf:
 | 
					 * gtp_conf:
 | 
				
			||||||
@@ -357,7 +425,7 @@ static uint32_t get_tei(void *pack)
 | 
				
			|||||||
 *   a predefined timeout.
 | 
					 *   a predefined timeout.
 | 
				
			||||||
 *************************************************************/
 | 
					 *************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
 | 
					static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
 | 
				
			||||||
	    union gtp_packet *packet, int len,
 | 
						    union gtp_packet *packet, int len,
 | 
				
			||||||
	    struct in_addr *inetaddr, void *cbp)
 | 
						    struct in_addr *inetaddr, void *cbp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -432,7 +500,7 @@ int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
 | 
				
			|||||||
 * Remove signalling packet from retransmission queue.
 | 
					 * Remove signalling packet from retransmission queue.
 | 
				
			||||||
 * return 0 on success, EOF if packet was not found */
 | 
					 * return 0 on success, EOF if packet was not found */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
 | 
					static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
 | 
				
			||||||
	     union gtp_packet *packet, int len, uint8_t * type, void **cbp)
 | 
						     union gtp_packet *packet, int len, uint8_t * type, void **cbp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
 | 
						uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
 | 
				
			||||||
@@ -523,7 +591,7 @@ int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
 | 
					static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
	     union gtp_packet *packet, int len,
 | 
						     union gtp_packet *packet, int len,
 | 
				
			||||||
	     struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
 | 
						     struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -581,7 +649,7 @@ int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_notification(struct gsn_t *gsn, int version,
 | 
					static int gtp_notification(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		     union gtp_packet *packet, int len,
 | 
							     union gtp_packet *packet, int len,
 | 
				
			||||||
		     struct sockaddr_in *peer, int fd, uint16_t seq)
 | 
							     struct sockaddr_in *peer, int fd, uint16_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -626,7 +694,7 @@ int gtp_notification(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_dublicate(struct gsn_t *gsn, int version,
 | 
					static int gtp_dublicate(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		  struct sockaddr_in *peer, uint16_t seq)
 | 
							  struct sockaddr_in *peer, uint16_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qmsg_t *qmsg;
 | 
						struct qmsg_t *qmsg;
 | 
				
			||||||
@@ -852,7 +920,7 @@ int gtp_free(struct gsn_t *gsn)
 | 
				
			|||||||
 * For response messages we need to be able to respond to
 | 
					 * For response messages we need to be able to respond to
 | 
				
			||||||
 * the relevant src port even if it is locally allocated by
 | 
					 * the relevant src port even if it is locally allocated by
 | 
				
			||||||
 * the peer.
 | 
					 * the peer.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * The need for path management!
 | 
					 * The need for path management!
 | 
				
			||||||
 * We might need to keep a list of active paths. This might
 | 
					 * We might need to keep a list of active paths. This might
 | 
				
			||||||
 * be in the form of remote IP address + UDP port numbers.
 | 
					 * be in the form of remote IP address + UDP port numbers.
 | 
				
			||||||
@@ -932,8 +1000,7 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
 | 
				
			|||||||
	if (gsn->cb_conf)
 | 
						if (gsn->cb_conf)
 | 
				
			||||||
		gsn->cb_conf(type, recovery, NULL, cbp);
 | 
							gsn->cb_conf(type, recovery, NULL, cbp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gsn->cb_recovery)
 | 
						emit_cb_recovery(gsn, peer, NULL, recovery);
 | 
				
			||||||
		gsn->cb_recovery(peer, recovery);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -942,9 +1009,9 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
 | 
				
			|||||||
/* This message is somewhat special in that it actually is a
 | 
					/* This message is somewhat special in that it actually is a
 | 
				
			||||||
 * response to some other message with unsupported GTP version
 | 
					 * response to some other message with unsupported GTP version
 | 
				
			||||||
 * For this reason it has parameters like a response, and does
 | 
					 * For this reason it has parameters like a response, and does
 | 
				
			||||||
 * its own message transmission. No signalling queue is used 
 | 
					 * its own message transmission. No signalling queue is used
 | 
				
			||||||
 * The reply is sent to the peer IP and peer UDP. This means that
 | 
					 * The reply is sent to the peer IP and peer UDP. This means that
 | 
				
			||||||
 * the peer will be receiving a GTP0 message on a GTP1 port! 
 | 
					 * the peer will be receiving a GTP0 message on a GTP1 port!
 | 
				
			||||||
 * In practice however this will never happen as a GTP0 GSN will
 | 
					 * In practice however this will never happen as a GTP0 GSN will
 | 
				
			||||||
 * only listen to the GTP0 port, and therefore will never receive
 | 
					 * only listen to the GTP0 port, and therefore will never receive
 | 
				
			||||||
 * anything else than GTP0 */
 | 
					 * anything else than GTP0 */
 | 
				
			||||||
@@ -971,7 +1038,7 @@ int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send off an Supported Extension Headers Notification */
 | 
					/* Send off an Supported Extension Headers Notification */
 | 
				
			||||||
int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
 | 
					static int gtp_extheader_req(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
 | 
				
			||||||
		      int fd, void *pack, unsigned len)
 | 
							      int fd, void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union gtp_packet packet;
 | 
						union gtp_packet packet;
 | 
				
			||||||
@@ -992,7 +1059,7 @@ int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle a Supported Extension Headers Notification */
 | 
					/* Handle a Supported Extension Headers Notification */
 | 
				
			||||||
int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
 | 
					static int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
 | 
				
			||||||
		      void *pack, unsigned len)
 | 
							      void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1007,7 +1074,7 @@ int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
 | 
				
			|||||||
 * Messages: create, update and delete PDP context
 | 
					 * Messages: create, update and delete PDP context
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Information storage
 | 
					 * Information storage
 | 
				
			||||||
 * Information storage for each PDP context is defined in 
 | 
					 * Information storage for each PDP context is defined in
 | 
				
			||||||
 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
 | 
					 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
 | 
				
			||||||
 * PDP-address (IP address), sequence numbers, charging ID.
 | 
					 * PDP-address (IP address), sequence numbers, charging ID.
 | 
				
			||||||
 * For the SGSN it also includes radio related mobility
 | 
					 * For the SGSN it also includes radio related mobility
 | 
				
			||||||
@@ -1015,7 +1082,7 @@ int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
 | 
				
			|||||||
 *************************************************************/
 | 
					 *************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Send Create PDP Context Request (7.3.1) */
 | 
					/* API: Send Create PDP Context Request (7.3.1) */
 | 
				
			||||||
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
					int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			||||||
				  void *cbp)
 | 
									  void *cbp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union gtp_packet packet;
 | 
						union gtp_packet packet;
 | 
				
			||||||
@@ -1093,7 +1160,7 @@ extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
				
			|||||||
				  pdp->cch_pdp);
 | 
									  pdp->cch_pdp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO 
 | 
						/* TODO
 | 
				
			||||||
	   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
 | 
						   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
 | 
				
			||||||
	   pdp->traceref);
 | 
						   pdp->traceref);
 | 
				
			||||||
	   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
 | 
						   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
 | 
				
			||||||
@@ -1265,6 +1332,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	struct pdp_t pdp_buf;
 | 
						struct pdp_t pdp_buf;
 | 
				
			||||||
	union gtpie_member *ie[GTPIE_SIZE];
 | 
						union gtpie_member *ie[GTPIE_SIZE];
 | 
				
			||||||
	uint8_t recovery;
 | 
						uint8_t recovery;
 | 
				
			||||||
 | 
						bool recovery_recvd = false;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint16_t seq = get_seq(pack);
 | 
						uint16_t seq = get_seq(pack);
 | 
				
			||||||
	int hlen = get_hlen(pack);
 | 
						int hlen = get_hlen(pack);
 | 
				
			||||||
@@ -1365,8 +1434,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Recovery (optional) */
 | 
						/* Recovery (optional) */
 | 
				
			||||||
	if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
						if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
				
			||||||
		if (gsn->cb_recovery)
 | 
							/* we use recovery futher down after announcing new pdp ctx to user */
 | 
				
			||||||
			gsn->cb_recovery(peer, recovery);
 | 
							recovery_recvd = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Selection mode (conditional) */
 | 
						/* Selection mode (conditional) */
 | 
				
			||||||
@@ -1537,7 +1606,7 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
		    (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
 | 
							    (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			/* OK! We are dealing with the same APN. We will copy new
 | 
								/* OK! We are dealing with the same APN. We will copy new
 | 
				
			||||||
			 * parameters to the old pdp and send off confirmation 
 | 
								 * parameters to the old pdp and send off confirmation
 | 
				
			||||||
			 * We ignore the following information elements:
 | 
								 * We ignore the following information elements:
 | 
				
			||||||
			 * QoS: MS will get originally negotiated QoS.
 | 
								 * QoS: MS will get originally negotiated QoS.
 | 
				
			||||||
			 * End user address (EUA). MS will get old EUA anyway.
 | 
								 * End user address (EUA). MS will get old EUA anyway.
 | 
				
			||||||
@@ -1567,6 +1636,9 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
			/* Switch to using the old pdp context */
 | 
								/* Switch to using the old pdp context */
 | 
				
			||||||
			pdp = pdp_old;
 | 
								pdp = pdp_old;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (recovery_recvd)
 | 
				
			||||||
 | 
									emit_cb_recovery(gsn, peer, pdp, recovery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Confirm to peer that things were "successful" */
 | 
								/* Confirm to peer that things were "successful" */
 | 
				
			||||||
			return gtp_create_pdp_resp(gsn, version, pdp,
 | 
								return gtp_create_pdp_resp(gsn, version, pdp,
 | 
				
			||||||
						   GTPCAUSE_ACC_REQ);
 | 
											   GTPCAUSE_ACC_REQ);
 | 
				
			||||||
@@ -1588,13 +1660,16 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Callback function to validata login */
 | 
						/* Callback function to validata login */
 | 
				
			||||||
	if (gsn->cb_create_context_ind != 0)
 | 
						if (gsn->cb_create_context_ind != 0)
 | 
				
			||||||
		return gsn->cb_create_context_ind(pdp);
 | 
							rc = gsn->cb_create_context_ind(pdp);
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
							GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
			    "No create_context_ind callback defined\n");
 | 
								    "No create_context_ind callback defined\n");
 | 
				
			||||||
		return gtp_create_pdp_resp(gsn, version, pdp,
 | 
							rc = gtp_create_pdp_resp(gsn, version, pdp,
 | 
				
			||||||
					   GTPCAUSE_NOT_SUPPORTED);
 | 
										   GTPCAUSE_NOT_SUPPORTED);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (recovery_recvd)
 | 
				
			||||||
 | 
							emit_cb_recovery(gsn, peer, pdp, recovery);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle Create PDP Context Response */
 | 
					/* Handle Create PDP Context Response */
 | 
				
			||||||
@@ -1651,8 +1726,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Extract recovery (optional) */
 | 
						/* Extract recovery (optional) */
 | 
				
			||||||
	if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
						if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
				
			||||||
		if (gsn->cb_recovery)
 | 
							emit_cb_recovery(gsn, peer, pdp, recovery);
 | 
				
			||||||
			gsn->cb_recovery(peer, recovery);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Extract protocol configuration options (optional) */
 | 
						/* Extract protocol configuration options (optional) */
 | 
				
			||||||
@@ -1853,14 +1927,14 @@ int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
 | 
						gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO 
 | 
						/* TODO
 | 
				
			||||||
	   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
 | 
						   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
 | 
				
			||||||
	   pdp->traceref);
 | 
						   pdp->traceref);
 | 
				
			||||||
	   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
 | 
						   gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
 | 
				
			||||||
	   pdp->tracetype); */
 | 
						   pdp->tracetype); */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO if ggsn update message
 | 
						/* TODO if ggsn update message
 | 
				
			||||||
	   gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, 
 | 
						   gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
 | 
				
			||||||
	   pdp->eua.l, pdp->eua.v);
 | 
						   pdp->eua.l, pdp->eua.v);
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1891,7 +1965,7 @@ int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send Update PDP Context Response */
 | 
					/* Send Update PDP Context Response */
 | 
				
			||||||
int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
 | 
					static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
			struct sockaddr_in *peer, int fd,
 | 
								struct sockaddr_in *peer, int fd,
 | 
				
			||||||
			void *pack, unsigned len,
 | 
								void *pack, unsigned len,
 | 
				
			||||||
			struct pdp_t *pdp, uint8_t cause)
 | 
								struct pdp_t *pdp, uint8_t cause)
 | 
				
			||||||
@@ -1932,8 +2006,8 @@ int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
 | 
				
			|||||||
		gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
 | 
							gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
 | 
				
			||||||
			  pdp->teid_own);
 | 
								  pdp->teid_own);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* If ggsn 
 | 
							/* If ggsn
 | 
				
			||||||
		   gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, 
 | 
							   gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
 | 
				
			||||||
		   pdp->eua.l, pdp->eua.v); */
 | 
							   pdp->eua.l, pdp->eua.v); */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
 | 
							gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
 | 
				
			||||||
@@ -1953,7 +2027,7 @@ int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle Update PDP Context Request */
 | 
					/* Handle Update PDP Context Request */
 | 
				
			||||||
int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
 | 
					static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		       struct sockaddr_in *peer, int fd,
 | 
							       struct sockaddr_in *peer, int fd,
 | 
				
			||||||
		       void *pack, unsigned len)
 | 
							       void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2061,8 +2135,7 @@ int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Recovery (optional) */
 | 
						/* Recovery (optional) */
 | 
				
			||||||
	if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
						if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
				
			||||||
		if (gsn->cb_recovery)
 | 
							emit_cb_recovery(gsn, peer, pdp, recovery);
 | 
				
			||||||
			gsn->cb_recovery(peer, recovery);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (version == 0) {
 | 
						if (version == 0) {
 | 
				
			||||||
@@ -2127,7 +2200,7 @@ int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	   GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
						   GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
	   "Missing mandatory information field");
 | 
						   "Missing mandatory information field");
 | 
				
			||||||
	   memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
 | 
						   memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
 | 
				
			||||||
	   return gtp_update_pdp_resp(gsn, version, pdp, 
 | 
						   return gtp_update_pdp_resp(gsn, version, pdp,
 | 
				
			||||||
	   GTPCAUSE_MAN_IE_MISSING);
 | 
						   GTPCAUSE_MAN_IE_MISSING);
 | 
				
			||||||
	   } */
 | 
						   } */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2181,7 +2254,7 @@ int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle Update PDP Context Response */
 | 
					/* Handle Update PDP Context Response */
 | 
				
			||||||
int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
 | 
					static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
			struct sockaddr_in *peer, void *pack, unsigned len)
 | 
								struct sockaddr_in *peer, void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pdp_t *pdp;
 | 
						struct pdp_t *pdp;
 | 
				
			||||||
@@ -2222,8 +2295,7 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Extract recovery (optional) */
 | 
						/* Extract recovery (optional) */
 | 
				
			||||||
	if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
						if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
 | 
				
			||||||
		if (gsn->cb_recovery)
 | 
							emit_cb_recovery(gsn, peer, pdp, recovery);
 | 
				
			||||||
			gsn->cb_recovery(peer, recovery);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check all conditional information elements */
 | 
						/* Check all conditional information elements */
 | 
				
			||||||
@@ -2292,16 +2364,66 @@ err_out:
 | 
				
			|||||||
	return EOF;
 | 
						return EOF;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API: Send Delete PDP Context Request */
 | 
					/* API: Deprecated. Send Delete PDP Context Request And free pdp ctx. */
 | 
				
			||||||
int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
					int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
				
			||||||
			   int teardown)
 | 
								   int teardown)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pdp_t *linked_pdp;
 | 
				
			||||||
 | 
						struct pdp_t *secondary_pdp;
 | 
				
			||||||
 | 
						int n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
 | 
				
			||||||
 | 
							LOGP(DLGTP, LOGL_ERROR,
 | 
				
			||||||
 | 
								"Unknown linked PDP context: %u\n", pdp->teic_own);
 | 
				
			||||||
 | 
							return EOF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF)
 | 
				
			||||||
 | 
							return EOF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (teardown) {		/* Remove all contexts */
 | 
				
			||||||
 | 
							for (n = 0; n < PDP_MAXNSAPI; n++) {
 | 
				
			||||||
 | 
								if (linked_pdp->secondary_tei[n]) {
 | 
				
			||||||
 | 
									if (pdp_getgtp1
 | 
				
			||||||
 | 
									    (&secondary_pdp,
 | 
				
			||||||
 | 
									     linked_pdp->secondary_tei[n])) {
 | 
				
			||||||
 | 
										LOGP(DLGTP, LOGL_ERROR,
 | 
				
			||||||
 | 
											"Unknown secondary PDP context\n");
 | 
				
			||||||
 | 
										return EOF;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (linked_pdp != secondary_pdp) {
 | 
				
			||||||
 | 
										if (gsn->cb_delete_context)
 | 
				
			||||||
 | 
											gsn->cb_delete_context
 | 
				
			||||||
 | 
											    (secondary_pdp);
 | 
				
			||||||
 | 
										pdp_freepdp(secondary_pdp);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (gsn->cb_delete_context)
 | 
				
			||||||
 | 
								gsn->cb_delete_context(linked_pdp);
 | 
				
			||||||
 | 
							pdp_freepdp(linked_pdp);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (gsn->cb_delete_context)
 | 
				
			||||||
 | 
								gsn->cb_delete_context(pdp);
 | 
				
			||||||
 | 
							if (pdp == linked_pdp) {
 | 
				
			||||||
 | 
								linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
 | 
				
			||||||
 | 
								linked_pdp->nodata = 1;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								pdp_freepdp(pdp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* API: Send Delete PDP Context Request. PDP CTX shall be free'd by user at cb_conf(GTP_DELETE_PDP_RSP) */
 | 
				
			||||||
 | 
					int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
				
			||||||
 | 
								   int teardown)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union gtp_packet packet;
 | 
						union gtp_packet packet;
 | 
				
			||||||
	unsigned int length =
 | 
						unsigned int length =
 | 
				
			||||||
	    get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
 | 
						    get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
 | 
				
			||||||
	struct in_addr addr;
 | 
						struct in_addr addr;
 | 
				
			||||||
	struct pdp_t *linked_pdp;
 | 
						struct pdp_t *linked_pdp;
 | 
				
			||||||
	struct pdp_t *secondary_pdp;
 | 
					 | 
				
			||||||
	int n;
 | 
						int n;
 | 
				
			||||||
	int count = 0;
 | 
						int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2338,37 +2460,6 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
 | 
						gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (teardown) {		/* Remove all contexts */
 | 
					 | 
				
			||||||
		for (n = 0; n < PDP_MAXNSAPI; n++) {
 | 
					 | 
				
			||||||
			if (linked_pdp->secondary_tei[n]) {
 | 
					 | 
				
			||||||
				if (pdp_getgtp1
 | 
					 | 
				
			||||||
				    (&secondary_pdp,
 | 
					 | 
				
			||||||
				     linked_pdp->secondary_tei[n])) {
 | 
					 | 
				
			||||||
					LOGP(DLGTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
						"Unknown secondary PDP context\n");
 | 
					 | 
				
			||||||
					return EOF;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if (linked_pdp != secondary_pdp) {
 | 
					 | 
				
			||||||
					if (gsn->cb_delete_context)
 | 
					 | 
				
			||||||
						gsn->cb_delete_context
 | 
					 | 
				
			||||||
						    (secondary_pdp);
 | 
					 | 
				
			||||||
					pdp_freepdp(secondary_pdp);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (gsn->cb_delete_context)
 | 
					 | 
				
			||||||
			gsn->cb_delete_context(linked_pdp);
 | 
					 | 
				
			||||||
		pdp_freepdp(linked_pdp);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (gsn->cb_delete_context)
 | 
					 | 
				
			||||||
			gsn->cb_delete_context(pdp);
 | 
					 | 
				
			||||||
		if (pdp == linked_pdp) {
 | 
					 | 
				
			||||||
			linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
 | 
					 | 
				
			||||||
			linked_pdp->nodata = 1;
 | 
					 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
			pdp_freepdp(pdp);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2397,7 +2488,7 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
 | 
				
			|||||||
					if (pdp_getgtp1
 | 
										if (pdp_getgtp1
 | 
				
			||||||
					    (&secondary_pdp,
 | 
										    (&secondary_pdp,
 | 
				
			||||||
					     linked_pdp->secondary_tei[n])) {
 | 
										     linked_pdp->secondary_tei[n])) {
 | 
				
			||||||
						LOGP(DLGTP, LOGL_ERROR, 
 | 
											LOGP(DLGTP, LOGL_ERROR,
 | 
				
			||||||
							"Unknown secondary PDP context\n");
 | 
												"Unknown secondary PDP context\n");
 | 
				
			||||||
						return EOF;
 | 
											return EOF;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -2508,6 +2599,9 @@ int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
				if (linked_pdp->secondary_tei[n])
 | 
									if (linked_pdp->secondary_tei[n])
 | 
				
			||||||
					count++;
 | 
										count++;
 | 
				
			||||||
			if (count <= 1) {
 | 
								if (count <= 1) {
 | 
				
			||||||
 | 
									GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
 | 
				
			||||||
 | 
										   "Ignoring CTX DEL without teardown and count=%d\n",
 | 
				
			||||||
 | 
										   count);
 | 
				
			||||||
				return 0;	/* 29.060 7.3.5 Ignore message */
 | 
									return 0;	/* 29.060 7.3.5 Ignore message */
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -2525,19 +2619,32 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	uint8_t cause;
 | 
						uint8_t cause;
 | 
				
			||||||
	void *cbp = NULL;
 | 
						void *cbp = NULL;
 | 
				
			||||||
	uint8_t type = 0;
 | 
						uint8_t type = 0;
 | 
				
			||||||
 | 
						struct pdp_t *pdp = NULL;
 | 
				
			||||||
	int hlen = get_hlen(pack);
 | 
						int hlen = get_hlen(pack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Remove packet from queue */
 | 
						/* Remove packet from queue */
 | 
				
			||||||
	if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
 | 
						if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
 | 
				
			||||||
		return EOF;
 | 
							return EOF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find the context in question. It may not be available if gtp_delete_context_req
 | 
				
			||||||
 | 
						 * was used and as a result the PDP ctx was already freed */
 | 
				
			||||||
 | 
						if (pdp_getgtp1(&pdp, get_tei(pack))) {
 | 
				
			||||||
 | 
							gsn->err_unknownpdp++;
 | 
				
			||||||
 | 
							GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
 | 
				
			||||||
 | 
								    "Unknown PDP context: %u (expected if gtp_delete_context_req is used)\n",
 | 
				
			||||||
 | 
								     get_tei(pack));
 | 
				
			||||||
 | 
							if (gsn->cb_conf)
 | 
				
			||||||
 | 
								gsn->cb_conf(type, EOF, NULL, cbp);
 | 
				
			||||||
 | 
							return EOF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Decode information elements */
 | 
						/* Decode information elements */
 | 
				
			||||||
	if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
 | 
						if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
 | 
				
			||||||
		gsn->invalid++;
 | 
							gsn->invalid++;
 | 
				
			||||||
		GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
							GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
			    "Invalid message format\n");
 | 
								    "Invalid message format\n");
 | 
				
			||||||
		if (gsn->cb_conf)
 | 
							if (gsn->cb_conf)
 | 
				
			||||||
			gsn->cb_conf(type, EOF, NULL, cbp);
 | 
								gsn->cb_conf(type, EOF, pdp, cbp);
 | 
				
			||||||
		return EOF;
 | 
							return EOF;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2547,7 +2654,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
		GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
							GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
			    "Missing mandatory information field\n");
 | 
								    "Missing mandatory information field\n");
 | 
				
			||||||
		if (gsn->cb_conf)
 | 
							if (gsn->cb_conf)
 | 
				
			||||||
			gsn->cb_conf(type, EOF, NULL, cbp);
 | 
								gsn->cb_conf(type, EOF, pdp, cbp);
 | 
				
			||||||
		return EOF;
 | 
							return EOF;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2557,19 +2664,19 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
		GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
							GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
			    "Unexpected cause value received: %d\n", cause);
 | 
								    "Unexpected cause value received: %d\n", cause);
 | 
				
			||||||
		if (gsn->cb_conf)
 | 
							if (gsn->cb_conf)
 | 
				
			||||||
			gsn->cb_conf(type, cause, NULL, cbp);
 | 
								gsn->cb_conf(type, cause, pdp, cbp);
 | 
				
			||||||
		return EOF;
 | 
							return EOF;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Callback function to notify application */
 | 
						/* Callback function to notify application */
 | 
				
			||||||
	if (gsn->cb_conf)
 | 
						if (gsn->cb_conf)
 | 
				
			||||||
		gsn->cb_conf(type, cause, NULL, cbp);
 | 
							gsn->cb_conf(type, cause, pdp, cbp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send Error Indication (response to a GPDU message) - 3GPP TS 29.060 7.3.7 */
 | 
					/* Send Error Indication (response to a GPDU message) - 3GPP TS 29.060 7.3.7 */
 | 
				
			||||||
int gtp_error_ind_resp(struct gsn_t *gsn, int version,
 | 
					static int gtp_error_ind_resp(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		       struct sockaddr_in *peer, int fd,
 | 
							       struct sockaddr_in *peer, int fd,
 | 
				
			||||||
		       void *pack, unsigned len)
 | 
							       void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2591,7 +2698,7 @@ int gtp_error_ind_resp(struct gsn_t *gsn, int version,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle Error Indication */
 | 
					/* Handle Error Indication */
 | 
				
			||||||
int gtp_error_ind_conf(struct gsn_t *gsn, int version,
 | 
					static int gtp_error_ind_conf(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		       struct sockaddr_in *peer, void *pack, unsigned len)
 | 
							       struct sockaddr_in *peer, void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union gtpie_member *ie[GTPIE_SIZE];
 | 
						union gtpie_member *ie[GTPIE_SIZE];
 | 
				
			||||||
@@ -2647,16 +2754,16 @@ int gtp_error_ind_conf(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gtp_gpdu_ind(struct gsn_t *gsn, int version,
 | 
					static int gtp_gpdu_ind(struct gsn_t *gsn, uint8_t version,
 | 
				
			||||||
		 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
 | 
							 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int hlen = GTP1_HEADER_SIZE_SHORT;
 | 
						int hlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Need to include code to verify packet src and dest addresses */
 | 
					 | 
				
			||||||
	struct pdp_t *pdp;
 | 
						struct pdp_t *pdp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (version == 0) {
 | 
						switch (version) {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
		if (pdp_getgtp0
 | 
							if (pdp_getgtp0
 | 
				
			||||||
		    (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
 | 
							    (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
 | 
				
			||||||
			gsn->err_unknownpdp++;
 | 
								gsn->err_unknownpdp++;
 | 
				
			||||||
@@ -2666,7 +2773,8 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
						  len);
 | 
											  len);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		hlen = GTP0_HEADER_SIZE;
 | 
							hlen = GTP0_HEADER_SIZE;
 | 
				
			||||||
	} else if (version == 1) {
 | 
							break;
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
		if (pdp_getgtp1
 | 
							if (pdp_getgtp1
 | 
				
			||||||
		    (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) {
 | 
							    (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) {
 | 
				
			||||||
			gsn->err_unknownpdp++;
 | 
								gsn->err_unknownpdp++;
 | 
				
			||||||
@@ -2681,9 +2789,11 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
			hlen = GTP1_HEADER_SIZE_LONG;
 | 
								hlen = GTP1_HEADER_SIZE_LONG;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			hlen = GTP1_HEADER_SIZE_SHORT;
 | 
								hlen = GTP1_HEADER_SIZE_SHORT;
 | 
				
			||||||
	} else {
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
		GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
							GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
 | 
				
			||||||
			    "Unknown version: %d\n", version);
 | 
								    "Unknown version: %d\n", version);
 | 
				
			||||||
 | 
							return EOF;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the GPDU was not from the peer GSN tell him to delete context */
 | 
						/* If the GPDU was not from the peer GSN tell him to delete context */
 | 
				
			||||||
@@ -2700,10 +2810,10 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Receives GTP packet and sends off for further processing 
 | 
					/* Receives GTP packet and sends off for further processing
 | 
				
			||||||
 * Function will check the validity of the header. If the header
 | 
					 * Function will check the validity of the header. If the header
 | 
				
			||||||
 * is not valid the packet is either dropped or a version not 
 | 
					 * is not valid the packet is either dropped or a version not
 | 
				
			||||||
 * supported is returned to the peer. 
 | 
					 * supported is returned to the peer.
 | 
				
			||||||
 * TODO: Need to decide on return values! */
 | 
					 * TODO: Need to decide on return values! */
 | 
				
			||||||
int gtp_decaps0(struct gsn_t *gsn)
 | 
					int gtp_decaps0(struct gsn_t *gsn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2712,7 +2822,7 @@ int gtp_decaps0(struct gsn_t *gsn)
 | 
				
			|||||||
	socklen_t peerlen;
 | 
						socklen_t peerlen;
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
	struct gtp0_header *pheader;
 | 
						struct gtp0_header *pheader;
 | 
				
			||||||
	int version = 0;	/* GTP version should be determined from header! */
 | 
						uint8_t version;
 | 
				
			||||||
	int fd = gsn->fd0;
 | 
						int fd = gsn->fd0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Need strategy of userspace buffering and blocking */
 | 
						/* TODO: Need strategy of userspace buffering and blocking */
 | 
				
			||||||
@@ -2748,15 +2858,17 @@ int gtp_decaps0(struct gsn_t *gsn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		pheader = (struct gtp0_header *)(buffer);
 | 
							pheader = (struct gtp0_header *)(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							version = GTPHDR_F_GET_VER(pheader->flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Version should be gtp0 (or earlier) */
 | 
							/* Version should be gtp0 (or earlier) */
 | 
				
			||||||
		/* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
 | 
							/* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
 | 
				
			||||||
		/* GTP 0 messages. If other version message is received we reply that we */
 | 
							/* GTP 0 messages. If other version message is received we reply that we */
 | 
				
			||||||
		/* only support version 0, implying that this is the only version */
 | 
							/* only support version 0, implying that this is the only version */
 | 
				
			||||||
		/* supported on this port */
 | 
							/* supported on this port */
 | 
				
			||||||
		if (GTPHDR_F_GET_VER(pheader->flags) > 0) {
 | 
							if (version > 0) {
 | 
				
			||||||
			gsn->unsup++;
 | 
								gsn->unsup++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
 | 
				
			||||||
				    status, "Unsupported GTP version\n");
 | 
									"Unsupported GTP version %"PRIu8"\n", version);
 | 
				
			||||||
			gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status);	/* 29.60: 11.1.1 */
 | 
								gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status);	/* 29.60: 11.1.1 */
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -2780,23 +2892,23 @@ int gtp_decaps0(struct gsn_t *gsn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if ((gsn->mode == GTP_MODE_GGSN) &&
 | 
							if ((gsn->mode == GTP_MODE_GGSN) &&
 | 
				
			||||||
		    ((pheader->type == GTP_CREATE_PDP_RSP) ||
 | 
							    ((pheader->type == GTP_CREATE_PDP_RSP) ||
 | 
				
			||||||
		     (pheader->type == GTP_UPDATE_PDP_RSP) ||
 | 
							     (pheader->type == GTP_UPDATE_PDP_RSP))) {
 | 
				
			||||||
		     (pheader->type == GTP_DELETE_PDP_RSP))) {
 | 
					 | 
				
			||||||
			gsn->unexpect++;
 | 
								gsn->unexpect++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
				
			||||||
				    status,
 | 
									    status,
 | 
				
			||||||
				    "Unexpected GTPv0 Signalling Message\n");
 | 
									    "Unexpected GTPv0 Signalling Message '%s'\n",
 | 
				
			||||||
 | 
									    get_value_string(gtp_type_names, pheader->type));
 | 
				
			||||||
			continue;	/* Silently discard 29.60: 11.1.4 */
 | 
								continue;	/* Silently discard 29.60: 11.1.4 */
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((gsn->mode == GTP_MODE_SGSN) &&
 | 
							if ((gsn->mode == GTP_MODE_SGSN) &&
 | 
				
			||||||
		    ((pheader->type == GTP_CREATE_PDP_REQ) ||
 | 
							    ((pheader->type == GTP_CREATE_PDP_REQ) ||
 | 
				
			||||||
		     (pheader->type == GTP_UPDATE_PDP_REQ) ||
 | 
							     (pheader->type == GTP_UPDATE_PDP_REQ))) {
 | 
				
			||||||
		     (pheader->type == GTP_DELETE_PDP_REQ))) {
 | 
					 | 
				
			||||||
			gsn->unexpect++;
 | 
								gsn->unexpect++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
				
			||||||
				    status,
 | 
									    status,
 | 
				
			||||||
				    "Unexpected GTPv0 Signalling Message\n");
 | 
									    "Unexpected GTPv0 Signalling Message '%s'\n",
 | 
				
			||||||
 | 
									    get_value_string(gtp_type_names, pheader->type));
 | 
				
			||||||
			continue;	/* Silently discard 29.60: 11.1.4 */
 | 
								continue;	/* Silently discard 29.60: 11.1.4 */
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2857,7 +2969,7 @@ int gtp_decaps1c(struct gsn_t *gsn)
 | 
				
			|||||||
	socklen_t peerlen;
 | 
						socklen_t peerlen;
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
	struct gtp1_header_short *pheader;
 | 
						struct gtp1_header_short *pheader;
 | 
				
			||||||
	int version = 1;	/* TODO GTP version should be determined from header! */
 | 
						uint8_t version;
 | 
				
			||||||
	int fd = gsn->fd1c;
 | 
						int fd = gsn->fd1c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Need strategy of userspace buffering and blocking */
 | 
						/* TODO: Need strategy of userspace buffering and blocking */
 | 
				
			||||||
@@ -2893,11 +3005,13 @@ int gtp_decaps1c(struct gsn_t *gsn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		pheader = (struct gtp1_header_short *)(buffer);
 | 
							pheader = (struct gtp1_header_short *)(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							version = GTPHDR_F_GET_VER(pheader->flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Version must be no larger than GTP 1 */
 | 
							/* Version must be no larger than GTP 1 */
 | 
				
			||||||
		if (GTPHDR_F_GET_VER(pheader->flags) > 1) {
 | 
							if (version > 1) {
 | 
				
			||||||
			gsn->unsup++;
 | 
								gsn->unsup++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
 | 
				
			||||||
				    status, "Unsupported GTP version\n");
 | 
									"Unsupported GTP version %"PRIu8"\n", version);
 | 
				
			||||||
			gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
 | 
								gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
 | 
				
			||||||
			/*29.60: 11.1.1 */
 | 
								/*29.60: 11.1.1 */
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
@@ -2907,10 +3021,10 @@ int gtp_decaps1c(struct gsn_t *gsn)
 | 
				
			|||||||
		/* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
 | 
							/* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
 | 
				
			||||||
		/* GTP 1 messages. If GTP 0 message is received we silently discard */
 | 
							/* GTP 1 messages. If GTP 0 message is received we silently discard */
 | 
				
			||||||
		/* the message */
 | 
							/* the message */
 | 
				
			||||||
		if (GTPHDR_F_GET_VER(pheader->flags) < 1) {
 | 
							if (version < 1) {
 | 
				
			||||||
			gsn->unsup++;
 | 
								gsn->unsup++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
 | 
				
			||||||
				    status, "Unsupported GTP version\n");
 | 
									"Unsupported GTP version %"PRIu8"\n", version);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2955,23 +3069,23 @@ int gtp_decaps1c(struct gsn_t *gsn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if ((gsn->mode == GTP_MODE_GGSN) &&
 | 
							if ((gsn->mode == GTP_MODE_GGSN) &&
 | 
				
			||||||
		    ((pheader->type == GTP_CREATE_PDP_RSP) ||
 | 
							    ((pheader->type == GTP_CREATE_PDP_RSP) ||
 | 
				
			||||||
		     (pheader->type == GTP_UPDATE_PDP_RSP) ||
 | 
							     (pheader->type == GTP_UPDATE_PDP_RSP))) {
 | 
				
			||||||
		     (pheader->type == GTP_DELETE_PDP_RSP))) {
 | 
					 | 
				
			||||||
			gsn->unexpect++;
 | 
								gsn->unexpect++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
				
			||||||
				    status,
 | 
									    status,
 | 
				
			||||||
				    "Unexpected GTPv1 Signalling Message\n");
 | 
									    "Unexpected GTPv1 Signalling Message '%s'\n",
 | 
				
			||||||
 | 
									    get_value_string(gtp_type_names, pheader->type));
 | 
				
			||||||
			continue;	/* Silently discard 29.60: 11.1.4 */
 | 
								continue;	/* Silently discard 29.60: 11.1.4 */
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((gsn->mode == GTP_MODE_SGSN) &&
 | 
							if ((gsn->mode == GTP_MODE_SGSN) &&
 | 
				
			||||||
		    ((pheader->type == GTP_CREATE_PDP_REQ) ||
 | 
							    ((pheader->type == GTP_CREATE_PDP_REQ) ||
 | 
				
			||||||
		     (pheader->type == GTP_UPDATE_PDP_REQ) ||
 | 
							     (pheader->type == GTP_UPDATE_PDP_REQ))) {
 | 
				
			||||||
		     (pheader->type == GTP_DELETE_PDP_REQ))) {
 | 
					 | 
				
			||||||
			gsn->unexpect++;
 | 
								gsn->unexpect++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
				
			||||||
				    status,
 | 
									    status,
 | 
				
			||||||
				    "Unexpected GTPv1 Signalling Message\n");
 | 
									    "Unexpected GTPv1 Signalling Message '%s'\n",
 | 
				
			||||||
 | 
									    get_value_string(gtp_type_names, pheader->type));
 | 
				
			||||||
			continue;	/* Silently discard 29.60: 11.1.4 */
 | 
								continue;	/* Silently discard 29.60: 11.1.4 */
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3032,7 +3146,7 @@ int gtp_decaps1u(struct gsn_t *gsn)
 | 
				
			|||||||
	socklen_t peerlen;
 | 
						socklen_t peerlen;
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
	struct gtp1_header_short *pheader;
 | 
						struct gtp1_header_short *pheader;
 | 
				
			||||||
	int version = 1;	/* GTP version should be determined from header! */
 | 
						uint8_t version;
 | 
				
			||||||
	int fd = gsn->fd1u;
 | 
						int fd = gsn->fd1u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Need strategy of userspace buffering and blocking */
 | 
						/* TODO: Need strategy of userspace buffering and blocking */
 | 
				
			||||||
@@ -3069,11 +3183,13 @@ int gtp_decaps1u(struct gsn_t *gsn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		pheader = (struct gtp1_header_short *)(buffer);
 | 
							pheader = (struct gtp1_header_short *)(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							version = GTPHDR_F_GET_VER(pheader->flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Version must be no larger than GTP 1 */
 | 
							/* Version must be no larger than GTP 1 */
 | 
				
			||||||
		if (GTPHDR_F_GET_VER(pheader->flags) > 1) {
 | 
							if (version > 1) {
 | 
				
			||||||
			gsn->unsup++;
 | 
								gsn->unsup++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
 | 
				
			||||||
				    status, "Unsupported GTP version\n");
 | 
									"Unsupported GTP version %"PRIu8"\n", version);
 | 
				
			||||||
			gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);	/*29.60: 11.1.1 */
 | 
								gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);	/*29.60: 11.1.1 */
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -3082,10 +3198,10 @@ int gtp_decaps1u(struct gsn_t *gsn)
 | 
				
			|||||||
		/* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
 | 
							/* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
 | 
				
			||||||
		/* GTP 1 messages. If GTP 0 message is received we silently discard */
 | 
							/* GTP 1 messages. If GTP 0 message is received we silently discard */
 | 
				
			||||||
		/* the message */
 | 
							/* the message */
 | 
				
			||||||
		if (GTPHDR_F_GET_VER(pheader->flags) < 1) {
 | 
							if (version < 1) {
 | 
				
			||||||
			gsn->unsup++;
 | 
								gsn->unsup++;
 | 
				
			||||||
			GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
 | 
								GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
 | 
				
			||||||
				    status, "Unsupported GTP version\n");
 | 
									"Unsupported GTP version %"PRIu8"\n", version);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3241,19 +3357,10 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
 | 
				
			|||||||
 * Conversion functions
 | 
					 * Conversion functions
 | 
				
			||||||
 *************************************************************/
 | 
					 *************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int char2ul_t(char *src, struct ul_t dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	dst.l = strlen(src) + 1;
 | 
					 | 
				
			||||||
	dst.v = malloc(dst.l);
 | 
					 | 
				
			||||||
	dst.v[0] = dst.l - 1;
 | 
					 | 
				
			||||||
	memcpy(&dst.v[1], src, dst.v[0]);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* ***********************************************************
 | 
					/* ***********************************************************
 | 
				
			||||||
 * IP address conversion functions
 | 
					 * IP address conversion functions
 | 
				
			||||||
 * There exist several types of address representations:
 | 
					 * There exist several types of address representations:
 | 
				
			||||||
 * - eua: End User Address. (29.060, 7.7.27, message type 128) 
 | 
					 * - eua: End User Address. (29.060, 7.7.27, message type 128)
 | 
				
			||||||
 *   Used for signalling address to mobile station. Supports IPv4
 | 
					 *   Used for signalling address to mobile station. Supports IPv4
 | 
				
			||||||
 *   IPv6 x.25 etc. etc.
 | 
					 *   IPv6 x.25 etc. etc.
 | 
				
			||||||
 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
 | 
					 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								gtp/gtp.h
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								gtp/gtp.h
									
									
									
									
									
								
							@@ -12,6 +12,9 @@
 | 
				
			|||||||
#ifndef _GTP_H
 | 
					#ifndef _GTP_H
 | 
				
			||||||
#define _GTP_H
 | 
					#define _GTP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GTP_MODE_GGSN 1
 | 
					#define GTP_MODE_GGSN 1
 | 
				
			||||||
#define GTP_MODE_SGSN 2
 | 
					#define GTP_MODE_SGSN 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,6 +88,10 @@
 | 
				
			|||||||
/* 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 */
 | 
				
			||||||
@@ -264,6 +271,7 @@ struct gsn_t {
 | 
				
			|||||||
	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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Counters */
 | 
						/* Counters */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -317,7 +325,10 @@ 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);
 | 
				
			||||||
@@ -351,6 +362,11 @@ extern int gtp_set_cb_conf(struct gsn_t *gsn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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));
 | 
									   uint8_t recovery));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Internal functions (not part of the API */
 | 
					/* Internal functions (not part of the API */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								gtp/pdp.c
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								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:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,17 +44,17 @@ static struct pdp_t *hashtid[PDP_MAX];	/* Hash table for IMSI + NSAPI */
 | 
				
			|||||||
 * 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 +64,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 +85,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.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -296,7 +296,7 @@ int pdp_iphash(void* ipif, struct ul66_t *eua) {
 | 
				
			|||||||
  /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
 | 
					  /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
 | 
				
			||||||
  return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
 | 
					  return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
 | 
					int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
 | 
				
			||||||
  int hash;
 | 
					  int hash;
 | 
				
			||||||
  struct pdp_t *pdp2;
 | 
					  struct pdp_t *pdp2;
 | 
				
			||||||
@@ -304,7 +304,7 @@ int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
 | 
					  if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
 | 
				
			||||||
			(unsigned) ipif, eua->l,
 | 
								(unsigned) ipif, eua->l,
 | 
				
			||||||
			eua->v[2], eua->v[3], 
 | 
								eua->v[2], eua->v[3],
 | 
				
			||||||
			eua->v[4], eua->v[5]);
 | 
								eua->v[4], eua->v[5]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pdp->ipnext = NULL;
 | 
					  pdp->ipnext = NULL;
 | 
				
			||||||
@@ -316,9 +316,9 @@ int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
 | 
					  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
 | 
				
			||||||
    pdp_prev = pdp2;
 | 
					    pdp_prev = pdp2;
 | 
				
			||||||
  if (!pdp_prev) 
 | 
					  if (!pdp_prev)
 | 
				
			||||||
    haship[hash] = pdp;
 | 
					    haship[hash] = pdp;
 | 
				
			||||||
  else 
 | 
					  else
 | 
				
			||||||
    pdp_prev->ipnext = pdp;
 | 
					    pdp_prev->ipnext = pdp;
 | 
				
			||||||
  if (PDP_DEBUG) printf("End pdp_ipset\n");
 | 
					  if (PDP_DEBUG) printf("End pdp_ipset\n");
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
@@ -331,9 +331,9 @@ int pdp_ipdel(struct pdp_t *pdp) {
 | 
				
			|||||||
  if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
 | 
					  if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
					  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
				
			||||||
    if (pdp2 == pdp) {
 | 
					    if (pdp2 == pdp) {
 | 
				
			||||||
      if (!pdp_prev) 
 | 
					      if (!pdp_prev)
 | 
				
			||||||
	haship[hash] = pdp2->ipnext;
 | 
						haship[hash] = pdp2->ipnext;
 | 
				
			||||||
      else 
 | 
					      else
 | 
				
			||||||
	pdp_prev->ipnext = pdp2->ipnext;
 | 
						pdp_prev->ipnext = pdp2->ipnext;
 | 
				
			||||||
      if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
 | 
					      if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
@@ -347,41 +347,23 @@ int pdp_ipdel(struct pdp_t *pdp) {
 | 
				
			|||||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
 | 
					int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
 | 
				
			||||||
  int hash = pdp_iphash(ipif, eua);
 | 
					  int hash = pdp_iphash(ipif, eua);
 | 
				
			||||||
  struct pdp_t *pdp2;
 | 
					  struct pdp_t *pdp2;
 | 
				
			||||||
  /#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l, 
 | 
					  /#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]);#/
 | 
					    eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
 | 
				
			||||||
  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
					  for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
 | 
				
			||||||
    if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) && 
 | 
					    if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
 | 
				
			||||||
	(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
 | 
						(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
 | 
				
			||||||
      *pdp = pdp2;
 | 
					      *pdp = pdp2;
 | 
				
			||||||
      /#printf("End pdp_ipget. Found\n");#/
 | 
					      /#printf("End pdp_ipget. Found\n");#/
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n", 
 | 
					  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]);
 | 
						 (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 #/
 | 
					  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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								gtp/pdp.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								gtp/pdp.h
									
									
									
									
									
								
							@@ -1,13 +1,13 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  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
 | 
				
			||||||
@@ -26,6 +26,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 +72,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 +89,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 +122,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. */
 | 
				
			||||||
@@ -266,8 +267,6 @@ int pdp_ipdel(struct pdp_t *pdp);
 | 
				
			|||||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua);
 | 
					int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua);
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_PDP_H */
 | 
					#endif /* !_PDP_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ENABLE_GTP_KERNEL
 | 
				
			||||||
 | 
					AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
 | 
				
			||||||
 | 
					libmisc_a_SOURCES += gtp-kernel.c
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,56 +77,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) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										109
									
								
								lib/in46_addr.c
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								lib/in46_addr.c
									
									
									
									
									
								
							@@ -253,33 +253,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 +328,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,5 @@ 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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										727
									
								
								lib/netdev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										727
									
								
								lib/netdev.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,727 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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_addroute(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 = 64;	/* 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_route(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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_addroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route(dst, gateway, mask, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int netdev_delroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return netdev_route(dst, gateway, mask, 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										72
									
								
								lib/netdev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/netdev.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					#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_addroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
 | 
				
			||||||
 | 
					extern int netdev_delroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list,
 | 
				
			||||||
 | 
									size_t prefix_size, int flags);
 | 
				
			||||||
							
								
								
									
										672
									
								
								lib/tun.c
									
									
									
									
									
								
							
							
						
						
									
										672
									
								
								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,98 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
	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, 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 (addr) {		/* Set the interface address */
 | 
					 | 
				
			||||||
		this->addr.s_addr = addr->s_addr;
 | 
							this->addr.s_addr = addr->s_addr;
 | 
				
			||||||
		memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
 | 
						if (dstaddr)
 | 
				
			||||||
		       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 */
 | 
					 | 
				
			||||||
		this->dstaddr.s_addr = dstaddr->s_addr;
 | 
							this->dstaddr.s_addr = dstaddr->s_addr;
 | 
				
			||||||
		memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
 | 
						if (netmask)
 | 
				
			||||||
		       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) {
 | 
					 | 
				
			||||||
		memcpy(&this->dstaddr, dstaddr, sizeof(*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)
 | 
						if (dstaddr)
 | 
				
			||||||
		memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
 | 
							memcpy(&this->dstaddr, dstaddr, sizeof(*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 +172,50 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ioctl((*tun)->fd, TUNSETNOCSUM, 1);	/* Disable checksums */
 | 
				
			||||||
 | 
							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 +267,17 @@ int tun_free(struct tun_t *tun)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tun->routes) {
 | 
						if (tun->routes) {
 | 
				
			||||||
		tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
 | 
							netdev_delroute(&tun->dstaddr, &tun->addr, &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);
 | 
				
			||||||
@@ -745,79 +338,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.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										54
									
								
								lib/tun.h
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								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
 | 
				
			||||||
@@ -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,9 +56,6 @@ 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,14 @@ 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",
 | 
				
			||||||
 | 
						"\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')",
 | 
				
			||||||
@@ -168,6 +170,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
 | 
				
			||||||
@@ -290,19 +294,19 @@ 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->pinghost_help = gengetopt_args_info_help[39];
 | 
				
			||||||
	args_info->pingrate_help = gengetopt_args_info_help[38];
 | 
						args_info->pingrate_help = gengetopt_args_info_help[40];
 | 
				
			||||||
	args_info->pingsize_help = gengetopt_args_info_help[39];
 | 
						args_info->pingsize_help = gengetopt_args_info_help[41];
 | 
				
			||||||
	args_info->pingcount_help = gengetopt_args_info_help[40];
 | 
						args_info->pingcount_help = gengetopt_args_info_help[42];
 | 
				
			||||||
	args_info->pingquiet_help = gengetopt_args_info_help[41];
 | 
						args_info->pingquiet_help = gengetopt_args_info_help[43];
 | 
				
			||||||
	args_info->no_tx_gpdu_seq_help = gengetopt_args_info_help[42];
 | 
						args_info->no_tx_gpdu_seq_help = gengetopt_args_info_help[44];
 | 
				
			||||||
	args_info->pdp_type_help = gengetopt_args_info_help[43];
 | 
						args_info->pdp_type_help = gengetopt_args_info_help[45];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -361,8 +365,7 @@ void cmdline_parser_params_init(struct cmdline_parser_params *params)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct cmdline_parser_params *cmdline_parser_params_create(void)
 | 
					struct cmdline_parser_params *cmdline_parser_params_create(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cmdline_parser_params *params =
 | 
						struct cmdline_parser_params *params = (struct cmdline_parser_params *)
 | 
				
			||||||
	    (struct cmdline_parser_params *)
 | 
					 | 
				
			||||||
	    malloc(sizeof(struct cmdline_parser_params));
 | 
						    malloc(sizeof(struct cmdline_parser_params));
 | 
				
			||||||
	cmdline_parser_params_init(params);
 | 
						cmdline_parser_params_init(params);
 | 
				
			||||||
	return params;
 | 
						return params;
 | 
				
			||||||
@@ -853,6 +856,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,
 | 
				
			||||||
@@ -976,7 +1003,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 +1100,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 +1419,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 +1434,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 +1449,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 +1465,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 +1481,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),
 | 
				
			||||||
@@ -1465,6 +1498,7 @@ cmdline_parser_internal(int argc, char **argv,
 | 
				
			|||||||
			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 +1515,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 +1531,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 +1548,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 +1564,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 +1604,31 @@ 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, -1
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							const char *createif_desc[] =
 | 
				
			||||||
 | 
							    { "--createif", "--net", "--defaultroute", "--ipup",
 | 
				
			||||||
 | 
								"--ipdown", "--tun-device", 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,18 @@ 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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
				
			||||||
@@ -370,6 +370,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 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
/* 
 | 
					/*
 | 
				
			||||||
 *  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.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -20,6 +20,7 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <netdb.h>
 | 
					#include <netdb.h>
 | 
				
			||||||
@@ -79,13 +80,14 @@ struct gsn_t *gsn = NULL;	/* GSN instance */
 | 
				
			|||||||
struct tun_t *tun = NULL;	/* TUN instance */
 | 
					struct tun_t *tun = NULL;	/* TUN instance */
 | 
				
			||||||
int maxfd = 0;			/* For select() */
 | 
					int maxfd = 0;			/* For select() */
 | 
				
			||||||
int echoversion = 1;		/* First try this version */
 | 
					int echoversion = 1;		/* First try this version */
 | 
				
			||||||
 | 
					void *tall_sgsnemu_ctx;		/* root talloc ctx */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Struct with local versions of gengetopt options */
 | 
					/* Struct with local versions of gengetopt options */
 | 
				
			||||||
struct {
 | 
					struct {
 | 
				
			||||||
	int debug;		/* Print debug messages */
 | 
						int debug;		/* Print debug messages */
 | 
				
			||||||
	int createif;		/* Create local network interface */
 | 
						int createif;		/* Create local network interface */
 | 
				
			||||||
	char *tun_dev_name;
 | 
						char *tun_dev_name;
 | 
				
			||||||
	struct in_addr netaddr, destaddr, net;	/* Network interface  */
 | 
						struct in46_addr netaddr, destaddr, net;	/* Network interface  */
 | 
				
			||||||
	size_t prefixlen;
 | 
						size_t prefixlen;
 | 
				
			||||||
	char *ipup, *ipdown;	/* Filename of scripts */
 | 
						char *ipup, *ipdown;	/* Filename of scripts */
 | 
				
			||||||
	int defaultroute;	/* Set up default route */
 | 
						int defaultroute;	/* Set up default route */
 | 
				
			||||||
@@ -372,10 +374,10 @@ static int process_options(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* foreground                                                   */
 | 
						/* foreground                                                   */
 | 
				
			||||||
	/* If fg flag not given run as a daemon                         */
 | 
						/* If fg flag not given run as a daemon                         */
 | 
				
			||||||
	/* Do not allow sgsnemu to run as deamon                        
 | 
						/* Do not allow sgsnemu to run as deamon
 | 
				
			||||||
	   if (!args_info.fg_flag)
 | 
						   if (!args_info.fg_flag)
 | 
				
			||||||
	   {
 | 
						   {
 | 
				
			||||||
	   closelog(); 
 | 
						   closelog();
 | 
				
			||||||
	   freopen("/dev/null", "w", stdout);
 | 
						   freopen("/dev/null", "w", stdout);
 | 
				
			||||||
	   freopen("/dev/null", "w", stderr);
 | 
						   freopen("/dev/null", "w", stderr);
 | 
				
			||||||
	   freopen("/dev/null", "r", stdin);
 | 
						   freopen("/dev/null", "r", stdin);
 | 
				
			||||||
@@ -873,23 +875,21 @@ static int process_options(int argc, char **argv)
 | 
				
			|||||||
	/* net                                                          */
 | 
						/* net                                                          */
 | 
				
			||||||
	/* Store net as in_addr net and mask                            */
 | 
						/* Store net as in_addr net and mask                            */
 | 
				
			||||||
	if (args_info.net_arg) {
 | 
						if (args_info.net_arg) {
 | 
				
			||||||
		struct in46_addr in46;
 | 
					 | 
				
			||||||
		if (ippool_aton
 | 
							if (ippool_aton
 | 
				
			||||||
		    (&in46, &options.prefixlen, args_info.net_arg, 0)) {
 | 
							    (&options.net, &options.prefixlen, args_info.net_arg, 0)) {
 | 
				
			||||||
			SYS_ERR(DSGSN, LOGL_ERROR, 0,
 | 
								SYS_ERR(DSGSN, LOGL_ERROR, 0,
 | 
				
			||||||
				"Invalid network address: %s!",
 | 
									"Invalid network address: %s!",
 | 
				
			||||||
				args_info.net_arg);
 | 
									args_info.net_arg);
 | 
				
			||||||
			exit(1);
 | 
								exit(1);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		options.net.s_addr = in46.v4.s_addr;
 | 
							options.netaddr = options.net;
 | 
				
			||||||
		options.netaddr.s_addr = options.net.s_addr;
 | 
							options.destaddr = options.net;
 | 
				
			||||||
		options.destaddr.s_addr = options.net.s_addr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		options.net.s_addr = 0;
 | 
							memset(&options.net, 0, sizeof(options.net));
 | 
				
			||||||
		options.prefixlen = 0;
 | 
							options.prefixlen = 0;
 | 
				
			||||||
		options.netaddr.s_addr = 0;
 | 
							memset(&options.netaddr, 0, sizeof(options.netaddr));
 | 
				
			||||||
		options.destaddr.s_addr = 0;
 | 
							memset(&options.destaddr, 0, sizeof(options.destaddr));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ipup */
 | 
						/* ipup */
 | 
				
			||||||
@@ -1314,8 +1314,8 @@ static int delete_context(struct pdp_t *pdp)
 | 
				
			|||||||
	if (tun && options.ipdown)
 | 
						if (tun && options.ipdown)
 | 
				
			||||||
		tun_runscript(tun, options.ipdown);
 | 
							tun_runscript(tun, options.ipdown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipdel((struct iphash_t *)pdp->peer);
 | 
						ipdel((struct iphash_t *)pdp->peer[0]);
 | 
				
			||||||
	memset(pdp->peer, 0, sizeof(struct iphash_t));	/* To be sure */
 | 
						memset(pdp->peer[0], 0, sizeof(struct iphash_t));	/* To be sure */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (1 == options.contexts)
 | 
						if (1 == options.contexts)
 | 
				
			||||||
		state = 5;	/* Disconnected */
 | 
							state = 5;	/* Disconnected */
 | 
				
			||||||
@@ -1402,7 +1402,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
 | 
				
			|||||||
		return EOF;	/* Not what we expected */
 | 
							return EOF;	/* Not what we expected */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (in46a_from_eua(&pdp->eua, &addr)) {
 | 
						if (in46a_from_eua(&pdp->eua, &addr) < 1) {
 | 
				
			||||||
		printf
 | 
							printf
 | 
				
			||||||
		    ("Received create PDP context response. Cause value: %d\n",
 | 
							    ("Received create PDP context response. Cause value: %d\n",
 | 
				
			||||||
		     cause);
 | 
							     cause);
 | 
				
			||||||
@@ -1427,17 +1427,16 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((options.createif) && (!options.net.s_addr)) {
 | 
						if ((options.createif) && (!options.net.len)) {
 | 
				
			||||||
		size_t prefixlen = 32;
 | 
							size_t prefixlen = 32;
 | 
				
			||||||
		if (addr.len == 16)
 | 
							if (addr.len == 16)
 | 
				
			||||||
			prefixlen = 64;
 | 
								prefixlen = 64;
 | 
				
			||||||
		/* printf("Setting up interface and routing\n"); */
 | 
							/* printf("Setting up interface and routing\n"); */
 | 
				
			||||||
		/* FIXME: use tun_addattr() not tun_setaddr() */
 | 
							tun_addaddr(tun, &addr, &addr, prefixlen);
 | 
				
			||||||
		tun_setaddr(tun, &addr, &addr, prefixlen);
 | 
					 | 
				
			||||||
		if (options.defaultroute) {
 | 
							if (options.defaultroute) {
 | 
				
			||||||
			struct in_addr rm;
 | 
								struct in_addr rm;
 | 
				
			||||||
			rm.s_addr = 0;
 | 
								rm.s_addr = 0;
 | 
				
			||||||
			tun_addroute(tun, &rm, &addr.v4, &rm);
 | 
								netdev_addroute(&rm, &addr.v4, &rm);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (options.ipup)
 | 
							if (options.ipup)
 | 
				
			||||||
			tun_runscript(tun, options.ipup);
 | 
								tun_runscript(tun, options.ipup);
 | 
				
			||||||
@@ -1464,7 +1463,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
 | 
				
			|||||||
		free(forwarding);
 | 
							free(forwarding);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipset((struct iphash_t *)pdp->peer, &addr);
 | 
						ipset(iph, &addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state = 2;		/* Connected */
 | 
						state = 2;		/* Connected */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1542,7 +1541,9 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	signal(SIGHUP,  signal_handler);
 | 
						signal(SIGHUP,  signal_handler);
 | 
				
			||||||
	signal(SIGINT,  signal_handler);
 | 
						signal(SIGINT,  signal_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_init_logging(&log_info);
 | 
						tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Process options given in configuration file and command line */
 | 
						/* Process options given in configuration file and command line */
 | 
				
			||||||
	if (process_options(argc, argv))
 | 
						if (process_options(argc, argv))
 | 
				
			||||||
@@ -1570,7 +1571,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	if (options.createif) {
 | 
						if (options.createif) {
 | 
				
			||||||
		printf("Setting up interface\n");
 | 
							printf("Setting up interface\n");
 | 
				
			||||||
		/* Create a tunnel interface */
 | 
							/* Create a tunnel interface */
 | 
				
			||||||
		if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
 | 
							if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
 | 
				
			||||||
			SYS_ERR(DSGSN, LOGL_ERROR, 0,
 | 
								SYS_ERR(DSGSN, LOGL_ERROR, 0,
 | 
				
			||||||
				"Failed to create tun");
 | 
									"Failed to create tun");
 | 
				
			||||||
			exit(1);
 | 
								exit(1);
 | 
				
			||||||
@@ -1580,15 +1581,13 @@ int main(int argc, char **argv)
 | 
				
			|||||||
			maxfd = tun->fd;
 | 
								maxfd = tun->fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((options.createif) && (options.net.s_addr)) {
 | 
						if ((options.createif) && (options.net.len)) {
 | 
				
			||||||
		struct in_addr mask;
 | 
					 | 
				
			||||||
		mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
 | 
					 | 
				
			||||||
		/* printf("Setting up interface and routing\n"); */
 | 
							/* printf("Setting up interface and routing\n"); */
 | 
				
			||||||
		tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
 | 
							tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
 | 
				
			||||||
		if (options.defaultroute) {
 | 
							if (options.defaultroute) {
 | 
				
			||||||
			struct in_addr rm;
 | 
								struct in_addr rm;
 | 
				
			||||||
			rm.s_addr = 0;
 | 
								rm.s_addr = 0;
 | 
				
			||||||
			tun_addroute(tun, &rm, &options.destaddr, &rm);
 | 
								netdev_addroute(&rm, &options.destaddr.v4, &rm);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (options.ipup)
 | 
							if (options.ipup)
 | 
				
			||||||
			tun_runscript(tun, options.ipup);
 | 
								tun_runscript(tun, options.ipup);
 | 
				
			||||||
@@ -1617,7 +1616,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		/* Otherwise it is deallocated by gtplib */
 | 
							/* Otherwise it is deallocated by gtplib */
 | 
				
			||||||
		pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
 | 
							pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pdp->peer = &iparr[n];
 | 
							pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
 | 
				
			||||||
		pdp->ipif = tun;	/* TODO */
 | 
							pdp->ipif = tun;	/* TODO */
 | 
				
			||||||
		iparr[n].pdp = pdp;
 | 
							iparr[n].pdp = pdp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1700,7 +1699,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		pdp->hisaddr0 = options.remote;
 | 
							pdp->hisaddr0 = options.remote;
 | 
				
			||||||
		pdp->hisaddr1 = options.remote;
 | 
							pdp->hisaddr1 = options.remote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pdp->cch_pdp = options.cch;	/* 2048 = Normal, 1024 = Prepaid, 
 | 
							pdp->cch_pdp = options.cch;	/* 2048 = Normal, 1024 = Prepaid,
 | 
				
			||||||
						   512 = Flat rate, 256 = Hot billing */
 | 
											   512 = Flat rate, 256 = Hot billing */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pdp->tx_gpdu_seq = options.tx_gpdu_seq;
 | 
							pdp->tx_gpdu_seq = options.tx_gpdu_seq;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,7 +109,9 @@ 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_filename(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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_filename(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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,31 @@ 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_filename(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,12 +8,25 @@ 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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user