9
0
Fork 0

Compare commits

...

178 Commits
0.91 ... master

Author SHA1 Message Date
Harald Welte be529a8bb1 update git URLs (git -> https; gitea)
Change-Id: I4ee58510742bcee8307bbd9c3897d5ef90e63c8a
2022-06-17 23:09:21 +02:00
Harald Welte 242266da78 contrib/jenkins.sh: Allow jenkins job to specify if kernel GTP is used
Change-Id: Id9869d0f3d516b5380430675f879887468b5803d
2017-11-14 14:44:06 +09:00
Harald Welte 6045efb642 sgsnemu: Fix gengetopt package name
gengetopt by default picks the program name from PACKAGE (autotools),
which is openggsn and is obviously wrong in case of sgsnemu.

After this patch, "sgsnemu --help" no longer shows "openggsn" but
"sgsnemu" at the top of the help text.

Change-Id: Ifabc2435a503ef71aa5a002ca46833f329068b37
2017-09-24 10:55:26 +08:00
Harald Welte 078bc097fc sgsnemu: Re-generate cmdline.[ch] using gengetopt
This will replace the manual additions to cmdline.[ch] with
auto-generated code from gengetopt.  We need to fix-up the RAT Type in
sgsnemu.c as the manually-added code diverged from what gengetopt
generates.

Change-Id: Ia687e13d5cec1655a57078a767d2123aa022842c
2017-09-24 10:47:50 +08:00
Harald Welte 3cce289e4b sgsnemu: Fix up gengetopt file for --norecovery
In commit 3a4c67b4bf we introduced the
--norecovery command line option, but this was apparently done by
manually editing the C source code rather than adding it to the .ggo
and letting gengetopt do its magic.  Let's fix this up.

Change-Id: I1698280a699b17cea65651c3736ef149aba7e432
2017-09-24 10:47:50 +08:00
Harald Welte b2a9aae35a sgsnemu: Fix up gengetopt file for RAI
In commit 41af5691ef we introduced the
--rai command line options, but this was apparently done by
manually editing the C source code rather than adding it to the .ggo
and letting gengetopt do its magic.  Let's fix this up.

Change-Id: Iaab404c3bcfc0c3943764f6616763f4f407d5644
2017-09-24 10:47:50 +08:00
Harald Welte 9523482193 sgsnemu: Fix up gengetopt file for rattype, userloc, mstz, imeisv
In commit 944dce3e66 we introduced various
command line options, but this was apparently done by manually editing
the C source code rather than adding it to the .ggo and letting
gengetopt do its magic.  Let's fix this up.

Change-Id: Ib8e7ef1cad5fc4423a1a4af628950aa93a4e073a
2017-09-24 10:47:50 +08:00
Harald Welte 74aa8b701c sgsnemu: Fix up gengetopt file for QoS Extensions of 24.008
In commit 11a398fbc3 we introduced the
--qose{1,2,3,4} command line options, but this was apparently done by
manually editing the C source code rather than adding it to the .ggo
and letting gengetopt do its magic.  Let's fix this up.

Change-Id: I4cd827a96ac17f6eb9f824342f195727426d0e20
2017-09-24 10:47:50 +08:00
Harald Welte 15ed792154 sgsnemu/cmdline.ggo: Remove 'unsigned' which is no longer supported
It seems like modern gengetopt no longer supports 'unsigned int'
argument types, and we need to use 'int' instead.  tested with 2.22.6

Change-Id: I34ca86cb3cc482400a7c4b3bf77c8668aaef562e
2017-09-24 10:47:50 +08:00
Harald Welte 01628985ec note OpenGGSN is obsoleted by OsmoGGSN
Change-Id: I477382cf3e015976401218b628b911580d935d53
2017-09-06 12:14:18 +02:00
Harald Welte 2778ae2b8f lib/tun: Mark internal helper functions 'static'
Change-Id: I53a8a89abb0080a39a153e9d3864c17b29aa193c
2017-09-05 23:13:14 +02:00
Harald Welte 1b6e8e7b5e Remove __sun__ code that is unmaintained
We haven nobody maintaining this platform, let's remove it.

In fact, only Linux and FreeBSD are part of the jenkins build tests,
so even Apple/MacOS is up for disposal.  However, as it's more
popular, let's keep the code.

Change-Id: Id6b8179259bacade52c39f96e688f828eff164ac
2017-09-05 23:13:14 +02:00
Harald Welte e257be1d69 libgtp: Add back-reference to gsn from pdp context
This is required once one wants to support multiple GSNs in a single
application.

WARNING: This breaks ABI compatibility, LIBVERSION must be adjusted

Change-Id: I68ae49a765828fa681054c68bf7f5e74dbe48ad2
2017-09-05 23:13:14 +02:00
Harald Welte 8a03ea8a32 libgtp: Remove ctrl_handle from gsn_t, replace with private context
The control interface handle never belonged into libgtp in the first
place.  Commit 727417dd28 should not
have added this to the shared library (used by sgsnemu, osmo-sgsn, ...),
but to some private state of the GGSN.

Introducing a private context pointer at the same location will keep
ABI compatibilty.

Change-Id: I4f17516dae3e04114564828a3e5f6e2ea54212a5
2017-09-05 23:13:10 +02:00
Harald Welte 9e6dfa0558 lib/tun.c: Proper cleanup during tun_new() error paths
Change-Id: I285be20df76774ac7258b6edb3d4f2d28703757d
2017-09-05 22:42:18 +02:00
Harald Welte 4857f3c2f3 lib/ippool: Move ippool_aton() out of ippool_new()
we rather pass the in46_prefix directly into ippool_new()

Change-Id: Iadf6274e881a9bfc75eb41f9380f5ae2d8c92a0f
2017-09-05 22:42:18 +02:00
Harald Welte b513b951bd lib/ippool: Add back-pointer from pool member to pool
This allows us to remove pool members without having to keep
a pointer to the pool around.

Change-Id: I9042eb85989c5451d7894678eca110dd19e78002
2017-09-05 22:42:17 +02:00
Harald Welte 33520b43ec lib/in46_addr: Avoid ASSERT() when in46a_ntop() is called on uninitialized address
Change-Id: I42d41ec1370b9cc15d372b649d8e1bc78e76af9b
2017-09-05 22:42:17 +02:00
Harald Welte 7fc8694b97 lib/in46_addr: Add 'struct in46_prefix' to represent addr + prefix
Change-Id: I797d105117e81951732bcfc2cc26a8d00fd69443
2017-09-05 22:42:17 +02:00
Harald Welte b62983d3c3 lib/in46_addr: Add in46a_ntoa() function, similar to inet_ntoa()
Change-Id: I752b7033a106a74dc219047da5c3a7ad3cd3602e
2017-09-05 22:42:17 +02:00
Harald Welte 881e97ed00 lib/tun: Add 'void *priv' pointer to tun_t
This allows the application to attach some private state to the tun
device, such as the context from which it was created/allocated

Change-Id: Ief43b9b5fab5830fa8e28362c795f88f0b4d353b
2017-09-05 22:42:17 +02:00
Harald Welte c55ece8d91 lib/tun: Add missing #include to net/if.h for IFNAMSIZ
Change-Id: I979867d643c9fa912884fe55105333dbad39ab97
2017-09-05 22:42:17 +02:00
Harald Welte 8ffd7fc782 gtp-kernel: Remove dependency to cmdline.[ch]
Change-Id: I760f25df609c309eba4d5716f3e23b49320449bf
2017-09-05 22:42:17 +02:00
Harald Welte e57cbe2e74 update jenkins.sh to conform with current build environment
Change-Id: I999d35cdffbdb61984da15d616f675005aa0688c
2017-09-05 22:42:17 +02:00
Pau Espin 0ab62fe081 ggsn: Fix DNS not sent in PDP context response
During IPv6 support implementation, helper function pco_contains_proto
was added which contains an error: It is only capable of finding first
protocol correctly, and as a consequence, in my setup DNS servers where not
sent back to the SGSN/MS, resulting in phone being able to connect to
IPs but not to domain names which required DNS resolution.

The condition in the while loop is also changed to match the increment
of the variable inside the loop to make it easier to understand at first
glance.

Fixes: 1ae98777d9

Change-Id: Icc2e6716c33d78d3c3e000f529806228d8aa155e
2017-08-30 15:56:27 +02:00
Max bdc504e29c Use release helper from libosmocore
See
https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
for details.

Change-Id: Icdcb388ad22b0c009dac7968408d1e2504c838c1
Related: OS#1861
2017-08-28 12:29:28 +02:00
Max b87da75ae4 Use value string check from osmo-ci
Change-Id: I036ed452826b9a6848d22d45bdcc95e20a110b8b
2017-08-26 06:10:17 +00:00
Max 14b1b63710 libgtp: expand logging
* print destination address on sendto error
* print address length on conversion error
* log listening address
* log GTP version on PDP context errors
* fix incorrect logging message for unknown GSN peer

Related: SYS#3610
Change-Id: I0f8ad8687acb7f6f0eeeb962f007e87cca0c4c27
2017-08-22 10:07:28 +00:00
Harald Welte 367baa3776 update debian/changelog to 0.94 + fix pkg-config version
This updates the debian changelog to 0.94 and adds some logic
to debian/rulres which fixes the version of the libgtp.pc file
built as part of our OBS builds (used to be UNKNOWN since
commit 23eea1d132)

Change-Id: I883feaef35ff5ffd1b22fb255b7c36112b4a8f3b
2017-08-14 00:21:57 +02:00
Harald Welte 37d5b1557b libgtp: Delete PDP context on receiving GTPv1 Error Indication
When a peer GSN receives a GPDU for an unknown PDP context, it sends
a GTP Error Indication.  This Error Indication should be used to
delete the offending PDP context locally.

In GTPv1, the Error Indication contains some mandatory IEs using
which we can look up the PDP context and delete it.

The existing code only dealt with GTPv0 Error Indications which lack
those IEs and use the TEI in the header instead.

Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9
Closes: OS#2426
2017-08-13 00:01:35 +02:00
Harald Welte 54d082e5e8 libgtp: Add missing mandatory IEs in GTP Error Indication
Change-Id: Iadd1fe3de7c476576a4409f22f5e84e9eade6b6e
2017-08-12 22:53:59 +02:00
Harald Welte b10ee08c2f Properly format IMSI before using it in trap
For some reason Max' commits introducing the CTRL/trap interface
about one year ago didn't convert the IMSI to its actual textual
representation before usign it in the CTRL interface.

Let's clean that up by properly interpreting the IMSI.

Change-Id: I8b20d2e47a29de266d93a7ddd5e6877f7e346a63
2017-08-12 22:53:54 +02:00
Harald Welte 23eea1d132 Use osmocom-style git-version-gen / .version magic
This generates the version number from the latest tag + git history

Change-Id: I71e1c3f8f534d9e9690c94068eccdee29a6fee12
2017-08-11 13:48:14 +02:00
Harald Welte 81bc2aea53 tun_new(): Fix array overflow in FreeBSD related code
Change-Id: I096e3b614e82e402886163274cfcf9355bd57580
2017-08-11 13:12:09 +02:00
Harald Welte ab6d189f8f replace hand-coded tun_gifindex() with standard POSIX if_nametoindex()
Change-Id: I738472765ab09f530dcf071455e1bb4e6fb3f6e5
2017-08-11 13:12:09 +02:00
Harald Welte 2e48a44952 Support setting TUN device IPv6 address + prefix
As we can now have PDP contexts with IPv6 user IP payload,
it is useful to extend the TUN related code to be able to
configure the tun device IPv6 address + prefix length

Change-Id: I899d21e52d02e0b8384af29ddd489ff19c8f2cf6
2017-08-11 13:12:04 +02:00
Harald Welte 72a38b55e3 IPv6: in46_addr: OSMO_ASSERT() in case of unsupported calls
There's a bit of trickery with the ip_pool and it's "lengty=8" IPv6
prefix handling, let's make sure we don't accidentially call any
support functions with addresses of wrong length.

Change-Id: I444c190bdcd18780344e1f0dad4faf3bcf9da5a5
2017-08-11 10:46:00 +02:00
Harald Welte 1ae98777d9 IPv6: Support PCO for IPv6 DNS addresses
In IPv6, DNS server information is not passed along as IPCP6 like
in IPv5 with IPCP.  The reason is that IPCP6 (for PPP) doesn't
support passing DNS server information.  Rather, the relevant RFCs
indicate DHCPv6 should be used even over point-to-point links.

3GPP decided to avoid DHCPv6 dependency for stateless autoconfiguration
(the only mandatory IPv6 configuration mechanism) and added some new
non-PPP-style PCO information elements ("containers") which can among
other things inform a MS about IPV6 DNS servers.

That same mechanism can also be used to inform the MS about IPv4 DNS
servers, so for IPv4 there are now two competing mechanisms: IPCP and
the new "native" PCO container.  With this patch, we support both
for IPv4.

Change-Id: I21499afd61def8c925f7838bde76f34d28214b56
2017-08-11 10:46:00 +02:00
Harald Welte d46bcd236e IPv6: Implement IPv6 prefix assignment via ICMPv6 router advertisement
The 3GPP specs are quite strange when it comes to how an IPv6 address
or rather prefix is assigned to an IPv6 PDP context.  The designated
method for allocating the IPv6 address via the PDP EUA (End User
Address) Information Element in the GTP signalling plane is *not*
used to allocate the address/prefix.  Instead, the EUA is used to
allocate an "interface identifier" to the MS, which it the uses
to derive its link-local source address to send a router solicitation.

The GGSN subsequently answers witha router advertisement, advertising
a single/64 prefix, whihcthe MS then uses to generate it's real IPv6
source address for subsequent communication.

Change-Id: Icddf7d30e01d76a4784bcef5787b36f52f703a9f
2017-08-11 10:45:56 +02:00
Harald Welte d4d6e09fd2 ippool: Extend pool to work with /64 prefixes
In IPv6 GPRS, we actually don't want to allocate an individual v6
address (like in IPv4), but we want to allocate a prefix.  The
standard prefix lengh is 8 bytes, i.e. a /64 prefix.  This patch
extends the pool to be able to work with such v6 prefixes.

Change-Id: I0cf700b6baf195a2e5fbea000531f801acaaa443
2017-08-09 22:37:57 +02:00
Harald Welte 365f8fa462 in46_addr: Add new function in46a_prefix_equal()
This function is used to compare an IPv6 address against another,
using the smaller of the two prefix lengths.

Change-Id: Ic993d8abdc90897cb55276f01ae3b8a5eadf5a0d
2017-08-09 22:09:34 +02:00
Harald Welte d1bf1e11ba ggsn: Send proper errors in create_context_ind()
When we receive PDP context requests for unknown PDP types or if
we run out of dynamic addresses, we need to inform the SGSN that
PDP context creation failed.

Change-Id: Ibf199c1726130d27c8f80230b30ee51101c93b06
2017-08-09 22:09:34 +02:00
Harald Welte a0d281db1c IPv6 support for user IP
This patch enables the use of IPv6 PDP contexts.  The phone will
have to request an IPv6 End-user-Address, and the GGSN will have
to be configured for an IPv6 pool.

The outer transport-layer IP between SGSN and GGSN must still be
IPv4, it is not modified by this patch

Change-Id: I22c3bf32a98e5daf99d6eaeac8c9f95cc7574774
2017-08-09 22:09:34 +02:00
Harald Welte 53165ede24 ippool_new(): const-ify input arguments
Change-Id: If3e53584e8c9c1f06bba4c183c9fd65fae913904
2017-08-09 22:09:34 +02:00
Harald Welte 63ebccdfe3 lib/tun.h: Remove non-endian-safe redefinition of IP header
We can simply use 'struct iphdr' from netinet/ip.h to achieve
the same goal (and be portable).

Change-Id: Ieece22e127dc14a7ffdc3b05656628989ad00b32
2017-08-09 22:09:34 +02:00
Harald Welte d12eab9c4e ippool: Add IPv6 support to IP pool implementation
Extend the IP pool implementation to be able to manage both pools
of 32bit addresses (IPv4) as well as pools of 128bit addresses (IPv6)

Change-Id: Ib98cc4bf634d6be9a7bf8c03a24e629455fcafc8
2017-08-09 22:08:57 +02:00
Harald Welte d9d8862a58 Proper fix for "Force Dynamic IP" in Create PDP CTX
An EUA length of *2* octets indicates dynamic IP address, while
an EUA length of 0 is invalid.  Let's fix this hack (which needs
to finally be removed anyway).

Change-Id: Ib1b57eb0654327882044d6862d955f4b32aa6bcd
2017-08-04 00:23:57 +02:00
Max 283188790b libgtp: improve error logging and propagation
* propagate error code from gtp_new() to caller instead of always
  returning -1
* on socket-related failures log explicitly which kind of socket caused
  error
* log expected GTP version for unexpected packets

Change-Id: Ie07f1e4246eb178838b7df21946a08a1f60f2084
related: SYS#3610
2017-06-09 08:53:10 +00:00
Max 3142d8d30b ctrl: cleanup trap creation
Move common trap create/send code into separate function.

Change-Id: Iaadc921b951aeb9b3ad5ab796e13d52017139468
2017-05-16 17:10:25 +02:00
Daniel Willmann a2861a7428 contrib: Start openggsn after networking
Change-Id: Ic617c618db17e7109ee864c4e6c86f3bee081d02
2017-05-09 17:50:03 +02:00
Harald Welte 19e19e3609 track README.md rename in spec file and debian/docs
When README was renamed to README.md, the debian and rpm packaging
information was not updated.

Change-Id: I3fb3016defb74cf4e9c0a363f70eff9d6f71a5f5
2017-03-18 14:23:01 +01:00
Harald Welte 93c3b386cf Update README with general project information + convert to Markdown
Change-Id: Ib4213388dffab125e75d9b1f7d72319e041059ea
2017-03-17 18:36:14 +01:00
Harald Welte bf6de7a289 Add MAkefile.* to EXTRA_DIST to ensure they end up in tarballs
Change-Id: Ibbae061fda3db49f8ecda263cfc3ca6873c0b1b3
2017-03-17 18:25:03 +01:00
Neels Hofmeyr 1fce2ce0b3 jenkins: add value_string termination check
Change-Id: I7c676debcdfef2471004deb9ef5a63e8f4e97e15
Depends: libosmocore change-id I2bc93ab4781487e7685cfb63091a489cd126b1a8
2017-03-16 19:00:27 +00:00
bjovan a8f71eb24e Code formatted to be in line with formatting rules.
Change-Id: I546dc0a8d814527b9a96943a52f2f6b700285167
2017-02-27 09:56:28 +01:00
Harald Welte 8c25b97d3f Update AUTHORS file to reflect the last 12 years
Change-Id: I0a8f5a69f2a943344331d36ba225c02b0209beeb
2017-02-23 22:10:12 +01:00
Harald Welte a892177dce remove ChangeLog, it hasn't been updated since 2004
We have a detailed log in git instead.

Change-Id: I6a7fe97995b5f65080a04423fee77030dea26b84
2017-02-23 22:10:08 +01:00
Harald Welte 9225bfc48c update version to 0.93
Change-Id: If65b8281933b5833b5ce83239688e775cc267f4c
2017-02-23 21:52:56 +01:00
Harald Welte bf5c0bb4b9 gtp.c: Don't print ""Unknown packet flags" error message in get_seq()
get_seq() is called also from contexts where GTP-U is used, and GTP-U
doesn't have sequence numbers.  Thus, it is perfectly normal if no
sequence number and/or no S flag in the header is present.

Change-Id: Ie19b95bbb4427e547843a019f5213a231a9f83da
2017-02-23 21:11:05 +01:00
Harald Welte 875e4dc8c3 gtp-kernel: Fix tunnel creation/removal for GTP Version 1
When Linux Kernel GTP-U support is enabled, OpenGGSN so far only worked
with GTPv0,but not with GTPv1, as the TEI values were not correctly
configured.  This patch fixes the initialzation of the local and remote
TEI before using libgtpnl to create a tunnel context in the kernel.

Change-Id: I3e953ff5b4ab44c26dbbe20d18b61038fa57ff32
2017-02-23 21:10:48 +01:00
Holger Hans Peter Freyther 68d244d302 abi/debian: Bump ABI version of libgtp after struct size change
The gsn_t changed the size with the addition of the ctrl pointer.
Bump the SO version to not break osmo-sgsn/ggsn on upgrade.

Call the -dev package libgtp-dev to follow the rest of Osmocom and
to ease making releases here.

Change-Id: Iac4d6d2effde1a6b2f60b1e1b49c91513d5ca8c3
2017-01-26 11:14:59 +01:00
Max 7716860845 Integrate Debian packaging changes
debian/control:
    * restructure to make it easier to incorporate further changes
    * update package descriptions
    * update project URL

debian/rules:
    * use proper hardening syntax
    * remove useless comment

debian/copyright: update to match Debian format

Change-Id: Ia7f0a3a583ad63f5c6e5cf5e5de2ff7dd9eed8a9
Related: OS#1694
2016-12-22 14:10:07 +00:00
Harald Welte d37b80a6d2 gtp.c: Improve debug statements about GTP header flags
* as there are muptiple flags in the field, use plural
* print the flags as hex value, not decimal.  Hex is customary for bitfields.

Change-Id: Ib23d80fae32b4e9fa146d82d8f5a1dada1a3cb2b
2016-12-15 20:55:54 +01:00
Max dbd7024919 Only send TRAP for defined PDP peer
Do not attempt to send TRAP message on PDP context deletion if peer is
unknown.

Change-Id: I5e02c1d42bb7aaf1ef81a9824aab7b12047cdd3e
Fixes: Coverity CID 150135
2016-11-02 09:32:31 +00:00
Neels Hofmeyr f41f5866ce gsn_restart file: wrap umask change tightly around file creation
An fopen("w") error used to omit the umask() call to reinstate the previous
umask. Also an fopen("r") at the top will never create a file and hence does
not need a umask set.

Instead, wrap the umask change and change-back tightly around the single
fopen("w") call.

Change-Id: If7d948e2f2ba47ecebba5614f18235a53b273d14
2016-10-14 11:39:49 +00:00
Neels Hofmeyr f7611c3cee fix gsn_restart file buffer overflow and missing path sep
Fix errors during gsn_restart file path composition:

- possible buffer overflow because the wrong remaining length was fed to
  strncat().
- missing path separator: put restart file in dir/gsn_restart instead of
  ../dirgsn_restart.

This assumes that the path separator is '/'.

Use talloc_asprintf() to fix all filename length problems and shorten the code.

In order to free the allocated path, add a free_filename label, and jump there
instead of returning from the fopen("w") failure branch. Also don't return from
"fclose failed" branch in order to free the path, remove the if {} braces.

Change-Id: Idf0a64ff45720aa818f2f9de1e8ba2fe2c82631b
2016-10-14 11:39:49 +00:00
Neels Hofmeyr 38929c9131 configure: check for pkg-config presence
Change-Id: I658152eb24fd783fce9ceac35872ab918c80209a
2016-10-12 23:26:17 +00:00
Neels Hofmeyr ee9d34a9cc build: be robust against install-sh files above the root dir
Explicitly set AC_CONFIG_AUX_DIR.

To reproduce the error avoided by this patch:

  rm install-sh        # in case it was already generated.
  touch ../install-sh  # yes, outside this source tree
  autoreconf -fi

This will produce an error like

  ...
  configure.ac:16: error: required file '../ltmain.sh' not found
  configure.ac:5: installing '../missing'
  src/Makefile.am: installing '../depcomp'
  autoreconf: automake failed with exit status: 1

See also automake (vim `which automake`) and look for 'sub locate_aux_dir'.

Change-Id: I4aef311d7a475800e09f48110a499c3759c69f5d
2016-10-12 23:26:17 +00:00
Max 727417dd28 Add control interface
Only generation of TRAP messages over Control Interface is supported so
far.

Note: requires corresponding version of libosmoctrl.

Change-Id: Ia76f841d2c9cd14394e9316fcd39f4060e23c898
Related: OS#1646
2016-10-12 09:30:30 +00:00
Max cd93f4f4be Add .gitreview to simplify gerrit integration
Change-Id: Ib141dc9ae03c2b10b8925e30a2782bf2d932e192
2016-10-12 09:25:49 +00:00
Max 395e213894 Remove unused function
Change-Id: Iff0f1499660b12a47277b16a435efecb42fab038
2016-10-11 15:31:49 +02:00
BJovke 03dbafb000 Add 'Bearer Control Mode' IE
This IE is known to be sent by a Cisco GGSN, and was added in
ETSI TS 129 060 V7.17.0 (2011-10) /
3GPP TS 29.060 version 7.17.0 Release 7

See https://lists.osmocom.org/pipermail/osmocom-net-gprs/2016-September/000711.html
Subject "sgsnemu failing to create PDP context with Cisco GGSN"
Tue Sep 13 08:00:37 UTC 2016

Tweaked-by: Neels Hofmeyr <nhofmeyr@sysmocom.de>
2016-09-15 13:53:13 +02:00
Alexander Couzens 86540de7f3 gtp/queue/queue_seqdel(): fix element check which was always true
Fix an apparent typo that prevented queue iteration to find the correct item to
be removed. Instead, the first item was always returned. Calling code has been
analyzed to find that mostly this fault is not visible, since usually, the
first item is indeed the correct item to be returned. See mail thread
http://lists.osmocom.org/pipermail/osmocom-net-gprs/2016-June/000618.html
Date: Wed Jun 1 11:51:38 UTC 2016
Subject: "[PATCH] gtp/queue/queue_seqdel(): fix element check which always was true"
2016-06-06 00:45:10 +02:00
Ruben Undheim cc077ae0bc Description: Fix some typos in the man pages and in the binary 2016-05-24 23:31:47 +02:00
Holger Hans Peter Freyther 6bf2f05df6 debian: Bump the version to ease upgrading from Debian
Debian SID has version 0.92-1 and we had 0.92. Bump it to 0.93.
2016-05-24 22:55:38 +02:00
Pablo Neira Ayuso 0eaa5b8e6c gtp: fix several compilation warnings
CC       gtpie.lo
gtpie.c: In function 'gtpie_encaps':
gtpie.c:437:22: warning: variable 'm' set but not used [-Wunused-but-set-variable]
  union gtpie_member *m;
                      ^
gtpie.c: In function 'gtpie_encaps2':
gtpie.c:537:22: warning: variable 'm' set but not used [-Wunused-but-set-variable]
  union gtpie_member *m;
                      ^

lookup.c: In function ‘lookup’:
lookup.c:40:24: warning: typedef ‘ub1’ locally defined but not used [-Wunused-local-typedefs]
  typedef unsigned char ub1; /* unsigned 1-byte quantities */
                        ^

Still one compilation warning left in cmdline.c, but that code
is autogenerated.
2016-05-12 17:02:34 +02:00
Pablo Neira Ayuso 176e895bd6 ggsn: fix compilation error with --disable-gtp-kernel
gtp-kernel.h: In function ‘gtp_kernel_init’:
gtp-kernel.h:25:15: error: ‘struct gengetopt_args_info’ has no member named ‘gtpnl_given’
  if (args_info->gtpnl_given) {
               ^
Makefile:422: recipe for target 'ggsn

Reported-by: Holger Freyther <holger@freyther.de>
2016-05-12 16:54:56 +02:00
Pablo Neira Ayuso 23d9976039 get rid of accidental copy of ggsn.conf
Included accidentaly in 8419e33 ("examples: ggsn.conf: document
tp-linux toggle").
2016-05-10 19:18:06 +02:00
Pablo Neira Ayuso 466da99934 configure: rename from --enable-gtp-kernel to --enable-gtp-linux
This software seems to run on other *nixes, so indicate explicitly that
this is the Linux kernel datapath support.
2016-05-10 19:11:43 +02:00
Pablo Neira Ayuso 8419e33c4a examples: ggsn.conf: document gtp-linux toggle
Enable Linux kernel GTP datapath driver.
2016-05-10 19:06:54 +02:00
Pablo Neira Ayuso d9d7be339d ggsn: cmdline: no need to specify interface anymore
--gtpnl is now gone, instead you have --gtpkernel that behaves as an on/off
toggle. We full rely on the kernel routing base to select the real device to
transmit.

I have updated ggsn/cmdline.ggo and then run 'gengetopt' to refresh the
automatic code generation for command line options that openggsn uses.
2016-05-10 19:06:01 +02:00
Pablo Neira Ayuso 7b31987a46 ggsn: gtp-kernel: adapt gtp_dev_create() to its new interface
Andreas modified this interface, so update so this compiles again.
2016-05-10 18:51:00 +02:00
Neels Hofmeyr f89dc4e127 queue_new(): fix NULL dereference on allocation failure
Coverity complains about a 'Dereference before null check' on *queue.
So, push the NULL check further up.

Though I doubt that 'return EOF' is the proper way to handle allocation
failure, this patch is only about the NULL dereference.

Fixes: CID#57918
2016-04-29 13:01:06 +02:00
Holger Hans Peter Freyther b29ff1da55 jenkins: Add the build script from jenkins here
This can be used to replicate a build issue more easily.
2016-04-13 19:02:13 -04:00
Daniel Willmann d997552d29 gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly
libgtp cannot understand its own update pdp request (in gtp v1)
Only require the conditional and mandatory fields for gtpv1 and not
others.
Refer to 3GPP TS 29.060 Ch. 7.3.4
2016-02-05 07:48:20 +01:00
Daniel Willmann 05f3ef3eb8 gtp: Make gtp_update_pdp_conf() work for gtp0 and gtp1 connections
pdp_getgtp1(&pdp, get_tei(pack)) works like pdp_getgtp0 for gtp0
connections.
Using get_hlen() for gtpie_decaps is used in other places to decode ies
for both version 0 and 1.
2016-02-04 13:17:19 +01:00
Daniel Willmann 134a7752fd gtp: Pass pdp along when calling gtp_req() in gtp_update_context()
With no pdp parameter gtp_req() will send the packet to TEID 0 which is
not what we want. When trying to modify an established pdp context the
correct TEID of that context must be used.
2016-02-04 13:17:02 +01:00
Holger Hans Peter Freyther 8ddb6805a9 gtp: Do not leak the restart counter file handle in case of error
If the file exists but can not be read the file would not be closed.
Jump to a label that will close f.

Fixes: CID#57917
2016-01-23 10:40:52 +01:00
Holger Hans Peter Freyther 3a9befb516 gtp: Fix a bunch of compiler warnings when just including gtp.h
Attempt to fix a bunch of compiler warnings in OpenBSC.
‘struct pdp_t’ declared inside parameter list
2016-01-23 10:16:53 +01:00
Andreas Schultz c80680a9c4 ggsn: fix autotool pkg-config invokation
see https://autotools.io/pkgconfig/pkg_check_modules.html, Optional Modules
for explanation

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
2015-12-21 08:37:50 +01:00
Andreas Schultz c5fbf9bd68 ggsn: update gpt-kernel logging to libosmocore
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
2015-12-21 08:37:26 +01:00
Pablo Neira Ayuso 4b075b6cb8 ggsn: add support for GTP kernel data encapsulation
This patch adds the -g, --gtpnl=device option that allows you to
enable the GTP kernel tunneling mode in openggsn. You have to specify
the real downlink device that will be used to tunnel traffic, eg.

	-g=eth0

This means that the gtp0 device will be created and it will use eth0
as the real device to encapsulate packet coming from the Internet that
are addressed to the MS (so the tunnel devuce encapsulates these IP
packets in GTP packets when traveling to the SGSN).

Alternatively, you can also add this to the ggsn.conf configuration file:

	gtpnl eth0

The device has to be the real device that can route packets to the SGSN,
if you select the wrong device, the kernel routing code may not find a
way to reach the SSGN, you've been warned.

Therefore, if this option is set, the operational becomes the following:

1) A gtp0 device is created via rtnetlink and configure the socket
   encapsulation infrastructure in the kernel.
2) Whenever a PDP context is created, this adds the necessary tunnel
   configuration via genetlink GTP interface.
3) Whenever a PDP context is destroyed, this deletes the tunnel via
   genetlink GTP interface.
4) Destroy the gtp0 device if ggsn is stopped, including all of the
   existing tunnels.

You require the osmo-ggsn.git tree, which contains the kernel module
gtp.ko and the libgtpnl library that you have to compile and install.
Make sure you have loaded the gtp.ko kernel module before launching
the ggsn daemon using the kernel driver mode, otherwise you will get
a nice "operation not supported" error message ;-).

This patch also adds supports for "ipup" configuration option to invoke
an external script after the gtp0 device has been brought up. Typical
command to add the route to reach the MS behind the GGSN is required,
eg. ip route add 10.0.0.0/8 dev gtp0.

The (horrible) ggsn parser has been manually extended to support the
new configuration option. That code doesn't look nice, but it just
mimics what we already have there for consistency, please don't blame
me for that.

If you want to run in debugging mode, I suggest you to use:

	sudo ggsn -c ggsn.conf -f -d

Note that you do have to run openggsn as root to bring up the gtp0
device. You have to see this message that announce that the GTP kernel
mode is enabled.

openggsn[1106]: ggsn.c: 656: Using the GTP kernel mode (genl ID is 25)

This patch also automagically sets up route to reach MS from Internet
just like tun mode does. This is fundamental to get this working,
better don't leave to the admin, he may forget to add this route.

In this patch, I tried to encapsulate this new feature as much as
possible as Harald initially suggested.

To compile this feature, you have to pass --enable-gtp-kernel, ie.

./configire --enable-gtp-kernel

Otherwise, the code to interact with the gtp kernel part is not compiled.

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
2015-12-21 08:37:11 +01:00
Holger Hans Peter Freyther 89dcb614e8 Release 0.92 of the GGSN needed for the gtphub 2015-11-30 14:06:09 +01:00
Harald Welte ac0b4f17fe update version to 0.92 2015-11-20 10:34:17 +01:00
Andreas Schultz 10abfba949 convert literal APN name to protocol encoded version before use
The definition of the APN field format in GTPv1 is hidden in a chain
of documents.

3GPP TS 29.060 (the GTPv1-C specification) Section 7.7.30:

> The Access Point Name contains a logical name (see 3GPP TS 23.060 [4]).
> It is coded as in the value part defined in 3GPP TS 24.008

3GPP TS 24.008 Section 10.5.6.1:

> The value part is defined in 3GPP TS 23.003.

3GPP TS 23.003 Section 9.1:

> The APN consists of one or more labels. Each label is coded as a one
> octet length field followed by that number of octets coded as 8 bit
> ASCII characters

This converts a literal APN (e.g. Label1.Label2.Label3) to a structured
field (e.g. \006Label1\006Label2\006Label3)

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
2015-11-13 17:16:03 +01:00
Holger Hans Peter Freyther a377b0874a Revert "Makefile.am: define ACLOCAL_AMFLAGS, include directory m4"
aclocal: couldn't open directory `m4': No such file or directory

This reverts commit 04cbae494d.
2015-11-07 20:47:26 +01:00
Alexander Huemer 04cbae494d Makefile.am: define ACLOCAL_AMFLAGS, include directory m4 2015-11-07 12:41:25 +01:00
Alexander Huemer db852a14fe fix some format specifiers 2015-11-07 12:40:48 +01:00
Alexander Huemer e740e81281 configure.in -> configure.ac 2015-11-07 12:39:32 +01:00
Neels Hofmeyr 2ea010a1ed gitignore: add 'compile' (from autoconf) 2015-11-02 14:27:53 +01:00
Neels Hofmeyr 041824dfc8 sgsnemu: improve an error message 2015-11-02 14:27:44 +01:00
Holger Hans Peter Freyther cd14094bb6 Dump dead code and never look at it again
This seems to be a wrong search. It seems to assume that there are
no buckets. Let's just remove it before looking at it too much.
2015-11-02 14:13:31 +01:00
Neels Hofmeyr 0dc4748447 add todo comments 2015-11-02 14:13:31 +01:00
Neels Hofmeyr 6c06d25667 make install: also install gtpie.h 2015-10-27 14:57:18 +01:00
Neels Hofmeyr e845cb9505 gtp.c: fix an error log.
Fix: the code handles fd1u but prints fd1c.
2015-10-12 14:23:54 +02:00
Neels Hofmeyr b18e811e24 gtp.h: rename gsn_t.dublicate to duplicate.
Fix spelling dublicate -> duplicate.

This is potentially breaking API compat, but currently, no users of
gsn_t.dublicate are known.
2015-10-12 14:10:27 +02:00
Neels Hofmeyr 9b09738891 gtp.c: improve 3 error logs.
It would print the memory location of the address buffer. Instead, print the
human readable host address and port.

The current code base supports only IPv4, and thread safety is apparently not
required, hence just use inet_ntoa(). (The IPv6 and thread capable version is 4
times longer and harder to read.)
2015-10-12 14:09:57 +02:00
Michael McTernan b07d07072e openggsn: Check return codes and take error paths on failure.
Return early when socket() returns -1, and check return codes
where indicated by some TODOs. This removes 2 TODOs and fixes
a compiler warning about assignment to a variable which then
isn't used.

Signed-off-by: Michael McTernan <mike.mcternan@wavemobile.com>
2015-05-02 07:53:34 +02:00
Holger Hans Peter Freyther 633cc0d7cb debian: Address lintian warning about -dbg package 2015-03-14 20:25:35 +01:00
Holger Hans Peter Freyther 7bfe18039b debian: Require libosmocore 2015-03-14 20:21:44 +01:00
Holger Hans Peter Freyther 0576f3bebf debian: Move to multi-arch support 2015-03-14 20:17:46 +01:00
Holger Hans Peter Freyther 91d0ee5c14 lib: Speculatively add libosmocore cflags to the lib 2014-12-23 19:52:54 +01:00
Holger Hans Peter Freyther 6ab58b466a ggsn: Move printf to DEBUGP statements in the ggsn as well
The specific log statements are not great yet but at least they
will end up in the log file. In the future everything should be
related to the IMSI or at least the tunnel id.
2014-12-04 19:29:57 +01:00
Holger Hans Peter Freyther 8e7e3ef686 ggsn: Remove unused dump/logging method 2014-12-04 19:19:33 +01:00
Holger Hans Peter Freyther c38bf64e3f ggsn: Be able to set the log level for the text file
Fixes: SYS#599
2014-12-04 18:54:58 +01:00
Holger Hans Peter Freyther 9c7fd8edc4 logging: Switch to using libosmocore logging for all the code 2014-12-04 16:51:15 +01:00
Holger Hans Peter Freyther e527ef105f syserr: Remove unused error packet logging code 2014-12-04 16:49:38 +01:00
Holger Hans Peter Freyther 01b40d0690 gtp: Make these regions runtime debuggable 2014-12-04 16:49:37 +01:00
Holger Hans Peter Freyther 752314ac43 gtp: Kill unused and non public method 2014-12-04 16:46:30 +01:00
Holger Hans Peter Freyther 42ca1d1a38 gtp: Move to using LOGP for logging GTP packages
Make libgtp depend on libosmocore and use the generic logging
infrastructure for it.
2014-12-04 16:45:59 +01:00
Holger Hans Peter Freyther ca524ef344 Begin to require libosmocore and libosmovty
We are not too specific about the version yet
2014-12-03 19:59:15 +01:00
Holger Hans Peter Freyther 839c2211dc debian: Attenpt to fix lintian warning on weak-dependency 2014-09-23 16:59:36 +02:00
Holger Hans Peter Freyther 7397b88485 debian: Make it a proper git version 2014-09-23 16:59:36 +02:00
Holger Hans Peter Freyther f97f58deb2 debian: Harden and build debug packages 2014-09-23 16:59:36 +02:00
Holger Hans Peter Freyther 493ec593f7 debian: Modernize/Fix the debian control file
W: openggsn source: ancient-standards-version 3.8.4 (current is 3.9.5)
W: libgtp: package-name-doesnt-match-sonames libgtp0
2014-09-23 16:59:36 +02:00
Holger Hans Peter Freyther 827aec1f31 debian: Add dependency for LSB script
E: openggsn: init.d-script-missing-dependency-on-remote_fs etc/init.d/openggsn: required-start
E: openggsn: init.d-script-missing-dependency-on-remote_fs etc/init.d/openggsn: required-stop
2014-09-23 16:59:36 +02:00
Holger Hans Peter Freyther 0b705bb4d1 debian: Create new changelog entry to please new tools
dpkg-source: error: can't build with source format '3.0 (native)': native package version may not have a revision
2014-09-23 16:59:36 +02:00
Daniel Willmann c190896437 openggsn.service: Add Install section to systemd service file
This way the service can be enabled through
> systemctl enable openggsn
2014-08-21 10:15:33 +02:00
Holger Hans Peter Freyther 5816bcfaff gtp: Speculative FreeBSD compile fix for htobe64 2014-04-04 11:43:09 +02:00
Pablo Neira Ayuso 746b944ad6 gtp: add pdp_set_imsi_nsapi
Encapsulate code to handle the teid with GTPv0.
2014-03-24 17:59:19 +01:00
Holger Hans Peter Freyther 9c0ff4fafe cli: Introduce a logfile command to log errors to a file
The evolution would be to introduce libosmocore and start using
the logging framework. But even then we can map this option to
the file target.

Fixes: SYS#263
2014-03-23 10:29:17 +01:00
Holger Hans Peter Freyther 1c4d9e6d87 cli: Manually patch the generated code to fix compiler warning
cmdline.c: In function ‘cmdline_parser_internal’:
cmdline.c:588:7: warning: variable ‘check_required’ set but not used [-Wunused-but-set-variable]
   int check_required;
       ^
2014-03-23 10:27:21 +01:00
Holger Hans Peter Freyther 6c0b9c2c42 cli: Re-generate the cmdline.c/cmdline.h with newer gengetopt 2014-03-23 10:27:19 +01:00
Holger Hans Peter Freyther 4afb44a25e systemd: Do not restart when the application exits with 1
This is the case of a wrong config or failure to create a tunnel
2014-03-21 18:01:07 +01:00
Holger Hans Peter Freyther 29567ed125 systemd: Add a simple ggsn service file 2014-03-21 18:01:01 +01:00
Pablo Neira Ayuso 1a1ba02292 gtp: fix endianness in teid field of GTPv0 header
This field needs to be in network byte order as well.
2014-03-20 14:11:25 +01:00
Pablo Neira Ayuso 0674f0b56c gtp: fix wrong binary layout for struct gtp0_header in x86_64
struct gtp0_header needs __attribute__((packed)) to make sure that
gcc doesn't add a hole of 4 bytes to align the 64-bits teid, resulting
in 24 bytes instead of 20 bytes. This was breaking gtpv0 in my gprs
testbed with my x86_64 laptop.

While at it, add also attribute packed to other headers just to
make sure that gcc doesn't pad the structures with holes.
2014-03-20 14:11:25 +01:00
Holger Hans Peter Freyther 0382996e10 gtp: Use struct ul16_t/struct ul66_t to avoid compiler warnings in OsmoSGSN
This is fixing various compiler warnings:
In file included from sgsn_libgtp.c:49:0:
include/gtp.h:397:48: warning: ‘struct ul66_t’ declared inside parameter list [enabled by default]
include/gtp.h:397:48: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
include/gtp.h:398:49: warning: ‘struct ul66_t’ declared inside parameter list [enabled by default]
include/gtp.h:399:53: warning: ‘struct ul16_t’ declared inside parameter list [enabled by default]
include/gtp.h:400:53: warning: ‘struct ul16_t’ declared inside parameter list [enabled by default]

include/gtp.h:397:48: warning: ‘struct ul66_t’ declared inside parameter list [enabled by default]
include/gtp.h:397:48: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
include/gtp.h:398:49: warning: ‘struct ul66_t’ declared inside parameter list [enabled by default]
include/gtp.h:399:53: warning: ‘struct ul16_t’ declared inside parameter list [enabled by default]
include/gtp.h:400:53: warning: ‘struct ul16_t’ declared inside parameter list [enabled by default]
2013-07-27 20:02:19 +02:00
Holger Hans Peter Freyther 0527289c2b build: Do not generate a Makefile in the empty src/ directory 2012-11-06 14:32:55 +01:00
Holger Hans Peter Freyther d7566b8280 pdp: Mark the data as static as only pdp.c should access this data 2012-11-06 14:17:45 +01:00
Holger Hans Peter Freyther 0aa17870bc build: Let the system decide where libraries are searched 2012-11-06 14:10:17 +01:00
Holger Hans Peter Freyther e071e30937 build: Remove subdir-objects as it breaks make distclean
We are not using this option in any of our projects and it is breaking
make distclean. Remove the option for now.

make[2]: Entering directory `/openggsn-0.91/_build/ggsn'
Makefile:307: ../lib/.deps/getopt.Po: No such file or directory
Makefile:308: ../lib/.deps/getopt1.Po: No such file or directory
make[2]: *** No rule to make target `../lib/.deps/getopt1.Po'.  Stop.
2012-11-06 13:59:59 +01:00
Tobias Engel 3d7500e686 Remove out-of-bounds write
This removes an out-of-bounds write. The whole statement can simply be
removed since snprintf already adds the trailing 0 byte.
2012-11-05 13:31:25 +01:00
Harald Welte f4594e236b Fix dpkg-buildpackage build for OpenGGSN
Attached is a trivial patch to make
	"dpkg-buildpackage -rfakeroot -uc -us"
work out of the box.

Tested on ubuntu 12.04 x86_64 but should work on any debian-based
distro.
2012-10-27 11:06:17 +02:00
Eric Butler ab9ff093cb Fix init script in debian package. 2012-08-24 21:16:01 -07:00
Eric Butler 235a095d08 Debian package updates.
* Split out a new libgtp-dev package.
* Updated dependencies.
2012-08-14 18:08:41 -07:00
Harald Welte 95848bafce GTP: don't use magic numbers for T3-REQUESTS and N3-REQUEST 2011-11-02 18:17:50 +01:00
Harald Welte ef71162a74 queue: fix copy+paste mistake in debug statements 2011-11-02 18:07:02 +01:00
Harald Welte b841e57f0b queue: Add some more comments throughout the code (doxygen style) 2011-11-02 13:45:50 +01:00
Harald Welte bb47c354b6 queue: mark non-public functions as static
This makes it a bit more explicit about what is the 'user API' of the
code and what is just used internally.
2011-11-02 13:30:37 +01:00
Harald Welte e65c7390ca queue: use %p format string when printing a pointer 2011-11-02 13:12:53 +01:00
Harald Welte bdca4b7886 configure: use AM_SILENT_RULES when available
this makes the compile process a bit easier to read/follow
2011-11-02 13:11:56 +01:00
Harald Welte d88e11d819 GTP: use socklen_t where appropriate
this fixes some compiler warnings
2011-11-02 13:09:43 +01:00
Harald Welte bed35df298 Convert all code to Linux coding style
After so many years of silence, we don't expect the original author to
return to the project.  To make things a bit simpler for us, we convert
the coding style to what we are used to (Linux style).

The conversion was made using the 'Lindent' script which is part of the
Linux kernel.
2011-11-02 13:06:18 +01:00
Sylvain Munaut ca36f29364 build: Add a proper pkgconfig libgtp.pc for the GTP library
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2011-10-18 13:15:29 +02:00
Harald Welte 3a4c67b4bf optionally do not send recovery with sgsnemu
According to 3GPP TS 29.060 recovery is optional, add command line option --norecovery to remove this field in sgsnemu

Signed-off-by: Yann BONNAMY <yann_bonnamy@yahoo.fr>
Signed-off-by: Harald Welte <laforge@gnumonks.org>
2011-10-07 18:45:54 +02:00
Harald Welte 41af5691ef Add optional RAI Field
Routing Area Information is an optional Field described in 3GPP TS 29.060 7.7.3
it can be added with command line option rai, in the dot separated format MCC.MNC.LAC.RAC
example :  --rai 208.10.65535.255

Signed-off-by: Yann BONNAMY <yann_bonnamy@yahoo.fr>
Signed-off-by: Harald Welte <laforge@gnumonks.org>
2011-10-07 18:42:34 +02:00
Yann BONNAMY 11a398fbc3 sgsnemu support for QoS as defined in 3GPP TS 24.008
this patch allows to tweak any bit of the QoS field of the Create PDP context generated by sgsnemu , aligned with 10.5.6.5 of 3GPP TS 24.008 V10.0.0 (2010-09)

QoS field can be extended to "lenght 12" with option --qose1, as seen in real life on UMTS networks.
extension to lenght 13, 15 and 17 can be done with option --qose2, --qose3, --qose4, never seen IRL but allows to test 3GPP compliance of GGSN.

Signed-off-by: Yann BONNAMY <yann_bonnamy@yahoo.fr>
2011-10-07 18:34:56 +02:00
Yann BONNAMY ad18ccb9df RAI fix
fix ggsn handling of create pdp context when RAI is included and Recovery field is absent

Signed-off-by: Yann BONNAMY <yann_bonnamy@yahoo.fr>
2011-10-07 18:34:02 +02:00
Isabelle Kraemer fe50409675 GTP: Fix bug in update PDP context procedure
I use OpenGGSN to create/update/delete PDP context and I found a bug
in the implementation: when the sgsnemu sends an "update PDP context"
request, it receives back a "create PDP context" response. Below is
the correction I made, I hope it helps.
2011-07-29 16:41:38 +02:00
Harald Welte f5cbbc9558 debian: add openggsn example config files 2011-05-13 21:14:40 +02:00
Harald Welte 142af72b13 debian packaging: add missing openggsn.install file 2011-05-13 21:10:52 +02:00
Harald Welte 38c8f6da35 remove autotools-generated INSTALL file 2011-05-10 17:45:07 +02:00
Harald Welte 6fc42401b9 properly build a library for the content of the lib directory 2011-05-10 17:44:39 +02:00
Harald Welte b502255b8f debian: update to source format git 2011-05-10 17:44:20 +02:00
Harald Welte 629e986ea4 libgtp: introduce cb_recovery() callback
The cb_recovery() callback enables the user application to detect
a change in the restart counter and thus start the appropriate
recovery procedures.
2010-12-24 20:58:09 +01:00
Yann BONNAMY 944dce3e66 Add support for GTP IE's from 3GPP R7
This adds support for the followng new GTP Information Elements:
	RAT_TYPE, USER_LOC, MS_TZ, IMEI_SV

Furthermore, it allows to specify those fields as sgsnemu command line
arguments.
2010-10-29 17:07:44 +02:00
Emmanuel Bretelle 87490d7fa9 IFNAMSIZ includes terminating 0
http://www.delorie.com/gnu/docs/glibc/libc_308.html
thus reverting devname to IFNAMSIZ
and making sure (*tun)->devname[IFNAMSIZ-1] = 0;

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 4e56c83be2 fixed compilation warning against gcc-4.4
* Change arguments of tun_gifindex from:
int tun_gifindex(struct tun_t *this, int *index)
to
int tun_gifindex(struct tun_t *this, __u32 *index)
solves:
../lib/tun.c: In function ‘tun_addaddr’:
../lib/tun.c:265: warning: pointer targets in passing argument 2 of
‘tun_gifindex’ differ in signedness
../lib/tun.c:88: note: expected ‘int *’ but argument is of type ‘__u32
*’

* handle system return code and returns -1 if system failed
solves:
../lib/tun.c: In function ‘tun_runscript’:
../lib/tun.c:895: warning: ignoring return value of ‘system’, declared
with attribute warn_unused_result

* do not dereference a pointer cast and use it as an lvalue
see
http://www.mail-archive.com/svn-commits@lists.digium.com/msg50931.html
solves:
../lib/tun.c: In function ‘tun_route’:
../lib/tun.c:533: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:533: note: initialized from here
../lib/tun.c:534: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:534: note: initialized from here
../lib/tun.c:535: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:535: note: initialized from here
../lib/tun.c: In function ‘tun_setaddr’:
../lib/tun.c:435: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:435: note: initialized from here
../lib/tun.c:452: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:452: note: initialized from here
../lib/tun.c:465: warning: dereferencing pointer ‘({anonymous})’ does
break strict-aliasing rules
../lib/tun.c:465: note: initialized from here

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 91384a4cb0 Do not exceed 80 characters per line
Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle eaaf50095b Set tun devname to IFNAMESIZ+1 to avoid warning
Relevant output from make:

../lib/tun.c: In function ‘tun_new’:
../lib/tun.c:688: warning: array subscript is above array bounds

Caused by assignement:
(*tun)->devname[IFNAMSIZ] = 0;
while devname defined as:
char devname[IFNAMSIZ];

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 2a103687b6 Move common sgsnemu/ggsn files to directory "lib"
Some files like in sgsnemu and ggsn directory where exactly the same.
They are now moved to the same directory for easier maintenance

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 2a7cad57ef Fixe compilation warning
Relevant output of make:

sgsnemu.c: In function ‘process_options’:
sgsnemu.c:443: warning: pointer targets in passing argument 1 of
‘strncpy’ differ in signedness
/usr/include/bits/string3.h:120: note: expected ‘char * __restrict__’
but argument is of type ‘unsigned char *’

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 68521860e0 Fixed compile warning,exit if cant daemonize
Relevant output of make:

ggsn.c: In function ‘main’:
ggsn.c:436: warning: ignoring return value of ‘freopen’, declared with
attribute warn_unused_result
ggsn.c:437: warning: ignoring return value of ‘freopen’, declared with
attribute warn_unused_result
ggsn.c:438: warning: ignoring return value of ‘freopen’, declared with
attribute warn_unused_result
ggsn.c:439: warning: ignoring return value of ‘daemon’, declared with
attribute warn_unused_result

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Emmanuel Bretelle 111e054543 Fix warning on unused fscanf return code
Relevant output of make:

gtp.c: In function ‘log_restart’:
gtp.c:697: warning: ignoring return value of ‘fscanf’, declared with
attribute warn_unused_result

Signed-off-by: Emmanuel Bretelle <chantra@debuntu.org>
2010-10-20 11:04:51 +02:00
Harald Welte 1e9b27b70e debian: add init script for OpenGGSN 2010-08-26 13:26:07 +02:00
Harald Welte a3f42e0738 debian: libgtp has architecture 'any' not 'all' 2010-08-25 12:56:25 +02:00
Harald Welte e916809a32 import debian packaging info 2010-08-24 15:23:33 +02:00
93 changed files with 13952 additions and 14796 deletions

15
.gitignore vendored
View File

@ -2,6 +2,7 @@ Makefile
Makefile.in
aclocal.m4
autom4te.cache
compile
config.guess
config.h.in*
config.h
@ -20,6 +21,20 @@ doc/Makefile.in
ggsn/Makefile.in
gtp/Makefile.in
sgsnemu/Makefile.in
debian/openggsn/
debian/*.debhelper
debian/libgtp/
debian/*.log
INSTALL
debian/autoreconf.*
debian/*.substvars
debian/tmp/
sgsnemu/sgsnemu
debian/files
debian/libgtp-dev/
libgtp.pc
ggsn/ggsn
m4/
*.swp
*.o
*.a

3
.gitreview Normal file
View File

@ -0,0 +1,3 @@
[gerrit]
host=gerrit.osmocom.org
project=openggsn

21
AUTHORS
View File

@ -1,9 +1,16 @@
OpenGGSN - Gateway GPRS Support Node
Copyright (C) 2002 Mondru AB.
The initial developer of the original code is
Jens Jakobsen <jj@openggsn.org>
Contributor(s):
Copyright (C) 2002-2004 Mondru AB, Author: Jens Jakobsen <jj@openggsn.org>
Copyright (C) 2010-2017 Harald Welte <laforge@gnumonks.org>
Copyright (C) 2012-2016 Holger Hans Peter Freyther <zecke@selfish.org>
Copyright (C) 2014-2016 Pablo Neira Ayuso <pablo@gnumonks.org>
Copyright (C) 2014-2016 sysmocom - s.f.m.c. GmbH
Contributors:
Emmanuel Bretelle <chantra@debuntu.org>
Yann BONNAMY <yann_bonnamy@yahoo.fr>
Eric Butler <eric@codebutler.com>
Michael McTernan <mike.mcternan@wavemobile.com>
Alexander Huemer <alexander.huemer@xx.vu>
BJovke <bjovan@gmail.com>
Alexander Couzens <lynxis@fe80.eu>
Ruben Undheim <ruben.undheim@gmail.com>

142
ChangeLog
View File

@ -1,142 +0,0 @@
2004-12-30: Jens Jakobsen <jj@openggsn.org>
Initial MAC OS X support
Quality assurance and improved error logging
QoS length bug fix.
2004-09-11: Jens Jakobsen <jj@openggsn.org>
Added selection mode option to sgsnemu.
Added charging characteristics option to sgsnemu.
Only include charging characteristics in create PDP context
request is if flags are set. (Thanks to Loic Bernable
<leto@vilya.org>).
PPP PCO length bug fix. (Thanks to Loic Bernable
<leto@vilya.org>).
IP pool hash table bugfix and improved logging.
Improved configure.in and Makefile.am for compilation under
Solaris. New config.sub and config.guess.
2004-04-28: Jens Jakobsen <jj@openggsn.org>
Improved Solaris support. OpenGGSN now correctly initializes
tun/tap driver under Solaris. As a consequence the ggsn network
interface IP address is set to the network address plus one.
Added routing manipulation and IP address alias capability for
FreeBSD.
2004-01-19: Jens Jakobsen <jj@openggsn.org>
Initial FreeBSD port (Thanks to Pavel Andreev <pavel.andreev@hp.com>).
IMSI bugfix. The IMSI encoding used by create PDP context was
missing the leading '1111' to indicate that the 16'nd digit was
unused. (Thanks to Pavel Andreev <pavel.andreev@hp.com>).
2004-01-15: Jens Jakobsen <jj@openggsn.org>
Added iptables firewall script.
2004-01-14: Jens Jakobsen <jj@openggsn.org>
Changes to allow compilation under Solaris: u_int8_t changed to uint8_t
and tun api changed for sun platform (#ifdef).
2004-01-09: Jens Jakobsen <jj@openggsn.org>
Fixed bug which included NSAPI in GTPv0 create PDP context messages.
2003-11-10: Jens Jakobsen <jj@openggsn.org>
Added --net option for sgsnemu. Allow user to specify the network
address and mask of the local interface.
Added --gtpversion option for sgsnemu. Allow user to specify which
GTP version to use.
Added --nsapi option for sgsnemu. Allow user to specify which
NSAPI to use.
Changed the functionality for multiple contexts. Previously
contexts were differentiated by nsapi. This limited the number of
contexts to 16. Now each context is established with a new imsi
and msisdn.
2003-10-22: Jens Jakobsen <jj@openggsn.org>
Support for GTP1. Currently without support for the secondary pdp
context activation procedure.
sgsnemu will first attempt to use GTP1. If that fails it will
proceed with GTP0.
Various gtplib API changes to allow support for GTP1.
gtplib now listens to 3 separate UDP ports: GTP0, GTP1 control
plane and GTP1 user plane. A socket for each port has to be
included in the application select loop.
gtplib now verifies that messages are valid for the particular
type of support node. As an example a received Create PDP Context
Request message is not allowed for an SGSN.
Standards compliance document.
2003-07-07: Jens Jakobsen <jj@openggsn.org>
Added spec.in file for building binary RPM packages. Now openggsn
will install binaries, man pages as well as scripts.
Added ggsn and sgsnemu man pages
Added ggsn Sys V init script
Added bootstrap script for autotools automation
2003-04-11: Jens Jakobsen <jj@openggsn.org>
Added -ggdb to gtp, sgsnemu and ggsn makefiles in order to include
debugging information.
Added ippool.c and ippool.h to ggsn. This allows for generic
allocation of dynamic ip addresses based on a <net>/<mask>
description of ip address space. The same files are also used in
sgsnemu, but only for hashing IP addresses. At the same time the
corresponding functionality is removed from pdp.c.
Added syserr.h and syserr.c to ggsn and sgsnemu. These files allow
writing to syslog with file name and line number. Later this
should also be introduced in gtp.
Added support for DNS protocol configuration options in ggsn for
create context response. This allow the MS to setup DNS
configuration correctly.
tun.c and tun.h have been updated to allow setting interface IP
addresses and routes by means of ioctl and netlink. This allow
sgsnemu to allocate an interface IP address for each context
established.
2003-01-29: Jens Jakobsen <jj@openggsn.org>
Added -L../gtp to sgsnemu and ggsn makefiles so that make will
work without an installed libgtp.
Added sgsnemu check to check for valid pointer when deleting tun.
Removed enabling of ip_forward = 1 from ggsn.c and sgsnemu. From a
security point of view it was not very good that openggsn
automatically enabled routing.
Added ipup, ipdown and createif to sgsnemu/cmdline.ggo. Now
sgsnemu will set up default route and then execute ipup script
after tun device has been set up. After tun has been deleted the
ipdown script is executed.
Added support for ping to sgsnemu.
Added ipup and ipdown to ggsn/cmdline.ggo.

182
INSTALL
View File

@ -1,182 +0,0 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

View File

@ -1,2 +1,15 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = gtp ggsn sgsnemu doc
SUBDIRS = lib gtp ggsn sgsnemu doc
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libgtp.pc
BUILT_SOURCES = $(top_srcdir)/.version
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version
EXTRA_DIST = git-version-gen .version README.md README.FreeBSD README.MacOSX README.Solaris
@RELMAKE@

View File

@ -1,3 +1,69 @@
** As of September 2017, OpenGGSN is obsoleted by OsmoGGSN, please use <https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn> instead**
OpenGGSN - Open Source GGSN
===========================
This repository contains a C-language implementation of a GGSN (Gateway
GPRS Support Node), a core network element of ETSI/3GPP cellular
networks such as GPRS, EDGE, UMTS or HSPA.
OpenGGSN is part of the [Osmocom](https://osmocom.org/) Open Source
Mobile Communications projects, even thogh it was previously developed
by Mondru AB.
** As of September 2017, OpenGGSN is obsoleted by OsmoGGSN, please use
<https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn> instead**
Homepage
--------
The official homepage of the project is
https://osmocom.org/projects/openggsn/wiki
GIT Repository
--------------
** As of September 2017, OpenGGSN is obsoleted by OsmoGGSN, please use <https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn> instead**
Homepage
You can clone from the official libosmocore.git repository using
git clone https://gitea.osmocom.org/cellular-infrastructure/openggsn
There is a cgit interface at https://gitea.osmocom.org/cellular-infrastructure/openggsn
Documentation
-------------
There currently is no other documentation other than the wiki on the
homepage. It would be great if somebody would work towards a user
manual that can become part of the osmo-gsm-manuals project.
Mailing List
------------
Discussions related to openggsn are happening on the
osmocom-net-gprs@lists.osmocom.org mailing list, please see
https://lists.osmocom.org/mailman/listinfo/osmocom-net-gprs for
subscription options and the list archive.
Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
Contributing
------------
Our coding standards are described at
https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards
We us a gerrit based patch submission/review process for managing
contributions. Please see
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
more details
The current patch queue for OpenGGSN can be seen at
https://gerrit.osmocom.org/#/q/project:openggsn+status:open
OPENGGSN README
===============
@ -5,19 +71,19 @@ OPENGGSN README
QuickStart
==========
Requirements
------------
*Linux*
OpenGGSN was developed and tested using Redhat 8.0 and 9.0. It should
run also on other Linux distributions as well as FreeBSD, but this is
OpenGGSN was originally developed and tested using Redhat 8.0 and 9.0
and is these days mostly developed on Debian GNU/Linux. It should run
also on other Linux distributions as well as FreeBSD, but this is
untested. Compilation on Solaris 2.8 has also been verified.
*Tun*
The tun driver is required for proper operation of openggsn. For linux
kernels later than 2.4.7 the driver is typically included, but need
to be configured for automatic loading:
The tun driver is required for proper operation of openggsn. For Linux
kernels later than 2.4.7 the driver is typically included, but might
need to be configured for automatic loading:
1. Add the following line to /etc/modules.conf: alias char-major-10-200 tun
2. depmod -a
@ -26,10 +92,10 @@ to be configured for automatic loading:
Installation from binary
------------------------
rpm -i openggsn-<version>.rpm
This will install binaries, man pages, configuration files as well as
a Sys V init script for the ggsn.
OpenGGSN is built for common versions of Debian and Ubuntu as part of
the [Osmocom Nightly Builds](https://osmocom.org/projects/cellular-infrastructure/wiki/Nightly_Builds)
project. If you don't want to do development, it is suggested to simply
use those binary packages, rather than building yourself from source.
Installation from source
@ -77,7 +143,7 @@ can use sgsnemu to test the GGSN.
Support
-------
If you have any questions drop me a line at jj@openggsn.org.
Please contact the Mailing List above for community-based support.
Features
@ -257,9 +323,8 @@ Documentation can be converted to html by issuing:
1. txt2html -pm -tf README > README.html
2. txt2html -pm -tf NEWS > NEWS.html
3. txt2html -pm -tf ChangeLog > ChangeLog.html
4. man2htm ggsn.8 > ggsn.html
5. man2htm sgsnemu.8 > sgsnemu.html
3. man2htm ggsn.8 > ggsn.html
4. man2htm sgsnemu.8 > sgsnemu.html
Installation from binary
@ -337,7 +402,6 @@ sgsnemu --listen 10.0.0.50 --remote 10.0.0.40 --dns 10.20.38.51 --timelimit 10 -
sgsnemu will print something like the following on the screen:
<PRE>
Using DNS server: 10.20.38.51 (10.20.38.51)
Local IP address is: 10.0.0.50 (10.0.0.50)
@ -355,8 +419,6 @@ sgsnemu will print something like the following on the screen:
Received echo response. Cause value: 0
</PRE>
This is quite good. It means that you managed to send off an echo
request to a remote GGSN, and it was friendly enough to answer you. If
you did not get an echo response it means that something is wrong
@ -377,8 +439,6 @@ sgsnemu --listen 10.0.0.50 --remote 10.0.0.40 --dns 10.20.38.51 --timelimit 10 -
sgsnemu will print something like the following on the screen:
<PRE>
Using DNS server: 10.20.38.51 (10.20.38.51)
Local IP address is: 10.0.0.50 (10.0.0.50)
Remote IP address is: 10.0.0.40 (10.0.0.40)
@ -400,7 +460,6 @@ sgsnemu will print something like the following on the screen:
/sbin/ifconfig tun0 192.168.0.1
/sbin/route add -net 192.168.0.0 netmask 255.255.255.0 gw 192.168.0.1
</PRE>
Now a context is established to the remote GGSN. The IP address of the
context is 192.168.0.1. You should be able to ping a known address on
@ -420,11 +479,7 @@ After --timelimit seconds the PDP context is disconnected with the
following messages from sgsnemu:
<PRE>
Disconnecting PDP context #0
Received delete PDP context response. Cause value: 128
Deleting tun interface
</PRE>

9
TODO-RELEASE Normal file
View File

@ -0,0 +1,9 @@
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
# In short:
# LIBVERSION=c:r:a
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line

View File

@ -13,5 +13,5 @@ AC_DEFUN([adl_FUNC_GETOPT_LONG],
[# use the GNU replacement
AC_LIBOBJ(getopt)
AC_LIBOBJ(getopt1)
AC_CONFIG_LINKS([ggsn/getopt.h:ggsn/gnugetopt.h])
AC_CONFIG_LINKS([sgsnemu/getopt.h:sgsnemu/gnugetopt.h])])])])
AC_CONFIG_LINKS([lib/getopt.h:lib/gnugetopt.h])])])])

View File

@ -1,23 +1,34 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(openggsn, 0.91, laforge@gnumonks.org)
AC_INIT(openggsn, m4_esyscmd([./git-version-gen .tarball-version]), osmocom-net-gprs@lists.osmocom.org)
AC_CONFIG_SRCDIR([gtp/gtp.c])
AM_CONFIG_HEADER([config.h])
#AC_CONFIG_HEADER([config.h])
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
AC_CONFIG_AUX_DIR([.])
AC_CANONICAL_SYSTEM
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_AWK
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
LT_INIT
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
AC_MSG_WARN([You need to install pkg-config])
fi
PKG_PROG_PKG_CONFIG([0.20])
#JJAKO Check for libtool
AC_PROG_LIBTOOL
AM_PROG_LIBTOOL
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_LIBOBJ_DIR([lib])
AC_ARG_ENABLE(static-exec,
[ --enable-static-exec Enable static linking of executables],
@ -28,7 +39,7 @@ AC_SUBST(EXEC_LDFLAGS)
case "${host}" in
i*86-*-linux-gnu*)
EXEC_LDADD="-Wl,--rpath -Wl,/usr/local/lib" ;;
EXEC_LDADD="" ;;
*solaris*)
EXEC_LDADD="-lresolv -lsocket -lnsl" ;;
esac
@ -44,10 +55,25 @@ AC_SUBST(EXEC_LDADD)
# FIXME: Replace `main' with a function in `-links':
#AC_CHECK_LIB([inks], [main])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
dnl GTP Linux kernel dependencies
AC_ARG_ENABLE([gtp-linux],
AS_HELP_STRING([--enable-gtp-linux], [Build GTP tunneling Linux kernel]),
[enable_gtp_linux="$enableval"], [enable_gtp_linux="no"])
AS_IF([test "x$enable_gtp_linux" = "xyes"], [
PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0])
])
AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_linux" = "yes"])
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h syslog.h unistd.h])
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
# Check for if header
AC_CHECK_HEADERS([linux/if.h net/if.h])
@ -90,6 +116,12 @@ AC_EGREP_HEADER(rt_msghdr, net/route.h,
AC_DEFINE([HAVE_RT_MSGHDR])],
AC_MSG_RESULT(no))
AC_MSG_CHECKING(whether struct iphdr exists)
AH_TEMPLATE(HAVE_IPHDR)
AC_EGREP_HEADER(struct iphdr, netinet/ip.h,
[AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_IPHDR])],
AC_MSG_RESULT(no))
# Checks for library functions.
AC_PROG_GCC_TRADITIONAL
@ -101,16 +133,25 @@ AC_CHECK_FUNCS(inet_aton inet_addr, break)
# check for getopt in standard library
adl_FUNC_GETOPT_LONG
AM_INIT_AUTOMAKE()
AM_INIT_AUTOMAKE([foreign])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
AC_CONFIG_FILES([Makefile
doc/Makefile
ggsn/Makefile
gtp/Makefile
lib/Makefile
intl/Makefile
po/Makefile
sgsnemu/Makefile
src/Makefile
tests/Makefile
libgtp.pc
openggsn.spec])
AC_OUTPUT
echo "
openggsn Configuration:
GTP Linux kernel support: ${enable_gtp_linux}"

View File

@ -1,48 +0,0 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([sgsnemu/cmdline.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_AWK
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
# Checks for libraries.
# FIXME: Replace `main' with a function in `-le':
AC_CHECK_LIB([e], [main])
# FIXME: Replace `main' with a function in `-lgtp':
AC_CHECK_LIB([gtp], [main])
# FIXME: Replace `main' with a function in `-links':
AC_CHECK_LIB([inks], [main])
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h syslog.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_MODE_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
# Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_CHECK_FUNCS([gethostbyname inet_ntoa memset select socket strdup strerror strtol])
AC_CONFIG_FILES([Makefile
doc/Makefile
ggsn/Makefile
gtp/Makefile
intl/Makefile
po/Makefile
sgsnemu/Makefile
src/Makefile
tests/Makefile])
AC_OUTPUT

39
contrib/jenkins.sh Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env bash
# jenkins build helper script for openbsc. This is how we build on jenkins.osmocom.org
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
set -ex
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
mkdir "$deps" || true
rm -rf "$inst"
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
set +x
echo
echo
echo
echo " =============================== openggsn ==============================="
echo
set -x
cd "$base"
autoreconf --install --force
./configure $GTP
$MAKE $PARALLEL_MAKE
$MAKE distcheck

13
contrib/openggsn.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=OpenGGSN
After=networking.service
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/ggsn -c /etc/ggsn.conf -f
RestartSec=2
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target

49
debian/changelog vendored Normal file
View File

@ -0,0 +1,49 @@
openggsn (0.94.0) UNRELEASED; urgency=medium
[ Holger Hans Peter Freyther ]
* Bump version to ease upgrading from Debian SID.
* Bump libgtp SO version after ABI change.
[ Harald Welte ]
* various documentation / README updates
* improve error logging and propagation
* endian-safe definition of IP header
* IPv6 user plane support
-- Harald Welte <laforge@gnumonks.org> Sun, 13 Aug 2017 09:34:20 +0200
openggsn (0.92) precise; urgency=medium
* Release 0.92
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Mon, 30 Nov 2015 14:05:59 +0100
openggsn (0.91+git34) precise; urgency=medium
* Non-maintainer upload.
-- Holger Hans Peter Freyther <holger@freyther.de> Tue, 23 Sep 2014 16:38:32 +0200
openggsn (0.91+git33) precise; urgency=low
* Fix init script.
-- Eric Butler <eric@codebutler.com> Fri, 24 Aug 2012 21:15:32 -0700
openggsn (0.91+git33) precise; urgency=low
* Update package for Ubuntu Precise.
-- Eric Butler <eric@codebutler.com> Tue, 14 Aug 2012 16:48:59 -0700
openggsn (0.91-2) unstable; urgency=low
* Switch to source/format (git)
-- Harald Welte <laforge@gnumonks.org> Tue, 10 May 2011 17:31:37 +0200
openggsn (0.91-1) unstable; urgency=low
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
-- Harald Welte <laforge@gnumonks.org> Tue, 24 Aug 2010 11:23:40 +0200

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
9

59
debian/control vendored Normal file
View File

@ -0,0 +1,59 @@
Source: openggsn
Maintainer: Harald Welte <laforge@gnumonks.org>
Section: net
Priority: optional
Build-Depends: debhelper (>= 9),
autotools-dev,
pkg-config,
libdpkg-perl, git,
dh-autoreconf,
libosmocore-dev (>= 0.8.0)
Standards-Version: 3.9.6
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/openggsn
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/openggsn
Homepage: https://projects.osmocom.org/projects/openggsn
Package: openggsn
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends}
Description: Gateway GPRS Support Node (GGSN)
OpenGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
operators as the interface between the Internet and the rest of the
mobile network infrastructure.
Package: libgtp1
Architecture: any
Multi-Arch: same
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends}
Description: library implementing the GTP protocol between SGSN and GGSN
OpenGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
operators as the interface between the Internet and the rest of the
mobile network infrastructure.
.
This library is part of openggsn and implements the GTP protocol between
SGSN (Serving GPRS support node) and GGSN.
Package: libgtp-dev
Architecture: any
Multi-Arch: same
Section: libdevel
Depends: ${misc:Depends},
libgtp1 (= ${binary:Version})
Description: Development files for libgtp
OpenGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
operators as the interface between the Internet and the rest of the
mobile network infrastructure.
.
The library libgtp implements the GTP protocol between SGSN and GGSN
and this package contains the development files for this library.
Package: openggsn-dbg
Section: debug
Architecture: any
Priority: extra
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp1 (= ${binary:Version}), openggsn (= ${binary:Version})
Multi-Arch: same
Description: Debug symbols for OpenGGSN

55
debian/copyright vendored Normal file
View File

@ -0,0 +1,55 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: openggsn
Source: http://sourceforge.net/projects/ggsn/
Files: *
Copyright: 2002 Jens Jakobsen <jj@openggsn.org>
2002-2004 Mondru AB
2010-2011 Harald Welte <laforge@gnumonks.org>
License: GPL-2
Files: lib/getopt.c
lib/gnugetopt.h
lib/getopt1.c
Copyright: 1987-2001 Free Software Foundation, Inc.
License: LGPL-2.1+
Files: debian/*
Copyright: 2010-2015 Harald Welte <laforge@gnumonks.org>
2016 Ruben Undheim <ruben.undheim@gmail.com>
License: GPL-2
License: GPL-2
This package is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License
.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public
License version 2 can be found in "/usr/share/common-licenses/GPL-2".
License: LGPL-2.1+
This package is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or (at
your option) any later version.
.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU Lesser General Public
License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1".

2
debian/docs vendored Normal file
View File

@ -0,0 +1,2 @@
NEWS
README.md

5
debian/libgtp-dev.install vendored Normal file
View File

@ -0,0 +1,5 @@
usr/include/*
usr/lib/*/lib*.a
usr/lib/*/lib*.so
usr/lib/*/lib*.la
usr/lib/*/pkgconfig/*

1
debian/libgtp1.install vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/*/lib*.so.*

2
debian/openggsn.examples vendored Normal file
View File

@ -0,0 +1,2 @@
examples/ggsn.conf
examples/sgsnemu.conf

163
debian/openggsn.init vendored Executable file
View File

@ -0,0 +1,163 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: openggsn
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Gateway GPRS Support Node
# Description: Gateway GPRS Support Node
### END INIT INFO
# Author: Harald Welte <laforge@gnumonks.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="OpenGGSN Gateway GPRS Support Node"
NAME=ggsn
DAEMON=/usr/bin/ggsn
DAEMON_ARGS="" # Arguments to run the daemon with
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/openggsn
# Exit if the package is not installed
[ -x $DAEMON ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/openggsn ] && . /etc/default/openggsn
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
DAEMON_ARGS="$DAEMON_ARGS"
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
# Check for runtime directory of nonvolatile data
if [ ! -d /var/lib/ggsn ]; then
mkdir /var/lib/ggsn
fi
# Check for GTP restart counter
if [ ! -f /var/lib/ggsn/gsn_restart ]; then
echo 0 > /var/lib/ggsn/gsn_restart
fi
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

3
debian/openggsn.install vendored Normal file
View File

@ -0,0 +1,3 @@
/usr/bin/ggsn
/usr/bin/sgsnemu
/usr/share/man/man8/*

22
debian/rules vendored Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2)
DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1)
VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
# This has to be exported to make some magic below work.
#export DH_OPTIONS
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@ --with autoreconf
override_dh_strip:
dh_strip --dbg-package=openggsn-dbg
override_dh_autoreconf:
echo $(VERSION) > .tarball-version
dh_autoreconf

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (native)

View File

@ -95,9 +95,8 @@ radio access network and the SGSN. When a connection request is
received the ggsn will allocate a dynamic IP address for the mobile
station, and allow the mobile station to access the Gi
interface. Connections are terminated by either the mobile station or
the SGSN. Runtime errors are reported using the
.B syslogd (8)
facility.
the SGSN. Runtime errors are reported using the Osmocom logging
framework.
Typically
.B ggsn
@ -190,7 +189,7 @@ name resolution.
.TP
.BI --timelimit " seconds"
Exit
.b ggsn
.B ggsn
after \fIseconds\fP. Used for debugging.
@ -219,8 +218,7 @@ billing mechanisms are missing.
.SH "SEE ALSO"
.BR sgsnemu (8),
.BR syslogd (8)
.BR sgsnemu (8)
.SH NOTES
.LP

View File

@ -1,272 +0,0 @@
.\" * OpenGGSN - Gateway GPRS Support Node
.\" * Copyright (C) 2002, 2003 Mondru AB.
.\" * Polish translation copyright (C) 2004 Marek Żakowicz <mazaczek@users.sourceforge.net>
.\" *
.\" * 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.
.\" *
.\" * The initial developer of the original code is
.\" * Jens Jakobsen <jj@openggsn.org>
.\" *
.\" * Contributor(s):
.\" *
.\" * Translation to polish: Marek Zakowicz <mazak@debian.linux.org.pl>
.\" Manual page for ggsn
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
.\" IP indented paragraph
.\" TP hanging label
.TH ggsn 8 "Lipiec 2003"
.SH NAZWA
ggsn \- Węzeł Wspierający Bramy GPRS (ang. Gateway GPRS Support Node).
.SH UŻYTKOWANIE
.B ggsn
\-\-help
.B ggsn
\-\-version
.B ggsn
[
.BI \-\-fg
] [
.BI \-\-debug
] [
.BI \-\-conf " plik"
] [
.BI \-\-pidfile " plik"
] [
.BI \-\-statedir " plik"
] [
.BI \-\-listen " host"
] [
.BI \-\-net " sieć"
] [
.BI \-\-ipup " skrypt"
] [
.BI \-\-ipdown " skrypt"
] [
.BI \-\-dynip " sieć"
] [
.BI \-\-statip " sieć"
] [
.BI \-\-pcodns1 " host"
] [
.BI \-\-pcodns2 " host"
] [
.BI \-\-timelimit " sekundy"
]
.SH OPIS
.B ggsn
jest częścią projektu
.B OpenGGSN
i implementuje funkcjonalność węzła wspierającego bramy GPRS.
Węzły GGSN wykorzystywane przez operatorów sieci komórkowych jako interfejsy
pomiędzy Internetem i resztą infrastruktury sieci komórkowej.
Funkcjonalność i protokoły GPRS zostały ustandaryzowane w ramach projektu
Third Generation Partnership Project (3GPP). Stosownie do specyfikacji 3GPP,
GGSN posiada dwa interfejsy: interfejs Gn/Gp oraz interfejs Gi.
Interfejs Gn/Gp może być postrzegany jako łącze podrzędne węzła GGSN.
Jest on wykorzystywany do komunikacji z Węzłem Dostarczającym Usług GPRS
(SGSN), który z kolei jest interfejsem do radiowej sieci dostępowej.
Interfejs Gn/Gp wykorzystuje protokół tunelowania GPRS (GTP). Pakiety danych
użytkownika (zazwyczaj pakiety IP) tunelowane za pośrednictwem protokołu GTP,
który z kolei wykorzystuje protokół UDP nad IP.
Drugi z interfejsów może być postrzegany jako łącze nadrzędne,
prowadzące z węzła GGSN do zewnętrznej sieci danych.
Gi jest najczęściej interfejsem do Internetu.
.B ggsn
wykorzystuje
.B sterownik TUN/TAP
jako interfejs Gi. Interfejs w sieci tun jest uruchamiany podczas startu
.B ggsn.
.B ggsn
odbiera połączenia nadchodzące od urządzeń ruchomych za pośrednictwem
sieci radiowej oraz SGSN. Gdy nadchodzi żądanie połączenia, ggsn rezerwuje
dla urządzenia ruchomego dynamiczny adres IP i pozwala urządzeniu ruchomemu
korzystać z interfejsu Gi. Połączenia mogą być zamykane zarówno przez
stacje ruchome, jak i SGSN. Błędy występujące podczas pracy programu
raportowane z wykorzystaniem
.B syslogd (8).
W typowej sytuacji
.B ggsn
jest uruchamiany na komputerze z dwoma kartami Ethernet - jedną
przeznaczoną dla interfejsu Gn/Gp i jedną dla interfejsu Gi.
Polityki trasowania i reguły ściany ogniowej powinny być wykorzystane
w celu rozdzielenia ruchu Gi od ruchu Gn/Gp.
.SH OPCJE
.TP
.BI --help
Wyświetla pomoc i na tym kończy wykonanie programu.
.TP
.BI --version
Wyświetla pomoc i na tym kończy wykonanie programu.
.TP
.BI --fg
Uruchamia na pierwszym planie (domyślnie wyłączone).
.TP
.BI --debug
Uruchamia w trybie usuwania błędów (domyślnie wyłączone).
.TP
.BI --conf " plik"
Odczytuje konfigurację z
.I pliku
(domyślnie /etc/ggsn.conf), którego każda linia odpowiada jednej opcji
linii poleceń pozbawionej przedrostka '--'. Opcje podane w linii poleceń
nadpisują opcje podane w pliku konfiguracyjnym.
.TP
.BI --pidfile " plik"
Nazwa
.I pliku
z identyfikatorem procesu (domyślnie /var/run/ggsn.pid)
.TP
.BI --statedir " ścieżka"
.I Ścieżka
do katalogu z trwałymi (nie ulotnymi) danymi (domyślnie /var/lib/ggsn/)
.TP
.BI --listen " host"
Lokalny adres IP, który zostanie użyty do nasłuchu przez interfejs Gn/Gp.
Ta opcja musi zostać podana.
Z przyczyn bezpieczeństwa nie może być wykorzystany INADDR_ANY.
.TP
.BI --net " sieć"
Adres sieci interfejsu Gi (domyślnie 192.168.0.0/24).
Adres sieci jest ustawiany podczas inicjalizacji, gdy
.B ggsn
uruchamia urządzenie tun dla interfejsu Gi.
.TP
.BI --ipup " skrypt"
Skrypt wykonywany po aktywacji interfejsu Gi w sieci tun.
Skrypt jest uruchamiany z następującymi parametrami <nazwa urządzenia> <adres ip>.
.TP
.BI --ipdown " skrypt"
Skrypt wykonywany po wyłączeniu interfejsu Gi w sieci tun.
Skrypt jest uruchamiany z następującymi parametrami <nazwa urządzenia> <adres ip>.
.TP
.BI --dynip " sieć"
Pula dynamicznych adresów sieci IP. Określa pulę dynamicznych adresów IP.
Jeśli ta opcja zostanie pominięta, ggsn wykorzystuje do dynamicznej rezerwacji
adresów IP, adres sieci określony przez opcję
.BI --net.
.TP
.BI --pcodns1 " host"
Serwer PCO DNS 1 (domyślnie 0.0.0.0). PCO jest akronimem
Protocol Configuration Options, co tłumaczy się jako Protokół Opcji
Konfiguracyjnych i jest częścią specyfikacji prtokołów GPRS. Jest
wykorzystywany do informowania stacji ruchomej o adresie serwera DNS
stosowanego do rozwiązywania nazw hostów.
.TP
.BI --pcodns2 " host"
Serwer PCO DNS 2 (domyślnie 0.0.0.0). PCO jest akronimem
Protocol Configuration Options, co tłumaczy się jako Protokół Opcji
Konfiguracyjnych i jest częścią specyfikacji prtokołów GPRS. Jest
wykorzystywany do informowania stacji ruchomej o adresie serwera DNS
stosowanego do rozwiązywania nazw hostów.
.TP
.BI --timelimit " sekundy"
Kończy wykonanie
.b ggsn
po upływie podanej liczy \fIsekund\fP.
Opcja wykorzystywana w celu usuwania błędów.
.SH PLIKI
.I /etc/ggsn.conf
.RS
Plik konfiguracyjny dla
.B ggsn.
.RE
.I /var/run/ggsn.pid
.RS
Plik zawierający identyfikator procesu.
.RE
.I /var/lib/ggsn
.RS
Katalog przechowujący trwałe (nie ulotne) dane.
.RE
.SH BŁĘDY
Zgłaszaj błędy na listę śledzenia błędów OpenGGSN
.I http://sourceforge.net/projects/ggsn/
.B ggsn
ma bardzo ograniczone wsparcie dla zarządzania.
Obecnie zarówno SNMP jak i mechanizmy rozliczania pominięte.
.SH "ZOBACZ TAKŻE"
.BR sgsnemu (8),
.BR syslogd (8)
.SH UWAGI
.LP
Oprócz długich, udokumentowanych w tym podręczniku, opcji
.B ggsn
wspiera również pewną liczbą krótkich opcji o tej samej funkcjonalności.
Wywołaj
.B ggsn --help
by uzyskać pełną listę dostępnych opcji.
Sterownik TUN/TAP jest wymagany dla poprawnego działania
.B ggsn.
Dla jąder linuksa późniejszych niż 2.4.7 sterownik TUN/TAP jest zawarty w jądrze,
chociaż w typowej sytuacji musi być ładowany oddzielnie za pomocą
.B modprobe tun.
Aby ładować automatycznie należy do pliku
.B /etc/modules.conf.
dodać linię
.B alias char-major-10-200 tun
Aby uzyskać informacje o innych platformach zobacz stronę
.I http://vtun.sourceforge.net/tun/
opisującą jak zainstalować i skonfigurować sterownik tun.
.B ggsn
wykorzystuje protokół tunelowania GPRS (GTP) wyspecyfikowany przez
Third Generation Partnership Project (3GPP). Specyfikacje protokołów 3GPP
mogą być znalezione na
.I http://www.3gpp.org
.SH COPYRIGHT
Copyright (C) 2002, 2003 by Mondru AB.
Zawartość tego pliku może być wykorzystywana stosownie do terminów
Ogólnej, Publicznej Licencji (GPL) GNU w wersji 2 dostarczonej wraz
z niniejszą uwagą o prawach autorskich zawartą we wszystkich kopiach
i istotnych fragmentach oprogramowania.
.SH AUTORZY
Jens Jakobsen <jj@openggsn.org>
.SH TŁUMACZENIE
Polish translation copyright (C) 2004 Marek Żakowicz <mazaczek@users.sourceforge.net>
Tłumaczenie jest chronione prawami autorskimi.
Dozwolone jest korzystanie, rozprowadzanie i modyfikacja na zasadach licencji GNU GPL 2.

View File

@ -123,9 +123,7 @@ uses the
for the local interface. A tun network interface is established for
each connection established to the GGSN.
Runtime errors are reported using the
.B syslogd (8)
facility.
Runtime errors are reported using the Osmocom logging framework.
.SH OPTIONS
@ -331,7 +329,7 @@ indicates infinite.
.TP
.BI --pingquiet
Do not print information for each packet received (default = off). Is
quite usefull for high pingrates.
quite useful for high pingrates.
.SH FILES
@ -355,8 +353,7 @@ Report all bugs to the OpenGGSN bug tracking list at
.SH "SEE ALSO"
.BR ggsn (8),
.BR syslog (8)
.BR ggsn (8)
.SH NOTES
.LP

View File

@ -1,407 +0,0 @@
.\" * OpenGGSN - Gateway GPRS Support Node
.\" * Copyright (C) 2002, 2003 Mondru AB.
.\" * Polish translation copyright (C) 2004 Marek Żakowicz <mazaczek@users.sourceforge.net>
.\" *
.\" * 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.
.\" *
.\" * The initial developer of the original code is
.\" * Jens Jakobsen <jj@openggsn.org>
.\" *
.\" * Contributor(s):
.\" *
.\" * Translation to polish: Marek Zakowicz <mazak@debian.linux.org.pl>
.\" Manual page for ggsn
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
.\" IP indented paragraph
.\" TP hanging label
.TH sgsnemu 8 "Maj 2004"
.SH NAZWA
sgsnemu \- Emulator Węzła Dostarczającego Usług GPRS
.SH UŻYTKOWANIE
.B sgsnemu
\-\-help
.B sgsnemu
\-\-version
.B sgsnemu
[
.BI \-\-debug
] [
.BI \-\-conf " plik"
] [
.BI \-\-pidfile " plik"
] [
.BI \-\-statedir " plik"
] [
.BI \-\-dns " host"
] [
.BI \-\-listen " host"
] [
.BI \-\-remote " host"
] [
.BI \-\-contexts " liczba"
] [
.BI \-\-timelimit " sekundy"
] [
.BI \-\-gtpversion " wersja"
] [
.BI \-\-apn " apn"
] [
.BI \-\-selmode " tryb"
] [
.BI \-\-imsi " imsi"
] [
.BI \-\-nsapi " nsapi"
] [
.BI \-\-msisdn " msisdn"
] [
.BI \-\-qos " qos"
] [
.BI \-\-charging " opłata"
] [
.BI \-\-uid " uid"
] [
.BI \-\-pwd " pwd"
] [
.BI \-\-createif
] [
.BI \-\-net " sieć"
] [
.BI \-\-defaultroute
] [
.BI \-\-ipup " skrypt"
] [
.BI \-\-ipdown " skrypt"
] [
.BI \-\-pinghost " host"
] [
.BI \-\-pingrate " liczba"
] [
.BI \-\-pingsize " liczba"
] [
.BI \-\-pingcount " liczba"
]
.SH OPIS
.B sgsnemu
jest częścią projektu
.B OpenGGSN
i implementuje emulator węzła dostarczającego usług GPRS (SGSN).
Może on być wykorzystywany zarówno do testowania węzłów GGSN,
jak rdzenia sieci GRPS, czy połączeń odwiedzających.
Funkcjonalność i protokoły GPRS zostały ustandaryzowane w ramach projektu
Third Generation Partnership Project (3GPP).
Według specyfikacji 3GPP, SGSN posiada kilka interfejsów.
.B sgsnemu
implementuje interfejs Gn/Gp, który jest wykorzystywany w kierunku
węzłów GGSN.
Interfejs Gn/Gp może być postrzegany jako łącze nadrzędne węzła SGSN.
Jest ono wykorzystywane do komunikacji z węzłem GGSN, który zazwyczaj jest
podłączony do Internetu.
Interfejs Gn/Gp wykorzystuje protokół tunelowania GPRS (GTP).
Pakiety użytkownika (zazwyczaj pakiety IP) tunelowane za pośrednictwem protokołu GTP,
który z kolei wykorzystuje protokół UDP nad IP.
.B sgsnemu
ustanawia pewną liczbę połączeń do GGSN.
Wewnętrzny ping transmituje żądania ICMP poprzez już ustanowione połączenia.
Alternatywnie, może być utworzony lokalny interfejs sieciowy.
W tym przypadku
.B sgsnemu
przekazuje pakiety pomiędzy lokalnym interfejsem sieciowym i połączeniami
ustanowionymi na interfejsie Gn/Gp.
.B sgsnemu
wykorzystuje sterownik
.B TUN/TAP
jako interfejs lokalny. Interfejs sieci tun jest ustanawiany dla każdego
połączenia zestawianego z węzłem GGSN.
Błędy występujące podczas pracy programu raportowane z wykorzystaniem
.B syslogd (8).
.SH OPCJE
.TP
.BI --help
Wyświetla pomoc i na tym kończy wykonanie programu.
.TP
.BI --version
Wyświetla pomoc i na tym kończy wykonanie programu.
.TP
.BI --debug
Uruchamia w trybie usuwania błędów (domyślnie wyłączone).
.TP
.BI --conf " plik"
Odczytuje konfigurację z
.I pliku
,którego każda linia odpowiada jednej opcji
linii poleceń pozbawionej przedrostka '--'. Opcje podane w linii poleceń
nadpisują opcje podane w pliku konfiguracyjnym.
.TP
.BI --pidfile " plik"
Nazwa
.I pliku
z identyfikatorem procesu (domyślnie ./sgsnemu.pid)
.TP
.BI --statedir " ścieżka"
.I Ścieżka
do katalogu z trwałymi (nie ulotnymi) danymi (domyślnie ./)
.TP
.BI --dns " host"
Serwer DNS wykorzystywany do zapytań APN.
Jeśli parametr został pominięty, wykorzystywana jest domyślna, systemowa konfiguracja DNS.
.TP
.BI --listen " host"
Lokalny adres IP, który zostanie użyty do nasłuchu przez interfejs Gn/Gp.
Ta opcja musi zostać podana.
Z przyczyn bezpieczeństwa nie może być wykorzystany INADDR_ANY.
.TP
.BI --remote " host"
.I Host
z węzłem GGSN wykorzystywanym do połączeń. Jeśli DNS jest prawidłowo skonfigurowany
to powinno być możliwe podanie nazwy punktu dostępowego (APN) jako nazwy zdalnego hosta.
.TP
.BI --contexts " liczba"
Liczba ustanawianych kontekstów (domyślnie = 1). W przypadku wielu kontekstów
pierwszy kontekst jest ustanawiany z wykorzystaniem imsi + 0 i msidn + 0.
Drugi kontekst jest ustanawiany z wykorzystaniem imsi + 1 i msidn +1.
Trzeci ...
.TP
.BI --timelimit " sekundy"
Kończy wykonanie
.b sgsnemu
po upływie podanej liczy \fIsekund\fP.
W przypadku wykorzystywania opcji ping można zakończyć
.B sgsnemu
po wyłaniu
.B --pingcount
pakietów.
.TP
.BI --gtpversion " wersja"
.I wersja
protokołu GTP wykorzystywana przy ustanawianiu kontekstów (domyślnie = 1).
Jeśli nie jest możliwe ustanowienie kontekstu GTPw1
.B sgsnemu
powtórzy żądanie wykorzystując GTPw0.
.TP
.BI --apn " apn"
.I apn
wykorzystywany przy łączeniu się z węzłem GGSN (domyślnie = internet).
APN jest akronimem angielskich słów Access Point Name.
.TP
.BI --selmode " tryb"
Tryb wyboru wykorzystywany w komunikacji z węzłem GGSN (domyślnie = 0x01).
Jako tryby wyboru mogą być wykorzystane następujące kody:
0: MS lub sieć dostarczana przez APN, subskrypcja zweryfikowana,
1: MS dostarczany przez APN, subskrypcja nie zweryfikowana,
2: sieć dostarczana przez APN, subskrypcja nie zweryfikowana.
.TP
.BI --imsi " imsi"
.I imsi
wykorzystywane w komunikacji z węzłem GGSN (domyślnie = 240010123456789).
IMSI jest akronimem angielskich słów International Mobile Subscriber Identity.
IMSI musi składać się z dokładnie 15 cyfr. Porównaj z opcją
.I contexts
by zobaczyć wykorzystanie
.I imsi
w przypadku wielu kontekstów.
.TP
.BI --nsapi " nsapi"
.I nsapi
wykorzystywane w komunikacji z węzłem GGSN (domyślnie = 0).
Wartość musi być pomiędzy 0, a 15.
.TP
.BI --msisdn " msisdn"
.I msisdn
wykorzystywane w komunikacji z węzłem GGSN (domyślnie = 46702123456).
MSISDN jest akronimem angielskich słów International Mobile Integrated Services Digital Network.
W istocie jest numerem telefonu zapisanym w międzynarodowym formacie bez wiodących 00 lub 011.
Porównaj z opcją
.I contexts
by zobaczyć wykorzystanie
.I msisdn
w przypadku wielu kontekstów.
.TP
.BI --qos " qos"
.I qos
wykorzystywany w komunikacji z węzłem GGSN (domyślnie = 0x0b921f).
QoS jest akronimem angielskich słów Quality of Service.
Format tego parametru został określony na podstawie specyfikacji 3GPP 09.60.
.TP
.BI --charging " opłata"
Charakterystyka rozliczania wykorzystywana w komunikacji z węzłem GGSN
(domyślnie = 0x0800). 0x0800 = normalna, 0x0400 = przedpłata,
0x0200 = płaska rata, 0x0100 = rozliczanie dynamiczne.
Format pola został opisany w specyfikacji 3GPP 32.015.
.TP
.BI --uid " uid"
Identyfikator użytkownika wysyłany do GGSN jako opcja konfiguracyjna protokołu.
.TP
.BI --pwd " hasło"
Identyfikator wysyłane do GGSN jako opcja konfiguracyjna protokołu.
.TP
.BI --createif
Tworzy lokalny interfejs tun, wykorzystywany dla
przesyłania pakietów do i z interfejsu Gn/Gp.
Należy zaznaczyć, że interfejs Gn/Gp zazwyczaj jest kierowany
do Internetu przez GGSN. Tylko jeden interfejs może być utworzony, chociaż
wiele kontekstów może zostać ustanowionych.
Interfejs może być podany dla każdego kontekstu jako adres IP, lub może być
określony za pomocą opcji
.I net.
.TP
.BI --net " sieć"
Adres sieci lokalnego interfejsu.
Opcja
.I net
jest poprawna tylko wtedy, gdy została wykorzystana opcja
.I createif.
Wartość parametru
.I net
jest podawana w formacie cidr (sieć/maska). Jeśli opcja
.I net
zostanie pominięta, adres IP jest rezerwowany dla każdego ustanawianego kontekstu.
.TP
.BI --defaultroute
Definiuje domyślne trasowanie przez lokalny interfejs tun.
.TP
.BI --ipup " skrypt"
Skrypt wykonywany po aktywacji interfejsu Gi w sieci tun.
Skrypt jest uruchamiany z następującymi parametrami <nazwa urządzenia> <adres ip>.
.TP
.BI --ipdown " skrypt"
Skrypt wykonywany po wyłączeniu interfejsu Gi w sieci tun.
Skrypt jest uruchamiany z następującymi parametrami <nazwa urządzenia> <adres ip>.
.TP
.BI --pinghost " host"
Powoduje wysyłanie pakietów ICMP do urządzenia
.I host
poprzez interfejs Gn/Gp. Statystyki połączeń raportowane w formie
bardzo zbliżonej do wyjścia oryginalnego programu ping. Możesz wykorzystać
to udogodnienie do testowania wydajności GGSN.
.TP
.BI --pingrate " liczba"
Ilość żądań ICMP generowanych w przeciągu sekundy (domyślnie = 1).
.TP
.BI --pingsize " liczba"
Rozmiar generowanych żądań ICMP wyrażony w oktetach (domyślnie = 56).
.TP
.BI --pingcount " liczba"
Oczekiwana ilość wygenerowanych żądań ICMP (domyślnie = 0).
Wartość 0 (zero) oznacza wielkość nieograniczoną.
.TP
.BI --pingquiet
Wyłącza wypisywanie informacji o otrzymanych pakietach (domyślnie pakiety wypisywane).
Jest to całkiem przydatne dla dużych ilości pakietów ICMP generowanych w przeciągu sekundy
(porównaj z opcją pingrate).
.SH PLIKI
.I sgsnemu.conf
.RS
Plik konfiguracyjny dla
.B sgsnemu.
.RE
.I .sgsnemu.pid
.RS
Plik zawierający identyfikator procesu.
.RE
.I ./
.RS
Katalog przechowujący trwałe (nie ulotne) dane.
.RE
.SH BŁĘDY
Zgłaszaj błędy na listę śledzenia błędów OpenGGSN
.I http://sourceforge.net/projects/sgsnemu/
.SH "ZOBACZ TAKŻE"
.BR ggsn (8),
.BR syslog (8)
.SH UWAGI
.LP
Oprócz długich, udokumentowanych w tym podręczniku, opcji
.B sgsnemu
wspiera również pewną liczbą krótkich opcji o tej samej funkcjonalności.
Wywołaj
.B sgsnemu --help
by uzyskać pełną listę dostępnych opcji.
Sterownik TUN/TAP jest wymagany dla poprawnego działania
.B sgsnemu.
Dla jąder linuksa późniejszych niż 2.4.7 sterownik TUN/TAP jest zawarty w jądrze,
chociaż w typowej sytuacji musi być ładowany oddzielnie za pomocą
.B modprobe tun.
Aby ładować automatycznie należy do pliku
.B /etc/modules.conf.
dodać linię
.B alias char-major-10-200 tun
Aby uzyskać informacje o innych platformach zobacz stronę
.I http://vtun.sourceforge.net/tun/
opisującą jak zainstalować i skonfigurować sterownik tun.
.B ggsn
wykorzystuje protokół tunelowania GPRS (GTP) wyspecyfikowany przez
Third Generation Partnership Project (3GPP). Specyfikacje protokołów 3GPP
mogą być znalezione na
.I http://www.3gpp.org
.SH COPYRIGHT
Copyright (C) 2002, 2003, 2004 by Mondru AB.
Zawartość tego pliku może być wykorzystywana stosownie do terminów
Ogólnej, Publicznej Licencji (GPL) GNU w wersji 2 dostarczonej wraz
z niniejszą uwagą o prawach autorskich zawartą we wszystkich kopiach
i istotnych fragmentach oprogramowania.
.SH AUTORZY
Jens Jakobsen <jj@openggsn.org>
.SH TŁUMACZENIE
Polish translation copyright (C) 2004 Marek Żakowicz <mazaczek@users.sourceforge.net>
Tłumaczenie jest chronione prawami autorskimi.
Dozwolone jest korzystanie, rozprowadzanie i modyfikacja na zasadach licencji GNU GPL 2.

View File

@ -86,7 +86,7 @@
# 3 bytes corresponding to ????
#qos 0x0b921f
# TAG: qos
# Enable GTP datapath through Linux kernel driver gtp.ko (since 4.7).
#gtp-linux

View File

@ -2,11 +2,18 @@ bin_PROGRAMS = ggsn
AM_LDFLAGS = @EXEC_LDFLAGS@
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
ggsn_LDADD = @LIBOBJS@ @EXEC_LDADD@ -lgtp -L../gtp
if ENABLE_GTP_KERNEL
AM_CFLAGS += -DGTP_KERNEL
ggsn_LDADD = @EXEC_LDADD@ -lgtp -lgtpnl -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS)
else
ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS)
endif
#ggsn_DEPENDENCIES = ../gtp/libgtp.la
ggsn_SOURCES = ggsn.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c lookup.c lookup.h
ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
ggsn_SOURCES = ggsn.c cmdline.c cmdline.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h
if ENABLE_GTP_KERNEL
ggsn_SOURCES += gtp-kernel.c
endif

211
ggsn/checksum.c Normal file
View File

@ -0,0 +1,211 @@
/*
*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* IP/TCP/UDP checksumming routines
*
* Authors: Jorge Cwik, <jorge@laser.satlink.net>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
* Tom May, <ftom@netcom.com>
* Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
* Lots of code moved from tcp.c and ip.c; see those files
* for more names.
*
* 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek:
* Fixed some nasty bugs, causing some horrible crashes.
* A: At some points, the sum (%0) was used as
* length-counter instead of the length counter
* (%1). Thanks to Roman Hodek for pointing this out.
* B: GCC seems to mess up if one uses too many
* data-registers to hold input values and one tries to
* specify d0 and d1 as scratch registers. Letting gcc
* choose these registers itself solves the problem.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
kills, so most of the assembly has to go. */
#if defined(__FreeBSD__)
#define _KERNEL /* needed on FreeBSD 10.x for s6_addr32 */
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/endian.h>
#endif
#include "checksum.h"
#include <arpa/inet.h>
static inline unsigned short from32to16(unsigned int x)
{
/* add up 16-bit and 16-bit for 16+c bit */
x = (x & 0xffff) + (x >> 16);
/* add up carry.. */
x = (x & 0xffff) + (x >> 16);
return x;
}
static unsigned int do_csum(const unsigned char *buff, int len)
{
int odd;
unsigned int result = 0;
if (len <= 0)
goto out;
odd = 1 & (unsigned long) buff;
if (odd) {
#if BYTE_ORDER == LITTLE_ENDIAN
result += (*buff << 8);
#else
result = *buff;
#endif
len--;
buff++;
}
if (len >= 2) {
if (2 & (unsigned long) buff) {
result += *(unsigned short *) buff;
len -= 2;
buff += 2;
}
if (len >= 4) {
const unsigned char *end = buff + ((unsigned)len & ~3);
unsigned int carry = 0;
do {
unsigned int w = *(unsigned int *) buff;
buff += 4;
result += carry;
result += w;
carry = (w > result);
} while (buff < end);
result += carry;
result = (result & 0xffff) + (result >> 16);
}
if (len & 2) {
result += *(unsigned short *) buff;
buff += 2;
}
}
if (len & 1)
#if BYTE_ORDER == LITTLE_ENDIAN
result += *buff;
#else
result += (*buff << 8);
#endif
result = from32to16(result);
if (odd)
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
out:
return result;
}
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
*/
uint16_t ip_fast_csum(const void *iph, unsigned int ihl)
{
return (uint16_t)~do_csum(iph, ihl*4);
}
/*
* computes the checksum of a memory block at buff, length len,
* and adds in "sum" (32-bit)
*
* returns a 32-bit number suitable for feeding into itself
* or csum_tcpudp_magic
*
* this function must be called with even lengths, except
* for the last fragment, which may be odd
*
* it's best to have buff aligned on a 32-bit boundary
*/
uint32_t csum_partial(const void *buff, int len, uint32_t wsum)
{
unsigned int sum = (unsigned int)wsum;
unsigned int result = do_csum(buff, len);
/* add in old sum, and carry.. */
result += sum;
if (sum > result)
result += 1;
return (uint32_t)result;
}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
* in icmp.c
*/
uint16_t ip_compute_csum(const void *buff, int len)
{
return (uint16_t)~do_csum(buff, len);
}
uint16_t csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
uint32_t len, uint8_t proto, uint32_t csum)
{
int carry;
uint32_t ulen;
uint32_t uproto;
uint32_t sum = (uint32_t)csum;
sum += (uint32_t)saddr->s6_addr32[0];
carry = (sum < (uint32_t)saddr->s6_addr32[0]);
sum += carry;
sum += (uint32_t)saddr->s6_addr32[1];
carry = (sum < (uint32_t)saddr->s6_addr32[1]);
sum += carry;
sum += (uint32_t)saddr->s6_addr32[2];
carry = (sum < (uint32_t)saddr->s6_addr32[2]);
sum += carry;
sum += (uint32_t)saddr->s6_addr32[3];
carry = (sum < (uint32_t)saddr->s6_addr32[3]);
sum += carry;
sum += (uint32_t)daddr->s6_addr32[0];
carry = (sum < (uint32_t)daddr->s6_addr32[0]);
sum += carry;
sum += (uint32_t)daddr->s6_addr32[1];
carry = (sum < (uint32_t)daddr->s6_addr32[1]);
sum += carry;
sum += (uint32_t)daddr->s6_addr32[2];
carry = (sum < (uint32_t)daddr->s6_addr32[2]);
sum += carry;
sum += (uint32_t)daddr->s6_addr32[3];
carry = (sum < (uint32_t)daddr->s6_addr32[3]);
sum += carry;
ulen = (uint32_t)htonl((uint32_t) len);
sum += ulen;
carry = (sum < ulen);
sum += carry;
uproto = (uint32_t)htonl(proto);
sum += uproto;
carry = (sum < uproto);
sum += carry;
return csum_fold((uint32_t)sum);
}
/* fold a partial checksum */
uint16_t csum_fold(uint32_t csum)
{
uint32_t sum = (uint32_t)csum;
sum = (sum & 0xffff) + (sum >> 16);
sum = (sum & 0xffff) + (sum >> 16);
return (uint16_t)~sum;
}

13
ggsn/checksum.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
uint16_t ip_fast_csum(const void *iph, unsigned int ihl);
uint32_t csum_partial(const void *buff, int len, uint32_t wsum);
uint16_t ip_compute_csum(const void *buff, int len);
uint16_t csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
uint32_t len, uint8_t proto, uint32_t csum);
uint16_t csum_fold(uint32_t csum);

File diff suppressed because it is too large Load Diff

View File

@ -31,5 +31,8 @@ option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "apn" a "Access point name" string default="internet" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "logfile" - "Logfile for errors" string no
option "loglevel" - "Global log ldevel" string default="error" no
option "gtp-linux" g "GTP linux kernel support" flag off

View File

@ -1,6 +1,9 @@
/* cmdline.h */
/* File autogenerated by gengetopt version 2.17 */
/** @file cmdline.h
* @brief The header file for the command line option parser
* generated by GNU Gengetopt version 2.22.6
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
#ifndef CMDLINE_H
#define CMDLINE_H
@ -10,112 +13,258 @@
#include "config.h"
#endif
#include <stdio.h> /* for FILE */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CMDLINE_PARSER_PACKAGE
/** @brief the program name (used for printing errors) */
#define CMDLINE_PARSER_PACKAGE PACKAGE
#endif
#ifndef CMDLINE_PARSER_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
#ifdef PACKAGE_NAME
#define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME
#else
#define CMDLINE_PARSER_PACKAGE_NAME PACKAGE
#endif
#endif
#ifndef CMDLINE_PARSER_VERSION
/** @brief the program version */
#define CMDLINE_PARSER_VERSION VERSION
#endif
/** @brief Where the command line options are stored */
struct gengetopt_args_info
{
const char *help_help; /* Print help and exit help description. */
const char *version_help; /* Print version and exit help description. */
int fg_flag; /* Run in foreground (default=off). */
const char *fg_help; /* Run in foreground help description. */
int debug_flag; /* Run in debug mode (default=off). */
const char *debug_help; /* Run in debug mode help description. */
char * conf_arg; /* Read configuration file (default='/etc/ggsn.conf'). */
char * conf_orig; /* Read configuration file original value given at command line. */
const char *conf_help; /* Read configuration file help description. */
char * pidfile_arg; /* Filename of process id file (default='/var/run/ggsn.pid'). */
char * pidfile_orig; /* Filename of process id file original value given at command line. */
const char *pidfile_help; /* Filename of process id file help description. */
char * statedir_arg; /* Directory of nonvolatile data (default='/var/lib/ggsn/'). */
char * statedir_orig; /* Directory of nonvolatile data original value given at command line. */
const char *statedir_help; /* Directory of nonvolatile data help description. */
char * listen_arg; /* Local interface. */
char * listen_orig; /* Local interface original value given at command line. */
const char *listen_help; /* Local interface help description. */
char * net_arg; /* Network (default='192.168.0.0/24'). */
char * net_orig; /* Network original value given at command line. */
const char *net_help; /* Network help description. */
char * ipup_arg; /* Script to run after link-up. */
char * ipup_orig; /* Script to run after link-up original value given at command line. */
const char *ipup_help; /* Script to run after link-up help description. */
char * ipdown_arg; /* Script to run after link-down. */
char * ipdown_orig; /* Script to run after link-down original value given at command line. */
const char *ipdown_help; /* Script to run after link-down help description. */
char * dynip_arg; /* Dynamic IP address pool. */
char * dynip_orig; /* Dynamic IP address pool original value given at command line. */
const char *dynip_help; /* Dynamic IP address pool help description. */
char * statip_arg; /* Static IP address pool. */
char * statip_orig; /* Static IP address pool original value given at command line. */
const char *statip_help; /* Static IP address pool help description. */
char * pcodns1_arg; /* PCO DNS Server 1 (default='0.0.0.0'). */
char * pcodns1_orig; /* PCO DNS Server 1 original value given at command line. */
const char *pcodns1_help; /* PCO DNS Server 1 help description. */
char * pcodns2_arg; /* PCO DNS Server 2 (default='0.0.0.0'). */
char * pcodns2_orig; /* PCO DNS Server 2 original value given at command line. */
const char *pcodns2_help; /* PCO DNS Server 2 help description. */
int timelimit_arg; /* Exit after timelimit seconds (default='0'). */
char * timelimit_orig; /* Exit after timelimit seconds original value given at command line. */
const char *timelimit_help; /* Exit after timelimit seconds help description. */
char * apn_arg; /* Access point name (default='internet'). */
char * apn_orig; /* Access point name original value given at command line. */
const char *apn_help; /* Access point name help description. */
int qos_arg; /* Requested quality of service (default='0x0b921f'). */
char * qos_orig; /* Requested quality of service original value given at command line. */
const char *qos_help; /* Requested quality of service help description. */
const char *help_help; /**< @brief Print help and exit help description. */
const char *version_help; /**< @brief Print version and exit help description. */
int fg_flag; /**< @brief Run in foreground (default=off). */
const char *fg_help; /**< @brief Run in foreground help description. */
int debug_flag; /**< @brief Run in debug mode (default=off). */
const char *debug_help; /**< @brief Run in debug mode help description. */
char * conf_arg; /**< @brief Read configuration file (default='/etc/ggsn.conf'). */
char * conf_orig; /**< @brief Read configuration file original value given at command line. */
const char *conf_help; /**< @brief Read configuration file help description. */
char * pidfile_arg; /**< @brief Filename of process id file (default='/var/run/ggsn.pid'). */
char * pidfile_orig; /**< @brief Filename of process id file original value given at command line. */
const char *pidfile_help; /**< @brief Filename of process id file help description. */
char * statedir_arg; /**< @brief Directory of nonvolatile data (default='/var/lib/ggsn/'). */
char * statedir_orig; /**< @brief Directory of nonvolatile data original value given at command line. */
const char *statedir_help; /**< @brief Directory of nonvolatile data help description. */
char * listen_arg; /**< @brief Local interface. */
char * listen_orig; /**< @brief Local interface original value given at command line. */
const char *listen_help; /**< @brief Local interface help description. */
char * net_arg; /**< @brief Network (default='192.168.0.0/24'). */
char * net_orig; /**< @brief Network original value given at command line. */
const char *net_help; /**< @brief Network help description. */
char * ipup_arg; /**< @brief Script to run after link-up. */
char * ipup_orig; /**< @brief Script to run after link-up original value given at command line. */
const char *ipup_help; /**< @brief Script to run after link-up help description. */
char * ipdown_arg; /**< @brief Script to run after link-down. */
char * ipdown_orig; /**< @brief Script to run after link-down original value given at command line. */
const char *ipdown_help; /**< @brief Script to run after link-down help description. */
char * dynip_arg; /**< @brief Dynamic IP address pool. */
char * dynip_orig; /**< @brief Dynamic IP address pool original value given at command line. */
const char *dynip_help; /**< @brief Dynamic IP address pool help description. */
char * statip_arg; /**< @brief Static IP address pool. */
char * statip_orig; /**< @brief Static IP address pool original value given at command line. */
const char *statip_help; /**< @brief Static IP address pool help description. */
char * pcodns1_arg; /**< @brief PCO DNS Server 1 (default='0.0.0.0'). */
char * pcodns1_orig; /**< @brief PCO DNS Server 1 original value given at command line. */
const char *pcodns1_help; /**< @brief PCO DNS Server 1 help description. */
char * pcodns2_arg; /**< @brief PCO DNS Server 2 (default='0.0.0.0'). */
char * pcodns2_orig; /**< @brief PCO DNS Server 2 original value given at command line. */
const char *pcodns2_help; /**< @brief PCO DNS Server 2 help description. */
int timelimit_arg; /**< @brief Exit after timelimit seconds (default='0'). */
char * timelimit_orig; /**< @brief Exit after timelimit seconds original value given at command line. */
const char *timelimit_help; /**< @brief Exit after timelimit seconds help description. */
char * apn_arg; /**< @brief Access point name (default='internet'). */
char * apn_orig; /**< @brief Access point name original value given at command line. */
const char *apn_help; /**< @brief Access point name help description. */
int qos_arg; /**< @brief Requested quality of service (default='0x0b921f'). */
char * qos_orig; /**< @brief Requested quality of service original value given at command line. */
const char *qos_help; /**< @brief Requested quality of service help description. */
char * logfile_arg; /**< @brief Logfile for errors. */
char * logfile_orig; /**< @brief Logfile for errors original value given at command line. */
const char *logfile_help; /**< @brief Logfile for errors help description. */
char * loglevel_arg; /**< @brief Global log ldevel (default='error'). */
char * loglevel_orig; /**< @brief Global log ldevel original value given at command line. */
const char *loglevel_help; /**< @brief Global log ldevel help description. */
int gtp_linux_flag; /**< @brief GTP linux kernel support (default=off). */
const char *gtp_linux_help; /**< @brief GTP linux kernel support help description. */
int help_given ; /* Whether help was given. */
int version_given ; /* Whether version was given. */
int fg_given ; /* Whether fg was given. */
int debug_given ; /* Whether debug was given. */
int conf_given ; /* Whether conf was given. */
int pidfile_given ; /* Whether pidfile was given. */
int statedir_given ; /* Whether statedir was given. */
int listen_given ; /* Whether listen was given. */
int net_given ; /* Whether net was given. */
int ipup_given ; /* Whether ipup was given. */
int ipdown_given ; /* Whether ipdown was given. */
int dynip_given ; /* Whether dynip was given. */
int statip_given ; /* Whether statip was given. */
int pcodns1_given ; /* Whether pcodns1 was given. */
int pcodns2_given ; /* Whether pcodns2 was given. */
int timelimit_given ; /* Whether timelimit was given. */
int apn_given ; /* Whether apn was given. */
int qos_given ; /* Whether qos was given. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
unsigned int fg_given ; /**< @brief Whether fg was given. */
unsigned int debug_given ; /**< @brief Whether debug was given. */
unsigned int conf_given ; /**< @brief Whether conf was given. */
unsigned int pidfile_given ; /**< @brief Whether pidfile was given. */
unsigned int statedir_given ; /**< @brief Whether statedir was given. */
unsigned int listen_given ; /**< @brief Whether listen was given. */
unsigned int net_given ; /**< @brief Whether net was given. */
unsigned int ipup_given ; /**< @brief Whether ipup was given. */
unsigned int ipdown_given ; /**< @brief Whether ipdown was given. */
unsigned int dynip_given ; /**< @brief Whether dynip was given. */
unsigned int statip_given ; /**< @brief Whether statip was given. */
unsigned int pcodns1_given ; /**< @brief Whether pcodns1 was given. */
unsigned int pcodns2_given ; /**< @brief Whether pcodns2 was given. */
unsigned int timelimit_given ; /**< @brief Whether timelimit was given. */
unsigned int apn_given ; /**< @brief Whether apn was given. */
unsigned int qos_given ; /**< @brief Whether qos was given. */
unsigned int logfile_given ; /**< @brief Whether logfile was given. */
unsigned int loglevel_given ; /**< @brief Whether loglevel was given. */
unsigned int gtp_linux_given ; /**< @brief Whether gtp-linux was given. */
} ;
/** @brief The additional parameters to pass to parser functions */
struct cmdline_parser_params
{
int override; /**< @brief whether to override possibly already present options (default 0) */
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
} ;
/** @brief the purpose string of the program */
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
/** @brief the description string of the program */
extern const char *gengetopt_args_info_description;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
int cmdline_parser (int argc, char * const *argv,
/**
* The command line parser
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser (int argc, char **argv,
struct gengetopt_args_info *args_info);
int cmdline_parser2 (int argc, char * const *argv,
/**
* The command line parser (version with additional parameters - deprecated)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_ext() instead
*/
int cmdline_parser2 (int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The command line parser (version with additional parameters)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_ext (int argc, char **argv,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
* @param outfile the stream where to dump options
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_dump(FILE *outfile,
struct gengetopt_args_info *args_info);
/**
* Save the contents of the option struct into a (text) file.
* This file can be read by the config file parser (if generated by gengetopt)
* @param filename the file where to save
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
void cmdline_parser_print_help(void);
/**
* Print the version
*/
void cmdline_parser_print_version(void);
/**
* Initializes all the fields a cmdline_parser_params structure
* to their default values
* @param params the structure to initialize
*/
void cmdline_parser_params_init(struct cmdline_parser_params *params);
/**
* Allocates dynamically a cmdline_parser_params structure and initializes
* all its fields to their default values
* @return the created and initialized cmdline_parser_params structure
*/
struct cmdline_parser_params *cmdline_parser_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
void cmdline_parser_init (struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
void cmdline_parser_free (struct gengetopt_args_info *args_info);
int cmdline_parser_configfile (char * const filename,
/**
* The config file parser (deprecated version)
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_config_file() instead
*/
int cmdline_parser_configfile (const char *filename,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The config file parser
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_config_file (const char *filename,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Checks that all the required options were specified
* @param args_info the structure to check
* @param prog_name the name of the program that will be used to print
* possible errors
* @return
*/
int cmdline_parser_required (struct gengetopt_args_info *args_info,
const char *prog_name);

File diff suppressed because it is too large Load Diff

View File

@ -1,188 +0,0 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +0,0 @@
/* Declarations for getopt.
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
/* If __GNU_LIBRARY__ is not already defined, either we are being used
standalone, or this is the first header included in the source file.
If we are being used with glibc, we need to include <features.h>, but
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
not defined, include <ctype.h>, which will pull in <features.h> for us
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
doesn't flood the namespace with stuff the way some other headers do.) */
#if !defined __GNU_LIBRARY__
# include <ctype.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
#ifndef __need_getopt
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
# if (defined __STDC__ && __STDC__) || defined __cplusplus
const char *name;
# else
char *name;
# endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, `optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in `optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU `getopt'.
The argument `--' causes premature termination of argument
scanning, explicitly telling `getopt' that there are no more
options.
If OPTS begins with `--', then non-option arguments are treated as
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
# else /* not __GNU_LIBRARY__ */
extern int getopt ();
# endif /* __GNU_LIBRARY__ */
# ifndef __need_getopt
extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */

223
ggsn/gtp-kernel.c Normal file
View File

@ -0,0 +1,223 @@
#ifdef __linux__
#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
#endif
#include "../config.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <libgtpnl/gtp.h>
#include <libgtpnl/gtpnl.h>
#include <libmnl/libmnl.h>
#include <errno.h>
#include <time.h>
#include "../lib/tun.h"
#include "../lib/syserr.h"
#include "../gtp/pdp.h"
#include "../gtp/gtp.h"
#include <libgtpnl/gtp.h>
#include <libgtpnl/gtpnl.h>
#include <libmnl/libmnl.h>
#include "gtp-kernel.h"
static void pdp_debug(struct pdp_t *pdp)
{
int i;
uint64_t teid;
if (!debug)
return;
printf("version %u\n", pdp->version);
if (pdp->version == 0) {
teid = pdp_gettid(pdp->imsi, pdp->nsapi);
printf("flowid %u\n", pdp->flru);
} else {
teid = pdp->teid_gn; /* GTPIE_TEI_DI */
}
printf("teid %llx\n", teid);
printf("address (%u)\n", pdp->eua.l);
/* Byte 0: 0xf1 == IETF */
/* Byte 1: 0x21 == IPv4 */
/* Byte 2-6: IPv4 address */
for (i = 0; i < 6; i++)
printf("%x ", pdp->eua.v[i] & 0xff); /* GTPIE_EUA */
printf("\n");
printf("sgsn-addr (%u)\n", pdp->gsnrc.l);
for (i = 0; i < 4; i++)
printf("%x ", pdp->gsnrc.v[i] & 0xff); /* GTPIE_GSN_ADDR */
printf("\n");
}
static struct {
int genl_id;
struct mnl_socket *nl;
bool enabled;
} gtp_nl;
/* Always forces the kernel to allocate gtp0. If it exists it hits EEXIST */
#define GTP_DEVNAME "gtp0"
int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
size_t prefixlen, const char *net_arg)
{
if (gtp_dev_create(-1, GTP_DEVNAME, gsn->fd0, gsn->fd1u) < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"cannot create GTP tunnel device: %s\n",
strerror(errno));
return -1;
}
gtp_nl.enabled = true;
gtp_nl.nl = genl_socket_open();
if (gtp_nl.nl == NULL) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"cannot create genetlink socket\n");
return -1;
}
gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
if (gtp_nl.genl_id < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"cannot lookup GTP genetlink ID\n");
return -1;
}
if (debug) {
SYS_ERR(DGGSN, LOGL_NOTICE, 0,
"Using the GTP kernel mode (genl ID is %d)\n",
gtp_nl.genl_id);
}
DEBUGP(DGGSN, "Setting route to reach %s via %s\n",
net_arg, GTP_DEVNAME);
if (gtp_dev_config(GTP_DEVNAME, net, prefixlen) < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"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, GTP_DEVNAME, net_arg);
cmd[sizeof(cmd)-1] = '\0';
err = system(cmd);
if (err < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"Failed to launch script `%s'", ipup);
return -1;
}
}
SYS_ERR(DGGSN, LOGL_NOTICE, 0, "GTP kernel configured\n");
return 0;
}
void gtp_kernel_stop(void)
{
if (!gtp_nl.enabled)
return;
gtp_dev_destroy(GTP_DEVNAME);
}
int gtp_kernel_tunnel_add(struct pdp_t *pdp)
{
struct in_addr ms, sgsn;
struct gtp_tunnel *t;
int ret;
if (!gtp_nl.enabled)
return 0;
pdp_debug(pdp);
t = gtp_tunnel_alloc();
if (t == NULL)
return -1;
memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME));
gtp_tunnel_set_version(t, pdp->version);
gtp_tunnel_set_ms_ip4(t, &ms);
gtp_tunnel_set_sgsn_ip4(t, &sgsn);
if (pdp->version == 0) {
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
gtp_tunnel_set_flowid(t, pdp->flru);
} else {
gtp_tunnel_set_i_tei(t, pdp->teid_own);
/* use the TEI advertised by SGSN when sending packets
* towards the SGSN */
gtp_tunnel_set_o_tei(t, pdp->teid_gn);
}
ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
gtp_tunnel_free(t);
return ret;
}
int gtp_kernel_tunnel_del(struct pdp_t *pdp)
{
struct gtp_tunnel *t;
int ret;
if (!gtp_nl.enabled)
return 0;
pdp_debug(pdp);
t = gtp_tunnel_alloc();
if (t == NULL)
return -1;
gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME));
gtp_tunnel_set_version(t, pdp->version);
if (pdp->version == 0) {
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
gtp_tunnel_set_flowid(t, pdp->flru);
} else {
gtp_tunnel_set_i_tei(t, pdp->teid_own);
}
ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
gtp_tunnel_free(t);
return ret;
}
int gtp_kernel_enabled(void)
{
return gtp_nl.enabled;
}

45
ggsn/gtp-kernel.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _GTP_KERNEL_H_
#define _GTP_KERNEL_H_
struct gengetopt_args_info;
extern int debug;
extern char *ipup;
#ifdef GTP_KERNEL
int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
size_t prefixlen, const char *net_arg);
void gtp_kernel_stop(void);
int gtp_kernel_tunnel_add(struct pdp_t *pdp);
int gtp_kernel_tunnel_del(struct pdp_t *pdp);
int gtp_kernel_enabled(void);
#else
static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
size_t prefixlen, const char *net_arg)
{
SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n");
return -1;
}
static inline void gtp_kernel_stop(void) {}
static inline int gtp_kernel_tunnel_add(struct pdp_t *pdp)
{
return 0;
}
static inline int gtp_kernel_tunnel_del(struct pdp_t *pdp)
{
return 0;
}
static inline int gtp_kernel_enabled(void)
{
return 0;
}
#endif
#endif /* _GTP_KERNEL_H_ */

238
ggsn/icmpv6.c Normal file
View File

@ -0,0 +1,238 @@
/* Minimal ICMPv6 code for generating router advertisements as required by
* relevant 3GPP specs for a GGSN with IPv6 PDP contexts */
/* (C) 2017 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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <netinet/in.h>
#if defined(__FreeBSD__)
#include <sys/types.h> /* FreeBSD 10.x needs this before ip6.h */
#include <sys/endian.h>
#endif
#include <netinet/ip6.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>
#include "checksum.h"
#include "../gtp/gtp.h"
#include "../gtp/pdp.h"
#include "../lib/ippool.h"
#include "../lib/syserr.h"
#include "config.h"
/* 29.061 11.2.1.3.4 IPv6 Router Configuration Variables in GGSN */
#define GGSN_MaxRtrAdvInterval 21600 /* 6 hours */
#define GGSN_MinRtrAdvInterval 16200 /* 4.5 hours */
#define GGSN_AdvValidLifetime 0xffffffff /* infinite */
#define GGSN_AdvPreferredLifetime 0xffffffff /* infinite */
struct icmpv6_hdr {
uint8_t type;
uint8_t code;
uint16_t csum;
} __attribute__ ((packed));
/* RFC4861 Section 4.2 */
struct icmpv6_radv_hdr {
struct icmpv6_hdr hdr;
uint8_t cur_ho_limit;
#if BYTE_ORDER == LITTLE_ENDIAN
uint8_t res:6,
m:1,
o:1;
#elif BYTE_ORDER == BIG_ENDIAN
uint8_t m:1,
o:1,
res:6;
#else
# error "Please fix <bits/endian.h>"
#endif
uint16_t router_lifetime;
uint32_t reachable_time;
uint32_t retrans_timer;
uint8_t options[0];
} __attribute__ ((packed));
/* RFC4861 Section 4.6 */
struct icmpv6_opt_hdr {
uint8_t type;
/* length in units of 8 octets, including type+len! */
uint8_t len;
uint8_t data[0];
} __attribute__ ((packed));
/* RFC4861 Section 4.6.2 */
struct icmpv6_opt_prefix {
struct icmpv6_opt_hdr hdr;
uint8_t prefix_len;
#if BYTE_ORDER == LITTLE_ENDIAN
uint8_t res:6,
a:1,
l:1;
#elif BYTE_ORDER == BIG_ENDIAN
uint8_t l:1,
a:1,
res:6;
#else
# error "Please fix <bits/endian.h>"
#endif
uint32_t valid_lifetime;
uint32_t preferred_lifetime;
uint32_t res2;
uint8_t prefix[16];
} __attribute__ ((packed));
/*! construct a 3GPP 29.061 compliant router advertisement for a given prefix
* \param[in] saddr Source IPv6 address for router advertisement
* \param[in] daddr Destination IPv6 address for router advertisement IPv6 header
* \param[in] prefix The single prefix to be advertised (/64 implied!)i
* \returns callee-allocated message buffer containing router advertisement */
struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr,
const struct in6_addr *daddr,
const struct in6_addr *prefix)
{
struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RA");
struct icmpv6_radv_hdr *ra;
struct icmpv6_opt_prefix *ra_opt_pref;
struct ip6_hdr *i6h;
uint32_t len;
uint16_t skb_csum;
OSMO_ASSERT(msg);
ra = (struct icmpv6_radv_hdr *) msgb_put(msg, sizeof(*ra));
ra->hdr.type = 134; /* see RFC4861 4.2 */
ra->hdr.code = 0; /* see RFC4861 4.2 */
ra->hdr.csum = 0; /* updated below */
ra->cur_ho_limit = 64; /* seems reasonable? */
/* the GGSN shall leave the M-flag cleared in the Router
* Advertisement messages */
ra->m = 0;
/* The GGSN may set the O-flag if there are additional
* configuration parameters that need to be fetched by the MS */
ra->o = 0; /* no DHCPv6 */
ra->res = 0;
/* RFC4861 Default: 3 * MaxRtrAdvInterval */
ra->router_lifetime = htons(3*GGSN_MaxRtrAdvInterval);
ra->reachable_time = 0; /* Unspecified */
/* RFC4861 Section 4.6.2 */
ra_opt_pref = (struct icmpv6_opt_prefix *) msgb_put(msg, sizeof(*ra_opt_pref));
ra_opt_pref->hdr.type = 3; /* RFC4861 4.6.2 */
ra_opt_pref->hdr.len = 4; /* RFC4861 4.6.2 */
ra_opt_pref->prefix_len = 64; /* only prefix length as per 3GPP */
/* The Prefix is contained in the Prefix Information Option of
* the Router Advertisements and shall have the A-flag set
* and the L-flag cleared */
ra_opt_pref->a = 1;
ra_opt_pref->l = 0;
ra_opt_pref->res = 0;
/* The lifetime of the prefix shall be set to infinity */
ra_opt_pref->valid_lifetime = htonl(GGSN_AdvValidLifetime);
ra_opt_pref->preferred_lifetime = htonl(GGSN_AdvPreferredLifetime);
ra_opt_pref->res2 = 0;
memcpy(ra_opt_pref->prefix, prefix, sizeof(ra_opt_pref->prefix));
/* checksum */
skb_csum = csum_partial(msgb_data(msg), msgb_length(msg), 0);
len = msgb_length(msg);
ra->hdr.csum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, skb_csum);
/* Push IPv6 header in front of ICMPv6 packet */
i6h = (struct ip6_hdr *) msgb_push(msg, sizeof(*i6h));
/* 4 bits version, 8 bits TC, 20 bits flow-ID */
i6h->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
i6h->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(len);
i6h->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_ICMPV6;
i6h->ip6_ctlun.ip6_un1.ip6_un1_hlim = 255;
i6h->ip6_src = *saddr;
i6h->ip6_dst = *daddr;
return msg;
}
/* Walidate an ICMPv6 router solicitation according to RFC4861 6.1.1 */
static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
{
const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
//const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
/* Hop limit field must have 255 */
if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_hlim != 255)
return false;
/* FIXME: ICMP checksum is valid */
/* ICMP length (derived from IP length) is 8 or more octets */
if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_plen < 8)
return false;
/* FIXME: All included options have a length > 0 */
/* FIXME: If IP source is unspecified, no source link-layer addr option */
return true;
}
/* RFC3307 link-local scope multicast address */
static const struct in6_addr my_local_addr = {
.s6_addr = { 0x01,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0xff }
};
/* handle incoming packets to the all-routers multicast address */
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const uint8_t *pack, unsigned len)
{
struct ippoolm_t *member = pdp->peer;
const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
struct msgb *msg;
OSMO_ASSERT(pdp);
OSMO_ASSERT(member);
if (len < sizeof(*ip6h)) {
LOGP(DICMP6, LOGL_NOTICE, "Packet too short: %u bytes\n", len);
return -1;
}
/* we only treat ICMPv6 here */
if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_ICMPV6) {
LOGP(DICMP6, LOGL_DEBUG, "Ignoring non-ICMP to all-routers mcast\n");
return 0;
}
if (len < sizeof(*ip6h) + sizeof(*ic6h)) {
LOGP(DICMP6, LOGL_NOTICE, "Short ICMPv6 packet: %s\n", osmo_hexdump(pack, len));
return -1;
}
switch (ic6h->type) {
case 133: /* router solicitation */
if (ic6h->code != 0) {
LOGP(DICMP6, LOGL_NOTICE, "ICMPv6 type 133 but code %d\n", ic6h->code);
return -1;
}
if (!icmpv6_validate_router_solicit(pack, len)) {
LOGP(DICMP6, LOGL_NOTICE, "Invalid Router Solicitation: %s\n",
osmo_hexdump(pack, len));
return -1;
}
/* FIXME: Send router advertisement from GGSN link-local
* address to MS link-local address, including prefix
* allocated to this PDP context */
msg = icmpv6_construct_ra(&my_local_addr, &ip6h->ip6_src, &member->addr.v6);
/* Send the constructed RA to the MS */
gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
msgb_free(msg);
break;
default:
LOGP(DICMP6, LOGL_DEBUG, "Unknown ICMPv6 type %u\n", ic6h->type);
break;
}
return 0;
}

6
ggsn/icmpv6.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include "../gtp/gtp.h"
#include "../gtp/pdp.h"
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const uint8_t *pack, unsigned len);

View File

@ -1,526 +0,0 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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 <sys/types.h>
#include <netinet/in.h> /* in_addr */
#include <stdlib.h> /* calloc */
#include <stdio.h> /* sscanf */
#include <syslog.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "syserr.h"
#include "ippool.h"
#include "lookup.h"
int ippool_printaddr(struct ippool_t *this) {
unsigned int n;
printf("ippool_printaddr\n");
printf("Firstdyn %d\n", this->firstdyn - this->member);
printf("Lastdyn %d\n", this->lastdyn - this->member);
printf("Firststat %d\n", this->firststat - this->member);
printf("Laststat %d\n", this->laststat - this->member);
printf("Listsize %d\n", this->listsize);
for (n=0; n<this->listsize; n++) {
printf("Unit %d inuse %d prev %d next %d addr %s %x\n",
n,
this->member[n].inuse,
this->member[n].prev - this->member,
this->member[n].next - this->member,
inet_ntoa(this->member[n].addr),
this->member[n].addr.s_addr
);
}
return 0;
}
int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member) {
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Insert into hash table */
hash = ippool_hash4(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash)
p_prev = p;
if (!p_prev)
this->hash[hash] = member;
else
p_prev->nexthash = member;
return 0; /* Always OK to insert */
}
int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member) {
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Find in hash table */
hash = ippool_hash4(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if (p == member) {
break;
}
p_prev = p;
}
if (p!= member) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"ippool_hashdel: Tried to delete member not in hash table");
return -1;
}
if (!p_prev)
this->hash[hash] = p->nexthash;
else
p_prev->nexthash = p->nexthash;
return 0;
}
unsigned long int ippool_hash4(struct in_addr *addr) {
return lookup((unsigned char*) &addr->s_addr, sizeof(addr->s_addr), 0);
}
#ifndef IPPOOL_NOIP6
unsigned long int ippool_hash6(struct in6_addr *addr) {
return lookup((unsigned char*) addr->u6_addr8, sizeof(addr->u6_addr8), 0);
}
#endif
/* Get IP address and mask */
int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number) {
/* Parse only first instance of network for now */
/* Eventually "number" will indicate the token which we want to parse */
unsigned int a1, a2, a3, a4;
unsigned int m1, m2, m3, m4;
int c;
int m;
int masklog;
c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u",
&a1, &a2, &a3, &a4,
&m1, &m2, &m3, &m4);
switch (c) {
case 4:
mask->s_addr = 0xffffffff;
break;
case 5:
if (m1 > 32) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Invalid mask */
}
mask->s_addr = htonl(0xffffffff << (32 - m1));
break;
case 8:
if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Wrong mask format */
}
m = m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4;
for (masklog = 0; ((1 << masklog) < ((~m)+1)); masklog++);
if (((~m)+1) != (1 << masklog)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Wrong mask format (not all ones followed by all zeros)*/
}
mask->s_addr = htonl(m);
break;
default:
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Invalid mask */
}
if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Wrong IP address format");
return -1;
}
else
addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
return 0;
}
/* Create new address pool */
int ippool_new(struct ippool_t **this, char *dyn, char *stat,
int allowdyn, int allowstat, int flags) {
/* Parse only first instance of pool for now */
int i;
struct in_addr addr;
struct in_addr mask;
struct in_addr stataddr;
struct in_addr statmask;
unsigned int m;
int listsize;
int dynsize;
unsigned int statsize;
if (!allowdyn) {
dynsize = 0;
}
else {
if (ippool_aton(&addr, &mask, dyn, 0)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to parse dynamic pool");
return -1;
}
/* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */
if (flags & IPPOOL_NOGATEWAY) {
flags |= IPPOOL_NONETWORK;
}
m = ntohl(mask.s_addr);
dynsize = ((~m)+1);
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
dynsize--;
if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */
dynsize--;
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
dynsize--;
}
if (!allowstat) {
statsize = 0;
stataddr.s_addr = 0;
statmask.s_addr = 0;
}
else {
if (ippool_aton(&stataddr, &statmask, stat, 0)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to parse static range");
return -1;
}
m = ntohl(statmask.s_addr);
statsize = ((~m)+1);
if (statsize > IPPOOL_STATSIZE) statsize = IPPOOL_STATSIZE;
}
listsize = dynsize + statsize; /* Allocate space for static IP addresses */
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for ippool");
return -1;
}
(*this)->allowdyn = allowdyn;
(*this)->allowstat = allowstat;
(*this)->stataddr = stataddr;
(*this)->statmask = statmask;
(*this)->listsize += listsize;
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))){
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for members in ippool");
return -1;
}
for ((*this)->hashlog = 0;
((1 << (*this)->hashlog) < listsize);
(*this)->hashlog++);
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
/* Determine hashsize */
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
(*this)->hashmask = (*this)->hashsize -1;
/* Allocate hash table */
if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for hash members in ippool");
return -1;
}
(*this)->firstdyn = NULL;
(*this)->lastdyn = NULL;
for (i = 0; i<dynsize; i++) {
if (flags & IPPOOL_NOGATEWAY)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 2);
else if (flags & IPPOOL_NONETWORK)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 1);
else
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i);
(*this)->member[i].inuse = 0;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->lastdyn;
if ((*this)->lastdyn) {
(*this)->lastdyn->next = &((*this)->member[i]);
}
else {
(*this)->firstdyn = &((*this)->member[i]);
}
(*this)->lastdyn = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
( void)ippool_hashadd(*this, &(*this)->member[i]);
}
(*this)->firststat = NULL;
(*this)->laststat = NULL;
for (i = dynsize; i<listsize; i++) {
(*this)->member[i].addr.s_addr = 0;
(*this)->member[i].inuse = 0;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->laststat;
if ((*this)->laststat) {
(*this)->laststat->next = &((*this)->member[i]);
}
else {
(*this)->firststat = &((*this)->member[i]);
}
(*this)->laststat = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
}
if (0) (void)ippool_printaddr(*this);
return 0;
}
/* Delete existing address pool */
int ippool_free(struct ippool_t *this) {
free(this->hash);
free(this->member);
free(this);
return 0; /* Always OK */
}
/* Find an IP address in the pool */
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
uint32_t hash;
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
if (member) *member = p;
return 0;
}
}
if (member) *member = NULL;
/*sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address could not be found");*/
return -1;
}
/**
* ippool_newip
* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
* check to see if the given address is available. If available within
* dynamic address space allocate it there, otherwise allocate within static
* address space.
**/
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr, int statip) {
struct ippoolm_t *p;
struct ippoolm_t *p2 = NULL;
uint32_t hash;
/* If static:
* Look in dynaddr.
* If found remove from firstdyn/lastdyn linked list.
* Else allocate from stataddr.
* Remove from firststat/laststat linked list.
* Insert into hash table.
*
* If dynamic
* Remove from firstdyn/lastdyn linked list.
*
*/
if (0) (void)ippool_printaddr(this);
/* First check to see if this type of address is allowed */
if ((addr) && (addr->s_addr) && statip) { /* IP address given */
if (!this->allowstat) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static IP address not allowed");
return -1;
}
if ((addr->s_addr & this->statmask.s_addr) != this->stataddr.s_addr) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static out of range");
return -1;
}
}
else {
if (!this->allowdyn) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Dynamic IP address not allowed");
return -1;
}
}
/* If IP address given try to find it in dynamic address pool */
if ((addr) && (addr->s_addr)) { /* IP address given */
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr)) {
p2 = p;
break;
}
}
}
/* If IP was already allocated we can not use it */
if ((!statip) && (p2) && (p2->inuse)) {
p2 = NULL;
}
/* If not found yet and dynamic IP then allocate dynamic IP */
if ((!p2) && (!statip)) {
if (!this ->firstdyn) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"No more IP addresses available");
return -1;
}
else
p2 = this ->firstdyn;
}
if (p2) { /* Was allocated from dynamic address pool */
if (p2->inuse) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"IP address allready in use");
return -1; /* Allready in use / Should not happen */
}
/* Remove from linked list of free dynamic addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firstdyn = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->lastdyn = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 1; /* Dynamic address in use */
*member = p2;
if (0) (void)ippool_printaddr(this);
return 0; /* Success */
}
/* It was not possible to allocate from dynamic address pool */
/* Try to allocate from static address space */
if ((addr) && (addr->s_addr) && (statip)) { /* IP address given */
if (!this->firststat) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"No more IP addresses available");
return -1; /* No more available */
}
else
p2 = this ->firststat;
/* Remove from linked list of free static addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firststat = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->laststat = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 2; /* Static address in use */
memcpy(&p2->addr, addr, sizeof(addr));
*member = p2;
(void)ippool_hashadd(this, *member);
if (0) (void)ippool_printaddr(this);
return 0; /* Success */
}
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Could not allocate IP address");
return -1; /* Should never get here. TODO: Bad code */
}
int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member) {
if (0) (void)ippool_printaddr(this);
if (!member->inuse) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use");
return -1; /* Not in use: Should not happen */
}
switch (member->inuse) {
case 0: /* Not in use: Should not happen */
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use");
return -1;
case 1: /* Allocated from dynamic address space */
/* Insert into list of unused */
member->prev = this->lastdyn;
if (this->lastdyn) {
this->lastdyn->next = member;
}
else {
this->firstdyn = member;
}
this->lastdyn = member;
member->inuse = 0;
member->peer = NULL;
if (0) (void)ippool_printaddr(this);
return 0;
case 2: /* Allocated from static address space */
if (ippool_hashdel(this, member))
return -1;
/* Insert into list of unused */
member->prev = this->laststat;
if (this->laststat) {
this->laststat->next = member;
}
else {
this->firststat = member;
}
this->laststat = member;
member->inuse = 0;
member->addr.s_addr = 0;
member->peer = NULL;
member->nexthash = NULL;
if (0) (void)ippool_printaddr(this);
return 0;
default: /* Should not happen */
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Could not free IP address");
return -1;
}
}
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif

View File

@ -1,105 +0,0 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _IPPOOL_H
#define _IPPOOL_H
/* Assuming that the address space is fragmented we need a hash table
in order to return the addresses.
The list pool should provide for both IPv4 and IPv6 addresses.
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
*/
#define IPPOOL_NOIP6
#define IPPOOL_NONETWORK 0x01
#define IPPOOL_NOBROADCAST 0x02
#define IPPOOL_NOGATEWAY 0x04
#define IPPOOL_STATSIZE 0x10000
struct ippoolm_t; /* Forward declaration */
struct ippool_t {
unsigned int listsize; /* Total number of addresses */
int allowdyn; /* Allow dynamic IP address allocation */
int allowstat; /* Allow static IP address allocation */
struct in_addr stataddr; /* Static address range network address */
struct in_addr statmask; /* Static address range network mask */
struct ippoolm_t *member; /* Listsize array of members */
unsigned int hashsize; /* Size of hash table */
int hashlog; /* Log2 size of hash table */
int hashmask; /* Bitmask for calculating hash */
struct ippoolm_t **hash; /* Hashsize array of pointer to member */
struct ippoolm_t *firstdyn; /* Pointer to first free dynamic member */
struct ippoolm_t *lastdyn; /* Pointer to last free dynamic member */
struct ippoolm_t *firststat; /* Pointer to first free static member */
struct ippoolm_t *laststat; /* Pointer to last free static member */
};
struct ippoolm_t {
#ifndef IPPOOL_NOIP6
struct in6_addr addr; /* IP address of this member */
#else
struct in_addr addr; /* IP address of this member */
#endif
int inuse; /* 0=available; 1= dynamic; 2 = static */
struct ippoolm_t *nexthash; /* Linked list part of hash table */
struct ippoolm_t *prev, *next; /* Linked list of free dynamic or static */
void *peer; /* Pointer to peer protocol handler */
};
/* The above structures require approximately 20+4 = 24 bytes for
each address (IPv4). For IPv6 the corresponding value is 32+4 = 36
bytes for each address. */
/* Hash an IP address using code based on Bob Jenkins lookupa */
extern unsigned long int ippool_hash4(struct in_addr *addr);
/* Create new address pool */
extern int ippool_new(struct ippool_t **this, char *dyn, char *stat,
int allowdyn, int allowstat, int flags);
/* Delete existing address pool */
extern int ippool_free(struct ippool_t *this);
/* Find an IP address in the pool */
extern int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
extern int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr, int statip);
/* Return a previously allocated IP address */
extern int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member);
/* Get net and mask based on ascii string */
extern int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number);
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif
#endif /* !_IPPOOL_H */

View File

@ -1,80 +0,0 @@
/*
* Hash lookup function.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
/**
* lookup()
* Generates a 32 bit hash.
* Based on public domain code by Bob Jenkins
* It should be one of the best hash functions around in terms of both
* statistical properties and speed. It is NOT recommended for cryptographic
* purposes.
**/
unsigned long int lookup( k, length, level)
register unsigned char *k; /* the key */
register unsigned long int length; /* the length of the key */
register unsigned long int level; /* the previous hash, or an arbitrary value*/
{
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
register unsigned long int a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}

View File

@ -1,71 +0,0 @@
/*
* Syslog functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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 <stdarg.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "syserr.h"
void sys_err(int pri, char *fn, int ln, int en, char *fmt, ...) {
va_list args;
char buf[SYSERR_MSGSIZE];
va_start(args, fmt);
vsnprintf(buf, SYSERR_MSGSIZE, fmt, args);
va_end(args);
buf[SYSERR_MSGSIZE-1] = 0; /* Make sure it is null terminated */
if (en)
syslog(pri, "%s: %d: %d (%s) %s", fn, ln, en, strerror(en), buf);
else
syslog(pri, "%s: %d: %s", fn, ln, buf);
}
void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
void *pack, unsigned len, char *fmt, ...) {
va_list args;
char buf[SYSERR_MSGSIZE];
char buf2[SYSERR_MSGSIZE];
unsigned int n;
int pos;
va_start(args, fmt);
vsnprintf(buf, SYSERR_MSGSIZE, fmt, args);
va_end(args);
buf[SYSERR_MSGSIZE-1] = 0;
snprintf(buf2, SYSERR_MSGSIZE, "Packet from %s:%u, length: %d, content:",
inet_ntoa(peer->sin_addr),
ntohs(peer->sin_port),
len);
buf2[SYSERR_MSGSIZE-1] = 0;
pos = strlen(buf2);
for(n=0; n<len; n++) {
if ((pos+4)<SYSERR_MSGSIZE) {
sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
pos += 3;
}
}
buf2[pos] = 0;
if (en)
syslog(pri, "%s: %d: %d (%s) %s. %s", fn, ln, en, strerror(en), buf, buf2);
else
syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
}

View File

@ -1,21 +0,0 @@
/*
* Syslog functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _SYSERR_H
#define _SYSERR_H
#define SYSERR_MSGSIZE 256
void sys_err(int pri, char *filename, int en, int line, char *fmt, ...);
void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
void *pack, unsigned len, char *fmt, ...);
#endif /* !_SYSERR_H */

View File

@ -1,897 +0,0 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003, 2004 Mondru AB.
*
* 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.
*
*/
/*
* tun.c: Contains all TUN functionality. Is able to handle multiple
* tunnels in the same program. Each tunnel is identified by the struct,
* which is passed to functions.
*
*/
#include <syslog.h>
#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>
#if defined(__linux__)
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#elif defined (__FreeBSD__)
#include <net/if.h>
#include <net/if_tun.h>
#elif defined (__APPLE__)
#include <net/if.h>
#elif defined (__sun__)
#include <stropts.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_tun.h>
/*#include "sun_if_tun.h"*/
#else
#error "Unknown platform!"
#endif
#include "tun.h"
#include "syserr.h"
#if defined(__linux__)
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;
}
int tun_gifindex(struct tun_t *this, int *index) {
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl() failed");
close(fd);
return -1;
}
close(fd);
*index = ifr.ifr_ifindex;
return 0;
}
#endif
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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFFLAGS) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
/* Currently unused
int tun_addroute2(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask) {
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
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 rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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); * TODO: Error check *
close(fd);
return 0;
}
*/
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_setaddr(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 */
if (tun_gifindex(this, &req.i.ifa_index)) {
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(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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); /* TODO Error check */
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
close(fd);
this->addrs++;
return 0;
#elif defined (__FreeBSD__) || defined (__APPLE__)
int fd;
struct ifaliasreq areq;
/* TODO: Is this needed on FreeBSD? */
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
memset(&areq, 0, sizeof(areq));
/* 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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCAIFADDR) failed");
close(fd);
return -1;
}
close(fd);
this->addrs++;
return 0;
#elif defined (__sun__)
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask);
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"Setting multiple addresses not possible on Solaris");
return -1;
#else
#error "Unknown platform!"
#endif
}
int tun_setaddr(struct tun_t *this,
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, 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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (addr) { /* Set the interface address */
this->addr.s_addr = addr->s_addr;
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
if (errno != EEXIST) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR) failed");
}
else {
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR): Address already exists");
}
close(fd);
return -1;
}
}
if (dstaddr) { /* Set the destination address */
this->dstaddr.s_addr = dstaddr->s_addr;
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
dstaddr->s_addr;
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFDSTADDR) failed");
close(fd);
return -1;
}
}
if (netmask) { /* Set the netmask */
this->netmask.s_addr = netmask->s_addr;
#if defined(__linux__)
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
netmask->s_addr;
#elif defined(__FreeBSD__) || defined (__APPLE__)
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
netmask->s_addr;
#elif defined(__sun__)
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
netmask->s_addr;
#else
#error "Unknown platform!"
#endif
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFNETMASK) failed");
close(fd);
return -1;
}
}
close(fd);
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__)
tun_addroute(this, dstaddr, addr, netmask);
this->routes = 1;
#endif
return 0;
}
int tun_route(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask,
int delete)
{
/* TODO: Learn how to set routing table on sun */
#if defined(__linux__)
struct rtentry r;
int fd;
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(LOG_ERR, __FILE__, __LINE__, 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;
((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
if (delete) {
if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCDELRT) failed");
close(fd);
return -1;
}
}
else {
if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"write() failed");
close(fd);
return -1;
}
close(fd);
return 0;
#elif defined(__sun__)
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"Could not set up routing on Solaris. Please add route manually.");
return 0;
#else
#error "Unknown platform!"
#endif
}
int tun_addroute(struct tun_t *this,
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)
{
#if defined(__linux__)
struct ifreq ifr;
#elif defined(__FreeBSD__) || defined (__APPLE__)
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
int devnum;
struct ifaliasreq areq;
int fd;
#elif defined(__sun__)
int if_fd, ppa = -1;
static int ip_fd = 0;
int muxid;
struct ifreq ifr;
#else
#error "Unknown platform!"
#endif
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
return EOF;
}
(*tun)->cb_ind = NULL;
(*tun)->addrs = 0;
(*tun)->routes = 0;
#if defined(__linux__)
/* Open the actual tun device */
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
return -1;
}
/* Set device flags. For some weird reason this is also the method
used to obtain the network interface name */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
close((*tun)->fd);
return -1;
}
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
(*tun)->devname[IFNAMSIZ] = 0;
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
return 0;
#elif defined(__FreeBSD__) || defined (__APPLE__)
/* Find suitable device */
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
devname[sizeof(devname)] = 0;
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
if (errno != EBUSY) break;
}
if ((*tun)->fd < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
return -1;
}
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
(*tun)->devname[sizeof((*tun)->devname)] = 0;
/* The tun device we found might have "old" IP addresses allocated */
/* We need to delete those. This problem is not present on Linux */
memset(&areq, 0, sizeof(areq));
/* Set up interface name */
strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
areq.ifra_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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
/* Delete any IP addresses until SIOCDIFADDR fails */
while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
close(fd);
return 0;
#elif defined(__sun__)
if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
return -1;
}
if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
return -1;
}
/* Assign a new PPA and get its unit number. */
if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
return -1;
}
if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
return -1;
}
if(ioctl(if_fd, I_PUSH, "ip") < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
return -1;
}
/* Assign ppa according to the unit number returned by tun device */
if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
return -1;
}
/* Link the two streams */
if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
return -1;
}
close (if_fd);
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
(*tun)->devname[sizeof((*tun)->devname)] = 0;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, (*tun)->devname);
ifr.ifr_ip_muxid = muxid;
if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
ioctl(ip_fd, I_PUNLINK, muxid);
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
return -1;
}
/* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
msg (M_ERR, "Set file descriptor to non-blocking failed"); */
return 0;
#else
#error "Unknown platform!"
#endif
}
int tun_free(struct tun_t *tun)
{
if (tun->routes) {
tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
}
if (close(tun->fd)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
}
/* TODO: For solaris we need to unlink streams */
free(tun);
return 0;
}
int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
this->cb_ind = cb_ind;
return 0;
}
int tun_decaps(struct tun_t *this)
{
#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
unsigned char buffer[PACKET_MAX];
int status;
if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, status);
return 0;
#elif defined (__sun__)
unsigned char buffer[PACKET_MAX];
struct strbuf sbuf;
int f = 0;
sbuf.maxlen = PACKET_MAX;
sbuf.buf = buffer;
if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, sbuf.len);
return 0;
#endif
}
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
return write(tun->fd, pack, len);
#elif defined (__sun__)
struct strbuf sbuf;
sbuf.len = len;
sbuf.buf = pack;
return putmsg(tun->fd, NULL, &sbuf, 0);
#endif
}
int tun_runscript(struct tun_t *tun, char* script) {
char buf[TUN_SCRIPTSIZE];
char snet[TUN_ADDRSIZE];
char smask[TUN_ADDRSIZE];
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
/* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
script, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
system(buf);
return 0;
}

View File

@ -1,74 +0,0 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* 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.
*
*/
#ifndef _TUN_H
#define _TUN_H
#define PACKET_MAX 8196 /* Maximum packet size we receive */
#define TUN_SCRIPTSIZE 256
#define TUN_ADDRSIZE 128
#define TUN_NLBUFSIZE 1024
struct tun_packet_t {
unsigned int ver:4;
unsigned int ihl:4;
unsigned int dscp:6;
unsigned int ecn:2;
unsigned int length:16;
unsigned int id:16;
unsigned int flags:3;
unsigned int fragment:13;
unsigned int ttl:8;
unsigned int protocol:8;
unsigned int check:16;
unsigned int src:32;
unsigned int dst:32;
};
/* ***********************************************************
* Information storage for each tun instance
*************************************************************/
struct tun_t {
int fd; /* File descriptor to tun interface */
struct in_addr addr;
struct in_addr dstaddr;
struct in_addr netmask;
int addrs; /* Number of allocated IP addresses */
int routes; /* One if we allocated an automatic route */
char devname[IFNAMSIZ];/* Name of the tun device */
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len);
};
extern int tun_new(struct tun_t **tun);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
extern int tun_setaddr(struct tun_t *this, struct in_addr *our_adr,
struct in_addr *his_adr, struct in_addr *net_mask);
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,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len));
extern int tun_runscript(struct tun_t *tun, char* script);
#endif /* !_TUN_H */

151
git-version-gen Executable file
View File

@ -0,0 +1,151 @@
#!/bin/sh
# Print a version string.
scriptversion=2010-01-28.01
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
# - from a non-git-repo directory containing a .tarball-version file, which
# presumes this script is invoked like "./git-version-gen .tarball-version".
# In order to use intra-version strings in your project, you will need two
# separate generated version string files:
#
# .tarball-version - present only in a distribution tarball, and not in
# a checked-out repository. Created with contents that were learned at
# the last time autoconf was run, and used by git-version-gen. Must not
# be present in either $(srcdir) or $(builddir) for git-version-gen to
# give accurate answers during normal development with a checked out tree,
# but must be present in a tarball when there is no version control system.
# Therefore, it cannot be used in any dependencies. GNUmakefile has
# hooks to force a reconfigure at distribution time to get the value
# correct, without penalizing normal development with extra reconfigures.
#
# .version - present in a checked-out repository and in a distribution
# tarball. Usable in dependencies, particularly for files that don't
# want to depend on config.h but do want to track version changes.
# Delete this file prior to any autoconf run where you want to rebuild
# files to pick up a version string change; and leave it stale to
# minimize rebuild time after unrelated changes to configure sources.
#
# It is probably wise to add these two files to .gitignore, so that you
# don't accidentally commit either generated file.
#
# Use the following line in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([GNU project],
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
# [bug-project@example])
#
# Then use the following lines in your Makefile.am, so that .version
# will be present for dependencies, and so that .tarball-version will
# exist in distribution tarballs.
#
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo $(VERSION) > $(distdir)/.tarball-version
case $# in
1) ;;
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
esac
tarball_version_file=$1
nl='
'
# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f $tarball_version_file
then
v=`cat $tarball_version_file` || exit 1
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test -z "$v" \
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
fi
if test -n "$v"
then
: # use $v
elif
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in
[0-9]*) ;;
v[0-9]*) ;;
*) (exit 1) ;;
esac
then
# Is this a new git that lists number of commits since the last
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
: git describe is older two part flavor
# Recreate the number of commits and rewrite such that the
# result is the same as if we were using the newer version
# of git describe.
vtag=`echo "$v" | sed 's/-.*//'`
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
;;
esac
# Change the first '-' to a '.', so version-comparing tools work properly.
# Remove the "g" in git describe's output string, to save a byte.
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
else
v=UNKNOWN
fi
v=`echo "$v" |sed 's/^v//'`
# Don't declare a version "dirty" merely because a time stamp has changed.
git status > /dev/null 2>&1
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
case "$dirty" in
'') ;;
*) # Append the suffix only if there isn't one already.
case $v in
*-dirty) ;;
*) v="$v-dirty" ;;
esac ;;
esac
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$v" | tr -d '\012'
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View File

@ -1,10 +1,16 @@
# This is _NOT_ the library release version, it's an API version.
# 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
LIBVERSION=1:0:0
lib_LTLIBRARIES = libgtp.la
include_HEADERS = gtp.h pdp.h
include_HEADERS = gtp.h pdp.h gtpie.h
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
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_LIBADD = $(LIBOSMOCORE_LIBS)

5060
gtp/gtp.c

File diff suppressed because it is too large Load Diff

447
gtp/gtp.h
View File

@ -12,8 +12,6 @@
#ifndef _GTP_H
#define _GTP_H
#define GTP_DEBUG 0 /* Print debug information */
#define GTP_MODE_GGSN 1
#define GTP_MODE_SGSN 2
@ -22,7 +20,7 @@
#define GTP1U_PORT 2152
#define PACKET_MAX 8196
#define GTP_MAX 0xffff /* TODO: Choose right number */
#define GTP_MAX 0xffff /* TODO: Choose right number */
#define GTP0_HEADER_SIZE 20
#define GTP1_HEADER_SIZE_SHORT 8
#define GTP1_HEADER_SIZE_LONG 12
@ -34,107 +32,108 @@
#define NAMESIZE 1024
/* GTP version 1 extension header type definitions. */
#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */
#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */
/* GTP version 1 message type definitions. Also covers version 0 except *
* for anonymous PDP context which was superceded in version 1 */
/* 0 For future use. */
#define GTP_ECHO_REQ 1 /* Echo Request */
#define GTP_ECHO_RSP 2 /* Echo Response */
#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */
#define GTP_ALIVE_REQ 4 /* Node Alive Request */
#define GTP_ALIVE_RSP 5 /* Node Alive Response */
#define GTP_REDIR_REQ 6 /* Redirection Request */
#define GTP_REDIR_RSP 7 /* Redirection Response */
#define GTP_ECHO_REQ 1 /* Echo Request */
#define GTP_ECHO_RSP 2 /* Echo Response */
#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */
#define GTP_ALIVE_REQ 4 /* Node Alive Request */
#define GTP_ALIVE_RSP 5 /* Node Alive Response */
#define GTP_REDIR_REQ 6 /* Redirection Request */
#define GTP_REDIR_RSP 7 /* Redirection Response */
/* 8-15 For future use. */
#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */
#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */
#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */
#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */
#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */
#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */
/* 22-25 For future use. */ /* In version GTP 1 anonomous PDP context */
#define GTP_ERROR 26 /* Error Indication */
#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */
#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */
#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */
#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */
#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */
#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */
#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */
#define GTP_FAILURE_REQ 34 /* Failure Report Request */
#define GTP_FAILURE_RSP 35 /* Failure Report Response */
#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */
#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */
/* 38-47 For future use. */
#define GTP_IDEN_REQ 48 /* Identification Request */
#define GTP_IDEN_RSP 49 /* Identification Response */
#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */
#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */
#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */
#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */
#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */
#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */
#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */
#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */
#define GTP_FWD_SRNS 58 /* Forward SRNS Context */
#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */
#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */
#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */
#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */
#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */
#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */
#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */
#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */
/* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */
#define GTP_ERROR 26 /* Error Indication */
#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */
#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */
#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */
#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */
#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */
#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */
#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */
#define GTP_FAILURE_REQ 34 /* Failure Report Request */
#define GTP_FAILURE_RSP 35 /* Failure Report Response */
#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */
#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */
/* 38-47 For future use. */
#define GTP_IDEN_REQ 48 /* Identification Request */
#define GTP_IDEN_RSP 49 /* Identification Response */
#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */
#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */
#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */
#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */
#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */
#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */
#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */
#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */
#define GTP_FWD_SRNS 58 /* Forward SRNS Context */
#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */
#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */
/* 61-239 For future use. */
#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */
#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */
#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */
#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */
/* 242-254 For future use. */
#define GTP_GPDU 255 /* G-PDU */
#define GTP_GPDU 255 /* G-PDU */
/* GTP information element cause codes from 29.060 v3.9.0 7.7 */
/* */
#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */
#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */
#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */
#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */
#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */
#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */
#define GTPCAUSE_006 6 /* For future use 6-48 */
#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */
#define GTPCAUSE_064 64 /* For future use 64-127 */
#define GTPCAUSE_ACC_REQ 128 /* Request accepted */
#define GTPCAUSE_129 129 /* For future use 129-176 */
#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */
#define GTPCAUSE_NON_EXIST 192 /* Non-existent */
#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */
#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */
#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */
#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */
#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */
#define GTPCAUSE_198 198 /* For future use */
#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */
#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */
#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */
#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */
#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */
#define GTPCAUSE_SYS_FAIL 204 /* System failure */
#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */
#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */
#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */
#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */
#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */
#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */
#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */
#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */
#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */
#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */
#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */
#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */
#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */
#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */
#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN*/
#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */
#define GTPCAUSE_221 221 /* For Future Use 221-240 */
#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */
#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */
#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */
#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */
#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */
#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */
#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */
#define GTPCAUSE_006 6 /* For future use 6-48 */
#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */
#define GTPCAUSE_064 64 /* For future use 64-127 */
#define GTPCAUSE_ACC_REQ 128 /* Request accepted */
#define GTPCAUSE_129 129 /* For future use 129-176 */
#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */
#define GTPCAUSE_NON_EXIST 192 /* Non-existent */
#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */
#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */
#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */
#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */
#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */
#define GTPCAUSE_198 198 /* For future use */
#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */
#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */
#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */
#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */
#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */
#define GTPCAUSE_SYS_FAIL 204 /* System failure */
#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */
#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */
#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */
#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */
#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */
#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */
#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */
#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */
#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */
#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */
#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */
#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */
#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */
#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */
#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN */
#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */
#define GTPCAUSE_221 221 /* For Future Use 221-240 */
#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */
struct ul66_t;
struct ul16_t;
struct pdp_t;
/* GTP 0 header.
* Explanation to some of the fields:
@ -147,75 +146,72 @@
* Tunnel ID is IMSI+NSAPI. Unique identifier of PDP context. Is somewhat
* redundant because the header also includes flow. */
struct gtp0_header { /* Descriptions from 3GPP 09.60 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 000..... Version: 1 (0) */
/* ...1111. Spare (7) */
/* .......0 SNDCP N-PDU Number flag (0) */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of G-PDU excluding header) */
uint16_t seq; /* 05 Sequence Number */
uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */
uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */
uint8_t spare1; /* 10 Spare */
uint8_t spare2; /* 11 Spare */
uint8_t spare3; /* 12 Spare */
uint64_t tid; /* 13 Tunnel ID */
}; /* 20 */
struct gtp0_header { /* Descriptions from 3GPP 09.60 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 000..... Version: 1 (0) */
/* ...1111. Spare (7) */
/* .......0 SNDCP N-PDU Number flag (0) */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of G-PDU excluding header) */
uint16_t seq; /* 05 Sequence Number */
uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */
uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */
uint8_t spare1; /* 10 Spare */
uint8_t spare2; /* 11 Spare */
uint8_t spare3; /* 12 Spare */
uint64_t tid; /* 13 Tunnel ID */
} __attribute__((packed)); /* 20 */
struct gtp1_header_short { /* Descriptions from 3GPP 29060 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 001..... Version: 1 */
/* ...1.... Protocol Type: GTP=1, GTP'=0 */
/* ....0... Spare = 0 */
/* .....0.. Extension header flag: 0 */
/* ......0. Sequence number flag: 0 */
/* .......0 PN: N-PDU Number flag */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of IP packet or signalling) */
uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */
};
struct gtp1_header_short { /* Descriptions from 3GPP 29060 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 001..... Version: 1 */
/* ...1.... Protocol Type: GTP=1, GTP'=0 */
/* ....0... Spare = 0 */
/* .....0.. Extension header flag: 0 */
/* ......0. Sequence number flag: 0 */
/* .......0 PN: N-PDU Number flag */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of IP packet or signalling) */
uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */
} __attribute__((packed));
struct gtp1_header_long { /* Descriptions from 3GPP 29060 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 001..... Version: 1 */
/* ...1.... Protocol Type: GTP=1, GTP'=0 */
/* ....0... Spare = 0 */
/* .....0.. Extension header flag: 0 */
/* ......1. Sequence number flag: 1 */
/* .......0 PN: N-PDU Number flag */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of IP packet or signalling) */
uint32_t tei; /* 05 Tunnel Endpoint ID */
uint16_t seq; /* 10 Sequence Number */
uint8_t npdu; /* 11 N-PDU Number */
uint8_t next; /* 12 Next extension header type. Empty = 0 */
};
struct gtp1_header_long { /* Descriptions from 3GPP 29060 */
uint8_t flags; /* 01 bitfield, with typical values */
/* 001..... Version: 1 */
/* ...1.... Protocol Type: GTP=1, GTP'=0 */
/* ....0... Spare = 0 */
/* .....0.. Extension header flag: 0 */
/* ......1. Sequence number flag: 1 */
/* .......0 PN: N-PDU Number flag */
uint8_t type; /* 02 Message type. T-PDU = 0xff */
uint16_t length; /* 03 Length (of IP packet or signalling) */
uint32_t tei; /* 05 Tunnel Endpoint ID */
uint16_t seq; /* 10 Sequence Number */
uint8_t npdu; /* 11 N-PDU Number */
uint8_t next; /* 12 Next extension header type. Empty = 0 */
} __attribute__((packed));
struct gtp0_packet {
struct gtp0_header h;
uint8_t p[GTP_MAX];
} __attribute__((packed));
struct gtp0_header h;
uint8_t p[GTP_MAX];
} __attribute__ ((packed));
struct gtp1_packet_short {
struct gtp1_header_short h;
uint8_t p[GTP_MAX];
} __attribute__((packed));
struct gtp1_header_short h;
uint8_t p[GTP_MAX];
} __attribute__ ((packed));
struct gtp1_packet_long {
struct gtp1_header_long h;
uint8_t p[GTP_MAX];
} __attribute__((packed));
struct gtp1_header_long h;
uint8_t p[GTP_MAX];
} __attribute__ ((packed));
union gtp_packet {
uint8_t flags;
struct gtp0_packet gtp0;
struct gtp1_packet_short gtp1s;
struct gtp1_packet_long gtp1l;
} __attribute__((packed));
uint8_t flags;
struct gtp0_packet gtp0;
struct gtp1_packet_short gtp1s;
struct gtp1_packet_long gtp1l;
} __attribute__ ((packed));
/* ***********************************************************
* Information storage for each gsn instance
@ -233,63 +229,63 @@ union gtp_packet {
*************************************************************/
struct gsn_t {
/* Parameters related to the network interface */
/* Parameters related to the network interface */
int fd0; /* GTP0 file descriptor */
int fd1c; /* GTP1 control plane file descriptor */
int fd1u; /* GTP0 user plane file descriptor */
int mode; /* Mode of operation: GGSN or SGSN */
struct in_addr gsnc; /* IP address of this gsn for signalling */
struct in_addr gsnu; /* IP address of this gsn for user traffic */
int fd0; /* GTP0 file descriptor */
int fd1c; /* GTP1 control plane file descriptor */
int fd1u; /* GTP0 user plane file descriptor */
int mode; /* Mode of operation: GGSN or SGSN */
struct in_addr gsnc; /* IP address of this gsn for signalling */
struct in_addr gsnu; /* IP address of this gsn for user traffic */
/* Parameters related to signalling messages */
uint16_t seq_next; /* Next sequence number to use */
int seq_first; /* First packet in queue (oldest timeout) */
int seq_last; /* Last packet in queue (youngest timeout) */
/* Parameters related to signalling messages */
uint16_t seq_next; /* Next sequence number to use */
int seq_first; /* First packet in queue (oldest timeout) */
int seq_last; /* Last packet in queue (youngest timeout) */
unsigned char restart_counter; /* Increment on restart. Stored on disk */
char *statedir; /* Disk location for permanent storage */
unsigned char restart_counter; /* Increment on restart. Stored on disk */
char *statedir; /* Disk location for permanent storage */
void *priv; /* used by libgtp users to attach their own state) */
struct queue_t *queue_req; /* Request queue */
struct queue_t *queue_resp; /* Response queue */
struct queue_t *queue_req; /* Request queue */
struct queue_t *queue_resp; /* Response queue */
/* Call back functions */
int (*cb_delete_context) (struct pdp_t *);
int (*cb_create_context_ind) (struct pdp_t *);
int (*cb_unsup_ind) (struct sockaddr_in * peer);
int (*cb_extheader_ind) (struct sockaddr_in * peer);
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_recovery) (struct sockaddr_in * peer, uint8_t recovery);
/* Call back functions */
int (*cb_delete_context) (struct pdp_t*);
int (*cb_create_context_ind) (struct pdp_t*);
int (*cb_unsup_ind) (struct sockaddr_in *peer);
int (*cb_extheader_ind) (struct sockaddr_in *peer);
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);
/* Counters */
/* Counters */
uint64_t err_socket; /* Number of socket errors */
uint64_t err_readfrom; /* Number of readfrom errors */
uint64_t err_sendto; /* Number of sendto errors */
uint64_t err_memcpy; /* Number of memcpy */
uint64_t err_queuefull; /* Number of times queue was full */
uint64_t err_seq; /* Number of seq out of range */
uint64_t err_address; /* GSN address conversion failed */
uint64_t err_unknownpdp; /* GSN address conversion failed */
uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */
uint64_t err_cause; /* Unexpected cause value received */
uint64_t err_outofpdp; /* Out of storage for PDP contexts */
uint64_t err_socket; /* Number of socket errors */
uint64_t err_readfrom; /* Number of readfrom errors */
uint64_t err_sendto; /* Number of sendto errors */
uint64_t err_memcpy; /* Number of memcpy */
uint64_t err_queuefull; /* Number of times queue was full */
uint64_t err_seq; /* Number of seq out of range */
uint64_t err_address; /* GSN address conversion failed */
uint64_t err_unknownpdp; /* GSN address conversion failed */
uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */
uint64_t err_cause; /* Unexpected cause value received */
uint64_t err_outofpdp; /* Out of storage for PDP contexts */
uint64_t empty; /* Number of empty packets */
uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */
uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */
uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */
uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */
uint64_t dublicate; /* Number of dublicate or unsolicited replies */
uint64_t missing; /* Number of missing information field messages */
uint64_t incorrect; /* Number of incorrect information field messages */
uint64_t invalid; /* Number of invalid message format messages */
uint64_t empty; /* Number of empty packets */
uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */
uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */
uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */
uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */
uint64_t duplicate; /* Number of duplicate or unsolicited replies */
uint64_t missing; /* Number of missing information field messages */
uint64_t incorrect; /* Number of incorrect information field messages */
uint64_t invalid; /* Number of invalid message format messages */
};
/* External API functions */
extern const char* gtp_version();
extern const char *gtp_version();
extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
int mode);
@ -299,27 +295,29 @@ extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
uint64_t imsi, uint8_t nsapi);
extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp);
extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct pdp_t* pdp));
int (*cb_create_context_ind) (struct
pdp_t *
pdp));
extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
int cause);
extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp, struct in_addr* inetaddr);
extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
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);
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
void *pack, unsigned len);
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len));
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len));
extern int gtp_fd(struct gsn_t *gsn);
extern int gtp_decaps0(struct gsn_t *gsn);
@ -328,43 +326,46 @@ extern int gtp_decaps1u(struct gsn_t *gsn);
extern int gtp_retrans(struct gsn_t *gsn);
extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout);
extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
int (*cb_delete_context) (struct pdp_t* pdp));
extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
int (*cb_delete_context) (struct pdp_t *
pdp));
/*extern int gtp_set_cb_create_context(struct gsn_t *gsn,
int (*cb_create_context) (struct pdp_t* pdp)); */
extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in *peer));
int (*cb) (struct sockaddr_in * peer));
extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in *peer));
int (*cb) (struct sockaddr_in * peer));
extern int gtp_set_cb_conf(struct gsn_t *gsn,
int (*cb) (int type, int cause, struct pdp_t* pdp, void *cbp));
int (*cb) (int type, int cause, struct pdp_t * pdp,
void *cbp));
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
uint8_t recovery));
/* Internal functions (not part of the API */
extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
struct in_addr *inetaddrs);
extern int gtp_echo_resp(struct gsn_t *gsn, int version,
extern int gtp_echo_resp(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len);
extern int gtp_echo_ind(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
extern int gtp_echo_ind(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len);
extern int gtp_echo_conf(struct gsn_t *gsn, int version,
struct sockaddr_in *peer,
void *pack, unsigned len);
extern int gtp_echo_conf(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, void *pack, unsigned len);
extern int gtp_unsup_req(struct gsn_t *gsn, int version,
extern int gtp_unsup_req(struct gsn_t *gsn, int version,
struct sockaddr_in *peer,
int fd, void *pack, unsigned len);
extern int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
void *pack, unsigned len);
extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version,
extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version,
struct pdp_t *pdp, uint8_t cause);
extern int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
@ -376,14 +377,14 @@ extern int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
void *pack, unsigned len);
extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *cbp,
struct in_addr* inetaddr, struct pdp_t *pdp);
struct in_addr *inetaddr, struct pdp_t *pdp);
extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *cbp,
struct pdp_t *pdp);
extern int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len,
void *pack, unsigned len,
struct pdp_t *pdp, struct pdp_t *linked_pdp,
uint8_t cause, int teardown);
@ -395,10 +396,10 @@ extern int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
struct sockaddr_in *peer,
void *pack, unsigned len);
extern int ipv42eua(struct ul66_t *eua, struct in_addr *src);
extern int eua2ipv4(struct in_addr *dst, struct ul66_t *eua);
extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna);
extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src);
extern const char *imsi_gtp2str(const uint64_t *imsi);
#endif /* !_GTP_H */
#endif /* !_GTP_H */

File diff suppressed because it is too large Load Diff

View File

@ -21,14 +21,13 @@
#define ntoh32(x) ntohl(x)
#if BYTE_ORDER == LITTLE_ENDIAN
static __inline uint64_t
hton64(uint64_t q)
static __inline uint64_t hton64(uint64_t q)
{
register uint32_t u, l;
u = q >> 32;
l = (uint32_t) q;
register uint32_t u, l;
u = q >> 32;
l = (uint32_t) q;
return htonl(u) | ((uint64_t)htonl(l) << 32);
return htonl(u) | ((uint64_t) htonl(l) << 32);
}
#define ntoh64(_x) hton64(_x)
@ -42,123 +41,125 @@ hton64(uint64_t q)
#error "Please fix <machine/endian.h>"
#endif
#define GTPIE_SIZE 256 /* Max number of information elements */
#define GTPIE_MAX 0xffff /* Max length of information elements */
#define GTPIE_MAX_TV 28 /* Max length of type value pair */
#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */
#define GTPIE_SIZE 256 /* Max number of information elements */
#define GTPIE_MAX 0xffff /* Max length of information elements */
#define GTPIE_MAX_TV 28 /* Max length of type value pair */
#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */
#define GTPIE_DEBUG 0 /* Print debug information */
#define GTPIE_DEBUG 0 /* Print debug information */
/* 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 *
* by 135: QOS Profile in version 1 */
#define GTPIE_CAUSE 1 /* Cause 1 */
#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */
#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */
#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */
#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */
#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3*/
/* 6-7 SPARE */ /* 6 is QoS Profile vers 0 */
#define GTPIE_REORDER 8 /* Reordering Required 1 */
#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */
/* 10 SPARE */
#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */
#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */
#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */
#define GTPIE_RECOVERY 14 /* Recovery 1 */
#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */
#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */
#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */
#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */
#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */
#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */
#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */
#define GTPIE_NSAPI 20 /* NSAPI 1 */
#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */
#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */
#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */
#define GTPIE_RP 24 /* Radio Priority 1 */
#define GTPIE_PFI 25 /* Packet Flow Id 2 */
#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */
#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */
#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */
#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */
/* 30-116 UNUSED */
#define GTPIE_CAUSE 1 /* Cause 1 */
#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */
#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */
#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */
#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */
#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3 */
/* 6-7 SPARE *//* 6 is QoS Profile vers 0 */
#define GTPIE_REORDER 8 /* Reordering Required 1 */
#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */
/* 10 SPARE */
#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */
#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */
#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */
#define GTPIE_RECOVERY 14 /* Recovery 1 */
#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */
#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */
#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */
#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */
#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */
#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */
#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */
#define GTPIE_NSAPI 20 /* NSAPI 1 */
#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */
#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */
#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */
#define GTPIE_RP 24 /* Radio Priority 1 */
#define GTPIE_PFI 25 /* Packet Flow Id 2 */
#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */
#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */
#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */
#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */
/* 30-116 UNUSED */
/* 117-126 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */
#define GTPIE_EUA 128 /* End User Address */
#define GTPIE_MM_CONTEXT 129 /* MM Context */
#define GTPIE_PDP_CONTEXT 130 /* PDP Context */
#define GTPIE_APN 131 /* Access Point Name */
#define GTPIE_PCO 132 /* Protocol Configuration Options */
#define GTPIE_GSN_ADDR 133 /* GSN Address */
#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */
#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */
#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */
#define GTPIE_TFT 137 /* Traffic Flow Template */
#define GTPIE_TARGET_INF 138 /* Target Identification */
#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */
#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */
#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */
#define GTPIE_TRIGGER_ID 142 /* Trigger Id */
#define GTPIE_OMC_ID 143 /* OMC Identity */
#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */
#define GTPIE_EUA 128 /* End User Address */
#define GTPIE_MM_CONTEXT 129 /* MM Context */
#define GTPIE_PDP_CONTEXT 130 /* PDP Context */
#define GTPIE_APN 131 /* Access Point Name */
#define GTPIE_PCO 132 /* Protocol Configuration Options */
#define GTPIE_GSN_ADDR 133 /* GSN Address */
#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */
#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */
#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */
#define GTPIE_TFT 137 /* Traffic Flow Template */
#define GTPIE_TARGET_INF 138 /* Target Identification */
#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */
#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */
#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */
#define GTPIE_TRIGGER_ID 142 /* Trigger Id */
#define GTPIE_OMC_ID 143 /* OMC Identity */
#define GTPIE_RAT_TYPE 151 /* Radio Access Technology Type */
#define GTPIE_USER_LOC 152 /* User Location Information */
#define GTPIE_MS_TZ 153 /* MS Time Zone */
#define GTPIE_IMEI_SV 154 /* IMEI Software Version */
#define GTPIE_BCM 184 /* Bearer control mode */
/* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */
#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */
/* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
#define GTPIE_PRIVATE 255 /* Private Extension */
#define GTPIE_PRIVATE 255 /* Private Extension */
/* GTP information element structs in network order */
struct gtpie_ext { /* Extension header */
uint8_t t; /* Type */
uint8_t l; /* Length */
uint8_t *p; /* Value */
} __attribute__((packed));
struct gtpie_ext { /* Extension header */
uint8_t t; /* Type */
uint8_t l; /* Length */
uint8_t *p; /* Value */
} __attribute__ ((packed));
struct gtpie_tlv { /* Type length value pair */
uint8_t t; /* Type */
uint16_t l; /* Length */
uint8_t v[GTPIE_MAX_TLV]; /* Value */
} __attribute__((packed));
struct gtpie_tlv { /* Type length value pair */
uint8_t t; /* Type */
uint16_t l; /* Length */
uint8_t v[GTPIE_MAX_TLV]; /* Value */
} __attribute__ ((packed));
struct gtpie_tv0 { /* 1 byte type value pair */
uint8_t t; /* Type */
uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */
}__attribute__((packed));
struct gtpie_tv0 { /* 1 byte type value pair */
uint8_t t; /* Type */
uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */
} __attribute__ ((packed));
struct gtpie_tv1 { /* 1 byte type value pair */
uint8_t t; /* Type */
uint8_t v; /* Value */
}__attribute__((packed));
struct gtpie_tv1 { /* 1 byte type value pair */
uint8_t t; /* Type */
uint8_t v; /* Value */
} __attribute__ ((packed));
struct gtpie_tv2 { /* 2 byte type value pair */
uint8_t t; /* Type */
uint16_t v; /* Value */
}__attribute__((packed));
struct gtpie_tv2 { /* 2 byte type value pair */
uint8_t t; /* Type */
uint16_t v; /* Value */
} __attribute__ ((packed));
struct gtpie_tv4 { /* 4 byte type value pair */
uint8_t t; /* Type */
uint32_t v; /* Value */
}__attribute__((packed));
struct gtpie_tv8 { /* 8 byte type value pair */
uint8_t t; /* Type */
uint64_t v; /* Value */
}__attribute__((packed));
struct gtpie_tv4 { /* 4 byte type value pair */
uint8_t t; /* Type */
uint32_t v; /* Value */
} __attribute__ ((packed));
struct gtpie_tv8 { /* 8 byte type value pair */
uint8_t t; /* Type */
uint64_t v; /* Value */
} __attribute__ ((packed));
union gtpie_member {
uint8_t t;
struct gtpie_ext ext;
struct gtpie_tlv tlv;
struct gtpie_tv0 tv0;
struct gtpie_tv1 tv1;
struct gtpie_tv2 tv2;
struct gtpie_tv4 tv4;
struct gtpie_tv8 tv8;
}__attribute__((packed));
uint8_t t;
struct gtpie_ext ext;
struct gtpie_tlv tlv;
struct gtpie_tv0 tv0;
struct gtpie_tv1 tv1;
struct gtpie_tv2 tv2;
struct gtpie_tv4 tv4;
struct gtpie_tv8 tv8;
} __attribute__ ((packed));
/*
cause
@ -210,45 +211,46 @@ private
*/
struct tlv1 {
uint8_t type;
uint8_t length;
}__attribute__((packed));
uint8_t type;
uint8_t length;
} __attribute__ ((packed));
struct tlv2 {
uint8_t type;
uint16_t length;
}__attribute__((packed));
uint8_t type;
uint16_t length;
} __attribute__ ((packed));
extern int gtpie_tlv(void *p, unsigned int *length, unsigned int size,
uint8_t t, int l, void *v);
extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size,
uint8_t t, int l, uint8_t *v);
extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v);
extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v);
extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v);
extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v);
extern int gtpie_getie(union gtpie_member* ie[], int type, int instance);
extern int gtpie_exist(union gtpie_member* ie[], int type, int instance);
extern int gtpie_gettlv(union gtpie_member* ie[], int type, int instance,
extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size,
uint8_t t, int l, uint8_t * v);
extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size,
uint8_t t, uint8_t v);
extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size,
uint8_t t, uint16_t v);
extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size,
uint8_t t, uint32_t v);
extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size,
uint8_t t, uint64_t v);
extern int gtpie_getie(union gtpie_member *ie[], int type, int instance);
extern int gtpie_exist(union gtpie_member *ie[], int type, int instance);
extern int gtpie_gettlv(union gtpie_member *ie[], int type, int instance,
unsigned int *length, void *dst, unsigned int size);
extern int gtpie_gettv0(union gtpie_member* ie[], int type, int instance,
extern int gtpie_gettv0(union gtpie_member *ie[], int type, int instance,
void *dst, unsigned int size);
extern int gtpie_gettv1(union gtpie_member* ie[], int type, int instance,
uint8_t *dst);
extern int gtpie_gettv2(union gtpie_member* ie[], int type, int instance,
uint16_t *dst);
extern int gtpie_gettv4(union gtpie_member* ie[], int type, int instance,
uint32_t *dst);
extern int gtpie_gettv8(union gtpie_member* ie[], int type, int instance,
uint64_t *dst);
extern int gtpie_gettv1(union gtpie_member *ie[], int type, int instance,
uint8_t * dst);
extern int gtpie_gettv2(union gtpie_member *ie[], int type, int instance,
uint16_t * dst);
extern int gtpie_gettv4(union gtpie_member *ie[], int type, int instance,
uint32_t * dst);
extern int gtpie_gettv8(union gtpie_member *ie[], int type, int instance,
uint64_t * dst);
extern int gtpie_decaps(union gtpie_member* ie[], int version,
extern int gtpie_decaps(union gtpie_member *ie[], int version,
void *pack, unsigned len);
extern int gtpie_encaps(union gtpie_member* ie[], void *pack, unsigned *len);
extern int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len);
extern int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
void *pack, unsigned *len);
#endif /* !_GTPIE_H */
void *pack, unsigned *len);
#endif /* !_GTPIE_H */

View File

@ -81,52 +81,64 @@ acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
ub4 lookup( k, length, level)
register ub1 *k; /* the key */
register ub4 length; /* the length of the key */
register ub4 level; /* the previous hash, or an arbitrary value */
ub4 lookup(k, length, level)
register ub1 *k; /* the key */
register ub4 length; /* the length of the key */
register ub4 level; /* the previous hash, or an arbitrary value */
{
register ub4 a,b,c,len;
register ub4 a, b, c, len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
while (len >= 12) {
a += (k[0] + ((ub4) k[1] << 8) + ((ub4) k[2] << 16) +
((ub4) k[3] << 24));
b += (k[4] + ((ub4) k[5] << 8) + ((ub4) k[6] << 16) +
((ub4) k[7] << 24));
c += (k[8] + ((ub4) k[9] << 8) + ((ub4) k[10] << 16) +
((ub4) k[11] << 24));
mix(a, b, c);
k += 12;
len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
c += length;
switch (len) { /* all the case statements fall through */
case 11:
c += ((ub4) k[10] << 24);
case 10:
c += ((ub4) k[9] << 16);
case 9:
c += ((ub4) k[8] << 8);
/* the first byte of c is reserved for the length */
case 8:
b += ((ub4) k[7] << 24);
case 7:
b += ((ub4) k[6] << 16);
case 6:
b += ((ub4) k[5] << 8);
case 5:
b += k[4];
case 4:
a += ((ub4) k[3] << 24);
case 3:
a += ((ub4) k[2] << 16);
case 2:
a += ((ub4) k[1] << 8);
case 1:
a += k[0];
/* case 0: nothing left to add */
}
mix(a, b, c);
/*-------------------------------------------- report the result */
return c;
return c;
}
/*
--------------------------------------------------------------------
mixc -- mixc 8 4-bit values as quickly and thoroughly as possible.
@ -169,78 +181,120 @@ Use to detect changes between revisions of documents, assuming nobody
is trying to cause collisions. Do NOT use for cryptography.
--------------------------------------------------------------------
*/
void checksum( k, len, state)
void checksum(k, len, state)
register ub1 *k;
register ub4 len;
register ub4 len;
register ub4 *state;
{
register ub4 a,b,c,d,e,f,g,h,length;
register ub4 a, b, c, d, e, f, g, h, length;
/* Use the length and level; add in the golden ratio. */
length = len;
a=state[0]; b=state[1]; c=state[2]; d=state[3];
e=state[4]; f=state[5]; g=state[6]; h=state[7];
/* Use the length and level; add in the golden ratio. */
length = len;
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
/*---------------------------------------- handle most of the key */
while (len >= 32)
{
a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24));
b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24));
c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24));
d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24));
e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24));
f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24));
g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24));
h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24));
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
k += 32; len -= 32;
}
while (len >= 32) {
a += (k[0] + (k[1] << 8) + (k[2] << 16) + (k[3] << 24));
b += (k[4] + (k[5] << 8) + (k[6] << 16) + (k[7] << 24));
c += (k[8] + (k[9] << 8) + (k[10] << 16) + (k[11] << 24));
d += (k[12] + (k[13] << 8) + (k[14] << 16) + (k[15] << 24));
e += (k[16] + (k[17] << 8) + (k[18] << 16) + (k[19] << 24));
f += (k[20] + (k[21] << 8) + (k[22] << 16) + (k[23] << 24));
g += (k[24] + (k[25] << 8) + (k[26] << 16) + (k[27] << 24));
h += (k[28] + (k[29] << 8) + (k[30] << 16) + (k[31] << 24));
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
k += 32;
len -= 32;
}
/*------------------------------------- handle the last 31 bytes */
h += length;
switch(len)
{
case 31: h+=(k[30]<<24);
case 30: h+=(k[29]<<16);
case 29: h+=(k[28]<<8);
case 28: g+=(k[27]<<24);
case 27: g+=(k[26]<<16);
case 26: g+=(k[25]<<8);
case 25: g+=k[24];
case 24: f+=(k[23]<<24);
case 23: f+=(k[22]<<16);
case 22: f+=(k[21]<<8);
case 21: f+=k[20];
case 20: e+=(k[19]<<24);
case 19: e+=(k[18]<<16);
case 18: e+=(k[17]<<8);
case 17: e+=k[16];
case 16: d+=(k[15]<<24);
case 15: d+=(k[14]<<16);
case 14: d+=(k[13]<<8);
case 13: d+=k[12];
case 12: c+=(k[11]<<24);
case 11: c+=(k[10]<<16);
case 10: c+=(k[9]<<8);
case 9 : c+=k[8];
case 8 : b+=(k[7]<<24);
case 7 : b+=(k[6]<<16);
case 6 : b+=(k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=(k[3]<<24);
case 3 : a+=(k[2]<<16);
case 2 : a+=(k[1]<<8);
case 1 : a+=k[0];
}
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
mixc(a,b,c,d,e,f,g,h);
h += length;
switch (len) {
case 31:
h += (k[30] << 24);
case 30:
h += (k[29] << 16);
case 29:
h += (k[28] << 8);
case 28:
g += (k[27] << 24);
case 27:
g += (k[26] << 16);
case 26:
g += (k[25] << 8);
case 25:
g += k[24];
case 24:
f += (k[23] << 24);
case 23:
f += (k[22] << 16);
case 22:
f += (k[21] << 8);
case 21:
f += k[20];
case 20:
e += (k[19] << 24);
case 19:
e += (k[18] << 16);
case 18:
e += (k[17] << 8);
case 17:
e += k[16];
case 16:
d += (k[15] << 24);
case 15:
d += (k[14] << 16);
case 14:
d += (k[13] << 8);
case 13:
d += k[12];
case 12:
c += (k[11] << 24);
case 11:
c += (k[10] << 16);
case 10:
c += (k[9] << 8);
case 9:
c += k[8];
case 8:
b += (k[7] << 24);
case 7:
b += (k[6] << 16);
case 6:
b += (k[5] << 8);
case 5:
b += k[4];
case 4:
a += (k[3] << 24);
case 3:
a += (k[2] << 16);
case 2:
a += (k[1] << 8);
case 1:
a += k[0];
}
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
mixc(a, b, c, d, e, f, g, h);
/*-------------------------------------------- report the result */
state[0]=a; state[1]=b; state[2]=c; state[3]=d;
state[4]=e; state[5]=f; state[6]=g; state[7]=h;
state[0] = a;
state[1] = b;
state[2] = c;
state[3] = d;
state[4] = e;
state[5] = f;
state[6] = g;
state[7] = h;
}

View File

@ -16,14 +16,14 @@ Source is http://burtleburtle.net/bob/c/lookupa.h
#ifndef LOOKUPA
#define LOOKUPA
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1;
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1;
#define CHECKSTATE 8
#define hashsize(n) ((ub4)1<<(n))
#define hashmask(n) (hashsize(n)-1)
ub4 lookup(/*_ ub1 *k, ub4 length, ub4 level _*/);
void checksum(/*_ ub1 *k, ub4 length, ub4 *state _*/);
ub4 lookup( /*_ ub1 *k, ub4 length, ub4 level _*/ );
void checksum( /*_ ub1 *k, ub4 length, ub4 *state _*/ );
#endif /* LOOKUPA */

316
gtp/pdp.c
View File

@ -16,6 +16,8 @@
#include <../config.h>
#include <osmocom/core/logging.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
@ -24,15 +26,17 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <inttypes.h>
#include "pdp.h"
#include "gtp.h"
#include "lookupa.h"
/* ***********************************************************
* Global variables TODO: most should be moved to gsn_t
*************************************************************/
struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */
static struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
/* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */
/* ***********************************************************
@ -107,144 +111,181 @@ struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */
*
*************************************************************/
int pdp_init() {
memset(&pdpa, 0, sizeof(pdpa));
memset(&hashtid, 0, sizeof(hashtid));
/* memset(&haship, 0, sizeof(haship)); */
int pdp_init()
{
memset(&pdpa, 0, sizeof(pdpa));
memset(&hashtid, 0, sizeof(hashtid));
/* memset(&haship, 0, sizeof(haship)); */
return 0;
return 0;
}
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
struct pdp_t *pdp_old){
int n;
for (n=0; n<PDP_MAX; n++) { /* TODO: Need to do better than linear search */
if (pdpa[n].inuse == 0) {
*pdp = &pdpa[n];
if (NULL != pdp_old) memcpy(*pdp, pdp_old, sizeof(struct pdp_t));
else memset(*pdp, 0, sizeof(struct pdp_t));
(*pdp)->inuse = 1;
(*pdp)->imsi = imsi;
(*pdp)->nsapi = nsapi;
(*pdp)->fllc = (uint16_t) n + 1;
(*pdp)->fllu = (uint16_t) n + 1;
(*pdp)->teid_own = (uint32_t) n + 1;
if (!(*pdp)->secondary) (*pdp)->teic_own = (uint32_t) n + 1;
pdp_tidset(*pdp, pdp_gettid(imsi, nsapi));
/* Insert reference in primary context */
if (((*pdp)->teic_own > 0 ) && ((*pdp)->teic_own <= PDP_MAX)) {
pdpa[(*pdp)->teic_own-1].secondary_tei[(*pdp)->nsapi & 0x0f] =
(*pdp)->teid_own;
}
return 0;
}
}
return EOF; /* No more available */
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
struct pdp_t *pdp_old)
{
int n;
for (n = 0; n < PDP_MAX; n++) { /* TODO: Need to do better than linear search */
if (pdpa[n].inuse == 0) {
*pdp = &pdpa[n];
if (NULL != pdp_old)
memcpy(*pdp, pdp_old, sizeof(struct pdp_t));
else
memset(*pdp, 0, sizeof(struct pdp_t));
(*pdp)->inuse = 1;
(*pdp)->imsi = imsi;
(*pdp)->nsapi = nsapi;
(*pdp)->fllc = (uint16_t) n + 1;
(*pdp)->fllu = (uint16_t) n + 1;
(*pdp)->teid_own = (uint32_t) n + 1;
if (!(*pdp)->secondary)
(*pdp)->teic_own = (uint32_t) n + 1;
pdp_tidset(*pdp, pdp_gettid(imsi, nsapi));
/* Insert reference in primary context */
if (((*pdp)->teic_own > 0)
&& ((*pdp)->teic_own <= PDP_MAX)) {
pdpa[(*pdp)->teic_own -
1].secondary_tei[(*pdp)->nsapi & 0x0f] =
(*pdp)->teid_own;
}
return 0;
}
}
return EOF; /* No more available */
}
int pdp_freepdp(struct pdp_t *pdp){
pdp_tiddel(pdp);
int pdp_freepdp(struct pdp_t *pdp)
{
pdp_tiddel(pdp);
/* Remove any references in primary context */
if ((pdp->secondary) && (pdp->teic_own > 0 ) && (pdp->teic_own <= PDP_MAX)) {
pdpa[pdp->teic_own-1].secondary_tei[pdp->nsapi & 0x0f] = 0;
}
/* Remove any references in primary context */
if ((pdp->secondary) && (pdp->teic_own > 0)
&& (pdp->teic_own <= PDP_MAX)) {
pdpa[pdp->teic_own - 1].secondary_tei[pdp->nsapi & 0x0f] = 0;
}
memset(pdp, 0, sizeof(struct pdp_t));
return 0;
memset(pdp, 0, sizeof(struct pdp_t));
return 0;
}
int pdp_getpdp(struct pdp_t **pdp){
*pdp = &pdpa[0];
return 0;
int pdp_getpdp(struct pdp_t **pdp)
{
*pdp = &pdpa[0];
return 0;
}
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl){
if ((fl>PDP_MAX) || (fl<1)) {
return EOF; /* Not found */
}
else {
*pdp = &pdpa[fl-1];
if ((*pdp)->inuse) return 0;
else return EOF;
/* Context exists. We do no further validity checking. */
}
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
{
if ((fl > PDP_MAX) || (fl < 1)) {
return EOF; /* Not found */
} else {
*pdp = &pdpa[fl - 1];
if ((*pdp)->inuse)
return 0;
else
return EOF;
/* Context exists. We do no further validity checking. */
}
}
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei){
if ((tei>PDP_MAX) || (tei<1)) {
return EOF; /* Not found */
}
else {
*pdp = &pdpa[tei-1];
if ((*pdp)->inuse) return 0;
else return EOF;
/* Context exists. We do no further validity checking. */
}
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
{
if ((tei > PDP_MAX) || (tei < 1)) {
return EOF; /* Not found */
} else {
*pdp = &pdpa[tei - 1];
if ((*pdp)->inuse)
return 0;
else
return EOF;
/* Context exists. We do no further validity checking. */
}
}
/* get a PDP based on the *peer* address + TEI-Data. Used for matching inbound Error Ind */
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
{
unsigned int i;
int pdp_tidhash(uint64_t tid) {
return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
/* this is O(n) but we don't have (nor want) another hash... */
for (i = 0; i < PDP_MAX; i++) {
struct pdp_t *candidate = &pdpa[i];
if (candidate->inuse && candidate->teid_gn == teid_gn &&
candidate->gsnru.l == sizeof(peer->sin_addr) &&
!memcmp(&peer->sin_addr, candidate->gsnru.v, sizeof(peer->sin_addr))) {
*pdp = &pdpa[i];
return 0;
}
}
return EOF;
}
int pdp_tidset(struct pdp_t *pdp, uint64_t tid) {
int hash = pdp_tidhash(tid);
struct pdp_t *pdp2;
struct pdp_t *pdp_prev = NULL;
if (PDP_DEBUG) printf("Begin pdp_tidset tid = %llx\n", tid);
pdp->tidnext = NULL;
pdp->tid = tid;
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
pdp_prev = pdp2;
if (!pdp_prev)
hashtid[hash] = pdp;
else
pdp_prev->tidnext = pdp;
if (PDP_DEBUG) printf("End pdp_tidset\n");
return 0;
int pdp_tidhash(uint64_t tid)
{
return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
}
int pdp_tiddel(struct pdp_t *pdp) {
int hash = pdp_tidhash(pdp->tid);
struct pdp_t *pdp2;
struct pdp_t *pdp_prev = NULL;
if (PDP_DEBUG) printf("Begin pdp_tiddel tid = %llx\n", pdp->tid);
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
if (pdp2 == pdp) {
if (!pdp_prev)
hashtid[hash] = pdp2->tidnext;
else
pdp_prev->tidnext = pdp2->tidnext;
if (PDP_DEBUG) printf("End pdp_tiddel: PDP found\n");
return 0;
}
pdp_prev = pdp2;
}
if (PDP_DEBUG) printf("End pdp_tiddel: PDP not found\n");
return EOF; /* End of linked list and not found */
int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
{
int hash = pdp_tidhash(tid);
struct pdp_t *pdp2;
struct pdp_t *pdp_prev = NULL;
DEBUGP(DLGTP, "Begin pdp_tidset tid = %"PRIx64"\n", tid);
pdp->tidnext = NULL;
pdp->tid = tid;
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
pdp_prev = pdp2;
if (!pdp_prev)
hashtid[hash] = pdp;
else
pdp_prev->tidnext = pdp;
DEBUGP(DLGTP, "End pdp_tidset\n");
return 0;
}
int pdp_tidget(struct pdp_t **pdp, uint64_t tid) {
int hash = pdp_tidhash(tid);
struct pdp_t *pdp2;
if (PDP_DEBUG) printf("Begin pdp_tidget tid = %llx\n", tid);
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
if (pdp2->tid == tid) {
*pdp = pdp2;
if (PDP_DEBUG) printf("Begin pdp_tidget. Found\n");
return 0;
}
}
if (PDP_DEBUG) printf("Begin pdp_tidget. Not found\n");
return EOF; /* End of linked list and not found */
int pdp_tiddel(struct pdp_t *pdp)
{
int hash = pdp_tidhash(pdp->tid);
struct pdp_t *pdp2;
struct pdp_t *pdp_prev = NULL;
DEBUGP(DLGTP, "Begin pdp_tiddel tid = %"PRIx64"\n", pdp->tid);
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
if (pdp2 == pdp) {
if (!pdp_prev)
hashtid[hash] = pdp2->tidnext;
else
pdp_prev->tidnext = pdp2->tidnext;
DEBUGP(DLGTP, "End pdp_tiddel: PDP found\n");
return 0;
}
pdp_prev = pdp2;
}
DEBUGP(DLGTP, "End pdp_tiddel: PDP not found\n");
return EOF; /* End of linked list and not found */
}
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) {
return pdp_tidget(pdp,
(imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60));
int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
{
int hash = pdp_tidhash(tid);
struct pdp_t *pdp2;
DEBUGP(DLGTP, "Begin pdp_tidget tid = %"PRIx64"\n", tid);
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
if (pdp2->tid == tid) {
*pdp = pdp2;
DEBUGP(DLGTP, "Begin pdp_tidget. Found\n");
return 0;
}
}
DEBUGP(DLGTP, "Begin pdp_tidget. Not found\n");
return EOF; /* End of linked list and not found */
}
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
{
return pdp_tidget(pdp,
(imsi & 0x0fffffffffffffffull) +
((uint64_t) nsapi << 60));
}
/*
@ -320,32 +361,31 @@ int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
*/
/* Various conversion functions */
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) {
eua->l=6;
eua->v[0]=0xf1; /* IETF */
eua->v[1]=0x21; /* IPv4 */
memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */
return 0;
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua)
{
eua->l = 6;
eua->v[0] = 0xf1; /* IETF */
eua->v[1] = 0x21; /* IPv4 */
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]!=0xf1) || (eua->v[1]!=0x21)) {
return EOF;
}
memcpy(dst, &eua->v[2], 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] != 0xf1) || (eua->v[1] != 0x21)) {
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) {
return (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60);
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi)
{
return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60);
}
int ulcpy(void* dst, void* src, size_t size) {
if (((struct ul255_t*)src)->l <= size) {
((struct ul255_t*)dst)->l = ((struct ul255_t*)src)->l;
memcpy(((struct ul255_t*)dst)->v, ((struct ul255_t*)src)->v,
((struct ul255_t*)dst)->l);
return 0;
}
else return EOF;
void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid)
{
pdp->imsi = teid & 0x0fffffffffffffffull;
pdp->nsapi = (teid & 0xf000000000000000ull) >> 60;
}

227
gtp/pdp.h
View File

@ -12,42 +12,40 @@
#ifndef _PDP_H
#define _PDP_H
#define PDP_MAX 1024 /* Max number of PDP contexts */
#define PDP_MAXNSAPI 16 /* Max number of NSAPI */
struct gsn_t;
#define PDP_DEBUG 0 /* Print debug information */
#define PDP_MAX 1024 /* Max number of PDP contexts */
#define PDP_MAXNSAPI 16 /* Max number of NSAPI */
/* 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 *
* by 135: QOS Profile in version 1 */
struct sl_t {
unsigned int l;
char *v;
unsigned int l;
char *v;
};
struct ul_t {
unsigned int l;
unsigned char *v;
unsigned int l;
unsigned char *v;
};
struct ul16_t {
unsigned int l;
unsigned char v[16];
unsigned int l;
unsigned char v[16];
};
struct ul66_t {
unsigned int l;
unsigned char v[66];
unsigned int l;
unsigned char v[66];
};
struct ul255_t {
unsigned int l;
unsigned char v[255];
unsigned int l;
unsigned char v[255];
};
/* *****************************************************************
* Information storage for each PDP context
*
@ -103,120 +101,132 @@ unsigned char v[255];
*****************************************************************/
struct pdp_t {
/* Parameter determining if this PDP is in use. */
uint8_t inuse; /* 0=free. 1=used by somebody */
/* Parameter determining if this PDP is in use. */
uint8_t inuse; /* 0=free. 1=used by somebody */
/* Pointers related to hash tables */
struct pdp_t *tidnext;
struct pdp_t *ipnext;
/* Pointers related to hash tables */
struct pdp_t *tidnext;
struct pdp_t *ipnext;
/* 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 *peer; /* Pointer to peer protocol */
void *asap; /* Application specific service access point */
void *ipif; /* IP network interface */
void *peer; /* Pointer to peer protocol */
void *asap; /* Application specific service access point */
uint64_t imsi; /* International Mobile Subscriber Identity.*/
struct ul16_t msisdn; /* The basic MSISDN of the MS. */
uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */
uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */
uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */
uint16_t tracetype;/* Indicates the type of trace. */
struct ul_t triggerid;/* Identifies the entity that initiated the trace. */
struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */
uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */
uint64_t imsi; /* International Mobile Subscriber Identity. */
struct ul16_t msisdn; /* The basic MSISDN of the MS. */
uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */
uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */
uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */
uint16_t tracetype; /* Indicates the type of trace. */
struct ul_t triggerid; /* Identifies the entity that initiated the trace. */
struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */
uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */
/* Parameters specific to each individual PDP context */
/* Parameters specific to each individual PDP context */
uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */
uint8_t pdp_state;/* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */
/* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */
/* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */
struct ul66_t eua; /* End user address. PDP type and address combined */
uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */
struct ul255_t apn_req;/* The APN requested. */
struct ul255_t apn_sub;/* The APN received from the HLR. */
struct ul255_t apn_use;/* The APN Network Identifier currently used. */
uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */
uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */
uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */
uint8_t pdp_state; /* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */
/* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */
/* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */
struct ul66_t eua; /* End user address. PDP type and address combined */
uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */
struct ul255_t apn_req; /* The APN requested. */
struct ul255_t apn_sub; /* The APN received from the HLR. */
struct ul255_t apn_use; /* The APN Network Identifier currently used. */
uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */
uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */
uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */
uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */
uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */
uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */
uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */
uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */
uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */
uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */
uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */
uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */
uint16_t fllc; /* (Local Flow Label Control, gtp0) */
uint16_t fllu; /* (Local Flow Label Data I, gtp0) */
uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */
uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */
uint16_t fllc; /* (Local Flow Label Control, gtp0) */
uint16_t fllu; /* (Local Flow Label Data I, gtp0) */
uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */
uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */
struct ul255_t tft; /* Traffic flow template. */
/*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */
/*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */
/*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */
/*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */
struct ul255_t tft; /* Traffic flow template. */
/*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */
/*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */
/*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */
/*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */
struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */
struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */
struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */
struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */
struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */
struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */
struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */
struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */
uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */
uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */
uint8_t qos_req0[3]; /* The quality of service profile requested. */
uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */
struct ul255_t qos_sub; /* The quality of service profile subscribed. */
struct ul255_t qos_req; /* The quality of service profile requested. */
struct ul255_t qos_neg; /* The quality of service profile negotiated. */
uint8_t radio_pri;/* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */
uint16_t flow_id; /* Packet flow identifier. */
/* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP)*/
uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */
uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */
uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */
uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */
uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */
uint8_t qos_req0[3]; /* The quality of service profile requested. */
uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */
struct ul255_t qos_sub; /* The quality of service profile subscribed. */
struct ul255_t qos_req; /* The quality of service profile requested. */
struct ul255_t qos_neg; /* The quality of service profile negotiated. */
uint8_t radio_pri; /* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */
uint16_t flow_id; /* Packet flow identifier. */
/* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP) */
uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */
uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */
uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */
/* uint16_t gtpsnd; GTP-U sequence number of the next downlink N-PDU to be sent to the SGSN / received from the GGSN. */
/* uint16_t gtpsnu; GTP-U sequence number of the next uplink N-PDU to be received from the SGSN / sent to the GGSN */
uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */
uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */
uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */
uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */
uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */
uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */
struct ul16_t rnc_addr;/* The IP address of the RNC currently used. */
uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */
struct ul255_t pco_req; /* Requested packet control options. */
struct ul255_t pco_neg; /* Negotiated packet control options. */
uint32_t selmode; /* Selection mode. */
uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */
uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */
uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */
uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */
uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */
uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */
struct ul16_t rnc_addr; /* The IP address of the RNC currently used. */
uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */
struct ul255_t pco_req; /* Requested packet control options. */
struct ul255_t pco_neg; /* Negotiated packet control options. */
uint32_t selmode; /* Selection mode. */
struct ul255_t rattype; /* Radio Access Technology Type */
int rattype_given; /* Radio Access Technology Type given */
struct ul255_t userloc; /* User Location Information */
int userloc_given; /* User Location Information given */
struct ul255_t rai; /* Routing Area Information */
int rai_given; /* Routing Area Information given */
struct ul255_t mstz; /* MS Time Zone */
int mstz_given; /* MS Time Zone given */
struct ul255_t imeisv; /* IMEI Software Version */
int imeisv_given; /* IMEI Software Version given */
int norecovery_given; /* norecovery given */
/* Additional parameters used by library */
/* Additional parameters used by library */
int version; /* Protocol version currently in use. 0 or 1 */
int version; /* Protocol version currently in use. 0 or 1 */
uint64_t tid; /* Combination of imsi and nsapi */
uint16_t seq; /* Sequence number of last request */
struct sockaddr_in sa_peer; /* Address of last request */
int fd; /* File descriptor request was received on */
uint64_t tid; /* Combination of imsi and nsapi */
uint16_t seq; /* Sequence number of last request */
struct sockaddr_in sa_peer; /* Address of last request */
int fd; /* File descriptor request was received on */
uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */
uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */
/* Parameters used for secondary activation procedure (tei data) */
/* If (secondary == 1) then teic_own indicates linked PDP context */
uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */
uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */
/* Parameters used for secondary activation procedure (tei data) */
/* If (secondary == 1) then teic_own indicates linked PDP context */
uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */
uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */
/* Secondary contexts of this primary context */
uint32_t secondary_tei[PDP_MAXNSAPI];
/* Secondary contexts of this primary context */
uint32_t secondary_tei[PDP_MAXNSAPI];
/* IP address used for Create and Update PDP Context Requests */
struct in_addr hisaddr0; /* Server address */
struct in_addr hisaddr1; /* Server address */
/* IP address used for Create and Update PDP Context Requests */
struct in_addr hisaddr0; /* Server address */
struct in_addr hisaddr1; /* Server address */
/* to be used by libgtp callers/users (to attach their own private state) */
void *priv;
/* to be used by libgtp callers/users (to attach their own private state) */
void *priv;
struct gsn_t *gsn;
};
/* functions related to pdp_t management */
int pdp_init();
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
@ -226,6 +236,7 @@ int pdp_getpdp(struct pdp_t **pdp);
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl);
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei);
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn);
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi);
@ -234,6 +245,7 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid);
int pdp_tiddel(struct pdp_t *pdp);
int pdp_tidget(struct pdp_t **pdp, uint64_t tid);
void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid);
/*
int pdp_iphash(void* ipif, struct ul66_t *eua);
@ -245,6 +257,5 @@ 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);
int ulcpy(void* dst, void* src, size_t size);
#endif /* !_PDP_H */
#endif /* !_PDP_H */

View File

@ -1,6 +1,7 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002, 2003, 2004 Mondru AB.
* Copyright (C) 2011 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
@ -29,224 +30,261 @@
#include "gtp.h"
#include "queue.h"
int queue_print(struct queue_t *queue) {
int n;
printf("Queue: %x Next: %d First: %d Last: %d\n", (int) queue, queue->next, queue->first, queue->last);
printf("# State seq next prev timeout retrans\n");
for (n=0; n<QUEUE_SIZE; n++) {
printf("%d %d %d %d %d %d %d\n",
n,
queue->qmsga[n].state,
queue->qmsga[n].seq,
queue->qmsga[n].next,
queue->qmsga[n].prev,
(int) queue->qmsga[n].timeout,
queue->qmsga[n].retrans);
}
return 0;
/*! \brief dump a queue_t to stdout */
static int queue_print(struct queue_t *queue)
{
int n;
printf("Queue: %p Next: %d First: %d Last: %d\n", queue,
queue->next, queue->first, queue->last);
printf("# State seq next prev timeout retrans\n");
for (n = 0; n < QUEUE_SIZE; n++) {
printf("%d %d %d %d %d %d %d\n",
n,
queue->qmsga[n].state,
queue->qmsga[n].seq,
queue->qmsga[n].next,
queue->qmsga[n].prev,
(int)queue->qmsga[n].timeout, queue->qmsga[n].retrans);
}
return 0;
}
int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) {
/* With QUEUE_HASH_SIZE = 2^16 this describes all possible
seq values. Thus we have perfect hash for the request queue.
For the response queue we might have collisions, but not very
often.
For performance optimisation we should remove the modulus
operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */
return seq % QUEUE_HASH_SIZE;
/*! \brief compute the hash function */
static int queue_seqhash(struct sockaddr_in *peer, uint16_t seq)
{
/* With QUEUE_HASH_SIZE = 2^16 this describes all possible
seq values. Thus we have perfect hash for the request queue.
For the response queue we might have collisions, but not very
often.
For performance optimisation we should remove the modulus
operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */
return seq % QUEUE_HASH_SIZE;
}
int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
struct sockaddr_in *peer, uint16_t seq) {
int hash = queue_seqhash(peer, seq);
struct qmsg_t *qmsg2;
struct qmsg_t *qmsg_prev = NULL;
/*! \brief Insert a message with given sequence number into the hash
*
* This function sets the peer and the seq of the qmsg and then inserts
* the qmsg into the queue hash. To do so, it does a hashtable lookup
* and appends the new entry as the last into the double-linked list of
* entries for this sequence number.
*/
static int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
struct sockaddr_in *peer, uint16_t seq)
{
int hash = queue_seqhash(peer, seq);
struct qmsg_t *qmsg2;
struct qmsg_t *qmsg_prev = NULL;
if (QUEUE_DEBUG) printf("Begin queue_seqset seq = %d\n", (int) seq);
if (QUEUE_DEBUG) printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), sizeof(*peer));
if (QUEUE_DEBUG)
printf("Begin queue_seqset seq = %d\n", (int)seq);
if (QUEUE_DEBUG)
printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer),
sizeof(*peer));
qmsg->seq = seq;
memcpy(&qmsg->peer, peer, sizeof(*peer));
qmsg->seq = seq;
memcpy(&qmsg->peer, peer, sizeof(*peer));
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext)
qmsg_prev = qmsg2;
if (!qmsg_prev)
queue->hashseq[hash] = qmsg;
else
qmsg_prev->seqnext = qmsg;
if (QUEUE_DEBUG) printf("End queue_seqset\n");
return 0;
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext)
qmsg_prev = qmsg2;
if (!qmsg_prev)
queue->hashseq[hash] = qmsg;
else
qmsg_prev->seqnext = qmsg;
if (QUEUE_DEBUG)
printf("End queue_seqset\n");
return 0;
}
/*! \brief Remove a given qmsg_t from the queue hash */
static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
{
int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
struct qmsg_t *qmsg2;
struct qmsg_t *qmsg_prev = NULL;
if (QUEUE_DEBUG)
printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq);
int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) {
int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
struct qmsg_t *qmsg2;
struct qmsg_t *qmsg_prev = NULL;
if (QUEUE_DEBUG) printf("Begin queue_seqdel seq = %d\n", (int) qmsg->seq);
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
if (qmsg == qmsg) {
if (!qmsg_prev)
queue->hashseq[hash] = qmsg2->seqnext;
else
qmsg_prev->seqnext = qmsg2->seqnext;
if (QUEUE_DEBUG) printf("End queue_seqset: SEQ found\n");
return 0;
}
qmsg_prev = qmsg2;
}
printf("End queue_seqset: SEQ not found\n");
return EOF; /* End of linked list and not found */
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
if (qmsg == qmsg2) {
if (!qmsg_prev)
queue->hashseq[hash] = qmsg2->seqnext;
else
qmsg_prev->seqnext = qmsg2->seqnext;
if (QUEUE_DEBUG)
printf("End queue_seqdel: SEQ found\n");
return 0;
}
qmsg_prev = qmsg2;
}
printf("End queue_seqdel: SEQ not found\n");
return EOF; /* End of linked list and not found */
}
/*! \brief Allocates and initialises new queue structure */
int queue_new(struct queue_t **queue)
{
if (QUEUE_DEBUG)
printf("queue_new\n");
*queue = calloc(1, sizeof(struct queue_t));
if (!(*queue))
return EOF;
(*queue)->next = 0;
(*queue)->first = -1;
(*queue)->last = -1;
/* Allocates and initialises new queue structure */
int queue_new(struct queue_t **queue) {
if (QUEUE_DEBUG) printf("queue_new\n");
*queue = calloc(1, sizeof(struct queue_t));
(*queue)->next = 0;
(*queue)->first = -1;
(*queue)->last = -1;
if (QUEUE_DEBUG) queue_print(*queue);
if (*queue) return 0;
else return EOF;
if (QUEUE_DEBUG)
queue_print(*queue);
return 0;
}
/* Deallocates queue structure */
int queue_free(struct queue_t *queue) {
if (QUEUE_DEBUG) printf("queue_free\n");
if (QUEUE_DEBUG) queue_print(queue);
free(queue);
return 0;
/*! \brief Deallocates queue structure */
int queue_free(struct queue_t *queue)
{
if (QUEUE_DEBUG)
printf("queue_free\n");
if (QUEUE_DEBUG)
queue_print(queue);
free(queue);
return 0;
}
/*! \brief Add a new message to the queue */
int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq) {
if (QUEUE_DEBUG) printf("queue_newmsg %d\n", (int) seq);
if (queue->qmsga[queue->next].state == 1) {
return EOF; /* Queue is full */
}
else {
*qmsg = &queue->qmsga[queue->next];
queue_seqset(queue, *qmsg, peer, seq);
(*qmsg)->state = 1; /* Space taken */
(*qmsg)->this = queue->next;
(*qmsg)->next=-1; /* End of the queue */
(*qmsg)->prev=queue->last; /* Link to the previous */
if (queue->last != -1)
queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
queue->last = queue->next; /* End of queue */
if (queue->first == -1) queue->first = queue->next;
queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */
if (QUEUE_DEBUG) queue_print(queue);
return 0;
}
struct sockaddr_in *peer, uint16_t seq)
{
if (QUEUE_DEBUG)
printf("queue_newmsg %d\n", (int)seq);
if (queue->qmsga[queue->next].state == 1) {
return EOF; /* Queue is full */
} else {
*qmsg = &queue->qmsga[queue->next];
queue_seqset(queue, *qmsg, peer, seq);
(*qmsg)->state = 1; /* Space taken */
(*qmsg)->this = queue->next;
(*qmsg)->next = -1; /* End of the queue */
(*qmsg)->prev = queue->last; /* Link to the previous */
if (queue->last != -1)
queue->qmsga[queue->last].next = queue->next; /* Link previous to us */
queue->last = queue->next; /* End of queue */
if (queue->first == -1)
queue->first = queue->next;
queue->next = (queue->next + 1) % QUEUE_SIZE; /* Increment */
if (QUEUE_DEBUG)
queue_print(queue);
return 0;
}
}
int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) {
if (QUEUE_DEBUG) printf("queue_freemsg\n");
if (qmsg->state != 1) {
return EOF; /* Not in queue */
}
/*! \brief Simply remoev a given qmsg_t from the queue
*
* Internally, we first delete the entry from the queue, and then update
* up our global queue->first / queue->last pointers. Finally,
* the qmsg_t is re-initialized with zero bytes. No memory is released.
*/
int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
{
if (QUEUE_DEBUG)
printf("queue_freemsg\n");
if (qmsg->state != 1) {
return EOF; /* Not in queue */
}
queue_seqdel(queue, qmsg);
queue_seqdel(queue, qmsg);
if (qmsg->next == -1) /* Are we the last in queue? */
queue->last = qmsg->prev;
else
queue->qmsga[qmsg->next].prev = qmsg->prev;
if (qmsg->prev == -1) /* Are we the first in queue? */
queue->first = qmsg->next;
else
queue->qmsga[qmsg->prev].next = qmsg->next;
if (qmsg->next == -1) /* Are we the last in queue? */
queue->last = qmsg->prev;
else
queue->qmsga[qmsg->next].prev = qmsg->prev;
memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
if (qmsg->prev == -1) /* Are we the first in queue? */
queue->first = qmsg->next;
else
queue->qmsga[qmsg->prev].next = qmsg->next;
if (QUEUE_DEBUG) queue_print(queue);
memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
return 0;
if (QUEUE_DEBUG)
queue_print(queue);
return 0;
}
int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) {
if (QUEUE_DEBUG) printf("queue_back\n");
if (qmsg->state != 1) {
return EOF; /* Not in queue */
}
/*! \brief Move a given qmsg_t to the end of the queue ?!? */
int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
{
if (QUEUE_DEBUG)
printf("queue_back\n");
if (qmsg->state != 1) {
return EOF; /* Not in queue */
}
/* Insert stuff to maintain hash table */
/* Insert stuff to maintain hash table */
if (qmsg->next != -1) {/* Only swop if there are others */
queue->qmsga[qmsg->next].prev = qmsg->prev;
queue->first = qmsg->next;
qmsg->next = -1;
qmsg->prev = queue->last;
if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this;
queue->last = qmsg->this;
}
if (QUEUE_DEBUG) queue_print(queue);
return 0;
if (qmsg->next != -1) { /* Only swop if there are others */
queue->qmsga[qmsg->next].prev = qmsg->prev;
queue->first = qmsg->next;
qmsg->next = -1;
qmsg->prev = queue->last;
if (queue->last != -1)
queue->qmsga[queue->last].next = qmsg->this;
queue->last = qmsg->this;
}
if (QUEUE_DEBUG)
queue_print(queue);
return 0;
}
/* Get the element with a particular sequence number */
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) {
/*printf("queue_getfirst\n");*/
if (queue->first == -1) {
*qmsg = NULL;
return EOF; /* End of queue = queue is empty. */
}
*qmsg = &queue->qmsga[queue->first];
if (QUEUE_DEBUG) queue_print(queue);
return 0;
}
int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq) {
int n;
if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq);
if (QUEUE_DEBUG) queue_print(queue);
for (n=0; n<QUEUE_SIZE; n++) {
if ((queue->qmsga[n].seq == seq) &&
(!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
*qmsg = &queue->qmsga[n];
return 0;
}
}
return EOF; /* Not found */
/*! \brief Get the first element in the entire queue */
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
{
/*printf("queue_getfirst\n"); */
if (queue->first == -1) {
*qmsg = NULL;
return EOF; /* End of queue = queue is empty. */
}
*qmsg = &queue->qmsga[queue->first];
if (QUEUE_DEBUG)
queue_print(queue);
return 0;
}
/*! \brief Get a queue entry for a given peer + seq */
int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq) {
int hash = queue_seqhash(peer, seq);
struct qmsg_t *qmsg2;
if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq);
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
if ((qmsg2->seq == seq) &&
(!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
*qmsg = qmsg2;
if (QUEUE_DEBUG) printf("End queue_seqget. Found\n");
return 0;
}
}
if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n");
return EOF; /* End of linked list and not found */
struct sockaddr_in *peer, uint16_t seq)
{
int hash = queue_seqhash(peer, seq);
struct qmsg_t *qmsg2;
if (QUEUE_DEBUG)
printf("Begin queue_seqget seq = %d\n", (int)seq);
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
if ((qmsg2->seq == seq) &&
(!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
*qmsg = qmsg2;
if (QUEUE_DEBUG)
printf("End queue_seqget. Found\n");
return 0;
}
}
if (QUEUE_DEBUG)
printf("End queue_seqget. Not found\n");
return EOF; /* End of linked list and not found */
}
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
uint16_t seq, uint8_t *type, void **cbp) {
struct qmsg_t *qmsg;
if (queue_seqget(queue, &qmsg, peer, seq)) {
*cbp = NULL;
*type = 0;
return EOF;
}
*cbp = qmsg->cbp;
*type = qmsg->type;
if (queue_freemsg(queue, qmsg)) {
return EOF;
}
return 0;
/*! \brief look-up a given seq/peer, return cbp + type and free entry */
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
uint16_t seq, uint8_t * type, void **cbp)
{
struct qmsg_t *qmsg;
if (queue_seqget(queue, &qmsg, peer, seq)) {
*cbp = NULL;
*type = 0;
return EOF;
}
*cbp = qmsg->cbp;
*type = qmsg->type;
if (queue_freemsg(queue, qmsg)) {
return EOF;
}
return 0;
}

View File

@ -17,37 +17,36 @@
#ifndef _QUEUE_H
#define _QUEUE_H
#define QUEUE_DEBUG 0 /* Print debug information */
#define QUEUE_DEBUG 0 /* Print debug information */
#define QUEUE_SIZE 1024 /* Size of retransmission queue */
#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */
#define QUEUE_SIZE 1024 /* Size of retransmission queue */
#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */
struct qmsg_t { /* Holder for queued packets */
int state; /* 0=empty, 1=full */
uint16_t seq; /* The sequence number */
uint8_t type; /* The type of packet */
void *cbp; /* Application specific pointer */
union gtp_packet p; /* The packet stored */
int l; /* Length of the packet */
int fd; /* Socket packet was sent to / received from */
struct sockaddr_in peer;/* Address packet was sent to / received from */
struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */
int next; /* Pointer to the next in queue. -1: Last */
int prev; /* Pointer to the previous in queue. -1: First */
int this; /* Pointer to myself */
time_t timeout; /* When do we retransmit this packet? */
int retrans; /* How many times did we retransmit this? */
struct qmsg_t { /* Holder for queued packets */
int state; /* 0=empty, 1=full */
uint16_t seq; /* The sequence number */
uint8_t type; /* The type of packet */
void *cbp; /* Application specific pointer */
union gtp_packet p; /* The packet stored */
int l; /* Length of the packet */
int fd; /* Socket packet was sent to / received from */
struct sockaddr_in peer; /* Address packet was sent to / received from */
struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */
int next; /* Pointer to the next in queue. -1: Last */
int prev; /* Pointer to the previous in queue. -1: First */
int this; /* Pointer to myself */
time_t timeout; /* When do we retransmit this packet? */
int retrans; /* How many times did we retransmit this? */
};
struct queue_t {
struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */
void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */
int next; /* Next location in queue to use */
int first; /* First packet in queue (oldest timeout) */
int last; /* Last packet in queue (youngest timeout) */
struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */
void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */
int next; /* Next location in queue to use */
int first; /* First packet in queue (oldest timeout) */
int last; /* Last packet in queue (youngest timeout) */
};
/* Allocates and initialises new queue structure */
int queue_new(struct queue_t **queue);
/* Deallocates queue structure */
@ -63,11 +62,9 @@ int queue_back(struct queue_t *queue, struct qmsg_t *qmsg);
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg);
/* Get the element with a particular sequence number */
int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq);
struct sockaddr_in *peer, uint16_t seq);
/* Free message based on sequence number */
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
uint16_t seq, uint8_t *type, void **cbp);
#endif /* !_QUEUE_H */
uint16_t seq, uint8_t * type, void **cbp);
#endif /* !_QUEUE_H */

7
lib/Makefile.am Normal file
View File

@ -0,0 +1,7 @@
noinst_LIBRARIES = libmisc.a
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h
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

39
lib/debug.c Normal file
View File

@ -0,0 +1,39 @@
/*
* (C) 2014 by Holger Hans Peter Freyther
*/
#include "syserr.h"
#include <osmocom/core/utils.h>
static const struct log_info_cat default_categories[] = {
[DIP] = {
.name = "DIP",
.description = "IP Pool and other groups",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTUN] = {
.name = "DTUN",
.description = "Tunnel interface",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DGGSN] = {
.name = "DGGSN",
.description = "GGSN",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DSGSN] = {
.name = "DSGSN",
.description = "SGSN Emulator",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DICMP6] = {
.name = "DICMP6",
.description = "ICMPv6",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
const struct log_info log_info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};

1011
lib/getopt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,6 @@
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
@ -63,15 +62,15 @@
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
int getopt_long(argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
return _getopt_internal(argc, argv, options, long_options, opt_index,
0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
@ -79,110 +78,106 @@ getopt_long (argc, argv, options, long_options, opt_index)
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
int getopt_long_only(argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
return _getopt_internal(argc, argv, options, long_options, opt_index,
1);
}
#endif /* Not ELIDE_CODE. */
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
int main(argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
c = getopt_long(argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0
&& digit_optind != this_option_optind)
printf
("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'a':
printf("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'c':
printf("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case 'd':
printf("option d with value `%s'\n", optarg);
break;
case '?':
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit (0);
exit(0);
}
#endif /* TEST */

View File

@ -20,7 +20,7 @@
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#define _GETOPT_H 1
#endif
/* If __GNU_LIBRARY__ is not already defined, either we are being used
@ -31,7 +31,7 @@
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
doesn't flood the namespace with stuff the way some other headers do.) */
#if !defined __GNU_LIBRARY__
# include <ctype.h>
#include <ctype.h>
#endif
#ifdef __cplusplus
@ -44,7 +44,7 @@ extern "C" {
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
@ -58,16 +58,16 @@ extern char *optarg;
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
extern int optopt;
#ifndef __need_getopt
/* Describe the long-named options requested by the application.
@ -91,27 +91,25 @@ extern int optopt;
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
# if (defined __STDC__ && __STDC__) || defined __cplusplus
const char *name;
# else
char *name;
# endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
struct option {
#if (defined __STDC__ && __STDC__) || defined __cplusplus
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
@ -138,43 +136,44 @@ struct option
`getopt'. */
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# ifdef __GNU_LIBRARY__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
# else /* not __GNU_LIBRARY__ */
extern int getopt ();
# endif /* __GNU_LIBRARY__ */
extern int getopt(int __argc, char *const *__argv,
const char *__shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt();
#endif /* __GNU_LIBRARY__ */
# ifndef __need_getopt
extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
#ifndef __need_getopt
extern int getopt_long(int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only(int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts,
int *__longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal(int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts,
int *__longind, int __long_only);
#endif
#else /* not __STDC__ */
extern int getopt();
#ifndef __need_getopt
extern int getopt_long();
extern int getopt_long_only();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
extern int _getopt_internal();
#endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */
#endif /* getopt.h */

257
lib/in46_addr.c Normal file
View File

@ -0,0 +1,257 @@
/*
* IPv4/v6 address functions.
* Copyright (C) 2017 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 "../lib/in46_addr.h"
#include <osmocom/core/utils.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
/*! Return the address family of given \reff in46_addr argument */
int in46a_to_af(const struct in46_addr *in)
{
switch (in->len) {
case 4:
return AF_INET;
case 8:
case 16:
return AF_INET6;
default:
OSMO_ASSERT(0);
return -1;
}
}
/*! Convert \ref in46_addr to sockaddr_storage */
int in46a_to_sas(struct sockaddr_storage *out, const struct in46_addr *in)
{
struct sockaddr_in *sin = (struct sockaddr_in *)out;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)out;
switch (in->len) {
case 4:
sin->sin_family = AF_INET;
sin->sin_addr = in->v4;
break;
case 16:
sin6->sin6_family = AF_INET;
sin6->sin6_addr = in->v6;
break;
default:
OSMO_ASSERT(0);
return -1;
}
return 0;
}
/*! Convenience wrapper around inet_ntop() for \ref in46_addr */
const char *in46a_ntop(const struct in46_addr *in, char *dst, socklen_t dst_size)
{
int af;
if (!in || in->len == 0) {
strncpy(dst, "UNDEFINED", dst_size);
return dst;
}
af = in46a_to_af(in);
if (af < 0)
return NULL;
return inet_ntop(af, (const void *) &in->v4, dst, dst_size);
}
/* like inet_ntoa() */
const char *in46a_ntoa(const struct in46_addr *in46)
{
static char addrstr_buf[256];
if (in46a_ntop(in46, addrstr_buf, sizeof(addrstr_buf)) < 0)
return "INVALID";
else
return addrstr_buf;
}
const char *in46p_ntoa(const struct in46_prefix *in46p)
{
static char addrstr_buf[256];
snprintf(addrstr_buf, sizeof(addrstr_buf), "%s/%u", in46a_ntoa(&in46p->addr), in46p->prefixlen);
return addrstr_buf;
}
/*! Determine if two in46_addr are equal or not
* \returns 1 in case they are equal; 0 otherwise */
int in46a_equal(const struct in46_addr *a, const struct in46_addr *b)
{
if (a->len == b->len && !memcmp(&a->v6, &b->v6, a->len))
return 1;
else
return 0;
}
/*! Determine if two in46_addr prefix are equal or not
* The prefix length is determined by the shortest of the prefixes of a and b
* \returns 1 in case the common prefix are equal; 0 otherwise */
int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b)
{
unsigned int len;
if (a->len > b->len)
len = b->len;
else
len = a->len;
if (!memcmp(&a->v6, &b->v6, len))
return 1;
else
return 0;
}
/*! Match if IPv6 addr1 + addr2 are within same \a mask */
static int ipv6_within_mask(const struct in6_addr *addr1, const struct in6_addr *addr2,
const struct in6_addr *mask)
{
struct in6_addr masked = *addr2;
#if defined(__linux__)
masked.s6_addr32[0] &= mask->s6_addr32[0];
masked.s6_addr32[1] &= mask->s6_addr32[1];
masked.s6_addr32[2] &= mask->s6_addr32[2];
masked.s6_addr32[3] &= mask->s6_addr32[3];
#else
masked.__u6_addr.__u6_addr32[0] &= mask->__u6_addr.__u6_addr32[0];
masked.__u6_addr.__u6_addr32[1] &= mask->__u6_addr.__u6_addr32[1];
masked.__u6_addr.__u6_addr32[2] &= mask->__u6_addr.__u6_addr32[2];
masked.__u6_addr.__u6_addr32[3] &= mask->__u6_addr.__u6_addr32[3];
#endif
if (!memcmp(addr1, &masked, sizeof(struct in6_addr)))
return 1;
else
return 0;
}
/*! Create an IPv6 netmask from the given prefix length */
static void create_ipv6_netmask(struct in6_addr *netmask, int prefixlen)
{
uint32_t *p_netmask;
memset(netmask, 0, sizeof(struct in6_addr));
if (prefixlen < 0)
prefixlen = 0;
else if (128 < prefixlen)
prefixlen = 128;
#if defined(__linux__)
p_netmask = &netmask->s6_addr32[0];
#else
p_netmask = &netmask->__u6_addr.__u6_addr32[0];
#endif
while (32 < prefixlen) {
*p_netmask = 0xffffffff;
p_netmask++;
prefixlen -= 32;
}
if (prefixlen != 0) {
*p_netmask = htonl(0xFFFFFFFF << (32 - prefixlen));
}
}
/*! Determine if given \a addr is within given \a net + \a prefixlen
* Builds the netmask from \a net + \a prefixlen and matches it to \a addr
* \returns 1 in case of a match, 0 otherwise */
int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen)
{
struct in_addr netmask;
struct in6_addr netmask6;
if (addr->len != net->len)
return 0;
switch (addr->len) {
case 4:
netmask.s_addr = htonl(0xFFFFFFFF << (32 - prefixlen));
if ((addr->v4.s_addr & netmask.s_addr) == net->v4.s_addr)
return 1;
else
return 0;
case 16:
create_ipv6_netmask(&netmask6, prefixlen);
return ipv6_within_mask(&addr->v6, &net->v6, &netmask6);
default:
OSMO_ASSERT(0);
return 0;
}
}
/*! Convert given PDP End User Address to in46_addr
* \returns 0 on success; negative on error */
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua)
{
switch (src->len) {
case 4:
eua->l = 6;
eua->v[0] = 0xf1; /* IETF */
eua->v[1] = 0x21; /* IPv4 */
memcpy(&eua->v[2], &src->v4, 4); /* Copy a 4 byte address */
break;
case 8:
case 16:
eua->l = 18;
eua->v[0] = 0xf1; /* IETF */
eua->v[1] = 0x57; /* IPv6 */
memcpy(&eua->v[2], &src->v6, 16); /* Copy a 16 byte address */
break;
default:
OSMO_ASSERT(0);
return -1;
}
return 0;
}
/*! Convert given in46_addr to PDP End User Address
* \returns 0 on success; negative on error */
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
{
if (eua->l < 2)
goto default_to_dyn_v4;
if (eua->v[0] != 0xf1)
return -1;
switch (eua->v[1]) {
case 0x21:
dst->len = 4;
if (eua->l >= 6)
memcpy(&dst->v4, &eua->v[2], 4); /* Copy a 4 byte address */
else
dst->v4.s_addr = 0;
break;
case 0x57:
dst->len = 16;
if (eua->l >= 18)
memcpy(&dst->v6, &eua->v[2], 16); /* Copy a 16 byte address */
else
memset(&dst->v6, 0, 16);
break;
default:
return -1;
}
return 0;
default_to_dyn_v4:
/* assume dynamic IPv4 by default */
dst->len = 4;
dst->v4.s_addr = 0;
return 0;
}

32
lib/in46_addr.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
#include "../gtp/pdp.h"
/* a simple wrapper around an in6_addr to also contain the length of the address,
* thereby implicitly indicating the address family of the address */
struct in46_addr {
uint8_t len;
union {
struct in_addr v4;
struct in6_addr v6;
};
};
struct in46_prefix {
struct in46_addr addr;
uint8_t prefixlen;
};
extern int in46a_to_af(const struct in46_addr *in);
extern int in46a_to_sas(struct sockaddr_storage *out, const struct in46_addr *in);
extern const char *in46a_ntop(const struct in46_addr *in, char *dst, socklen_t dst_size);
extern const char *in46a_ntoa(const struct in46_addr *in46);
extern const char *in46p_ntoa(const struct in46_prefix *in46p);
extern int in46a_equal(const struct in46_addr *a, const struct in46_addr *b);
extern int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b);
extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen);
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua);
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);

571
lib/ippool.c Normal file
View File

@ -0,0 +1,571 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
* Copyright (C) 2017 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 <sys/types.h>
#include <netinet/in.h> /* in_addr */
#include <stdlib.h> /* calloc */
#include <stdio.h> /* sscanf */
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "syserr.h"
#include "ippool.h"
#include "lookup.h"
int ippool_printaddr(struct ippool_t *this)
{
unsigned int n;
printf("ippool_printaddr\n");
printf("Firstdyn %d\n", this->firstdyn - this->member);
printf("Lastdyn %d\n", this->lastdyn - this->member);
printf("Firststat %d\n", this->firststat - this->member);
printf("Laststat %d\n", this->laststat - this->member);
printf("Listsize %d\n", this->listsize);
for (n = 0; n < this->listsize; n++) {
char s[256];
in46a_ntop(&this->member[n].addr, s, sizeof(s));
printf("Unit %d inuse %d prev %d next %d addr %s\n",
n,
this->member[n].inuse,
this->member[n].prev - this->member,
this->member[n].next - this->member,
s);
}
return 0;
}
int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member)
{
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Insert into hash table */
hash = ippool_hash(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash)
p_prev = p;
if (!p_prev)
this->hash[hash] = member;
else
p_prev->nexthash = member;
return 0; /* Always OK to insert */
}
int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member)
{
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Find in hash table */
hash = ippool_hash(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if (p == member) {
break;
}
p_prev = p;
}
if (p != member) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"ippool_hashdel: Tried to delete member not in hash table");
return -1;
}
if (!p_prev)
this->hash[hash] = p->nexthash;
else
p_prev->nexthash = p->nexthash;
return 0;
}
static unsigned long int ippool_hash4(struct in_addr *addr)
{
return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0);
}
static unsigned long int ippool_hash6(struct in6_addr *addr, unsigned int len)
{
/* TODO: Review hash spread for IPv6 */
return lookup((unsigned char *)addr->s6_addr, len, 0);
}
unsigned long int ippool_hash(struct in46_addr *addr)
{
if (addr->len == 4)
return ippool_hash4(&addr->v4);
else
return ippool_hash6(&addr->v6, addr->len);
}
/* Get IP address and mask */
int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool_in, int number)
{
struct addrinfo *ai;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_flags = 0,
.ai_protocol = 0
};
char pool[strlen(pool_in)+1];
strcpy(pool, pool_in);
int err;
/* Find '/' and point to first char after it */
char *prefixlen_str = strchr(pool, '/');
if (prefixlen_str) {
*prefixlen_str = '\0';
prefixlen_str++;
if (*prefixlen_str == '\0') {
SYS_ERR(DIP, LOGL_ERROR, 0, "Empty prefix length specified");
return -1;
}
}
/* convert address */
if ((err = getaddrinfo(pool, NULL, &hints, &ai))) {
SYS_ERR(DIP, LOGL_ERROR, 0, "Bad address");
return -1;
}
/* Copy address, set lengths */
if (ai->ai_family == AF_INET) {
*prefixlen = 32;
addr->len = sizeof(struct in_addr);
addr->v4 = ((struct sockaddr_in*)ai->ai_addr)->sin_addr;
} else {
*prefixlen = 128;
addr->len = sizeof(struct in6_addr);
addr->v6 = ((struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
}
freeaddrinfo(ai);
/* parse prefixlen */
if (prefixlen_str) {
char *e;
*prefixlen = strtol(prefixlen_str, &e, 10);
if (*e != '\0') {
SYS_ERR(DIP, LOGL_ERROR, 0, "Prefixlen is not an int");
return -1;
}
}
if (*prefixlen > (addr->len * 8)) {
SYS_ERR(DIP, LOGL_ERROR, 0, "Perfixlen too big");
return -1;
}
return 0;
}
/* Increase IPv4/IPv6 address by 1 */
void in46a_inc(struct in46_addr *addr)
{
size_t addrlen;
uint8_t *a = (uint8_t *)&addr->v6;
for (addrlen = addr->len; addrlen > 0; addrlen--) {
if (++a[addrlen-1])
break;
}
}
/* Create new address pool */
int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const struct in46_prefix *stat,
int flags)
{
/* Parse only first instance of pool for now */
int i;
struct in46_addr addr;
size_t addrprefixlen;
struct in46_addr stataddr;
size_t stataddrprefixlen;
int listsize;
int dynsize;
unsigned int statsize;
if (!dyn || dyn->addr.len == 0) {
dynsize = 0;
} else {
addr = dyn->addr;
addrprefixlen = dyn->prefixlen;
/* we want to work with /64 prefixes, i.e. allocate /64 prefixes rather
* than /128 (single IPv6 addresses) */
if (addr.len == sizeof(struct in6_addr))
addr.len = 64/8;
/* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */
if (flags & IPPOOL_NOGATEWAY) {
flags |= IPPOOL_NONETWORK;
}
dynsize = (1 << (addr.len*8 - addrprefixlen)) -1;
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
dynsize--;
if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */
dynsize--;
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
dynsize--;
}
if (!stat || stat->addr.len == 0) {
statsize = 0;
stataddr.len = 0;
stataddrprefixlen = 0;
} else {
stataddr = stat->addr;
stataddrprefixlen = stat->prefixlen;
statsize = (1 << (addr.len - stataddrprefixlen + 1)) -1;
if (statsize > IPPOOL_STATSIZE)
statsize = IPPOOL_STATSIZE;
}
listsize = dynsize + statsize; /* Allocate space for static IP addresses */
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"Failed to allocate memory for ippool");
return -1;
}
(*this)->allowdyn = dyn ? 1 : 0;
(*this)->allowstat = stat ? 1 : 0;
if (stataddr.len > 0)
(*this)->stataddr = stataddr;
(*this)->stataddrprefixlen = stataddrprefixlen;
(*this)->listsize += listsize;
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"Failed to allocate memory for members in ippool");
return -1;
}
for ((*this)->hashlog = 0;
((1 << (*this)->hashlog) < listsize); (*this)->hashlog++) ;
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
/* Determine hashsize */
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet */
(*this)->hashmask = (*this)->hashsize - 1;
/* Allocate hash table */
if (!
((*this)->hash =
calloc(sizeof(struct ippoolm_t), (*this)->hashsize))) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"Failed to allocate memory for hash members in ippool");
return -1;
}
(*this)->firstdyn = NULL;
(*this)->lastdyn = NULL;
if (flags & IPPOOL_NOGATEWAY) {
in46a_inc(&addr);
in46a_inc(&addr);
} else if (flags & IPPOOL_NONETWORK) {
in46a_inc(&addr);
}
for (i = 0; i < dynsize; i++) {
(*this)->member[i].addr = addr;
in46a_inc(&addr);
(*this)->member[i].inuse = 0;
(*this)->member[i].pool = *this;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->lastdyn;
if ((*this)->lastdyn) {
(*this)->lastdyn->next = &((*this)->member[i]);
} else {
(*this)->firstdyn = &((*this)->member[i]);
}
(*this)->lastdyn = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
(void)ippool_hashadd(*this, &(*this)->member[i]);
}
(*this)->firststat = NULL;
(*this)->laststat = NULL;
for (i = dynsize; i < listsize; i++) {
struct in46_addr *i6al = &(*this)->member[i].addr;
memset(i6al, 0, sizeof(*i6al));
(*this)->member[i].inuse = 0;
(*this)->member[i].pool = *this;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->laststat;
if ((*this)->laststat) {
(*this)->laststat->next = &((*this)->member[i]);
} else {
(*this)->firststat = &((*this)->member[i]);
}
(*this)->laststat = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
}
if (0)
(void)ippool_printaddr(*this);
return 0;
}
/* Delete existing address pool */
int ippool_free(struct ippool_t *this)
{
free(this->hash);
free(this->member);
free(this);
return 0; /* Always OK */
}
/* Find an IP address in the pool */
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in46_addr *addr)
{
struct ippoolm_t *p;
uint32_t hash;
/* Find in hash table */
hash = ippool_hash(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if (in46a_prefix_equal(&p->addr, addr)) {
if (member)
*member = p;
return 0;
}
}
if (member)
*member = NULL;
/*SYS_ERR(DIP, LOGL_ERROR, 0, "Address could not be found"); */
return -1;
}
/**
* ippool_newip
* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
* check to see if the given address is available. If available within
* dynamic address space allocate it there, otherwise allocate within static
* address space.
**/
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in46_addr *addr, int statip)
{
struct ippoolm_t *p;
struct ippoolm_t *p2 = NULL;
uint32_t hash;
/* If static:
* Look in dynaddr.
* If found remove from firstdyn/lastdyn linked list.
* Else allocate from stataddr.
* Remove from firststat/laststat linked list.
* Insert into hash table.
*
* If dynamic
* Remove from firstdyn/lastdyn linked list.
*
*/
if (0)
(void)ippool_printaddr(this);
int specified = 0;
if (addr) {
if (addr->len == 4 && addr->v4.s_addr)
specified = 1;
if (addr->len == 16 && !IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
specified = 1;
}
/* First check to see if this type of address is allowed */
if (specified && statip) { /* IP address given */
if (!this->allowstat) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"Static IP address not allowed");
return -GTPCAUSE_NOT_SUPPORTED;
}
if (!in46a_within_mask(addr, &this->stataddr, this->stataddrprefixlen)) {
SYS_ERR(DIP, LOGL_ERROR, 0, "Static out of range");
return -1;
}
} else {
if (!this->allowdyn) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"Dynamic IP address not allowed");
return -GTPCAUSE_NOT_SUPPORTED;
}
}
/* If IP address given try to find it in dynamic address pool */
if (specified) { /* IP address given */
/* Find in hash table */
hash = ippool_hash(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if (in46a_prefix_equal(&p->addr, addr)) {
p2 = p;
break;
}
}
}
/* If IP was already allocated we can not use it */
if ((!statip) && (p2) && (p2->inuse)) {
p2 = NULL;
}
/* If not found yet and dynamic IP then allocate dynamic IP */
if ((!p2) && (!statip)) {
if (!this->firstdyn) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"No more IP addresses available");
return -GTPCAUSE_ADDR_OCCUPIED;
} else
p2 = this->firstdyn;
}
if (p2) { /* Was allocated from dynamic address pool */
if (p2->inuse) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"IP address allready in use");
return -GTPCAUSE_SYS_FAIL; /* Allready in use / Should not happen */
}
if (p2->addr.len != addr->len && !(addr->len == 16 && p2->addr.len == 8)) {
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
return -GTPCAUSE_UNKNOWN_PDP;
}
/* Remove from linked list of free dynamic addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firstdyn = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->lastdyn = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 1; /* Dynamic address in use */
*member = p2;
if (0)
(void)ippool_printaddr(this);
return 0; /* Success */
}
/* It was not possible to allocate from dynamic address pool */
/* Try to allocate from static address space */
if (specified && (statip)) { /* IP address given */
if (!this->firststat) {
SYS_ERR(DIP, LOGL_ERROR, 0,
"No more IP addresses available");
return -GTPCAUSE_ADDR_OCCUPIED; /* No more available */
} else
p2 = this->firststat;
if (p2->addr.len != addr->len) {
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
return -GTPCAUSE_UNKNOWN_PDP;
}
/* Remove from linked list of free static addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firststat = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->laststat = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 2; /* Static address in use */
memcpy(&p2->addr, addr, sizeof(addr));
*member = p2;
(void)ippool_hashadd(this, *member);
if (0)
(void)ippool_printaddr(this);
return 0; /* Success */
}
SYS_ERR(DIP, LOGL_ERROR, 0,
"Could not allocate IP address");
return -GTPCAUSE_SYS_FAIL; /* Should never get here. TODO: Bad code */
}
int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
{
if (0)
(void)ippool_printaddr(this);
if (!member->inuse) {
SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
return -1; /* Not in use: Should not happen */
}
switch (member->inuse) {
case 0: /* Not in use: Should not happen */
SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
return -1;
case 1: /* Allocated from dynamic address space */
/* Insert into list of unused */
member->prev = this->lastdyn;
if (this->lastdyn) {
this->lastdyn->next = member;
} else {
this->firstdyn = member;
}
this->lastdyn = member;
member->inuse = 0;
member->peer = NULL;
if (0)
(void)ippool_printaddr(this);
return 0;
case 2: /* Allocated from static address space */
if (ippool_hashdel(this, member))
return -1;
/* Insert into list of unused */
member->prev = this->laststat;
if (this->laststat) {
this->laststat->next = member;
} else {
this->firststat = member;
}
this->laststat = member;
member->inuse = 0;
memset(&member->addr, 0, sizeof(member->addr));
member->peer = NULL;
member->nexthash = NULL;
if (0)
(void)ippool_printaddr(this);
return 0;
default: /* Should not happen */
SYS_ERR(DIP, LOGL_ERROR, 0,
"Could not free IP address");
return -1;
}
}

98
lib/ippool.h Normal file
View File

@ -0,0 +1,98 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _IPPOOL_H
#define _IPPOOL_H
#include "../lib/in46_addr.h"
#include "../gtp/gtp.h"
/* Assuming that the address space is fragmented we need a hash table
in order to return the addresses.
The list pool should provide for both IPv4 and IPv6 addresses.
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
*/
#define IPPOOL_NONETWORK 0x01
#define IPPOOL_NOBROADCAST 0x02
#define IPPOOL_NOGATEWAY 0x04
#define IPPOOL_STATSIZE 0x10000
struct ippoolm_t; /* Forward declaration */
struct ippool_t {
unsigned int listsize; /* Total number of addresses */
int allowdyn; /* Allow dynamic IP address allocation */
int allowstat; /* Allow static IP address allocation */
struct in46_addr stataddr; /* Static address range network address */
size_t stataddrprefixlen; /* IPv6 prefix length of stataddr */
struct ippoolm_t *member; /* Listsize array of members */
unsigned int hashsize; /* Size of hash table */
int hashlog; /* Log2 size of hash table */
int hashmask; /* Bitmask for calculating hash */
struct ippoolm_t **hash; /* Hashsize array of pointer to member */
struct ippoolm_t *firstdyn; /* Pointer to first free dynamic member */
struct ippoolm_t *lastdyn; /* Pointer to last free dynamic member */
struct ippoolm_t *firststat; /* Pointer to first free static member */
struct ippoolm_t *laststat; /* Pointer to last free static member */
};
struct ippoolm_t {
struct in46_addr addr; /* IP address of this member */
struct ippool_t *pool; /* Pool to which we belong */
int inuse; /* 0=available; 1= dynamic; 2 = static */
struct ippoolm_t *nexthash; /* Linked list part of hash table */
struct ippoolm_t *prev, *next; /* Linked list of free dynamic or static */
void *peer; /* Pointer to peer protocol handler */
};
/* The above structures require approximately 20+4 = 24 bytes for
each address (IPv4). For IPv6 the corresponding value is 32+4 = 36
bytes for each address. */
/* Hash an IP address using code based on Bob Jenkins lookupa */
extern unsigned long int ippool_hash(struct in46_addr *addr);
/* Create new address pool */
extern int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn,
const struct in46_prefix *stat, int flags);
/* Delete existing address pool */
extern int ippool_free(struct ippool_t *this);
/* Find an IP address in the pool */
extern int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in46_addr *addr);
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
extern int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in46_addr *addr, int statip);
/* Return a previously allocated IP address */
extern int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member);
/* Get net and mask based on ascii string */
int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool, int number);
/* Increase IPv4/IPv6 address by 1 */
extern void in46a_inc(struct in46_addr *addr);
#endif /* !_IPPOOL_H */

91
lib/lookup.c Executable file
View File

@ -0,0 +1,91 @@
/*
* Hash lookup function.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
/**
* lookup()
* Generates a 32 bit hash.
* Based on public domain code by Bob Jenkins
* It should be one of the best hash functions around in terms of both
* statistical properties and speed. It is NOT recommended for cryptographic
* purposes.
**/
unsigned long int lookup(k, length, level)
register unsigned char *k; /* the key */
register unsigned long int length; /* the length of the key */
register unsigned long int level; /* the previous hash, or an arbitrary value */
{
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
register unsigned long int a, b, c, len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12) {
a += (k[0] + ((ub4) k[1] << 8) + ((ub4) k[2] << 16) +
((ub4) k[3] << 24));
b += (k[4] + ((ub4) k[5] << 8) + ((ub4) k[6] << 16) +
((ub4) k[7] << 24));
c += (k[8] + ((ub4) k[9] << 8) + ((ub4) k[10] << 16) +
((ub4) k[11] << 24));
mix(a, b, c);
k += 12;
len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch (len) { /* all the case statements fall through */
case 11:
c += ((ub4) k[10] << 24);
case 10:
c += ((ub4) k[9] << 16);
case 9:
c += ((ub4) k[8] << 8);
/* the first byte of c is reserved for the length */
case 8:
b += ((ub4) k[7] << 24);
case 7:
b += ((ub4) k[6] << 16);
case 6:
b += ((ub4) k[5] << 8);
case 5:
b += k[4];
case 4:
a += ((ub4) k[3] << 24);
case 3:
a += ((ub4) k[2] << 16);
case 2:
a += ((ub4) k[1] << 8);
case 1:
a += k[0];
/* case 0: nothing left to add */
}
mix(a, b, c);
/*-------------------------------------------- report the result */
return c;
}

View File

@ -20,6 +20,7 @@
#ifndef _LOOKUP_H
#define _LOOKUP_H
unsigned long int lookup( unsigned char *k, unsigned long int length, unsigned long int level);
unsigned long int lookup(unsigned char *k, unsigned long int length,
unsigned long int level);
#endif /* !_LOOKUP_H */
#endif /* !_LOOKUP_H */

37
lib/syserr.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Syslog functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _SYSERR_H
#define _SYSERR_H
#include <osmocom/core/logging.h>
enum {
DIP,
DTUN,
DGGSN,
DSGSN,
DICMP6,
};
#define SYS_ERR(sub, pri, en, fmt, args...) \
if (en) { \
logp2(sub, pri, __FILE__, __LINE__, 0, \
"errno=%d/%s " fmt "\n", en, strerror(en), \
##args); \
} else { \
logp2(sub, pri, __FILE__, __LINE__, 0, \
fmt "\n", ##args); \
}
extern const struct log_info log_info;
#endif /* !_SYSERR_H */

748
lib/tun.c Normal file
View File

@ -0,0 +1,748 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003, 2004 Mondru AB.
* Copyright (C) 2017 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.
*
*/
/*
* tun.c: Contains all TUN functionality. Is able to handle multiple
* tunnels in the same program. Each tunnel is identified by the struct,
* which is passed to functions.
*
*/
#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/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#elif defined (__FreeBSD__)
#include <net/if_tun.h>
#include <net/if_var.h>
#include <netinet/in_var.h>
#elif defined (__APPLE__)
#include <net/if.h>
#else
#error "Unknown platform!"
#endif
#include "tun.h"
#include "syserr.h"
static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
#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;
}
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? */
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
memset(&areq, 0, sizeof(areq));
/* 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++;
return 0;
#endif
}
static int tun_setaddr4(struct tun_t *this, 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, 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;
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 */
this->dstaddr.s_addr = dstaddr->s_addr;
memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
dstaddr, sizeof(*dstaddr));
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
SYS_ERR(DTUN, LOGL_ERROR, errno,
"ioctl(SIOCSIFDSTADDR) failed");
close(fd);
return -1;
}
}
if (netmask) { /* Set the netmask */
this->netmask.s_addr = netmask->s_addr;
#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++;
/* 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__)
tun_addroute(this, dstaddr, addr, &this->netmask);
this->routes = 1;
#endif
return 0;
}
static int tun_setaddr6(struct tun_t *this, 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(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(&this->addr, addr, sizeof(*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 alreadsy 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)
memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
close(fd);
return -1;
}
#endif
close(fd);
this->addrs++;
/* 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;
#endif
return 0;
}
int tun_setaddr(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_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;
}
}
static int tun_route(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway, struct in_addr *mask, int delete)
{
#if defined(__linux__)
struct rtentry r;
int fd;
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;
}
}
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,
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)
{
#if defined(__linux__)
struct ifreq ifr;
#elif defined(__FreeBSD__) || defined (__APPLE__)
char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
int devnum;
struct ifaliasreq areq;
int fd;
#endif
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
return EOF;
}
(*tun)->cb_ind = NULL;
(*tun)->addrs = 0;
(*tun)->routes = 0;
#if defined(__linux__)
/* Open the actual tun device */
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
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));
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__)
/* Find suitable device */
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
break;
if (errno != EBUSY)
break;
}
if ((*tun)->fd < 0) {
SYS_ERR(DTUN, LOGL_ERROR, errno,
"Can't find tunnel device");
goto err_free;
}
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
(*tun)->devname[sizeof((*tun)->devname)-1] = 0;
/* The tun device we found might have "old" IP addresses allocated */
/* We need to delete those. This problem is not present on Linux */
memset(&areq, 0, sizeof(areq));
/* Set up interface name */
strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
areq.ifra_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");
goto err_close;
}
/* Delete any IP addresses until SIOCDIFADDR fails */
while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
close(fd);
return 0;
#endif
err_close:
close((*tun)->fd);
err_free:
free(*tun);
*tun = NULL;
return -1;
}
int tun_free(struct tun_t *tun)
{
if (tun->routes) {
tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
}
if (close(tun->fd)) {
SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
}
/* TODO: For solaris we need to unlink streams */
free(tun);
return 0;
}
int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
{
this->cb_ind = cb_ind;
return 0;
}
int tun_decaps(struct tun_t *this)
{
unsigned char buffer[PACKET_MAX];
int status;
if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, status);
return 0;
}
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
return write(tun->fd, pack, len);
}
int tun_runscript(struct tun_t *tun, char *script)
{
char buf[TUN_SCRIPTSIZE];
char snet[TUN_ADDRSIZE];
char smask[TUN_ADDRSIZE];
int rc;
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
snet[sizeof(snet) - 1] = 0;
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
smask[sizeof(smask) - 1] = 0;
/* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
script, tun->devname, snet, smask);
buf[sizeof(buf) - 1] = 0;
rc = system(buf);
if (rc == -1) {
SYS_ERR(DTUN, LOGL_ERROR, errno,
"Error executing command %s", buf);
return -1;
}
return 0;
}

88
lib/tun.h Normal file
View File

@ -0,0 +1,88 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
* Copyright (C) 2017 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.
*
*/
#ifndef _TUN_H
#define _TUN_H
#include <net/if.h>
#include "../lib/in46_addr.h"
#define PACKET_MAX 8196 /* Maximum packet size we receive */
#define TUN_SCRIPTSIZE 256
#define TUN_ADDRSIZE 128
#define TUN_NLBUFSIZE 1024
#include "config.h"
#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
*************************************************************/
struct tun_t {
int fd; /* File descriptor to tun interface */
struct in_addr addr;
struct in_addr dstaddr;
struct in_addr netmask;
int addrs; /* Number of allocated IP addresses */
int routes; /* One if we allocated an automatic route */
char devname[IFNAMSIZ]; /* Name of the tun device */
int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len);
/* to be used by libgtp callers/users (to attach their own private state) */
void *priv;
};
extern int tun_new(struct tun_t **tun);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
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,
int (*cb_ind) (struct tun_t * tun, void *pack,
unsigned len));
extern int tun_runscript(struct tun_t *tun, char *script);
#endif /* !_TUN_H */

11
libgtp.pc.in Normal file
View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenGGSN STP Library
Description: C Utility Library
Version: @VERSION@
Libs: -L${libdir} -lgtp
Cflags: -I${includedir}/

View File

@ -63,7 +63,7 @@ make clean
%dir /var/lib/ggsn
/var/lib/ggsn/gsn_restart
%doc AUTHORS ChangeLog COPYING INSTALL NEWS README
%doc AUTHORS COPYING INSTALL NEWS README.md
%doc examples/ggsn.conf
%doc examples/sgsnemu.conf
%doc examples/ggsn.init

View File

@ -2,10 +2,8 @@ bin_PROGRAMS = sgsnemu
AM_LDFLAGS = @EXEC_LDFLAGS@
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
sgsnemu_LDADD = @LIBOBJS@ @EXEC_LDADD@ -lgtp -L../gtp
#sgsnemu_DEPENDENCIES = ../gtp/libgtp.la
sgsnemu_SOURCES = sgsnemu.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c lookup.c lookup.h
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
sgsnemu_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
sgsnemu_SOURCES = sgsnemu.c cmdline.c cmdline.h

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,15 @@
# notice and this permission notice is included in all copies or
# substantial portions of the software.
#
# Use "gengetopt --conf-parser < cmdline.ggo"
# Use
# gengetopt --conf-parser < cmdline.ggo
# linux-2.6/scripts/Lindent cmdline.c
# linux-2.6/scripts/Lindent cmdline.h
# sed -i -e 's/int qose1_arg;/unsigned long long int qose1_arg;/' cmdline.h
# to generate cmdline.c and cmdline.h
package "sgsnemu"
option "debug" d "Run in debug mode" flag off
option "conf" c "Read configuration file" string no
@ -25,10 +31,20 @@ option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "gtpversion" - "GTP version to use" int default="1" no
option "apn" a "Access point name" string default="internet" no
option "selmode" - "Selection mode" int default="0x01" no
option "rattype" - "Radio Access Technology Type" int default="1" no typestr="1..5"
option "userloc" - "User Location Information" string default="02509946241207" no typestr="type.MCC.MNC.LAC.CIorSACorRAC"
option "rai" - "Routing Area Information" string default="02509946241207" no typestr="MCC.MNC.LAC.RAC"
option "mstz" - "MS Time Zone" string default="0" no typestr="sign.NbQuartersOfAnHour.DSTAdjustment"
option "imeisv" - "IMEI(SV) International Mobile Equipment Identity (and Software Version)" string default="2143658709214365" no
option "norecovery" - "Do not send recovery" flag off
option "imsi" i "IMSI" string default="240010123456789" no
option "nsapi" - "NSAPI" int default="0" no
option "msisdn" m "Mobile Station ISDN number" string default="46702123456" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "qos" q "Requested quality of service" int default="0x000b921f" no
option "qose1" - "Requested quality of service Extension 1" int default="0x9396404074f9ffff" no
option "qose2" - "Requested quality of service Extension 2" int default="0x11" no
option "qose3" - "Requested quality of service Extension 3" int default="0x0101" no
option "qose4" - "Requested quality of service Extension 4" int default="0x4040" no
option "charging" - "Charging characteristics" int default="0x0800" no
option "uid" u "Login user ID" string default="mig" no
option "pwd" p "Login password" string default="hemmelig" no
@ -40,8 +56,8 @@ option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no
option "pinghost" - "Ping remote host" string no
option "pingrate" - "Number of ping req per second" unsigned int default="1" no
option "pingsize" - "Number of ping data bytes" unsigned int default="56" no
option "pingcount" - "Number of ping req to send" unsigned int default="0" no
option "pingrate" - "Number of ping req per second" int default="1" no
option "pingsize" - "Number of ping data bytes" int default="56" no
option "pingcount" - "Number of ping req to send" int default="0" no
option "pingquiet" - "Do not print ping packet info" flag off

View File

@ -1,6 +1,9 @@
/* cmdline.h */
/* File autogenerated by gengetopt version 2.17 */
/** @file cmdline.h
* @brief The header file for the command line option parser
* generated by GNU Gengetopt version 2.22.6
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
#ifndef CMDLINE_H
#define CMDLINE_H
@ -10,167 +13,495 @@
#include "config.h"
#endif
#include <stdio.h> /* for FILE */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#ifndef CMDLINE_PARSER_PACKAGE
#define CMDLINE_PARSER_PACKAGE PACKAGE
/** @brief the program name (used for printing errors) */
#define CMDLINE_PARSER_PACKAGE "sgsnemu"
#endif
#ifndef CMDLINE_PARSER_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
#define CMDLINE_PARSER_PACKAGE_NAME "sgsnemu"
#endif
#ifndef CMDLINE_PARSER_VERSION
/** @brief the program version */
#define CMDLINE_PARSER_VERSION VERSION
#endif
struct gengetopt_args_info
{
const char *help_help; /* Print help and exit help description. */
const char *version_help; /* Print version and exit help description. */
int debug_flag; /* Run in debug mode (default=off). */
const char *debug_help; /* Run in debug mode help description. */
char * conf_arg; /* Read configuration file. */
char * conf_orig; /* Read configuration file original value given at command line. */
const char *conf_help; /* Read configuration file help description. */
char * pidfile_arg; /* Filename of process id file (default='./sgsnemu.pid'). */
char * pidfile_orig; /* Filename of process id file original value given at command line. */
const char *pidfile_help; /* Filename of process id file help description. */
char * statedir_arg; /* Directory of nonvolatile data (default='./'). */
char * statedir_orig; /* Directory of nonvolatile data original value given at command line. */
const char *statedir_help; /* Directory of nonvolatile data help description. */
char * dns_arg; /* DNS Server to use. */
char * dns_orig; /* DNS Server to use original value given at command line. */
const char *dns_help; /* DNS Server to use help description. */
char * listen_arg; /* Local interface. */
char * listen_orig; /* Local interface original value given at command line. */
const char *listen_help; /* Local interface help description. */
char * remote_arg; /* Remote host. */
char * remote_orig; /* Remote host original value given at command line. */
const char *remote_help; /* Remote host help description. */
int contexts_arg; /* Number of contexts (default='1'). */
char * contexts_orig; /* Number of contexts original value given at command line. */
const char *contexts_help; /* Number of contexts help description. */
int timelimit_arg; /* Exit after timelimit seconds (default='0'). */
char * timelimit_orig; /* Exit after timelimit seconds original value given at command line. */
const char *timelimit_help; /* Exit after timelimit seconds help description. */
int gtpversion_arg; /* GTP version to use (default='1'). */
char * gtpversion_orig; /* GTP version to use original value given at command line. */
const char *gtpversion_help; /* GTP version to use help description. */
char * apn_arg; /* Access point name (default='internet'). */
char * apn_orig; /* Access point name original value given at command line. */
const char *apn_help; /* Access point name help description. */
int selmode_arg; /* Selection mode (default='0x01'). */
char * selmode_orig; /* Selection mode original value given at command line. */
const char *selmode_help; /* Selection mode help description. */
char * imsi_arg; /* IMSI (default='240010123456789'). */
char * imsi_orig; /* IMSI original value given at command line. */
const char *imsi_help; /* IMSI help description. */
int nsapi_arg; /* NSAPI (default='0'). */
char * nsapi_orig; /* NSAPI original value given at command line. */
const char *nsapi_help; /* NSAPI help description. */
char * msisdn_arg; /* Mobile Station ISDN number (default='46702123456'). */
char * msisdn_orig; /* Mobile Station ISDN number original value given at command line. */
const char *msisdn_help; /* Mobile Station ISDN number help description. */
int qos_arg; /* Requested quality of service (default='0x0b921f'). */
char * qos_orig; /* Requested quality of service original value given at command line. */
const char *qos_help; /* Requested quality of service help description. */
int charging_arg; /* Charging characteristics (default='0x0800'). */
char * charging_orig; /* Charging characteristics original value given at command line. */
const char *charging_help; /* Charging characteristics help description. */
char * uid_arg; /* Login user ID (default='mig'). */
char * uid_orig; /* Login user ID original value given at command line. */
const char *uid_help; /* Login user ID help description. */
char * pwd_arg; /* Login password (default='hemmelig'). */
char * pwd_orig; /* Login password original value given at command line. */
const char *pwd_help; /* Login password help description. */
int createif_flag; /* Create local network interface (default=off). */
const char *createif_help; /* Create local network interface help description. */
char * net_arg; /* Network address for local interface. */
char * net_orig; /* Network address for local interface original value given at command line. */
const char *net_help; /* Network address for local interface help description. */
int defaultroute_flag; /* Create default route (default=off). */
const char *defaultroute_help; /* Create default route help description. */
char * ipup_arg; /* Script to run after link-up. */
char * ipup_orig; /* Script to run after link-up original value given at command line. */
const char *ipup_help; /* Script to run after link-up help description. */
char * ipdown_arg; /* Script to run after link-down. */
char * ipdown_orig; /* Script to run after link-down original value given at command line. */
const char *ipdown_help; /* Script to run after link-down help description. */
char * pinghost_arg; /* Ping remote host. */
char * pinghost_orig; /* Ping remote host original value given at command line. */
const char *pinghost_help; /* Ping remote host help description. */
int pingrate_arg; /* Number of ping req per second (default='1'). */
char * pingrate_orig; /* Number of ping req per second original value given at command line. */
const char *pingrate_help; /* Number of ping req per second help description. */
int pingsize_arg; /* Number of ping data bytes (default='56'). */
char * pingsize_orig; /* Number of ping data bytes original value given at command line. */
const char *pingsize_help; /* Number of ping data bytes help description. */
int pingcount_arg; /* Number of ping req to send (default='0'). */
char * pingcount_orig; /* Number of ping req to send original value given at command line. */
const char *pingcount_help; /* Number of ping req to send help description. */
int pingquiet_flag; /* Do not print ping packet info (default=off). */
const char *pingquiet_help; /* Do not print ping packet info help description. */
int help_given ; /* Whether help was given. */
int version_given ; /* Whether version was given. */
int debug_given ; /* Whether debug was given. */
int conf_given ; /* Whether conf was given. */
int pidfile_given ; /* Whether pidfile was given. */
int statedir_given ; /* Whether statedir was given. */
int dns_given ; /* Whether dns was given. */
int listen_given ; /* Whether listen was given. */
int remote_given ; /* Whether remote was given. */
int contexts_given ; /* Whether contexts was given. */
int timelimit_given ; /* Whether timelimit was given. */
int gtpversion_given ; /* Whether gtpversion was given. */
int apn_given ; /* Whether apn was given. */
int selmode_given ; /* Whether selmode was given. */
int imsi_given ; /* Whether imsi was given. */
int nsapi_given ; /* Whether nsapi was given. */
int msisdn_given ; /* Whether msisdn was given. */
int qos_given ; /* Whether qos was given. */
int charging_given ; /* Whether charging was given. */
int uid_given ; /* Whether uid was given. */
int pwd_given ; /* Whether pwd was given. */
int createif_given ; /* Whether createif was given. */
int net_given ; /* Whether net was given. */
int defaultroute_given ; /* Whether defaultroute was given. */
int ipup_given ; /* Whether ipup was given. */
int ipdown_given ; /* Whether ipdown was given. */
int pinghost_given ; /* Whether pinghost was given. */
int pingrate_given ; /* Whether pingrate was given. */
int pingsize_given ; /* Whether pingsize was given. */
int pingcount_given ; /* Whether pingcount was given. */
int pingquiet_given ; /* Whether pingquiet was given. */
/** @brief Where the command line options are stored */
struct gengetopt_args_info {
const char *help_help;
/**< @brief Print help and exit help description. */
const char *version_help;
/**< @brief Print version and exit help description. */
int debug_flag;
/**< @brief Run in debug mode (default=off). */
const char *debug_help;
/**< @brief Run in debug mode help description. */
char *conf_arg;
/**< @brief Read configuration file. */
char *conf_orig;
/**< @brief Read configuration file original value given at command line. */
const char *conf_help;
/**< @brief Read configuration file help description. */
char *pidfile_arg;
/**< @brief Filename of process id file (default='./sgsnemu.pid'). */
char *pidfile_orig;
/**< @brief Filename of process id file original value given at command line. */
const char *pidfile_help;
/**< @brief Filename of process id file help description. */
char *statedir_arg;
/**< @brief Directory of nonvolatile data (default='./'). */
char *statedir_orig;
/**< @brief Directory of nonvolatile data original value given at command line. */
const char *statedir_help;
/**< @brief Directory of nonvolatile data help description. */
char *dns_arg;
/**< @brief DNS Server to use. */
char *dns_orig;
/**< @brief DNS Server to use original value given at command line. */
const char *dns_help;
/**< @brief DNS Server to use help description. */
char *listen_arg;
/**< @brief Local interface. */
char *listen_orig;
/**< @brief Local interface original value given at command line. */
const char *listen_help;
/**< @brief Local interface help description. */
char *remote_arg;
/**< @brief Remote host. */
char *remote_orig;
/**< @brief Remote host original value given at command line. */
const char *remote_help;
/**< @brief Remote host help description. */
int contexts_arg;
/**< @brief Number of contexts (default='1'). */
char *contexts_orig;
/**< @brief Number of contexts original value given at command line. */
const char *contexts_help;
/**< @brief Number of contexts help description. */
int timelimit_arg;
/**< @brief Exit after timelimit seconds (default='0'). */
char *timelimit_orig;
/**< @brief Exit after timelimit seconds original value given at command line. */
const char *timelimit_help;
/**< @brief Exit after timelimit seconds help description. */
int gtpversion_arg;
/**< @brief GTP version to use (default='1'). */
char *gtpversion_orig;
/**< @brief GTP version to use original value given at command line. */
const char *gtpversion_help;
/**< @brief GTP version to use help description. */
char *apn_arg;
/**< @brief Access point name (default='internet'). */
char *apn_orig;
/**< @brief Access point name original value given at command line. */
const char *apn_help;
/**< @brief Access point name help description. */
int selmode_arg;
/**< @brief Selection mode (default='0x01'). */
char *selmode_orig;
/**< @brief Selection mode original value given at command line. */
const char *selmode_help;
/**< @brief Selection mode help description. */
int rattype_arg;
/**< @brief Radio Access Technology Type (default='1'). */
char *rattype_orig;
/**< @brief Radio Access Technology Type original value given at command line. */
const char *rattype_help;
/**< @brief Radio Access Technology Type help description. */
char *userloc_arg;
/**< @brief User Location Information (default='02509946241207'). */
char *userloc_orig;
/**< @brief User Location Information original value given at command line. */
const char *userloc_help;
/**< @brief User Location Information help description. */
char *rai_arg;
/**< @brief Routing Area Information (default='02509946241207'). */
char *rai_orig;
/**< @brief Routing Area Information original value given at command line. */
const char *rai_help;
/**< @brief Routing Area Information help description. */
char *mstz_arg;
/**< @brief MS Time Zone (default='0'). */
char *mstz_orig;
/**< @brief MS Time Zone original value given at command line. */
const char *mstz_help;
/**< @brief MS Time Zone help description. */
char *imeisv_arg;
/**< @brief IMEI(SV) International Mobile Equipment Identity (and Software Version) (default='2143658709214365'). */
char *imeisv_orig;
/**< @brief IMEI(SV) International Mobile Equipment Identity (and Software Version) original value given at command line. */
const char *imeisv_help;
/**< @brief IMEI(SV) International Mobile Equipment Identity (and Software Version) help description. */
int norecovery_flag;
/**< @brief Do not send recovery (default=off). */
const char *norecovery_help;
/**< @brief Do not send recovery help description. */
char *imsi_arg;
/**< @brief IMSI (default='240010123456789'). */
char *imsi_orig;
/**< @brief IMSI original value given at command line. */
const char *imsi_help;
/**< @brief IMSI help description. */
int nsapi_arg;
/**< @brief NSAPI (default='0'). */
char *nsapi_orig;
/**< @brief NSAPI original value given at command line. */
const char *nsapi_help;
/**< @brief NSAPI help description. */
char *msisdn_arg;
/**< @brief Mobile Station ISDN number (default='46702123456'). */
char *msisdn_orig;
/**< @brief Mobile Station ISDN number original value given at command line. */
const char *msisdn_help;
/**< @brief Mobile Station ISDN number help description. */
int qos_arg;
/**< @brief Requested quality of service (default='0x000b921f'). */
char *qos_orig;
/**< @brief Requested quality of service original value given at command line. */
const char *qos_help;
/**< @brief Requested quality of service help description. */
unsigned long long int qose1_arg;
/**< @brief Requested quality of service Extension 1 (default='0x9396404074f9ffff'). */
char *qose1_orig;
/**< @brief Requested quality of service Extension 1 original value given at command line. */
const char *qose1_help;
/**< @brief Requested quality of service Extension 1 help description. */
int qose2_arg;
/**< @brief Requested quality of service Extension 2 (default='0x11'). */
char *qose2_orig;
/**< @brief Requested quality of service Extension 2 original value given at command line. */
const char *qose2_help;
/**< @brief Requested quality of service Extension 2 help description. */
int qose3_arg;
/**< @brief Requested quality of service Extension 3 (default='0x0101'). */
char *qose3_orig;
/**< @brief Requested quality of service Extension 3 original value given at command line. */
const char *qose3_help;
/**< @brief Requested quality of service Extension 3 help description. */
int qose4_arg;
/**< @brief Requested quality of service Extension 4 (default='0x4040'). */
char *qose4_orig;
/**< @brief Requested quality of service Extension 4 original value given at command line. */
const char *qose4_help;
/**< @brief Requested quality of service Extension 4 help description. */
int charging_arg;
/**< @brief Charging characteristics (default='0x0800'). */
char *charging_orig;
/**< @brief Charging characteristics original value given at command line. */
const char *charging_help;
/**< @brief Charging characteristics help description. */
char *uid_arg;
/**< @brief Login user ID (default='mig'). */
char *uid_orig;
/**< @brief Login user ID original value given at command line. */
const char *uid_help;
/**< @brief Login user ID help description. */
char *pwd_arg;
/**< @brief Login password (default='hemmelig'). */
char *pwd_orig;
/**< @brief Login password original value given at command line. */
const char *pwd_help;
/**< @brief Login password help description. */
int createif_flag;
/**< @brief Create local network interface (default=off). */
const char *createif_help;
/**< @brief Create local network interface help description. */
char *net_arg;
/**< @brief Network address for local interface. */
char *net_orig;
/**< @brief Network address for local interface original value given at command line. */
const char *net_help;
/**< @brief Network address for local interface help description. */
int defaultroute_flag;
/**< @brief Create default route (default=off). */
const char *defaultroute_help;
/**< @brief Create default route help description. */
char *ipup_arg;
/**< @brief Script to run after link-up. */
char *ipup_orig;
/**< @brief Script to run after link-up original value given at command line. */
const char *ipup_help;
/**< @brief Script to run after link-up help description. */
char *ipdown_arg;
/**< @brief Script to run after link-down. */
char *ipdown_orig;
/**< @brief Script to run after link-down original value given at command line. */
const char *ipdown_help;
/**< @brief Script to run after link-down help description. */
char *pinghost_arg;
/**< @brief Ping remote host. */
char *pinghost_orig;
/**< @brief Ping remote host original value given at command line. */
const char *pinghost_help;
/**< @brief Ping remote host help description. */
int pingrate_arg;
/**< @brief Number of ping req per second (default='1'). */
char *pingrate_orig;
/**< @brief Number of ping req per second original value given at command line. */
const char *pingrate_help;
/**< @brief Number of ping req per second help description. */
int pingsize_arg;
/**< @brief Number of ping data bytes (default='56'). */
char *pingsize_orig;
/**< @brief Number of ping data bytes original value given at command line. */
const char *pingsize_help;
/**< @brief Number of ping data bytes help description. */
int pingcount_arg;
/**< @brief Number of ping req to send (default='0'). */
char *pingcount_orig;
/**< @brief Number of ping req to send original value given at command line. */
const char *pingcount_help;
/**< @brief Number of ping req to send help description. */
int pingquiet_flag;
/**< @brief Do not print ping packet info (default=off). */
const char *pingquiet_help;
/**< @brief Do not print ping packet info help description. */
} ;
unsigned int help_given;
/**< @brief Whether help was given. */
unsigned int version_given;
/**< @brief Whether version was given. */
unsigned int debug_given;
/**< @brief Whether debug was given. */
unsigned int conf_given;
/**< @brief Whether conf was given. */
unsigned int pidfile_given;
/**< @brief Whether pidfile was given. */
unsigned int statedir_given;
/**< @brief Whether statedir was given. */
unsigned int dns_given;
/**< @brief Whether dns was given. */
unsigned int listen_given;
/**< @brief Whether listen was given. */
unsigned int remote_given;
/**< @brief Whether remote was given. */
unsigned int contexts_given;
/**< @brief Whether contexts was given. */
unsigned int timelimit_given;
/**< @brief Whether timelimit was given. */
unsigned int gtpversion_given;
/**< @brief Whether gtpversion was given. */
unsigned int apn_given;
/**< @brief Whether apn was given. */
unsigned int selmode_given;
/**< @brief Whether selmode was given. */
unsigned int rattype_given;
/**< @brief Whether rattype was given. */
unsigned int userloc_given;
/**< @brief Whether userloc was given. */
unsigned int rai_given;
/**< @brief Whether rai was given. */
unsigned int mstz_given;
/**< @brief Whether mstz was given. */
unsigned int imeisv_given;
/**< @brief Whether imeisv was given. */
unsigned int norecovery_given;
/**< @brief Whether norecovery was given. */
unsigned int imsi_given;
/**< @brief Whether imsi was given. */
unsigned int nsapi_given;
/**< @brief Whether nsapi was given. */
unsigned int msisdn_given;
/**< @brief Whether msisdn was given. */
unsigned int qos_given;
/**< @brief Whether qos was given. */
unsigned int qose1_given;
/**< @brief Whether qose1 was given. */
unsigned int qose2_given;
/**< @brief Whether qose2 was given. */
unsigned int qose3_given;
/**< @brief Whether qose3 was given. */
unsigned int qose4_given;
/**< @brief Whether qose4 was given. */
unsigned int charging_given;
/**< @brief Whether charging was given. */
unsigned int uid_given;
/**< @brief Whether uid was given. */
unsigned int pwd_given;
/**< @brief Whether pwd was given. */
unsigned int createif_given;
/**< @brief Whether createif was given. */
unsigned int net_given;
/**< @brief Whether net was given. */
unsigned int defaultroute_given;
/**< @brief Whether defaultroute was given. */
unsigned int ipup_given;
/**< @brief Whether ipup was given. */
unsigned int ipdown_given;
/**< @brief Whether ipdown was given. */
unsigned int pinghost_given;
/**< @brief Whether pinghost was given. */
unsigned int pingrate_given;
/**< @brief Whether pingrate was given. */
unsigned int pingsize_given;
/**< @brief Whether pingsize was given. */
unsigned int pingcount_given;
/**< @brief Whether pingcount was given. */
unsigned int pingquiet_given;
/**< @brief Whether pingquiet was given. */
extern const char *gengetopt_args_info_purpose;
extern const char *gengetopt_args_info_usage;
extern const char *gengetopt_args_info_help[];
};
int cmdline_parser (int argc, char * const *argv,
struct gengetopt_args_info *args_info);
int cmdline_parser2 (int argc, char * const *argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/** @brief The additional parameters to pass to parser functions */
struct cmdline_parser_params {
int override;
/**< @brief whether to override possibly already present options (default 0) */
int initialize;
/**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
int check_required;
/**< @brief whether to check that all required options were provided (default 1) */
int check_ambiguity;
/**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
int print_errors;
/**< @brief whether getopt_long should print an error message for a bad option (default 1) */
};
void cmdline_parser_print_help(void);
void cmdline_parser_print_version(void);
/** @brief the purpose string of the program */
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
/** @brief the description string of the program */
extern const char *gengetopt_args_info_description;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
void cmdline_parser_init (struct gengetopt_args_info *args_info);
void cmdline_parser_free (struct gengetopt_args_info *args_info);
/**
* The command line parser
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser(int argc, char **argv,
struct gengetopt_args_info *args_info);
int cmdline_parser_configfile (char * const filename,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The command line parser (version with additional parameters - deprecated)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_ext() instead
*/
int cmdline_parser2(int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
int cmdline_parser_required (struct gengetopt_args_info *args_info,
const char *prog_name);
/**
* The command line parser (version with additional parameters)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_ext(int argc, char **argv,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
* @param outfile the stream where to dump options
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_dump(FILE * outfile,
struct gengetopt_args_info *args_info);
/**
* Save the contents of the option struct into a (text) file.
* This file can be read by the config file parser (if generated by gengetopt)
* @param filename the file where to save
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
void cmdline_parser_print_help(void);
/**
* Print the version
*/
void cmdline_parser_print_version(void);
/**
* Initializes all the fields a cmdline_parser_params structure
* to their default values
* @param params the structure to initialize
*/
void cmdline_parser_params_init(struct cmdline_parser_params *params);
/**
* Allocates dynamically a cmdline_parser_params structure and initializes
* all its fields to their default values
* @return the created and initialized cmdline_parser_params structure
*/
struct cmdline_parser_params *cmdline_parser_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
void cmdline_parser_init(struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
void cmdline_parser_free(struct gengetopt_args_info *args_info);
/**
* The config file parser (deprecated version)
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_config_file() instead
*/
int cmdline_parser_configfile(const char *filename,
struct gengetopt_args_info *args_info,
int override, int initialize,
int check_required);
/**
* The config file parser
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_config_file(const char *filename,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Checks that all the required options were specified
* @param args_info the structure to check
* @param prog_name the name of the program that will be used to print
* possible errors
* @return
*/
int cmdline_parser_required(struct gengetopt_args_info *args_info,
const char *prog_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CMDLINE_H */
#endif /* __cplusplus */
#endif /* CMDLINE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,526 +0,0 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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 <sys/types.h>
#include <netinet/in.h> /* in_addr */
#include <stdlib.h> /* calloc */
#include <stdio.h> /* sscanf */
#include <syslog.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "syserr.h"
#include "ippool.h"
#include "lookup.h"
int ippool_printaddr(struct ippool_t *this) {
unsigned int n;
printf("ippool_printaddr\n");
printf("Firstdyn %d\n", this->firstdyn - this->member);
printf("Lastdyn %d\n", this->lastdyn - this->member);
printf("Firststat %d\n", this->firststat - this->member);
printf("Laststat %d\n", this->laststat - this->member);
printf("Listsize %d\n", this->listsize);
for (n=0; n<this->listsize; n++) {
printf("Unit %d inuse %d prev %d next %d addr %s %x\n",
n,
this->member[n].inuse,
this->member[n].prev - this->member,
this->member[n].next - this->member,
inet_ntoa(this->member[n].addr),
this->member[n].addr.s_addr
);
}
return 0;
}
int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member) {
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Insert into hash table */
hash = ippool_hash4(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash)
p_prev = p;
if (!p_prev)
this->hash[hash] = member;
else
p_prev->nexthash = member;
return 0; /* Always OK to insert */
}
int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member) {
uint32_t hash;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
/* Find in hash table */
hash = ippool_hash4(&member->addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if (p == member) {
break;
}
p_prev = p;
}
if (p!= member) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"ippool_hashdel: Tried to delete member not in hash table");
return -1;
}
if (!p_prev)
this->hash[hash] = p->nexthash;
else
p_prev->nexthash = p->nexthash;
return 0;
}
unsigned long int ippool_hash4(struct in_addr *addr) {
return lookup((unsigned char*) &addr->s_addr, sizeof(addr->s_addr), 0);
}
#ifndef IPPOOL_NOIP6
unsigned long int ippool_hash6(struct in6_addr *addr) {
return lookup((unsigned char*) addr->u6_addr8, sizeof(addr->u6_addr8), 0);
}
#endif
/* Get IP address and mask */
int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number) {
/* Parse only first instance of network for now */
/* Eventually "number" will indicate the token which we want to parse */
unsigned int a1, a2, a3, a4;
unsigned int m1, m2, m3, m4;
int c;
int m;
int masklog;
c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u",
&a1, &a2, &a3, &a4,
&m1, &m2, &m3, &m4);
switch (c) {
case 4:
mask->s_addr = 0xffffffff;
break;
case 5:
if (m1 > 32) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Invalid mask */
}
mask->s_addr = htonl(0xffffffff << (32 - m1));
break;
case 8:
if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Wrong mask format */
}
m = m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4;
for (masklog = 0; ((1 << masklog) < ((~m)+1)); masklog++);
if (((~m)+1) != (1 << masklog)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Wrong mask format (not all ones followed by all zeros)*/
}
mask->s_addr = htonl(m);
break;
default:
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask");
return -1; /* Invalid mask */
}
if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Wrong IP address format");
return -1;
}
else
addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
return 0;
}
/* Create new address pool */
int ippool_new(struct ippool_t **this, char *dyn, char *stat,
int allowdyn, int allowstat, int flags) {
/* Parse only first instance of pool for now */
int i;
struct in_addr addr;
struct in_addr mask;
struct in_addr stataddr;
struct in_addr statmask;
unsigned int m;
int listsize;
int dynsize;
unsigned int statsize;
if (!allowdyn) {
dynsize = 0;
}
else {
if (ippool_aton(&addr, &mask, dyn, 0)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to parse dynamic pool");
return -1;
}
/* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */
if (flags & IPPOOL_NOGATEWAY) {
flags |= IPPOOL_NONETWORK;
}
m = ntohl(mask.s_addr);
dynsize = ((~m)+1);
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
dynsize--;
if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */
dynsize--;
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
dynsize--;
}
if (!allowstat) {
statsize = 0;
stataddr.s_addr = 0;
statmask.s_addr = 0;
}
else {
if (ippool_aton(&stataddr, &statmask, stat, 0)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to parse static range");
return -1;
}
m = ntohl(statmask.s_addr);
statsize = ((~m)+1);
if (statsize > IPPOOL_STATSIZE) statsize = IPPOOL_STATSIZE;
}
listsize = dynsize + statsize; /* Allocate space for static IP addresses */
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for ippool");
return -1;
}
(*this)->allowdyn = allowdyn;
(*this)->allowstat = allowstat;
(*this)->stataddr = stataddr;
(*this)->statmask = statmask;
(*this)->listsize += listsize;
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))){
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for members in ippool");
return -1;
}
for ((*this)->hashlog = 0;
((1 << (*this)->hashlog) < listsize);
(*this)->hashlog++);
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
/* Determine hashsize */
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
(*this)->hashmask = (*this)->hashsize -1;
/* Allocate hash table */
if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate memory for hash members in ippool");
return -1;
}
(*this)->firstdyn = NULL;
(*this)->lastdyn = NULL;
for (i = 0; i<dynsize; i++) {
if (flags & IPPOOL_NOGATEWAY)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 2);
else if (flags & IPPOOL_NONETWORK)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 1);
else
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i);
(*this)->member[i].inuse = 0;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->lastdyn;
if ((*this)->lastdyn) {
(*this)->lastdyn->next = &((*this)->member[i]);
}
else {
(*this)->firstdyn = &((*this)->member[i]);
}
(*this)->lastdyn = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
( void)ippool_hashadd(*this, &(*this)->member[i]);
}
(*this)->firststat = NULL;
(*this)->laststat = NULL;
for (i = dynsize; i<listsize; i++) {
(*this)->member[i].addr.s_addr = 0;
(*this)->member[i].inuse = 0;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->laststat;
if ((*this)->laststat) {
(*this)->laststat->next = &((*this)->member[i]);
}
else {
(*this)->firststat = &((*this)->member[i]);
}
(*this)->laststat = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
}
if (0) (void)ippool_printaddr(*this);
return 0;
}
/* Delete existing address pool */
int ippool_free(struct ippool_t *this) {
free(this->hash);
free(this->member);
free(this);
return 0; /* Always OK */
}
/* Find an IP address in the pool */
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
uint32_t hash;
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
if (member) *member = p;
return 0;
}
}
if (member) *member = NULL;
/*sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address could not be found");*/
return -1;
}
/**
* ippool_newip
* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
* check to see if the given address is available. If available within
* dynamic address space allocate it there, otherwise allocate within static
* address space.
**/
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr, int statip) {
struct ippoolm_t *p;
struct ippoolm_t *p2 = NULL;
uint32_t hash;
/* If static:
* Look in dynaddr.
* If found remove from firstdyn/lastdyn linked list.
* Else allocate from stataddr.
* Remove from firststat/laststat linked list.
* Insert into hash table.
*
* If dynamic
* Remove from firstdyn/lastdyn linked list.
*
*/
if (0) (void)ippool_printaddr(this);
/* First check to see if this type of address is allowed */
if ((addr) && (addr->s_addr) && statip) { /* IP address given */
if (!this->allowstat) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static IP address not allowed");
return -1;
}
if ((addr->s_addr & this->statmask.s_addr) != this->stataddr.s_addr) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static out of range");
return -1;
}
}
else {
if (!this->allowdyn) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Dynamic IP address not allowed");
return -1;
}
}
/* If IP address given try to find it in dynamic address pool */
if ((addr) && (addr->s_addr)) { /* IP address given */
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr)) {
p2 = p;
break;
}
}
}
/* If IP was already allocated we can not use it */
if ((!statip) && (p2) && (p2->inuse)) {
p2 = NULL;
}
/* If not found yet and dynamic IP then allocate dynamic IP */
if ((!p2) && (!statip)) {
if (!this ->firstdyn) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"No more IP addresses available");
return -1;
}
else
p2 = this ->firstdyn;
}
if (p2) { /* Was allocated from dynamic address pool */
if (p2->inuse) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"IP address allready in use");
return -1; /* Allready in use / Should not happen */
}
/* Remove from linked list of free dynamic addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firstdyn = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->lastdyn = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 1; /* Dynamic address in use */
*member = p2;
if (0) (void)ippool_printaddr(this);
return 0; /* Success */
}
/* It was not possible to allocate from dynamic address pool */
/* Try to allocate from static address space */
if ((addr) && (addr->s_addr) && (statip)) { /* IP address given */
if (!this->firststat) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"No more IP addresses available");
return -1; /* No more available */
}
else
p2 = this ->firststat;
/* Remove from linked list of free static addresses */
if (p2->prev)
p2->prev->next = p2->next;
else
this->firststat = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->laststat = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 2; /* Static address in use */
memcpy(&p2->addr, addr, sizeof(addr));
*member = p2;
(void)ippool_hashadd(this, *member);
if (0) (void)ippool_printaddr(this);
return 0; /* Success */
}
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Could not allocate IP address");
return -1; /* Should never get here. TODO: Bad code */
}
int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member) {
if (0) (void)ippool_printaddr(this);
if (!member->inuse) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use");
return -1; /* Not in use: Should not happen */
}
switch (member->inuse) {
case 0: /* Not in use: Should not happen */
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use");
return -1;
case 1: /* Allocated from dynamic address space */
/* Insert into list of unused */
member->prev = this->lastdyn;
if (this->lastdyn) {
this->lastdyn->next = member;
}
else {
this->firstdyn = member;
}
this->lastdyn = member;
member->inuse = 0;
member->peer = NULL;
if (0) (void)ippool_printaddr(this);
return 0;
case 2: /* Allocated from static address space */
if (ippool_hashdel(this, member))
return -1;
/* Insert into list of unused */
member->prev = this->laststat;
if (this->laststat) {
this->laststat->next = member;
}
else {
this->firststat = member;
}
this->laststat = member;
member->inuse = 0;
member->addr.s_addr = 0;
member->peer = NULL;
member->nexthash = NULL;
if (0) (void)ippool_printaddr(this);
return 0;
default: /* Should not happen */
sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Could not free IP address");
return -1;
}
}
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif

View File

@ -1,105 +0,0 @@
/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _IPPOOL_H
#define _IPPOOL_H
/* Assuming that the address space is fragmented we need a hash table
in order to return the addresses.
The list pool should provide for both IPv4 and IPv6 addresses.
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
*/
#define IPPOOL_NOIP6
#define IPPOOL_NONETWORK 0x01
#define IPPOOL_NOBROADCAST 0x02
#define IPPOOL_NOGATEWAY 0x04
#define IPPOOL_STATSIZE 0x10000
struct ippoolm_t; /* Forward declaration */
struct ippool_t {
unsigned int listsize; /* Total number of addresses */
int allowdyn; /* Allow dynamic IP address allocation */
int allowstat; /* Allow static IP address allocation */
struct in_addr stataddr; /* Static address range network address */
struct in_addr statmask; /* Static address range network mask */
struct ippoolm_t *member; /* Listsize array of members */
unsigned int hashsize; /* Size of hash table */
int hashlog; /* Log2 size of hash table */
int hashmask; /* Bitmask for calculating hash */
struct ippoolm_t **hash; /* Hashsize array of pointer to member */
struct ippoolm_t *firstdyn; /* Pointer to first free dynamic member */
struct ippoolm_t *lastdyn; /* Pointer to last free dynamic member */
struct ippoolm_t *firststat; /* Pointer to first free static member */
struct ippoolm_t *laststat; /* Pointer to last free static member */
};
struct ippoolm_t {
#ifndef IPPOOL_NOIP6
struct in6_addr addr; /* IP address of this member */
#else
struct in_addr addr; /* IP address of this member */
#endif
int inuse; /* 0=available; 1= dynamic; 2 = static */
struct ippoolm_t *nexthash; /* Linked list part of hash table */
struct ippoolm_t *prev, *next; /* Linked list of free dynamic or static */
void *peer; /* Pointer to peer protocol handler */
};
/* The above structures require approximately 20+4 = 24 bytes for
each address (IPv4). For IPv6 the corresponding value is 32+4 = 36
bytes for each address. */
/* Hash an IP address using code based on Bob Jenkins lookupa */
extern unsigned long int ippool_hash4(struct in_addr *addr);
/* Create new address pool */
extern int ippool_new(struct ippool_t **this, char *dyn, char *stat,
int allowdyn, int allowstat, int flags);
/* Delete existing address pool */
extern int ippool_free(struct ippool_t *this);
/* Find an IP address in the pool */
extern int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
extern int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr, int statip);
/* Return a previously allocated IP address */
extern int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member);
/* Get net and mask based on ascii string */
extern int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number);
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif
#endif /* !_IPPOOL_H */

View File

@ -1,80 +0,0 @@
/*
* Hash lookup function.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
/**
* lookup()
* Generates a 32 bit hash.
* Based on public domain code by Bob Jenkins
* It should be one of the best hash functions around in terms of both
* statistical properties and speed. It is NOT recommended for cryptographic
* purposes.
**/
unsigned long int lookup( k, length, level)
register unsigned char *k; /* the key */
register unsigned long int length; /* the length of the key */
register unsigned long int level; /* the previous hash, or an arbitrary value*/
{
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
register unsigned long int a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}

View File

@ -1,25 +0,0 @@
/*
* Hash lookup function.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
/**
* lookup()
* Generates a 32 bit hash.
* Based on public domain code by Bob Jenkins
* It should be one of the best hash functions around in terms of both
* statistical properties and speed. It is NOT recommended for cryptographic
* purposes.
**/
#ifndef _LOOKUP_H
#define _LOOKUP_H
unsigned long int lookup( unsigned char *k, unsigned long int length, unsigned long int level);
#endif /* !_LOOKUP_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
/*
* Syslog functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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 <stdarg.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "syserr.h"
void sys_err(int pri, char *fn, int ln, int en, char *fmt, ...) {
va_list args;
char buf[SYSERR_MSGSIZE];
va_start(args, fmt);
vsnprintf(buf, SYSERR_MSGSIZE, fmt, args);
va_end(args);
buf[SYSERR_MSGSIZE-1] = 0; /* Make sure it is null terminated */
if (en)
syslog(pri, "%s: %d: %d (%s) %s", fn, ln, en, strerror(en), buf);
else
syslog(pri, "%s: %d: %s", fn, ln, buf);
}
void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
void *pack, unsigned len, char *fmt, ...) {
va_list args;
char buf[SYSERR_MSGSIZE];
char buf2[SYSERR_MSGSIZE];
unsigned int n;
int pos;
va_start(args, fmt);
vsnprintf(buf, SYSERR_MSGSIZE, fmt, args);
va_end(args);
buf[SYSERR_MSGSIZE-1] = 0;
snprintf(buf2, SYSERR_MSGSIZE, "Packet from %s:%u, length: %d, content:",
inet_ntoa(peer->sin_addr),
ntohs(peer->sin_port),
len);
buf2[SYSERR_MSGSIZE-1] = 0;
pos = strlen(buf2);
for(n=0; n<len; n++) {
if ((pos+4)<SYSERR_MSGSIZE) {
sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
pos += 3;
}
}
buf2[pos] = 0;
if (en)
syslog(pri, "%s: %d: %d (%s) %s. %s", fn, ln, en, strerror(en), buf, buf2);
else
syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
}

View File

@ -1,21 +0,0 @@
/*
* Syslog functions.
* Copyright (C) 2003, 2004 Mondru AB.
*
* 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.
*
*/
#ifndef _SYSERR_H
#define _SYSERR_H
#define SYSERR_MSGSIZE 256
void sys_err(int pri, char *filename, int en, int line, char *fmt, ...);
void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
void *pack, unsigned len, char *fmt, ...);
#endif /* !_SYSERR_H */

View File

@ -1,897 +0,0 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003, 2004 Mondru AB.
*
* 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.
*
*/
/*
* tun.c: Contains all TUN functionality. Is able to handle multiple
* tunnels in the same program. Each tunnel is identified by the struct,
* which is passed to functions.
*
*/
#include <syslog.h>
#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>
#if defined(__linux__)
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#elif defined (__FreeBSD__)
#include <net/if.h>
#include <net/if_tun.h>
#elif defined (__APPLE__)
#include <net/if.h>
#elif defined (__sun__)
#include <stropts.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_tun.h>
/*#include "sun_if_tun.h"*/
#else
#error "Unknown platform!"
#endif
#include "tun.h"
#include "syserr.h"
#if defined(__linux__)
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;
}
int tun_gifindex(struct tun_t *this, int *index) {
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl() failed");
close(fd);
return -1;
}
close(fd);
*index = ifr.ifr_ifindex;
return 0;
}
#endif
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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFFLAGS) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
/* Currently unused
int tun_addroute2(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask) {
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
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 rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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); * TODO: Error check *
close(fd);
return 0;
}
*/
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_setaddr(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 */
if (tun_gifindex(this, &req.i.ifa_index)) {
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(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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); /* TODO Error check */
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
close(fd);
this->addrs++;
return 0;
#elif defined (__FreeBSD__) || defined (__APPLE__)
int fd;
struct ifaliasreq areq;
/* TODO: Is this needed on FreeBSD? */
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
memset(&areq, 0, sizeof(areq));
/* 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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCAIFADDR) failed");
close(fd);
return -1;
}
close(fd);
this->addrs++;
return 0;
#elif defined (__sun__)
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask);
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"Setting multiple addresses not possible on Solaris");
return -1;
#else
#error "Unknown platform!"
#endif
}
int tun_setaddr(struct tun_t *this,
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, 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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (addr) { /* Set the interface address */
this->addr.s_addr = addr->s_addr;
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
if (errno != EEXIST) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR) failed");
}
else {
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR): Address already exists");
}
close(fd);
return -1;
}
}
if (dstaddr) { /* Set the destination address */
this->dstaddr.s_addr = dstaddr->s_addr;
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
dstaddr->s_addr;
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFDSTADDR) failed");
close(fd);
return -1;
}
}
if (netmask) { /* Set the netmask */
this->netmask.s_addr = netmask->s_addr;
#if defined(__linux__)
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
netmask->s_addr;
#elif defined(__FreeBSD__) || defined (__APPLE__)
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
netmask->s_addr;
#elif defined(__sun__)
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
netmask->s_addr;
#else
#error "Unknown platform!"
#endif
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFNETMASK) failed");
close(fd);
return -1;
}
}
close(fd);
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__)
tun_addroute(this, dstaddr, addr, netmask);
this->routes = 1;
#endif
return 0;
}
int tun_route(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask,
int delete)
{
/* TODO: Learn how to set routing table on sun */
#if defined(__linux__)
struct rtentry r;
int fd;
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(LOG_ERR, __FILE__, __LINE__, 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;
((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
if (delete) {
if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCDELRT) failed");
close(fd);
return -1;
}
}
else {
if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, 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(LOG_ERR, __FILE__, __LINE__, errno,
"write() failed");
close(fd);
return -1;
}
close(fd);
return 0;
#elif defined(__sun__)
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"Could not set up routing on Solaris. Please add route manually.");
return 0;
#else
#error "Unknown platform!"
#endif
}
int tun_addroute(struct tun_t *this,
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)
{
#if defined(__linux__)
struct ifreq ifr;
#elif defined(__FreeBSD__) || defined (__APPLE__)
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
int devnum;
struct ifaliasreq areq;
int fd;
#elif defined(__sun__)
int if_fd, ppa = -1;
static int ip_fd = 0;
int muxid;
struct ifreq ifr;
#else
#error "Unknown platform!"
#endif
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
return EOF;
}
(*tun)->cb_ind = NULL;
(*tun)->addrs = 0;
(*tun)->routes = 0;
#if defined(__linux__)
/* Open the actual tun device */
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
return -1;
}
/* Set device flags. For some weird reason this is also the method
used to obtain the network interface name */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
close((*tun)->fd);
return -1;
}
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
(*tun)->devname[IFNAMSIZ] = 0;
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
return 0;
#elif defined(__FreeBSD__) || defined (__APPLE__)
/* Find suitable device */
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
devname[sizeof(devname)] = 0;
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
if (errno != EBUSY) break;
}
if ((*tun)->fd < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
return -1;
}
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
(*tun)->devname[sizeof((*tun)->devname)] = 0;
/* The tun device we found might have "old" IP addresses allocated */
/* We need to delete those. This problem is not present on Linux */
memset(&areq, 0, sizeof(areq));
/* Set up interface name */
strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
areq.ifra_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(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
/* Delete any IP addresses until SIOCDIFADDR fails */
while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
close(fd);
return 0;
#elif defined(__sun__)
if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
return -1;
}
if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
return -1;
}
/* Assign a new PPA and get its unit number. */
if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
return -1;
}
if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
return -1;
}
if(ioctl(if_fd, I_PUSH, "ip") < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
return -1;
}
/* Assign ppa according to the unit number returned by tun device */
if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
return -1;
}
/* Link the two streams */
if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
return -1;
}
close (if_fd);
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
(*tun)->devname[sizeof((*tun)->devname)] = 0;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, (*tun)->devname);
ifr.ifr_ip_muxid = muxid;
if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
ioctl(ip_fd, I_PUNLINK, muxid);
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
return -1;
}
/* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
msg (M_ERR, "Set file descriptor to non-blocking failed"); */
return 0;
#else
#error "Unknown platform!"
#endif
}
int tun_free(struct tun_t *tun)
{
if (tun->routes) {
tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
}
if (close(tun->fd)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
}
/* TODO: For solaris we need to unlink streams */
free(tun);
return 0;
}
int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
this->cb_ind = cb_ind;
return 0;
}
int tun_decaps(struct tun_t *this)
{
#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
unsigned char buffer[PACKET_MAX];
int status;
if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, status);
return 0;
#elif defined (__sun__)
unsigned char buffer[PACKET_MAX];
struct strbuf sbuf;
int f = 0;
sbuf.maxlen = PACKET_MAX;
sbuf.buf = buffer;
if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, sbuf.len);
return 0;
#endif
}
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
return write(tun->fd, pack, len);
#elif defined (__sun__)
struct strbuf sbuf;
sbuf.len = len;
sbuf.buf = pack;
return putmsg(tun->fd, NULL, &sbuf, 0);
#endif
}
int tun_runscript(struct tun_t *tun, char* script) {
char buf[TUN_SCRIPTSIZE];
char snet[TUN_ADDRSIZE];
char smask[TUN_ADDRSIZE];
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
/* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
script, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
system(buf);
return 0;
}

View File

@ -1,74 +0,0 @@
/*
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* 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.
*
*/
#ifndef _TUN_H
#define _TUN_H
#define PACKET_MAX 8196 /* Maximum packet size we receive */
#define TUN_SCRIPTSIZE 256
#define TUN_ADDRSIZE 128
#define TUN_NLBUFSIZE 1024
struct tun_packet_t {
unsigned int ver:4;
unsigned int ihl:4;
unsigned int dscp:6;
unsigned int ecn:2;
unsigned int length:16;
unsigned int id:16;
unsigned int flags:3;
unsigned int fragment:13;
unsigned int ttl:8;
unsigned int protocol:8;
unsigned int check:16;
unsigned int src:32;
unsigned int dst:32;
};
/* ***********************************************************
* Information storage for each tun instance
*************************************************************/
struct tun_t {
int fd; /* File descriptor to tun interface */
struct in_addr addr;
struct in_addr dstaddr;
struct in_addr netmask;
int addrs; /* Number of allocated IP addresses */
int routes; /* One if we allocated an automatic route */
char devname[IFNAMSIZ];/* Name of the tun device */
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len);
};
extern int tun_new(struct tun_t **tun);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
extern int tun_setaddr(struct tun_t *this, struct in_addr *our_adr,
struct in_addr *his_adr, struct in_addr *net_mask);
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,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len));
extern int tun_runscript(struct tun_t *tun, char* script);
#endif /* !_TUN_H */