Compare commits
178 Commits
Author | SHA1 | Date |
---|---|---|
Harald Welte | be529a8bb1 | |
Harald Welte | 242266da78 | |
Harald Welte | 6045efb642 | |
Harald Welte | 078bc097fc | |
Harald Welte | 3cce289e4b | |
Harald Welte | b2a9aae35a | |
Harald Welte | 9523482193 | |
Harald Welte | 74aa8b701c | |
Harald Welte | 15ed792154 | |
Harald Welte | 01628985ec | |
Harald Welte | 2778ae2b8f | |
Harald Welte | 1b6e8e7b5e | |
Harald Welte | e257be1d69 | |
Harald Welte | 8a03ea8a32 | |
Harald Welte | 9e6dfa0558 | |
Harald Welte | 4857f3c2f3 | |
Harald Welte | b513b951bd | |
Harald Welte | 33520b43ec | |
Harald Welte | 7fc8694b97 | |
Harald Welte | b62983d3c3 | |
Harald Welte | 881e97ed00 | |
Harald Welte | c55ece8d91 | |
Harald Welte | 8ffd7fc782 | |
Harald Welte | e57cbe2e74 | |
Pau Espin | 0ab62fe081 | |
Max | bdc504e29c | |
Max | b87da75ae4 | |
Max | 14b1b63710 | |
Harald Welte | 367baa3776 | |
Harald Welte | 37d5b1557b | |
Harald Welte | 54d082e5e8 | |
Harald Welte | b10ee08c2f | |
Harald Welte | 23eea1d132 | |
Harald Welte | 81bc2aea53 | |
Harald Welte | ab6d189f8f | |
Harald Welte | 2e48a44952 | |
Harald Welte | 72a38b55e3 | |
Harald Welte | 1ae98777d9 | |
Harald Welte | d46bcd236e | |
Harald Welte | d4d6e09fd2 | |
Harald Welte | 365f8fa462 | |
Harald Welte | d1bf1e11ba | |
Harald Welte | a0d281db1c | |
Harald Welte | 53165ede24 | |
Harald Welte | 63ebccdfe3 | |
Harald Welte | d12eab9c4e | |
Harald Welte | d9d8862a58 | |
Max | 283188790b | |
Max | 3142d8d30b | |
Daniel Willmann | a2861a7428 | |
Harald Welte | 19e19e3609 | |
Harald Welte | 93c3b386cf | |
Harald Welte | bf6de7a289 | |
Neels Hofmeyr | 1fce2ce0b3 | |
bjovan | a8f71eb24e | |
Harald Welte | 8c25b97d3f | |
Harald Welte | a892177dce | |
Harald Welte | 9225bfc48c | |
Harald Welte | bf5c0bb4b9 | |
Harald Welte | 875e4dc8c3 | |
Holger Hans Peter Freyther | 68d244d302 | |
Max | 7716860845 | |
Harald Welte | d37b80a6d2 | |
Max | dbd7024919 | |
Neels Hofmeyr | f41f5866ce | |
Neels Hofmeyr | f7611c3cee | |
Neels Hofmeyr | 38929c9131 | |
Neels Hofmeyr | ee9d34a9cc | |
Max | 727417dd28 | |
Max | cd93f4f4be | |
Max | 395e213894 | |
BJovke | 03dbafb000 | |
Alexander Couzens | 86540de7f3 | |
Ruben Undheim | cc077ae0bc | |
Holger Hans Peter Freyther | 6bf2f05df6 | |
Pablo Neira Ayuso | 0eaa5b8e6c | |
Pablo Neira Ayuso | 176e895bd6 | |
Pablo Neira Ayuso | 23d9976039 | |
Pablo Neira Ayuso | 466da99934 | |
Pablo Neira Ayuso | 8419e33c4a | |
Pablo Neira Ayuso | d9d7be339d | |
Pablo Neira Ayuso | 7b31987a46 | |
Neels Hofmeyr | f89dc4e127 | |
Holger Hans Peter Freyther | b29ff1da55 | |
Daniel Willmann | d997552d29 | |
Daniel Willmann | 05f3ef3eb8 | |
Daniel Willmann | 134a7752fd | |
Holger Hans Peter Freyther | 8ddb6805a9 | |
Holger Hans Peter Freyther | 3a9befb516 | |
Andreas Schultz | c80680a9c4 | |
Andreas Schultz | c5fbf9bd68 | |
Pablo Neira Ayuso | 4b075b6cb8 | |
Holger Hans Peter Freyther | 89dcb614e8 | |
Harald Welte | ac0b4f17fe | |
Andreas Schultz | 10abfba949 | |
Holger Hans Peter Freyther | a377b0874a | |
Alexander Huemer | 04cbae494d | |
Alexander Huemer | db852a14fe | |
Alexander Huemer | e740e81281 | |
Neels Hofmeyr | 2ea010a1ed | |
Neels Hofmeyr | 041824dfc8 | |
Holger Hans Peter Freyther | cd14094bb6 | |
Neels Hofmeyr | 0dc4748447 | |
Neels Hofmeyr | 6c06d25667 | |
Neels Hofmeyr | e845cb9505 | |
Neels Hofmeyr | b18e811e24 | |
Neels Hofmeyr | 9b09738891 | |
Michael McTernan | b07d07072e | |
Holger Hans Peter Freyther | 633cc0d7cb | |
Holger Hans Peter Freyther | 7bfe18039b | |
Holger Hans Peter Freyther | 0576f3bebf | |
Holger Hans Peter Freyther | 91d0ee5c14 | |
Holger Hans Peter Freyther | 6ab58b466a | |
Holger Hans Peter Freyther | 8e7e3ef686 | |
Holger Hans Peter Freyther | c38bf64e3f | |
Holger Hans Peter Freyther | 9c7fd8edc4 | |
Holger Hans Peter Freyther | e527ef105f | |
Holger Hans Peter Freyther | 01b40d0690 | |
Holger Hans Peter Freyther | 752314ac43 | |
Holger Hans Peter Freyther | 42ca1d1a38 | |
Holger Hans Peter Freyther | ca524ef344 | |
Holger Hans Peter Freyther | 839c2211dc | |
Holger Hans Peter Freyther | 7397b88485 | |
Holger Hans Peter Freyther | f97f58deb2 | |
Holger Hans Peter Freyther | 493ec593f7 | |
Holger Hans Peter Freyther | 827aec1f31 | |
Holger Hans Peter Freyther | 0b705bb4d1 | |
Daniel Willmann | c190896437 | |
Holger Hans Peter Freyther | 5816bcfaff | |
Pablo Neira Ayuso | 746b944ad6 | |
Holger Hans Peter Freyther | 9c0ff4fafe | |
Holger Hans Peter Freyther | 1c4d9e6d87 | |
Holger Hans Peter Freyther | 6c0b9c2c42 | |
Holger Hans Peter Freyther | 4afb44a25e | |
Holger Hans Peter Freyther | 29567ed125 | |
Pablo Neira Ayuso | 1a1ba02292 | |
Pablo Neira Ayuso | 0674f0b56c | |
Holger Hans Peter Freyther | 0382996e10 | |
Holger Hans Peter Freyther | 0527289c2b | |
Holger Hans Peter Freyther | d7566b8280 | |
Holger Hans Peter Freyther | 0aa17870bc | |
Holger Hans Peter Freyther | e071e30937 | |
Tobias Engel | 3d7500e686 | |
Harald Welte | f4594e236b | |
Eric Butler | ab9ff093cb | |
Eric Butler | 235a095d08 | |
Harald Welte | 95848bafce | |
Harald Welte | ef71162a74 | |
Harald Welte | b841e57f0b | |
Harald Welte | bb47c354b6 | |
Harald Welte | e65c7390ca | |
Harald Welte | bdca4b7886 | |
Harald Welte | d88e11d819 | |
Harald Welte | bed35df298 | |
Sylvain Munaut | ca36f29364 | |
Harald Welte | 3a4c67b4bf | |
Harald Welte | 41af5691ef | |
Yann BONNAMY | 11a398fbc3 | |
Yann BONNAMY | ad18ccb9df | |
Isabelle Kraemer | fe50409675 | |
Harald Welte | f5cbbc9558 | |
Harald Welte | 142af72b13 | |
Harald Welte | 38c8f6da35 | |
Harald Welte | 6fc42401b9 | |
Harald Welte | b502255b8f | |
Harald Welte | 629e986ea4 | |
Yann BONNAMY | 944dce3e66 | |
Emmanuel Bretelle | 87490d7fa9 | |
Emmanuel Bretelle | 4e56c83be2 | |
Emmanuel Bretelle | 91384a4cb0 | |
Emmanuel Bretelle | eaaf50095b | |
Emmanuel Bretelle | 2a103687b6 | |
Emmanuel Bretelle | 2a7cad57ef | |
Emmanuel Bretelle | 68521860e0 | |
Emmanuel Bretelle | 111e054543 | |
Harald Welte | 1e9b27b70e | |
Harald Welte | a3f42e0738 | |
Harald Welte | e916809a32 |
|
@ -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
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[gerrit]
|
||||
host=gerrit.osmocom.org
|
||||
project=openggsn
|
21
AUTHORS
21
AUTHORS
|
@ -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
142
ChangeLog
|
@ -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
182
INSTALL
|
@ -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.
|
15
Makefile.am
15
Makefile.am
|
@ -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@
|
||||
|
|
|
@ -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>
|
||||
|
|
@ -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
|
|
@ -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])])])])
|
||||
|
||||
|
|
|
@ -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}"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -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
|
|
@ -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".
|
|
@ -0,0 +1,2 @@
|
|||
NEWS
|
||||
README.md
|
|
@ -0,0 +1,5 @@
|
|||
usr/include/*
|
||||
usr/lib/*/lib*.a
|
||||
usr/lib/*/lib*.so
|
||||
usr/lib/*/lib*.la
|
||||
usr/lib/*/pkgconfig/*
|
|
@ -0,0 +1 @@
|
|||
usr/lib/*/lib*.so.*
|
|
@ -0,0 +1,2 @@
|
|||
examples/ggsn.conf
|
||||
examples/sgsnemu.conf
|
|
@ -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
|
||||
|
||||
:
|
|
@ -0,0 +1,3 @@
|
|||
/usr/bin/ggsn
|
||||
/usr/bin/sgsnemu
|
||||
/usr/share/man/man8/*
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
10
doc/ggsn.8
10
doc/ggsn.8
|
@ -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
|
||||
|
|
272
doc/ggsn.8.pl
272
doc/ggsn.8.pl
|
@ -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 są 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) są 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
|
||||
są 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 są 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.
|
|
@ -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
|
||||
|
|
407
doc/sgsnemu.8.pl
407
doc/sgsnemu.8.pl
|
@ -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) są 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 są 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ń są 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 są 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.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
1226
ggsn/cmdline.c
1226
ggsn/cmdline.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
||||
|
|
293
ggsn/cmdline.h
293
ggsn/cmdline.h
|
@ -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);
|
||||
|
||||
|
|
1055
ggsn/getopt.c
1055
ggsn/getopt.c
File diff suppressed because it is too large
Load Diff
188
ggsn/getopt1.c
188
ggsn/getopt1.c
|
@ -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 */
|
1097
ggsn/ggsn.c
1097
ggsn/ggsn.c
File diff suppressed because it is too large
Load Diff
180
ggsn/gnugetopt.h
180
ggsn/gnugetopt.h
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
526
ggsn/ippool.c
526
ggsn/ippool.c
|
@ -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
|
105
ggsn/ippool.h
105
ggsn/ippool.h
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 */
|
897
ggsn/tun.c
897
ggsn/tun.c
|
@ -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;
|
||||
}
|
74
ggsn/tun.h
74
ggsn/tun.h
|
@ -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 */
|
|
@ -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:
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
447
gtp/gtp.h
447
gtp/gtp.h
|
@ -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 */
|
||||
|
|
1054
gtp/gtpie.c
1054
gtp/gtpie.c
File diff suppressed because it is too large
Load Diff
272
gtp/gtpie.h
272
gtp/gtpie.h
|
@ -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 */
|
||||
|
|
256
gtp/lookupa.c
256
gtp/lookupa.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
316
gtp/pdp.c
|
@ -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
227
gtp/pdp.h
|
@ -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 */
|
||||
|
|
406
gtp/queue.c
406
gtp/queue.c
|
@ -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;
|
||||
}
|
||||
|
|
55
gtp/queue.h
55
gtp/queue.h
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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),
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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}/
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
2892
sgsnemu/cmdline.c
2892
sgsnemu/cmdline.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
1055
sgsnemu/getopt.c
1055
sgsnemu/getopt.c
File diff suppressed because it is too large
Load Diff
526
sgsnemu/ippool.c
526
sgsnemu/ippool.c
|
@ -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
|
105
sgsnemu/ippool.h
105
sgsnemu/ippool.h
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
2517
sgsnemu/sgsnemu.c
2517
sgsnemu/sgsnemu.c
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 */
|
897
sgsnemu/tun.c
897
sgsnemu/tun.c
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Reference in New Issue