mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-11-03 05:33:23 +00:00
Compare commits
318 Commits
neels/refa
...
35c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64158720d7 | ||
|
|
6da888c5d0 | ||
|
|
33c537e5a7 | ||
|
|
aa69034c00 | ||
|
|
bf47f71785 | ||
|
|
2b7a860ffb | ||
|
|
932eeec240 | ||
|
|
6f7aabf6a3 | ||
|
|
a491e42129 | ||
|
|
1ce111f72b | ||
|
|
e010dea56e | ||
|
|
f4530447f6 | ||
|
|
e7361067ac | ||
|
|
606837597f | ||
|
|
5f8b332e6b | ||
|
|
43001cbc7a | ||
|
|
65d61c347b | ||
|
|
c8ca02b937 | ||
|
|
3ce5a3648a | ||
|
|
a4cb02699e | ||
|
|
f0fb2c2ddd | ||
|
|
8a1e7b8658 | ||
|
|
b7782d4d41 | ||
|
|
b0b9c28284 | ||
|
|
3730c550cd | ||
|
|
cc8181fefe | ||
|
|
7327360d10 | ||
|
|
e405c2f196 | ||
|
|
411ff3b984 | ||
|
|
aee905b790 | ||
|
|
fb75adfeda | ||
|
|
7b9230acfe | ||
|
|
5662cb2152 | ||
|
|
e1412d9493 | ||
|
|
d1e2342f91 | ||
|
|
381b723543 | ||
|
|
ee44b82b96 | ||
|
|
b5f93346df | ||
|
|
8e8c7ef3c7 | ||
|
|
57238889eb | ||
|
|
d70ab97fa4 | ||
|
|
d1bd6fce9c | ||
|
|
a32e4c4fb8 | ||
|
|
3b84e92ab3 | ||
|
|
3e0baa6146 | ||
|
|
b673d1c438 | ||
|
|
6a2856bab5 | ||
|
|
0d95ca59f9 | ||
|
|
906c2099da | ||
|
|
ac07625086 | ||
|
|
36c4fac9c9 | ||
|
|
a06b2d3877 | ||
|
|
546884d9a1 | ||
|
|
f2286395e9 | ||
|
|
9eebe15cd1 | ||
|
|
31e1dab2c0 | ||
|
|
db0366c9e4 | ||
|
|
47adad0817 | ||
|
|
c5efb5bccb | ||
|
|
9a6da455b9 | ||
|
|
b4c0828039 | ||
|
|
df3dcac439 | ||
|
|
0757504a86 | ||
|
|
042a445cf3 | ||
|
|
a16c7501a4 | ||
|
|
9f98822255 | ||
|
|
fc8357a2db | ||
|
|
3e443ca502 | ||
|
|
2c10211d60 | ||
|
|
5fdda13f89 | ||
|
|
dbeaa044f8 | ||
|
|
7ad4d5e8cb | ||
|
|
ab4db10750 | ||
|
|
dddbbaaee1 | ||
|
|
134855c45e | ||
|
|
a4942e6566 | ||
|
|
4e43ef5ab0 | ||
|
|
4ae8d8232d | ||
|
|
0bdd8bf5bc | ||
|
|
5b1ef9589c | ||
|
|
7d54ed48e7 | ||
|
|
07730bb9cc | ||
|
|
7b38af5cd3 | ||
|
|
85ef5833cb | ||
|
|
a2a08f7602 | ||
|
|
282d4e3dda | ||
|
|
42d3250d17 | ||
|
|
5aed8de11d | ||
|
|
5f5fcff5f3 | ||
|
|
a884a95a7b | ||
|
|
a4aada0b5f | ||
|
|
732131d4d0 | ||
|
|
36b940d1fe | ||
|
|
e661277b48 | ||
|
|
6f539aa259 | ||
|
|
1c8c62667f | ||
|
|
e5a082d64a | ||
|
|
37c45e3998 | ||
|
|
f5e40b7011 | ||
|
|
02e21af657 | ||
|
|
bffc3f9012 | ||
|
|
7c4de0776b | ||
|
|
077b903e11 | ||
|
|
2d6a69e69a | ||
|
|
4f0343233b | ||
|
|
bcab7fb4af | ||
|
|
427699e6eb | ||
|
|
9c0f4f49e9 | ||
|
|
ac51c7e68e | ||
|
|
55d639f0fb | ||
|
|
b9ace14717 | ||
|
|
d9fff0c543 | ||
|
|
1d85bea152 | ||
|
|
f1e44c5493 | ||
|
|
bebd75c2d1 | ||
|
|
878ece768b | ||
|
|
a00e79242b | ||
|
|
840ce8a0a8 | ||
|
|
afd76a731f | ||
|
|
fd30bd1032 | ||
|
|
227034c88e | ||
|
|
3dad951171 | ||
|
|
318795635e | ||
|
|
22e1573831 | ||
|
|
c85e89961a | ||
|
|
2fc2bc6bc4 | ||
|
|
0d0e242685 | ||
|
|
698a2339eb | ||
|
|
490782d18e | ||
|
|
e3c5918aee | ||
|
|
e2a1de5ca5 | ||
|
|
4c7d29107f | ||
|
|
f55a039048 | ||
|
|
fc6676c4a0 | ||
|
|
1af543f44c | ||
|
|
bd228244da | ||
|
|
a06120de77 | ||
|
|
b589e78f13 | ||
|
|
b11ed0f132 | ||
|
|
9c332104eb | ||
|
|
51127ea962 | ||
|
|
dabb8b4860 | ||
|
|
ff069172ce | ||
|
|
7bee06e1cc | ||
|
|
6c10aa0e6f | ||
|
|
a4e24f5546 | ||
|
|
29caaab817 | ||
|
|
859f9b0752 | ||
|
|
a037e5908a | ||
|
|
2e7b9ff891 | ||
|
|
361cb9e910 | ||
|
|
5bacb59a6c | ||
|
|
5b0096a236 | ||
|
|
df6a105024 | ||
|
|
226e95af1f | ||
|
|
e37f48eaf9 | ||
|
|
8a55263a1b | ||
|
|
fed3389112 | ||
|
|
081f30cba4 | ||
|
|
ea0c26a436 | ||
|
|
9d9d91b8e8 | ||
|
|
73abc38dc5 | ||
|
|
be4baa6d97 | ||
|
|
d369013250 | ||
|
|
8afec5f86d | ||
|
|
5943cbb73f | ||
|
|
f6c5f9524f | ||
|
|
bc41c8d581 | ||
|
|
89e1abcb18 | ||
|
|
8376972050 | ||
|
|
a964027344 | ||
|
|
c5150cecc5 | ||
|
|
02af9b3ca2 | ||
|
|
db924d3908 | ||
|
|
34a7416ec0 | ||
|
|
45ce2725ac | ||
|
|
a2eb5eb760 | ||
|
|
fdd732b130 | ||
|
|
1d8ffc6b23 | ||
|
|
58c0da7833 | ||
|
|
958256f5cf | ||
|
|
6748dc90b8 | ||
|
|
7bd7b6815a | ||
|
|
b16c46b4c3 | ||
|
|
840a8e9713 | ||
|
|
cee7546f15 | ||
|
|
ed1ba2c902 | ||
|
|
ed08eb1c5a | ||
|
|
2e84d2c29a | ||
|
|
dd266066c7 | ||
|
|
b5624c3d48 | ||
|
|
6a21527a2d | ||
|
|
1a8bc9839a | ||
|
|
79aa4bd837 | ||
|
|
fbb9c7f59a | ||
|
|
3c1cce245e | ||
|
|
93fed3bc51 | ||
|
|
00d346092b | ||
|
|
3ca419a2ef | ||
|
|
ff438174aa | ||
|
|
f85fe9720b | ||
|
|
fed598f41d | ||
|
|
471e349ecc | ||
|
|
7e1175f6d8 | ||
|
|
f621498129 | ||
|
|
7c20148e39 | ||
|
|
b6fc227763 | ||
|
|
1d94585f96 | ||
|
|
05ac095006 | ||
|
|
73d28c9dda | ||
|
|
ea70f3619a | ||
|
|
98146776dd | ||
|
|
b5b02c2a51 | ||
|
|
bd60930f36 | ||
|
|
720c939799 | ||
|
|
4aa22db1b4 | ||
|
|
db08819f85 | ||
|
|
8fcfe58269 | ||
|
|
ce316f4962 | ||
|
|
59ffc89d42 | ||
|
|
632e843e5f | ||
|
|
e80494726c | ||
|
|
3591437e0f | ||
|
|
dda21ed7d4 | ||
|
|
2778ae2b8f | ||
|
|
1b6e8e7b5e | ||
|
|
e257be1d69 | ||
|
|
8a03ea8a32 | ||
|
|
9e6dfa0558 | ||
|
|
4857f3c2f3 | ||
|
|
b513b951bd | ||
|
|
33520b43ec | ||
|
|
7fc8694b97 | ||
|
|
b62983d3c3 | ||
|
|
881e97ed00 | ||
|
|
c55ece8d91 | ||
|
|
8ffd7fc782 | ||
|
|
e57cbe2e74 | ||
|
|
0ab62fe081 | ||
|
|
bdc504e29c | ||
|
|
b87da75ae4 | ||
|
|
14b1b63710 | ||
|
|
367baa3776 | ||
|
|
37d5b1557b | ||
|
|
54d082e5e8 | ||
|
|
b10ee08c2f | ||
|
|
23eea1d132 | ||
|
|
81bc2aea53 | ||
|
|
ab6d189f8f | ||
|
|
2e48a44952 | ||
|
|
72a38b55e3 | ||
|
|
1ae98777d9 | ||
|
|
d46bcd236e | ||
|
|
d4d6e09fd2 | ||
|
|
365f8fa462 | ||
|
|
d1bf1e11ba | ||
|
|
a0d281db1c | ||
|
|
53165ede24 | ||
|
|
63ebccdfe3 | ||
|
|
d12eab9c4e | ||
|
|
d9d8862a58 | ||
|
|
283188790b | ||
|
|
3142d8d30b | ||
|
|
a2861a7428 | ||
|
|
19e19e3609 | ||
|
|
93c3b386cf | ||
|
|
bf6de7a289 | ||
|
|
1fce2ce0b3 | ||
|
|
a8f71eb24e | ||
|
|
8c25b97d3f | ||
|
|
a892177dce | ||
|
|
9225bfc48c | ||
|
|
bf5c0bb4b9 | ||
|
|
875e4dc8c3 | ||
|
|
68d244d302 | ||
|
|
7716860845 | ||
|
|
d37b80a6d2 | ||
|
|
dbd7024919 | ||
|
|
f41f5866ce | ||
|
|
f7611c3cee | ||
|
|
38929c9131 | ||
|
|
ee9d34a9cc | ||
|
|
727417dd28 | ||
|
|
cd93f4f4be | ||
|
|
395e213894 | ||
|
|
03dbafb000 | ||
|
|
86540de7f3 | ||
|
|
cc077ae0bc | ||
|
|
6bf2f05df6 | ||
|
|
0eaa5b8e6c | ||
|
|
176e895bd6 | ||
|
|
23d9976039 | ||
|
|
466da99934 | ||
|
|
8419e33c4a | ||
|
|
d9d7be339d | ||
|
|
7b31987a46 | ||
|
|
f89dc4e127 | ||
|
|
b29ff1da55 | ||
|
|
d997552d29 | ||
|
|
05f3ef3eb8 | ||
|
|
134a7752fd | ||
|
|
8ddb6805a9 | ||
|
|
3a9befb516 | ||
|
|
c80680a9c4 | ||
|
|
c5fbf9bd68 | ||
|
|
4b075b6cb8 | ||
|
|
89dcb614e8 | ||
|
|
ac0b4f17fe | ||
|
|
10abfba949 | ||
|
|
a377b0874a | ||
|
|
04cbae494d | ||
|
|
db852a14fe | ||
|
|
e740e81281 | ||
|
|
2ea010a1ed | ||
|
|
041824dfc8 | ||
|
|
cd14094bb6 | ||
|
|
0dc4748447 | ||
|
|
6c06d25667 |
68
.gitignore
vendored
68
.gitignore
vendored
@@ -1,7 +1,9 @@
|
||||
# autotools
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
compile
|
||||
config.guess
|
||||
config.h.in*
|
||||
config.h
|
||||
@@ -14,33 +16,67 @@ install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
openggsn.spec
|
||||
osmo-ggsn.spec
|
||||
stamp-h1
|
||||
doc/Makefile.in
|
||||
ggsn/Makefile.in
|
||||
gtp/Makefile.in
|
||||
sgsnemu/Makefile.in
|
||||
debian/openggsn/
|
||||
debian/*.debhelper
|
||||
debian/libgtp/
|
||||
debian/*.log
|
||||
INSTALL
|
||||
m4/
|
||||
Makefile
|
||||
osmo-ggsn-*.tar*
|
||||
.version
|
||||
.tarball-version
|
||||
|
||||
# debian
|
||||
debian/osmo-ggsn/
|
||||
debian/*.debhelper
|
||||
debian/libgtp1
|
||||
debian/osmo-ggsn-dbg
|
||||
debian/*.log
|
||||
debian/autoreconf.*
|
||||
debian/*.substvars
|
||||
debian/tmp/
|
||||
sgsnemu/sgsnemu
|
||||
debian/files
|
||||
debian/libgtp-dev/
|
||||
|
||||
# programs / libraries
|
||||
sgsnemu/sgsnemu
|
||||
libgtp.pc
|
||||
ggsn/ggsn
|
||||
m4/
|
||||
*.swp
|
||||
ggsn/osmo-ggsn
|
||||
|
||||
# compiler results
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
*.pyc
|
||||
.deps
|
||||
.libs
|
||||
|
||||
# misc
|
||||
*.swp
|
||||
.dirstamp
|
||||
.deps
|
||||
*.orig
|
||||
*.new
|
||||
*.rej
|
||||
*/.deps
|
||||
*/.libs
|
||||
*/Makefile
|
||||
*~
|
||||
osmo-ggsn.cfg
|
||||
sgsnemu.pid
|
||||
gsn_restart
|
||||
|
||||
# testsuite
|
||||
tests/atconfig
|
||||
tests/*/*_test
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
tests/package.m4
|
||||
|
||||
# manuals
|
||||
doc/manuals/*.html
|
||||
doc/manuals/*.svg
|
||||
doc/manuals/*.pdf
|
||||
doc/manuals/*__*.png
|
||||
doc/manuals/*.check
|
||||
doc/manuals/generated/
|
||||
doc/manuals/osmomsc-usermanual.xml
|
||||
doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
3
.gitreview
Normal file
3
.gitreview
Normal file
@@ -0,0 +1,3 @@
|
||||
[gerrit]
|
||||
host=gerrit.osmocom.org
|
||||
project=osmo-ggsn
|
||||
23
AUTHORS
23
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):
|
||||
|
||||
OsmoGGSN - Osmocom Gateway GPRS Support Node, based on OpenGGSN
|
||||
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.
|
||||
|
||||
15
Makefile.am
15
Makefile.am
@@ -1,5 +1,18 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
SUBDIRS = lib gtp ggsn sgsnemu doc
|
||||
SUBDIRS = lib gtp ggsn sgsnemu doc contrib tests
|
||||
|
||||
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
|
||||
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||
|
||||
@RELMAKE@
|
||||
|
||||
78
NEWS
78
NEWS
@@ -1,78 +0,0 @@
|
||||
OPENGGSN NEWS
|
||||
=============
|
||||
|
||||
OpenGGSN - Gateway GPRS Support Node
|
||||
Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
|
||||
Version 0.84
|
||||
============
|
||||
|
||||
* Initial MAC OSX support (Thanks to Pekka Nikander)
|
||||
* Quality assurance and improved error logging (Thanks to Pekka
|
||||
Nikander and Jonny Winberg)
|
||||
|
||||
Version 0.83
|
||||
============
|
||||
|
||||
* Added selection mode and charging characteristics option to sgsnemu.
|
||||
* Bug fixes on charging characteristics and PPP PCO length.(Thanks to
|
||||
Loic Bernable <leto@vilya.org>).
|
||||
* Improved Solaris support, hash table bugfix and improved logging.
|
||||
|
||||
Version 0.82
|
||||
============
|
||||
|
||||
* Improved Solaris support.
|
||||
* Routing manipulation and IP address alias capability for FreeBSD.
|
||||
* Initial Debian port (Thanks to ARAKI Yasuhiro <ar@debian.org>).
|
||||
|
||||
Version 0.81
|
||||
============
|
||||
|
||||
* Initial FreeBSD port (Thanks to Pavel Andreev <pavel.andreev@hp.com>).
|
||||
* IMSI '1111' bugfix (Thanks to Pavel Andreev <pavel.andreev@hp.com>).
|
||||
|
||||
Version 0.8
|
||||
===========
|
||||
|
||||
* Support for compilation under Solaris.
|
||||
* Iptables firewall script.
|
||||
* New options for sgsnemu
|
||||
|
||||
|
||||
Version 0.7
|
||||
===========
|
||||
|
||||
* 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
|
||||
fallback to using GTP0.
|
||||
* Standards compliance document.
|
||||
|
||||
Version 0.6
|
||||
===========
|
||||
|
||||
* Improved README file.
|
||||
* Now uses ioctl instead of ifconfig and route in ggsn and sgsnemu.
|
||||
* Absolute path to gtp library in ggsn/Makefile.am and ggsn/Makefile.am
|
||||
* Compiles with gengetopt 2.8 (Thanks to Lorenzo Bettini <bettini@gnu.org>)
|
||||
* sgsnemu is now able to handle several contexts and allocate
|
||||
interface IP addresses for each context.
|
||||
* ggsn now supports protocol configuration option DNS
|
||||
addresses. This allow mobile stations to set up DNS based on
|
||||
information configured in the ggsn.
|
||||
* Ping facility in sgsnemu allow testing without the need to route
|
||||
packets through the tun interface.
|
||||
* Man pages for ggsn and sgsnemu.
|
||||
* Sys 5 init script.
|
||||
* Spec file for building binary RPM packages.
|
||||
* If not --createif exit after "ping" or "echo" finishes
|
||||
* If sgsnemu echo failure, exit with code != 0
|
||||
|
||||
|
||||
Version 0.5
|
||||
===========
|
||||
|
||||
* Initial release. See README file for installation and usage
|
||||
instructions.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
OpenGGSN/FreeBSD notes
|
||||
OsmoGGSN/FreeBSD notes
|
||||
|
||||
FreeBSD support is experimental, please test and report bugs. The FreeBSD port is
|
||||
tested on FreeBSD 4.x, but may also work on 5.x series.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
OpenGGSN/Mac OS X notes
|
||||
OsmoGGSN/Mac OS X notes
|
||||
|
||||
Mac OS X support is experimental, please test and report bugs. The
|
||||
Mac OS X port is tested on Mac OS X 10.3.5, but may also work on
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
OpenGGSN/Solaris notes
|
||||
======================
|
||||
|
||||
Solaris support is experimental, please test and report bugs. The
|
||||
Solaris port is tested under Solaris 8.
|
||||
|
||||
Compiling
|
||||
---------
|
||||
|
||||
You need to edit the following line in ggsn/Makefile.in and
|
||||
sgsnemu/Makefile.in:
|
||||
|
||||
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib @EXEC_LDFLAGS@
|
||||
|
||||
should be changed to:
|
||||
|
||||
LDFLAGS = -lresolv -lsocket -lnsl @EXEC_LDFLAGS@
|
||||
|
||||
After this you install by the following commands:
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
|
||||
TUN
|
||||
---
|
||||
|
||||
You might or might not need to install the tun driver manually. For
|
||||
general information about tun see http://vtun.sourceforge.net/tun/
|
||||
|
||||
|
||||
Known problems
|
||||
--------------
|
||||
|
||||
Currently multiple IP addresses on the same network interface is not
|
||||
implemented for Solaris.
|
||||
|
||||
Currently routing table manipulation is not implemented for
|
||||
Solaris. You have to set the routes manually after you start ggsn or
|
||||
sgsnemu.
|
||||
|
||||
@@ -1,23 +1,79 @@
|
||||
OPENGGSN README
|
||||
===============
|
||||
OsmoGGSN - 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.
|
||||
|
||||
OsmoGGSN is part of the [Osmocom](https://osmocom.org/) Open Source
|
||||
Mobile Communications projects and the successor to OpenGGSN.
|
||||
OpenGGSN was developed until 2004 by Mondru AB.
|
||||
|
||||
Homepage
|
||||
--------
|
||||
|
||||
The official homepage of the project is
|
||||
https://osmocom.org/projects/openggsn/wiki
|
||||
|
||||
GIT Repository
|
||||
--------------
|
||||
|
||||
You can clone from the official osmo-ggsn.git repository using
|
||||
|
||||
git clone git://git.osmocom.org/osmo-ggsn.git
|
||||
|
||||
There is a cgit interface at http://git.osmocom.org/osmo-ggsn/
|
||||
|
||||
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 OsmoGGSN 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 OsmoGGSN can be seen at
|
||||
https://gerrit.osmocom.org/#/q/project:osmo-ggsn+status:open
|
||||
|
||||
|
||||
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
|
||||
OsmoGGSN 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 +82,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.
|
||||
OsmoGGSN 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,19 +133,19 @@ 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
|
||||
========
|
||||
|
||||
OpenGGSN is an open source implementation of GPRS Support Nodes
|
||||
OsmoGGSN is an open source implementation of GPRS Support Nodes
|
||||
(GSNs). It implements the GPRS tunneling protocol (GTP) version 0 and
|
||||
version 1.
|
||||
|
||||
OpenGGSN provides 3 components:
|
||||
OsmoGGSN provides 3 components:
|
||||
* gtplib
|
||||
* ggsn
|
||||
* osmo-ggsn
|
||||
* sgsnemu
|
||||
|
||||
*gtplib*
|
||||
@@ -99,8 +155,8 @@ GSN. gtplib supports both GTPv0 (GSM 09.60) and GTPv1 (3GPP
|
||||
29.060). At the moment no interface documentation is available for
|
||||
download.
|
||||
|
||||
*ggsn*
|
||||
The ggsn implements a Gateway GPRS Support Node. The GGSN is a small
|
||||
*osmo-ggsn*
|
||||
The osmo-ggsn implements a Gateway GPRS Support Node. The GGSN is a small
|
||||
application which is provided in order to test and demonstrate the use
|
||||
of gtplib. It is fully compliant to the 3GPP standards, but lacks
|
||||
important functionality such as charging and management. Use this
|
||||
@@ -116,33 +172,13 @@ exchange. sgsnemu will first attempt to use GTPv1. If unsuccessful it
|
||||
will fallback to GTPv0.
|
||||
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
Two experiments were performed in order to test the performance of
|
||||
sgsnemu and ggsn. The ggsn used a 550 MHz Athlon with 384 MB of
|
||||
RAM. sgsnemu used a 1 GHz Athlon with 256 MB of RAM. Both machines had
|
||||
100 Mb/s NICs (RTL-8139) and were connected through a crossed patch
|
||||
cable. Both tests were performed by sending ICMP echo packets from
|
||||
sgsnemu to the ggsn.
|
||||
|
||||
89.5 Mb/s IP throughput when sending 10000 ICMP ping packets with a
|
||||
payload of 1400 bytes. Transfer time 1.27 sec, no packets lost.
|
||||
|
||||
71.4 Mb/s IP throughput when sending 10000 ICMP ping packets with a
|
||||
payload of 1000 bytes. Transfer time 1.15 sec, no packets lost.
|
||||
|
||||
12,1 Mb/s IP throughput when sending 10000 ICMP ping packets with a
|
||||
payload of 100 bytes. Transfer time 0.84 sec, no packets lost.
|
||||
|
||||
|
||||
Required software
|
||||
=================
|
||||
|
||||
Tun
|
||||
---
|
||||
|
||||
Both ggsn and sgsnemu uses the tun package. You need at least tun
|
||||
Both osmo-ggsn and sgsnemu uses the tun package. You need at least tun
|
||||
version 1.1. With Linux tun is normally included from kernel version
|
||||
2.4.7. To configure automatic loading:
|
||||
|
||||
@@ -151,9 +187,6 @@ version 1.1. With Linux tun is normally included from kernel version
|
||||
|
||||
Alternatively you can execute "modprobe tun" on the commandline.
|
||||
|
||||
For Solaris the tun driver needs to be installed manually. For general
|
||||
information about tun see http://vtun.sourceforge.net/tun/
|
||||
|
||||
Gengetopt
|
||||
---------
|
||||
|
||||
@@ -161,10 +194,6 @@ Gengetopt is required if you want to change the options defined in the
|
||||
cmdline.ggo source file. You need at least gengetopt version 2.8. If
|
||||
you are just going to compile the programs you don't need gengetopt.
|
||||
|
||||
To use gengetopt for the ggsn do the following:
|
||||
cd ggsn
|
||||
gengetopt < cmdline.ggo --conf-parser
|
||||
|
||||
To use gengetopt for the sgsnemu do the following:
|
||||
cd sgsnemu
|
||||
gengetopt < cmdline.ggo --conf-parser
|
||||
@@ -176,111 +205,19 @@ http://www.gnu.org/software/gengetopt/gengetopt.html
|
||||
Compilation and Installation
|
||||
============================
|
||||
|
||||
|
||||
Setting up autotools
|
||||
--------------------
|
||||
|
||||
You do not need to perform this step if you are only going to compile
|
||||
the package:
|
||||
|
||||
1. Get version from somewhere: Script to extract version from configure.in
|
||||
2. Copy the latest config.guess and config.sub from ftp://ftp.gnu.org/gnu/config
|
||||
3. Run autoscan and copy configure.scan to configure.in
|
||||
4. Add/edit the following lines in configure.in:
|
||||
- AC_INIT(openggsn, 0.70, jj@openggsn.org)
|
||||
- AC_CONFIG_SRCDIR([gtp/gtp.c])
|
||||
- AM_CONFIG_HEADER([config.h])
|
||||
- AC_PROG_LIBTOOL
|
||||
- AM_PROG_LIBTOOL
|
||||
- AM_INIT_AUTOMAKE()
|
||||
5. libtoolize --automake --copy
|
||||
(ads copy of ltmain.sh)
|
||||
6. aclocal
|
||||
7. autoheader
|
||||
8. automake --add-missing --copy
|
||||
(Ads copy of mkinstalldirs missing, install-sh, depcomp)
|
||||
9. automake
|
||||
10. autoconf
|
||||
|
||||
The above will initialise the project to the current version of
|
||||
autotools (As installed in RedHat 8.0). See
|
||||
http://sources.redhat.com/autobook/autobook/autobook_25.html#SEC25
|
||||
for details on autotools.
|
||||
Please refer to the project homepage
|
||||
|
||||
|
||||
Checking out from CVS
|
||||
---------------------
|
||||
Running osmo-ggsn
|
||||
=================
|
||||
|
||||
To download the latest source code from anonymous CVS:
|
||||
|
||||
cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ggsn login
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ggsn co openggsn
|
||||
|
||||
Or to download from developer CVS:
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -z3 -d:ext:developername@cvs.sourceforge.net:/cvsroot/ggsn co openggsn
|
||||
|
||||
Both the above sets of commands creates a new directory called openggsn.
|
||||
|
||||
|
||||
Compilation and installation
|
||||
----------------------------
|
||||
|
||||
If compiling under Solaris you need to edit the following line in
|
||||
ggsn/Makefile.in and sgsnemu/Makefile.in:
|
||||
|
||||
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib @EXEC_LDFLAGS@
|
||||
|
||||
should be changed to:
|
||||
|
||||
LDFLAGS = -lresolv -lsocket -lnsl @EXEC_LDFLAGS@
|
||||
|
||||
Note that the above is not necessary on other platforms. Compilation
|
||||
and installation is performed by the following steps:
|
||||
|
||||
1. ./configure
|
||||
2. make clean
|
||||
3. cd gtp
|
||||
4. make
|
||||
5. make install (as root)
|
||||
6. cd ..
|
||||
(Step 3 to 6 you only need to run the first time to install libgtp)
|
||||
7. make
|
||||
8. make install (as root)
|
||||
9. Add /usr/local/lib to /etc/ld.so.conf
|
||||
10. run ldconfig
|
||||
|
||||
(Steps 9 and 10 are not required as path to libgtp is included in Makefile)
|
||||
|
||||
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
|
||||
|
||||
|
||||
Installation from binary
|
||||
------------------------
|
||||
|
||||
1. rpm -i openggsn-<version>.rpm
|
||||
|
||||
This will install binaries, man pages, configuration files as well as
|
||||
a Sys V init script for the ggsn.
|
||||
|
||||
|
||||
Running ggsn
|
||||
============
|
||||
|
||||
Use ggsn -h for a list of available options. All options available on
|
||||
Use osmo-ggsn -h for a list of available options. All options available on
|
||||
the command line can also be given in a configuration file. See
|
||||
examples/ggsn.conf for the format of this file.
|
||||
examples/osmo-ggsn.cfg for the format of this file.
|
||||
|
||||
Start the ggsn as root using the command:
|
||||
Start osmo-ggsn as root using the command:
|
||||
|
||||
ggsn -c examples/ggsn.conf --fg -l 10.0.0.40 --net 192.168.0.0/24 --dynip 192.168.0.0/24
|
||||
osmo-ggsn -c examples/osmo-ggsn.cfg
|
||||
|
||||
First a tun network interface will be created. In the above example
|
||||
the network interface address is 192.168.0.0 and the mask is
|
||||
@@ -309,9 +246,9 @@ Remember to enable routing:
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
If you installed using a binary RPM package it is possible to start
|
||||
ggsn by using the Sys 5 script:
|
||||
osmo-ggsn by using the Sys 5 script:
|
||||
|
||||
/etc/init.d/ggsn start
|
||||
/etc/init.d/osmo-ggsn start
|
||||
|
||||
|
||||
Running sgsnemu
|
||||
@@ -326,8 +263,7 @@ following:
|
||||
|
||||
1. Install sgsnemu on a Linux Box. See under installation above.
|
||||
2. Connect your Linux box with sgsnemu installed to the GPRS core
|
||||
network. Use the same LAN switch as the one your SGSN is connected
|
||||
to. You also need a free IP address that can be used by sgsnemu.
|
||||
network. You also need a free IP address that can be used by sgsnemu.
|
||||
3. You need to configure networking in terms of interface address,
|
||||
subnet mask and default route. See the Linux Networking HOWTO for
|
||||
details.
|
||||
@@ -337,7 +273,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)
|
||||
@@ -347,7 +282,7 @@ sgsnemu will print something like the following on the screen:
|
||||
Using MSISDN: 46702123456
|
||||
|
||||
Initialising GTP library
|
||||
OpenGGSN[1823]: GTP: gtp_newgsn() started
|
||||
OsmoGGSN[1823]: GTP: gtp_newgsn() started
|
||||
Done initialising GTP library
|
||||
|
||||
Sending off echo request
|
||||
@@ -355,8 +290,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 +310,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)
|
||||
@@ -387,7 +318,7 @@ sgsnemu will print something like the following on the screen:
|
||||
Using MSISDN: 46702123456
|
||||
|
||||
Initialising GTP library
|
||||
OpenGGSN[1838]: GTP: gtp_newgsn() started
|
||||
OsmoGGSN[1838]: GTP: gtp_newgsn() started
|
||||
Done initialising GTP library
|
||||
|
||||
Sending off echo request
|
||||
@@ -400,7 +331,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 +350,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>
|
||||
|
||||
10
TODO-RELEASE
Normal file
10
TODO-RELEASE
Normal file
@@ -0,0 +1,10 @@
|
||||
# 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
|
||||
libmisc tun_t tun_t structure has grown due to switch from in_addr to in46_addr (g#11870)
|
||||
254
configure.ac
Normal file
254
configure.ac
Normal file
@@ -0,0 +1,254 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(osmo-ggsn, m4_esyscmd([./git-version-gen .tarball-version]), osmocom-net-gprs@lists.osmocom.org)
|
||||
AC_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_CONFIG_TESTDIR(tests)
|
||||
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
|
||||
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])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_LIBOBJ_DIR([lib])
|
||||
|
||||
AC_ARG_ENABLE(static-exec,
|
||||
[ --enable-static-exec Enable static linking of executables],
|
||||
[ EXEC_LDFLAGS="-all-static"])
|
||||
|
||||
AC_SUBST(EXEC_LDFLAGS)
|
||||
|
||||
|
||||
case "${host}" in
|
||||
i*86-*-linux-gnu*)
|
||||
EXEC_LDADD="" ;;
|
||||
*solaris*)
|
||||
EXEC_LDADD="-lresolv -lsocket -lnsl" ;;
|
||||
esac
|
||||
|
||||
AC_SUBST(EXEC_LDADD)
|
||||
|
||||
|
||||
# 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])
|
||||
|
||||
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.2.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 unistd.h])
|
||||
|
||||
# Check for if header
|
||||
AC_CHECK_HEADERS([linux/if.h net/if.h])
|
||||
|
||||
# Check for tun header
|
||||
AC_CHECK_HEADERS([linux/if_tun.h net/if_tun.h])
|
||||
|
||||
# Check for netlink and rtnetlink headers
|
||||
AC_CHECK_HEADERS([linux/netlink.h linux/rtnetlink.h])
|
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
# check for ifaliasreq
|
||||
AC_MSG_CHECKING(whether struct ifaliasreq exist)
|
||||
AH_TEMPLATE(HAVE_IFALIASREQ)
|
||||
AC_EGREP_HEADER(ifaliasreq, net/if.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_IFALIASREQ])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
# check for ifreq.ifru_netmask
|
||||
AC_MSG_CHECKING(whether struct ifreq.ifru_netmask exist)
|
||||
AH_TEMPLATE(HAVE_IFREQ_IFRU_NETMASK)
|
||||
AC_EGREP_HEADER(ifru_netmask, linux/if.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_IFREQ_IFRU_NETMASK])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
|
||||
# check for rt_msghdr
|
||||
AC_MSG_CHECKING(whether struct rt_msghdr exist)
|
||||
AH_TEMPLATE(HAVE_RT_MSGHDR)
|
||||
AC_EGREP_HEADER(rt_msghdr, net/route.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
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
|
||||
# AC_FUNC_MALLOC
|
||||
# AC_FUNC_MEMCMP
|
||||
AC_CHECK_FUNCS([gethostbyname inet_ntoa memset select socket strdup strerror strtol])
|
||||
AC_CHECK_FUNCS(inet_aton inet_addr, break)
|
||||
|
||||
# check for getopt in standard library
|
||||
adl_FUNC_GETOPT_LONG
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
|
||||
|
||||
AC_ARG_ENABLE(sanitize,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-sanitize],
|
||||
[Compile with address sanitizer enabled],
|
||||
)],
|
||||
[sanitize=$enableval], [sanitize="no"])
|
||||
if test x"$sanitize" = x"yes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
|
||||
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(werror,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-werror],
|
||||
[Turn all compiler warnings into errors, with exceptions:
|
||||
a) deprecation (allow upstream to mark deprecation without breaking builds);
|
||||
b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
|
||||
]
|
||||
)],
|
||||
[werror=$enableval], [werror="no"])
|
||||
if test x"$werror" = x"yes"
|
||||
then
|
||||
WERROR_FLAGS="-Werror"
|
||||
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
||||
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
||||
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
|
||||
fi
|
||||
|
||||
# Generate manuals
|
||||
AC_ARG_ENABLE(manuals,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-manuals],
|
||||
[Generate manual PDFs [default=no]],
|
||||
)],
|
||||
[osmo_ac_build_manuals=$enableval], [osmo_ac_build_manuals="no"])
|
||||
AM_CONDITIONAL([BUILD_MANUALS], [test x"$osmo_ac_build_manuals" = x"yes"])
|
||||
AC_ARG_VAR(OSMO_GSM_MANUALS_DIR, [path to common osmo-gsm-manuals files, overriding pkg-config and "../osmo-gsm-manuals"
|
||||
fallback])
|
||||
if test x"$osmo_ac_build_manuals" = x"yes"
|
||||
then
|
||||
# Find OSMO_GSM_MANUALS_DIR (env, pkg-conf, fallback)
|
||||
if test -n "$OSMO_GSM_MANUALS_DIR"; then
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from env)"
|
||||
else
|
||||
OSMO_GSM_MANUALS_DIR="$($PKG_CONFIG osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)"
|
||||
if test -n "$OSMO_GSM_MANUALS_DIR"; then
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from pkg-conf)"
|
||||
else
|
||||
OSMO_GSM_MANUALS_DIR="../osmo-gsm-manuals"
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (fallback)"
|
||||
fi
|
||||
fi
|
||||
if ! test -d "$OSMO_GSM_MANUALS_DIR"; then
|
||||
AC_MSG_ERROR("OSMO_GSM_MANUALS_DIR does not exist! Install osmo-gsm-manuals or set OSMO_GSM_MANUALS_DIR.")
|
||||
fi
|
||||
|
||||
# Find and run check-depends
|
||||
CHECK_DEPENDS="$OSMO_GSM_MANUALS_DIR/check-depends.sh"
|
||||
if ! test -x "$CHECK_DEPENDS"; then
|
||||
CHECK_DEPENDS="osmo-gsm-manuals-check-depends"
|
||||
fi
|
||||
if ! $CHECK_DEPENDS; then
|
||||
AC_MSG_ERROR("missing dependencies for --enable-manuals")
|
||||
fi
|
||||
|
||||
# Put in Makefile with absolute path
|
||||
OSMO_GSM_MANUALS_DIR="$(realpath "$OSMO_GSM_MANUALS_DIR")"
|
||||
AC_SUBST([OSMO_GSM_MANUALS_DIR])
|
||||
fi
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/daemon.html
|
||||
AC_ARG_WITH([systemdsystemunitdir],
|
||||
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
|
||||
[with_systemdsystemunitdir=auto])
|
||||
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
|
||||
def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
|
||||
|
||||
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
|
||||
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
|
||||
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
|
||||
with_systemdsystemunitdir=no],
|
||||
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
|
||||
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
|
||||
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
|
||||
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
|
||||
|
||||
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
|
||||
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
ggsn/Makefile
|
||||
gtp/Makefile
|
||||
lib/Makefile
|
||||
intl/Makefile
|
||||
po/Makefile
|
||||
sgsnemu/Makefile
|
||||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
tests/Makefile
|
||||
tests/lib/Makefile
|
||||
tests/gtp/Makefile
|
||||
libgtp.pc
|
||||
osmo-ggsn.spec])
|
||||
AC_OUTPUT
|
||||
|
||||
echo "
|
||||
osmo-ggsn Configuration:
|
||||
GTP Linux kernel support: ${enable_gtp_linux}"
|
||||
121
configure.in
121
configure.in
@@ -1,121 +0,0 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(openggsn, 0.91, laforge@gnumonks.org)
|
||||
AC_CONFIG_SRCDIR([gtp/gtp.c])
|
||||
AM_CONFIG_HEADER([config.h])
|
||||
#AC_CONFIG_HEADER([config.h])
|
||||
|
||||
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
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_LIBOBJ_DIR([lib])
|
||||
|
||||
AC_ARG_ENABLE(static-exec,
|
||||
[ --enable-static-exec Enable static linking of executables],
|
||||
[ EXEC_LDFLAGS="-all-static"])
|
||||
|
||||
AC_SUBST(EXEC_LDFLAGS)
|
||||
|
||||
|
||||
case "${host}" in
|
||||
i*86-*-linux-gnu*)
|
||||
EXEC_LDADD="" ;;
|
||||
*solaris*)
|
||||
EXEC_LDADD="-lresolv -lsocket -lnsl" ;;
|
||||
esac
|
||||
|
||||
AC_SUBST(EXEC_LDADD)
|
||||
|
||||
|
||||
# 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 unistd.h])
|
||||
|
||||
# Check for if header
|
||||
AC_CHECK_HEADERS([linux/if.h net/if.h])
|
||||
|
||||
# Check for tun header
|
||||
AC_CHECK_HEADERS([linux/if_tun.h net/if_tun.h])
|
||||
|
||||
# Check for netlink and rtnetlink headers
|
||||
AC_CHECK_HEADERS([linux/netlink.h linux/rtnetlink.h])
|
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
# check for ifaliasreq
|
||||
AC_MSG_CHECKING(whether struct ifaliasreq exist)
|
||||
AH_TEMPLATE(HAVE_IFALIASREQ)
|
||||
AC_EGREP_HEADER(ifaliasreq, net/if.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_IFALIASREQ])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
# check for ifreq.ifru_netmask
|
||||
AC_MSG_CHECKING(whether struct ifreq.ifru_netmask exist)
|
||||
AH_TEMPLATE(HAVE_IFREQ_IFRU_NETMASK)
|
||||
AC_EGREP_HEADER(ifru_netmask, linux/if.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_IFREQ_IFRU_NETMASK])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
|
||||
# check for rt_msghdr
|
||||
AC_MSG_CHECKING(whether struct rt_msghdr exist)
|
||||
AH_TEMPLATE(HAVE_RT_MSGHDR)
|
||||
AC_EGREP_HEADER(rt_msghdr, net/route.h,
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_RT_MSGHDR])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
|
||||
# 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_CHECK_FUNCS(inet_aton inet_addr, break)
|
||||
|
||||
# check for getopt in standard library
|
||||
adl_FUNC_GETOPT_LONG
|
||||
|
||||
AM_INIT_AUTOMAKE()
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
doc/Makefile
|
||||
ggsn/Makefile
|
||||
gtp/Makefile
|
||||
lib/Makefile
|
||||
intl/Makefile
|
||||
po/Makefile
|
||||
sgsnemu/Makefile
|
||||
tests/Makefile
|
||||
libgtp.pc
|
||||
openggsn.spec])
|
||||
AC_OUTPUT
|
||||
1
contrib/Makefile.am
Normal file
1
contrib/Makefile.am
Normal file
@@ -0,0 +1 @@
|
||||
SUBDIRS = systemd
|
||||
63
contrib/jenkins.sh
Executable file
63
contrib/jenkins.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# jenkins build helper script for openbsc. This is how we build on jenkins.osmocom.org
|
||||
#
|
||||
# environment variables:
|
||||
# * GTP: configure GTP tunneling Linux kernel (values: "--enable-gtp-linux" or "--disable-gtp-linux")
|
||||
# * WITH_MANUALS: build manual PDFs if set to "1"
|
||||
# * PUBLISH: upload manuals after building if set to "1" (ignored without WITH_MANUALS = "1")
|
||||
#
|
||||
|
||||
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
|
||||
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
|
||||
|
||||
osmo-clean-workspace.sh
|
||||
|
||||
mkdir "$deps" || true
|
||||
|
||||
if [ "x$GTP" == "x--enable-gtp-linux" ]; then
|
||||
osmo-build-dep.sh libgtpnl
|
||||
fi
|
||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
|
||||
|
||||
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"
|
||||
export PATH="$inst/bin:$PATH"
|
||||
|
||||
# Additional configure options and depends
|
||||
CONFIG=""
|
||||
if [ "$WITH_MANUALS" = "1" ]; then
|
||||
osmo-build-dep.sh osmo-gsm-manuals
|
||||
CONFIG="--enable-manuals"
|
||||
fi
|
||||
|
||||
set +x
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo " =============================== OsmoGGSN ==============================="
|
||||
echo
|
||||
set -x
|
||||
|
||||
cd "$base"
|
||||
autoreconf --install --force
|
||||
./configure --enable-sanitize --enable-werror $GTP $CONFIG
|
||||
$MAKE $PARALLEL_MAKE
|
||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE distcheck
|
||||
|
||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
osmo-clean-workspace.sh
|
||||
@@ -1,12 +0,0 @@
|
||||
[Unit]
|
||||
Description=OpenGGSN
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/ggsn -c /etc/ggsn.conf -f
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# ggsn This shell script takes care of starting and stopping
|
||||
# ggsn.
|
||||
# osmo-ggsn This shell script takes care of starting and stopping
|
||||
# osmo-ggsn.
|
||||
#
|
||||
# chkconfig: - 65 35
|
||||
# description: ggsn is a Gateway GPRS Support Node.
|
||||
# description: osmo-ggsn is a Gateway GPRS Support Node.
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
@@ -12,18 +12,18 @@
|
||||
# Source networking configuration.
|
||||
. /etc/sysconfig/network
|
||||
|
||||
if [ -f /etc/sysconfig/ggsn ]; then
|
||||
. /etc/sysconfig/ggsn
|
||||
if [ -f /etc/sysconfig/osmo-ggsn ]; then
|
||||
. /etc/sysconfig/osmo-ggsn
|
||||
fi
|
||||
|
||||
# Check that networking is up.
|
||||
[ ${NETWORKING} = "no" ] && exit 0
|
||||
|
||||
[ -f /usr/bin/ggsn ] || exit 0
|
||||
[ -f /etc/ggsn.conf ] || exit 0
|
||||
[ -f /usr/bin/osmo-ggsn ] || exit 0
|
||||
[ -f /etc/osmo-ggsn.cfg ] || exit 0
|
||||
|
||||
RETVAL=0
|
||||
prog="ggsn"
|
||||
prog="osmo-ggsn"
|
||||
|
||||
start() {
|
||||
# Start daemons.
|
||||
@@ -37,30 +37,30 @@ start() {
|
||||
# echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
# Check for runtime directory of nonvolatile data
|
||||
if [ ! -d /var/lib/ggsn ]; then
|
||||
mkdir /var/lib/ggsn
|
||||
if [ ! -d /var/lib/osmo-ggsn ]; then
|
||||
mkdir /var/lib/osmo-ggsn
|
||||
fi
|
||||
|
||||
# Check for GTP restart counter
|
||||
if [ ! -d /var/lib/ggsn/gsn_restart ]; then
|
||||
echo 0 > /var/lib/ggsn/gsn_restart
|
||||
if [ ! -d /var/lib/osmo-ggsn/gsn_restart ]; then
|
||||
echo 0 > /var/lib/osmo-ggsn/gsn_restart
|
||||
fi
|
||||
|
||||
|
||||
daemon /usr/bin/ggsn
|
||||
daemon /usr/bin/osmo-ggsn
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ggsn
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/osmo-ggsn
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop() {
|
||||
# Stop daemons.
|
||||
echo -n $"Shutting down $prog: "
|
||||
killproc ggsn
|
||||
killproc osmo-ggsn
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/ggsn /var/run/ggsn.pid
|
||||
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/osmo-ggsn /var/run/osmo-ggsn.pid
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
@@ -78,14 +78,14 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f /var/lock/subsys/ggsn ] ; then
|
||||
if [ -f /var/lock/subsys/osmo-ggsn ] ; then
|
||||
stop
|
||||
start
|
||||
RETVAL=$?
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status ggsn
|
||||
status osmo-ggsn
|
||||
RETVAL=$?
|
||||
;;
|
||||
*)
|
||||
6
contrib/systemd/Makefile.am
Normal file
6
contrib/systemd/Makefile.am
Normal file
@@ -0,0 +1,6 @@
|
||||
EXTRA_DIST = osmo-ggsn.service
|
||||
|
||||
if HAVE_SYSTEMD
|
||||
systemdsystemunit_DATA = \
|
||||
osmo-ggsn.service
|
||||
endif
|
||||
14
contrib/systemd/osmo-ggsn.service
Normal file
14
contrib/systemd/osmo-ggsn.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=OsmoGGSN
|
||||
After=networking.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
ExecStopPost=/usr/local/bin/save_log_tail osmo-ggsn
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
159
debian/changelog
vendored
159
debian/changelog
vendored
@@ -1,4 +1,161 @@
|
||||
openggsn (0.91+git34) UNRELEASED; urgency=medium
|
||||
osmo-ggsn (1.2.2) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* ggsn_vty.c: fix: use CONFIG_NODE as parent by default
|
||||
|
||||
[ Philipp Maier ]
|
||||
* ggsn: fix misinterpreted length field in ipcp_contains_option()
|
||||
* ggsn: make sure ipcp_option_hdr and and ipcp_hdr are packed
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 31 May 2018 12:44:54 +0200
|
||||
|
||||
osmo-ggsn (1.2.1) unstable; urgency=medium
|
||||
|
||||
* debian/rules: Fix debian packaging after 1.2.0 release
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 04 May 2018 12:19:58 +0200
|
||||
|
||||
osmo-ggsn (1.2.0) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix compiler warnings: return 0 in main(), in 3 tests
|
||||
* add --enable-sanitize config option
|
||||
* sanitize build: ensure uint16/32 alignment in gtpie_test and in46a_test
|
||||
* configure: add --enable-werror
|
||||
* jenkins.sh: use --enable-werror configure flag, not CFLAGS
|
||||
|
||||
[ Harald Welte ]
|
||||
* sgsnemu: Don't leak FILE handle in proc_read()
|
||||
* sgsnemu: Fix format string in printing tun-device name
|
||||
* sgsnemu: Make sure buffer has space for terminating-NUL
|
||||
* sgsnemu: Free strings in error path
|
||||
* gtp: Fix buffer overflow in imsi_gtp2str()
|
||||
* gtp: Explicit OSMO_ASSERT to ensure pdp variable is set
|
||||
* tun: Don't copy 16byte IPv6 address to 'struct in_addr'
|
||||
* ippool: Correctly compute size of static pool
|
||||
* remove unused argument to alloc_ippool_blacklist()
|
||||
* factor out netdev_ip_local_get() from tun_ip_local_get()
|
||||
* Properly NULL-out blacklist in alloc_ippool_blacklist()
|
||||
* gtp_kernel: Change gtp_kernel_init() function signature
|
||||
* gtp-kernel: Re-add support for kernel GTP-U acceleration
|
||||
* gtp-kernel: Get rid of hard-coded kernel GTP device name
|
||||
* gtp-kernel: shut down kernel GTP device in apn_down()
|
||||
* gtp-kernel: Align logging for APN start in kernel-gtp case with that of TUN
|
||||
* gtp-kernel: Avoid global state variable
|
||||
* gtp-kernel: Make sure repeated calls to gtp_kernel_init() are safe
|
||||
* gtp-kernel: proper cleanup in error path
|
||||
* gtp-kernel: Get rid of SYS_ERR where not applicable
|
||||
* gtp-kernel: Add function name to pdp_debug() function calls
|
||||
* gtp-kernel: Add device nime in pdp_debug() log statements
|
||||
* contrib/jenkins.sh: Allow jenkins job to specify if kernel GTP is used
|
||||
* ggsn.c: Fix byte order of IPCP IPv4 DNS servers
|
||||
* ggsn: Ignore PCO with length 0, don't abort processing
|
||||
* README.md: Remove misleading sentence on sgsnemu
|
||||
* Add talloc context introspection via VTY
|
||||
* fix segfault in case of kernel gtp-u
|
||||
* lib/tun.c: Generalize tun_sifflags() to netdev_sifflags
|
||||
* lib/tun.c: generalize tun_*route() to netdev_*route()
|
||||
* lib/tun.c: Generalize tun_{set,add}addr*() functions
|
||||
* lib/tun: split generic network device related stuff to lib/netdev
|
||||
* lib/netdev.c: Cosmetic changes (coding style / cleanups)
|
||||
* ggsn: Don't explicitly use tun_setaddr() API anymore
|
||||
* sgsnemu: Convert from tun_setaddr() to tun_addaddr()
|
||||
* lib/tun: Remove tun_setaddr() API, as everyone is using tun_addaddr() now
|
||||
* Move kernel GTP support from ggsn/ to lib/
|
||||
* ggsn: don't use gtp_kernel_tunnel_{add,del}() for userspace tun
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* ggsn_vty: Stop using deprecated API vty_install_default
|
||||
* contrib/jenkins.sh: Enable Werror in C(PP)FLAGS
|
||||
* examples: Add secondary ipv6 google DNS to osmo-ggsn.cfg
|
||||
* tun_setaddr6: Fix log typo
|
||||
* cosmetic: Reorder tun_addaddr to get rid of decl of tun_setaddr4
|
||||
* ggsn.c: Print version of unhandled ip packet
|
||||
* Remove unused empty src/Makefile.in
|
||||
* tests: Split ipv6 specific tests into a new test group
|
||||
* Add support for IPv4v6 End User Addresses
|
||||
* contrib: jenkins.sh: Build libgtpnl as dep when building with gtp kernel support
|
||||
* cosmetic: sgsnemu.c: Fix trailing whitespace
|
||||
* ggsn.c: Improve logging info on link-local ipv6 addr not found
|
||||
* tun.c: tun_addaddr: Fix segfault and wrong usage of tun_nlattr
|
||||
* Set tun_addaddr ipv agnostic and add support for ipv6
|
||||
* ggsn: Add 'ipv6 link-local' vty cmd
|
||||
* ggsn_vty.c: Print ipv6 link-local cmd when writing config to file
|
||||
* gtp.c: Fix trailing whitespace
|
||||
* gtp.c: Determine GTP version from header
|
||||
* gtp.c: Log unsupported GTP version number
|
||||
* gtp/pdp: Fix trailing whitespace
|
||||
* gtp/pdp: Remove unused APIs pdp_ntoeua pdp_euaton
|
||||
* gtp.c: gtp_gpdu_ind: Convert ifelse to switch statement
|
||||
* gtp.c: gtp_gpdu_ind: Early return to avoid use of uninitialized var
|
||||
* gtp/gtp.c: Remove unused function char2ul_t
|
||||
* gtp/gtp.c: Mark non exported functions as static
|
||||
* gtp/gtp.c: Use uint8_t for version param in static functions
|
||||
* ggsn: encaps_tun: Avoid forwarding packet if EUA is unassigned, fix crash
|
||||
* ggsn: Validate packet src addr from MS
|
||||
* ggsn: Parse PCO_IPCP
|
||||
* ggsn: Parse PCO_IPCP for IPv4v6 pdp ctx
|
||||
* ggsn: Print all addresses on successful pdp ctx creation
|
||||
* ggsn.c: cb_tun_ind: Convert ifelse to switch statement
|
||||
* ggsn.c: cb_tun_ind: log dst addr of packet without pdp ctx
|
||||
* ggsn.c: cb_tun_ind: Don't drop packets targeting pdp ctx ll addr
|
||||
* sgsnemu: Fix bad ptr during context deallocation
|
||||
* sgsnemu: listen param is a host, not an interface
|
||||
* use osmo_init_logging2
|
||||
|
||||
[ Max ]
|
||||
* Log APN and tun names for packets
|
||||
* Enable sanitize for CI tests
|
||||
* Fix stow-enabled jenkins build failure
|
||||
* Add GTP message names
|
||||
|
||||
[ Viktor Tsymbalyuk ]
|
||||
* sgsnemu: sgsnemu stopped after recieving "Request accepted" from ggsn
|
||||
* sgsnemu: created "pinghost" and "createif" modes for mutual exclusion
|
||||
* sgsnemu: fix: no outgoing GTP-U in "createif" mode
|
||||
|
||||
[ Martin Hauke ]
|
||||
* build: Remove AC_PROG_CXX, C++ is never used
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* remove the -f option from osmo-ggsn.service
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 03 May 2018 16:05:27 +0200
|
||||
|
||||
osmo-ggsn (1.1.0) unstable; urgency=medium
|
||||
|
||||
* libgtp: pdp.h: Addition of new tx_gpdu_seq struct member member
|
||||
* libgtp: pdp.h: add LOGPDPX() helper to public API
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Sat, 28 Oct 2017 19:00:23 +0200
|
||||
|
||||
osmo-ggsn (1.0.0) unstable; urgency=medium
|
||||
|
||||
* Transition to OsmoGGSN
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Wed, 06 Sep 2017 12:19:48 +0200
|
||||
|
||||
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.
|
||||
|
||||
|
||||
76
debian/control
vendored
76
debian/control
vendored
@@ -1,36 +1,76 @@
|
||||
Source: openggsn
|
||||
Source: osmo-ggsn
|
||||
Maintainer: Harald Welte <laforge@gnumonks.org>
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Harald Welte <laforge@gnumonks.org>
|
||||
Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libdpkg-perl, git, dh-autoreconf, libosmocore-dev (>= 0.8.0)
|
||||
Build-Depends: debhelper (>= 9),
|
||||
autotools-dev,
|
||||
pkg-config,
|
||||
libdpkg-perl, git,
|
||||
dh-autoreconf,
|
||||
libosmocore-dev (>= 0.8.0)
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://sourceforge.net/projects/ggsn/
|
||||
Vcs-Git: git://ggsn.git.sourceforge.net/gitroot/ggsn/ggsn
|
||||
Vcs-Browser: http://ggsn.git.sourceforge.net/git/gitweb.cgi?p=ggsn/ggsn;a=summary
|
||||
Vcs-Browser: http://git.osmocom.org/osmo-ggsn/
|
||||
Vcs-Git: git://git.osmocom.org/osmo-ggsn
|
||||
Homepage: https://projects.osmocom.org/projects/openggsn
|
||||
|
||||
Package: openggsn
|
||||
Package: osmo-ggsn
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Gateway GPRS Support Node
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
Description: Osmocom Gateway GPRS Support Node (GGSN)
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure.
|
||||
|
||||
Package: libgtp0
|
||||
Package: libgtp3
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Section: libs
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Multi-Arch: same
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
Description: library implementing the GTP protocol between SGSN and GGSN
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure.
|
||||
.
|
||||
This library is part of OsmoGGSN and implements the GTP protocol between
|
||||
SGSN (Serving GPRS support node) and GGSN.
|
||||
|
||||
Package: libgtp0-dev
|
||||
Depends: ${misc:Depends}, libgtp0 (= ${binary:Version})
|
||||
Multi-Arch: same
|
||||
Package: libgtp-dev
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Section: libdevel
|
||||
Depends: ${misc:Depends},
|
||||
libgtp3 (= ${binary:Version})
|
||||
Description: Development files for libgtp
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure.
|
||||
.
|
||||
The library libgtp implements the GTP protocol between SGSN and GGSN
|
||||
and this package contains the development files for this library.
|
||||
|
||||
Package: openggsn-dbg
|
||||
Package: osmo-ggsn-dbg
|
||||
Section: debug
|
||||
Architecture: any
|
||||
Priority: extra
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp0 (= ${binary:Version}), openggsn (= ${binary:Version})
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp3 (= ${binary:Version}), osmo-ggsn (= ${binary:Version})
|
||||
Multi-Arch: same
|
||||
Description: Debug symbols for OpenGGSN
|
||||
Description: Debug symbols for OsmoGGSN
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure.
|
||||
|
||||
Package: libgtp-dbg
|
||||
Section: debug
|
||||
Architecture: any
|
||||
Priority: extra
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libgtp3 (= ${binary:Version})
|
||||
Multi-Arch: same
|
||||
Description: Debug symbols for OsmoGGSN
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure.
|
||||
.
|
||||
The library libgtp implements the GTP protocol between SGSN and GGSN
|
||||
and this package contains the development files for this library.
|
||||
|
||||
89
debian/copyright
vendored
89
debian/copyright
vendored
@@ -1,46 +1,57 @@
|
||||
This work was packaged for Debian by:
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: osmo-ggsn
|
||||
Source: https://osmocom.org/projects/openggsn
|
||||
|
||||
Harald Welte <laforge@gnumonks.org> on Tue, 24 Aug 2010 11:23:40 +0200
|
||||
Files: *
|
||||
Copyright: 2002-2004 Mondru AB, Author: Jens Jakobsen <jj@openggsn.org>
|
||||
2010-2017 Harald Welte <laforge@gnumonks.org>
|
||||
2012-2016 Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
2014-2016 Pablo Neira Ayuso <pablo@gnumonks.org>
|
||||
2014-2016 sysmocom - s.f.m.c. GmbH
|
||||
License: GPL-2
|
||||
|
||||
It was downloaded from:
|
||||
Files: lib/getopt.c
|
||||
lib/gnugetopt.h
|
||||
lib/getopt1.c
|
||||
Copyright: 1987-2001 Free Software Foundation, Inc.
|
||||
License: LGPL-2.1+
|
||||
|
||||
http://sourceforge.net/projects/ggsn
|
||||
Files: debian/*
|
||||
Copyright: 2010-2017 Harald Welte <laforge@gnumonks.org>
|
||||
2016 Ruben Undheim <ruben.undheim@gmail.com>
|
||||
License: GPL-2
|
||||
|
||||
Upstream Author(s):
|
||||
|
||||
Jens Jakobsen <jj@openggsn.org>
|
||||
Harald Welte <laforge@gnumonks.org>
|
||||
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".
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2002 Mondru AB
|
||||
Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>
|
||||
|
||||
License:
|
||||
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This package 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".
|
||||
|
||||
The Debian packaging is:
|
||||
|
||||
Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>
|
||||
|
||||
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.
|
||||
|
||||
# Please also look if there are files or directories which have a
|
||||
# different copyright/license attached and list them here.
|
||||
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".
|
||||
|
||||
3
debian/docs
vendored
3
debian/docs
vendored
@@ -1,2 +1 @@
|
||||
NEWS
|
||||
README
|
||||
README.md
|
||||
|
||||
2
debian/openggsn.examples
vendored
2
debian/openggsn.examples
vendored
@@ -1,2 +0,0 @@
|
||||
examples/ggsn.conf
|
||||
examples/sgsnemu.conf
|
||||
3
debian/openggsn.install
vendored
3
debian/openggsn.install
vendored
@@ -1,3 +0,0 @@
|
||||
/usr/bin/ggsn
|
||||
/usr/bin/sgsnemu
|
||||
/usr/share/man/man8/*
|
||||
2
debian/osmo-ggsn.examples
vendored
Normal file
2
debian/osmo-ggsn.examples
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
doc/examples/osmo-ggsn.cfg
|
||||
doc/examples/sgsnemu.conf
|
||||
18
debian/openggsn.init → debian/osmo-ggsn.init
vendored
18
debian/openggsn.init → debian/osmo-ggsn.init
vendored
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: openggsn
|
||||
# Provides: osmo-ggsn
|
||||
# Required-Start: $network $local_fs $remote_fs
|
||||
# Required-Stop: $network $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
@@ -13,18 +13,18 @@
|
||||
|
||||
# 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"
|
||||
DESC="OsmoGGSN Gateway GPRS Support Node"
|
||||
NAME=ggsn
|
||||
DAEMON=/usr/bin/ggsn
|
||||
DAEMON=/usr/bin/osmo-ggsn
|
||||
DAEMON_ARGS="" # Arguments to run the daemon with
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/openggsn
|
||||
SCRIPTNAME=/etc/init.d/osmo-ggsn
|
||||
|
||||
# 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
|
||||
[ -r /etc/default/osmo-ggsn ] && . /etc/default/osmo-ggsn
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
@@ -46,13 +46,13 @@ do_start()
|
||||
|| return 1
|
||||
|
||||
# Check for runtime directory of nonvolatile data
|
||||
if [ ! -d /var/lib/ggsn ]; then
|
||||
mkdir /var/lib/ggsn
|
||||
if [ ! -d /var/lib/osmo-ggsn ]; then
|
||||
mkdir /var/lib/osmo-ggsn
|
||||
fi
|
||||
|
||||
# Check for GTP restart counter
|
||||
if [ ! -f /var/lib/ggsn/gsn_restart ]; then
|
||||
echo 0 > /var/lib/ggsn/gsn_restart
|
||||
if [ ! -f /var/lib/osmo-ggsn/gsn_restart ]; then
|
||||
echo 0 > /var/lib/osmo-ggsn/gsn_restart
|
||||
fi
|
||||
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
5
debian/osmo-ggsn.install
vendored
Normal file
5
debian/osmo-ggsn.install
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/etc/osmocom/osmo-ggsn.cfg
|
||||
/lib/systemd/system/osmo-ggsn.service
|
||||
/usr/bin/osmo-ggsn
|
||||
/usr/bin/sgsnemu
|
||||
/usr/share/man/man8/*
|
||||
22
debian/rules
vendored
22
debian/rules
vendored
@@ -1,24 +1,22 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
#
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
#
|
||||
# Modified to make a template file for a multi-binary package with separated
|
||||
# build-arch and build-indep targets by Bill Allombert 2001
|
||||
|
||||
# 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_HARDENING=1
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
%:
|
||||
dh $@ --with autoreconf
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=openggsn-dbg
|
||||
dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
|
||||
dh_strip -plibgtp3 --dbg-package=libgtp-dbg
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>Protocol Compliance List</h1>
|
||||
OpenGGSN supports both GTP0 (GSM 09.60) and GTP1 (3GPP 29.060). In the
|
||||
OsmoGGSN supports both GTP0 (GSM 09.60) and GTP1 (3GPP 29.060). In the
|
||||
following tables the support of each individual message type is
|
||||
detailed. The numbers before each feature indicates the relevant
|
||||
section in the standard.<br>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
man_MANS = ggsn.8 sgsnemu.8
|
||||
man_MANS = osmo-ggsn.8 sgsnemu.8
|
||||
man_aux = $(man_MANS:.1=.x)
|
||||
EXTRA_DIST = $(man_MANS)
|
||||
|
||||
|
||||
|
||||
SUBDIRS = \
|
||||
examples \
|
||||
manuals \
|
||||
$(NULL)
|
||||
|
||||
27
doc/examples/Makefile.am
Normal file
27
doc/examples/Makefile.am
Normal file
@@ -0,0 +1,27 @@
|
||||
osmoconfdir = $(sysconfdir)/osmocom
|
||||
osmoconf_DATA = osmo-ggsn.cfg
|
||||
|
||||
EXTRA_DIST = osmo-ggsn.cfg
|
||||
|
||||
CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,'
|
||||
|
||||
dist-hook:
|
||||
for f in $$($(CFG_FILES)); do \
|
||||
j="$(distdir)/$$f" && \
|
||||
mkdir -p "$$(dirname $$j)" && \
|
||||
$(INSTALL_DATA) $(srcdir)/$$f $$j; \
|
||||
done
|
||||
|
||||
install-data-hook:
|
||||
for f in $$($(CFG_FILES)); do \
|
||||
j="$(DESTDIR)$(docdir)/examples/$$f" && \
|
||||
mkdir -p "$$(dirname $$j)" && \
|
||||
$(INSTALL_DATA) $(srcdir)/$$f $$j; \
|
||||
done
|
||||
|
||||
uninstall-hook:
|
||||
@$(PRE_UNINSTALL)
|
||||
for f in $$($(CFG_FILES)); do \
|
||||
j="$(DESTDIR)$(docdir)/examples/$$f" && \
|
||||
$(RM) $$j; \
|
||||
done
|
||||
73
doc/examples/osmo-ggsn.cfg
Normal file
73
doc/examples/osmo-ggsn.cfg
Normal file
@@ -0,0 +1,73 @@
|
||||
!
|
||||
! OpenGGSN (0.94.1-adac) configuration saved from vty
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 0
|
||||
logging timestamp 0
|
||||
logging level ip info
|
||||
logging level tun info
|
||||
logging level ggsn info
|
||||
logging level sgsn notice
|
||||
logging level icmp6 notice
|
||||
logging level lglobal notice
|
||||
logging level llapd notice
|
||||
logging level linp notice
|
||||
logging level lmux notice
|
||||
logging level lmi notice
|
||||
logging level lmib notice
|
||||
logging level lsms notice
|
||||
logging level lctrl notice
|
||||
logging level lgtp info
|
||||
logging level lstats notice
|
||||
logging level lgsup notice
|
||||
logging level loap notice
|
||||
logging level lss7 notice
|
||||
logging level lsccp notice
|
||||
logging level lsua notice
|
||||
logging level lm3ua notice
|
||||
logging level lmgcp notice
|
||||
!
|
||||
stats interval 5
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
ggsn ggsn0
|
||||
gtp state-dir /tmp
|
||||
gtp bind-ip 127.0.0.6
|
||||
apn internet
|
||||
gtpu-mode tun
|
||||
tun-device tun4
|
||||
type-support v4
|
||||
ip prefix dynamic 176.16.222.0/24
|
||||
ip dns 0 192.168.100.1
|
||||
ip dns 1 8.8.8.8
|
||||
ip ifconfig 176.16.222.0/24
|
||||
no shutdown
|
||||
apn inet6
|
||||
gtpu-mode tun
|
||||
tun-device tun6
|
||||
type-support v6
|
||||
ipv6 prefix dynamic 2001:780:44:2000:0:0:0:0/56
|
||||
ipv6 dns 0 2001:4860:4860::8888
|
||||
ipv6 dns 1 2001:4860:4860::8844
|
||||
ipv6 ifconfig 2001:780:44:2000:0:0:0:0/56
|
||||
no shutdown
|
||||
apn inet46
|
||||
gtpu-mode tun
|
||||
tun-device tun46
|
||||
type-support v4v6
|
||||
ip prefix dynamic 176.16.46.0/24
|
||||
ip dns 0 192.168.100.1
|
||||
ip dns 1 8.8.8.8
|
||||
ip ifconfig 176.16.46.0/24
|
||||
ipv6 prefix dynamic 2001:780:44:2100:0:0:0:0/56
|
||||
ipv6 dns 0 2001:4860:4860::8888
|
||||
ipv6 dns 1 2001:4860:4860::8844
|
||||
ipv6 ifconfig 2001:780:44:2100:0:0:0:0/56
|
||||
no shutdown
|
||||
default-apn internet
|
||||
no shutdown ggsn
|
||||
16
doc/manuals/Makefile.am
Normal file
16
doc/manuals/Makefile.am
Normal file
@@ -0,0 +1,16 @@
|
||||
EXTRA_DIST = osmoggsn-usermanual.adoc \
|
||||
osmoggsn-usermanual-docinfo.xml \
|
||||
osmoggsn-vty-reference.xml \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
if BUILD_MANUALS
|
||||
ASCIIDOC = osmoggsn-usermanual.adoc
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||
|
||||
VTY_REFERENCE = osmoggsn-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
|
||||
endif
|
||||
335
doc/manuals/chapters/configuration.adoc
Normal file
335
doc/manuals/chapters/configuration.adoc
Normal file
@@ -0,0 +1,335 @@
|
||||
== Configuring OsmoGGSN
|
||||
|
||||
All configuration of OsmoGGSN is performed using the VTY. For more
|
||||
general information on the VTY interface, see <<vty>>.
|
||||
|
||||
=== Configuring a virtual GGSN instance
|
||||
|
||||
OsmoGGSN can run multiple GGSN instances inside one program/process.
|
||||
Each GGSN instance binds to its own transport-layer GTP IP address and
|
||||
has its own set of APNs and associated IP address pools + tun/gtp
|
||||
devices.
|
||||
|
||||
In most usage cases, yo will only have a single GGSN instance inside
|
||||
your configuration file, like in below example:
|
||||
|
||||
.Example: Single GGSN configuration section
|
||||
----
|
||||
ggsn ggsn0
|
||||
gtp state-dir /tmp
|
||||
gtp bind-ip 127.0.0.6
|
||||
apn internet
|
||||
gtpu-mode tun
|
||||
tun-device tun4
|
||||
type-support v4
|
||||
ip prefix dynamic 176.16.222.0/24
|
||||
ip dns 0 192.168.100.1
|
||||
ip dns 1 8.8.8.8
|
||||
ip ifconfig 176.16.222.0/24
|
||||
no shutdown
|
||||
----
|
||||
|
||||
|
||||
==== Creating/Editing a GGSN instance
|
||||
|
||||
Creating/Editing a GGSN instance can be done by the following sequence
|
||||
of VTY commands:
|
||||
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Create or edit the GGSN instance `ggsn0`. The name can be any ASCII
|
||||
string, its significance is only to the local user.
|
||||
<4> Your prompt is now in the `ggsn` config node, where you can
|
||||
configure the properties of this GGSN instance.
|
||||
|
||||
NOTE:: After creating a new GGSN instance, it is in `shutdown` mode. See
|
||||
<<unshutdown_apn>> to take it out of shutdown, but make sure to configure it fully
|
||||
before taking it out of shutdown.
|
||||
|
||||
==== Configuring a GGSN instance
|
||||
|
||||
The following two mandatory configuration statements have to be given
|
||||
for every GGSN instance:
|
||||
|
||||
----
|
||||
OsmoGGSN(config-ggsn)# gtp state-dir /var/lib/ggsn/ggsn0 <1>
|
||||
OsmoGGSN(config-ggsn)# gtp bind-ip 127.0.0.6 <2>
|
||||
----
|
||||
<1> Store the GSN restart state in the specified directory
|
||||
<2> Bind the GGSN instance to the specified local IPv4 address
|
||||
|
||||
There are some further configuration statements that can be used at the
|
||||
GGSN node, some examples are given below. For a full list, see the
|
||||
_OsmoGGSN VTY reference manual_ <<vty-ref-osmoggsn>>.
|
||||
|
||||
----
|
||||
OsmoGGSN(config-ggsn)# default-apn foobar <1>
|
||||
----
|
||||
<1> Configure a default APN to be used if the user-requested APN is not
|
||||
found. The named APN must previously be configured
|
||||
|
||||
|
||||
==== Deleting a GGSN instance
|
||||
|
||||
A GGSN instance can be removed like this
|
||||
|
||||
.Example: Deleting a GGSN instance
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# no ggsn ggsn0 <3>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Delete the GGSN instance
|
||||
|
||||
|
||||
==== Taking a GGSN instance out of shutdown
|
||||
|
||||
.Example: Taking a GGSN instance out of shutdown
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# no shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Take the GGSN instance out of shutdown
|
||||
|
||||
|
||||
==== Shutting a GGSN instance down
|
||||
|
||||
If you would like to take a GGSN instance out of service, you can
|
||||
put it into shutdown mode. This will make the entire GGSN unavailable
|
||||
to user traffic and permit you to e.g. reconfigure it before taking it
|
||||
out of shutdown again.
|
||||
|
||||
.Example: Shutting down a GGSN instance
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Shut down the GGSN instance
|
||||
|
||||
|
||||
=== Configuring an Access Point Name
|
||||
|
||||
An Access Point Name (APN) represents a connection to an external packet
|
||||
data network, such as the public Internet or private corporate networsk.
|
||||
|
||||
APNs are selected by terminals (MS/UE) when establishing PDP contexts.
|
||||
|
||||
Each OsmoGGSN GGSN instance can have any number of APNs configured.
|
||||
Each APN is identified by a string name.
|
||||
|
||||
==== Creating/Editing an APN
|
||||
|
||||
.Example: Creating a new APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Create or Edit an APN called `internet`
|
||||
<5> Your prompt is now in the `ggsn` config node, where you can
|
||||
configure the properties of this GGSN instance.
|
||||
|
||||
NOTE:: The newly-create APN is created in `shutdown` mode. See <<unshutdown_apn>> to take it
|
||||
out of shutdown.
|
||||
|
||||
|
||||
==== Configuring an APN
|
||||
|
||||
.Example: Configuring an APN
|
||||
----
|
||||
OsmoGGSN(config-ggsn-apn)# gtpu-mode tun <1>
|
||||
OsmoGGSN(config-ggsn-apn)# type-support v4 <2>
|
||||
OsmoGGSN(config-ggsn-apn)# ip prefix dynamic 176.16.222.0/24 <3>
|
||||
OsmoGGSN(config-ggsn-apn)# ip dns 0 192.168.100.1 <4>
|
||||
OsmoGGSN(config-ggsn-apn)# ip dns 1 8.8.8.8 <5>
|
||||
OsmoGGSN(config-ggsn-apn)# ip ifconfig 176.16.222.0/24 <6>
|
||||
----
|
||||
<1> Use the userspace GTP-U handling using a TUN device
|
||||
<2> Support (only) IPv4 Addresses
|
||||
<3> Specify the pool of dynamic IPv4 addresses to be allocated to PDP
|
||||
contexts
|
||||
<4> Specify the primary DNS server to be provided using IPCP/PCO
|
||||
<5> Specify the secondary DNS server to be provided using IPCP/PCO
|
||||
<6> Request OsmoGGSN to configure the `tun4` device network/netmask
|
||||
|
||||
NOTE:: If you use the optional `ip ifconfig` command to set the network
|
||||
device address/mask, OsmoGGSN must run with root or `CAP_NET_ADMIN`
|
||||
support. It might be better to configure related tun devices at system
|
||||
startup and run OsmoGGSN as non-privileged user. See <<ggsn_no_root>> for more
|
||||
details.
|
||||
|
||||
|
||||
==== Deleting an APN
|
||||
|
||||
An APN configuration can be removed like this
|
||||
|
||||
.Example: Deleting an APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# no apn internet <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Delete the APN `internet`
|
||||
|
||||
[[unshutdown_apn]]
|
||||
==== Taking an APN out of shutdown
|
||||
|
||||
In order to bring a deactived APN in `shutdown` state into active
|
||||
operation, use the `no shutdown` command at the APN node as explained in
|
||||
the following example:
|
||||
|
||||
.Example: Taking an APN out of shutdown
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# no shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<5> Take the APN out of shutdown
|
||||
|
||||
|
||||
==== Shutting an APN down
|
||||
|
||||
If you would like to take an APN instance out of service, you can
|
||||
put it into shutdown mode. This will make the APN unavailable
|
||||
to user traffic and permit you to e.g. reconfigure it before taking it
|
||||
out of shutdown again.
|
||||
|
||||
.Example: Shutting down an APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<5> Shut down the APN
|
||||
|
||||
[[ggsn_no_root]]
|
||||
=== Configuring for running without root privileges
|
||||
|
||||
It's possible to run OsmoGGSN without root privileges if the tun devices are already configured.
|
||||
|
||||
The interface creation + configuration must then happen before osmo-ggsn starting up. This can be
|
||||
achieved by means such as
|
||||
|
||||
* a custom shell script run as root before starting osmo-ggsn (e.g. as init script)
|
||||
* systemd .netdev and .network files, if your system is using systemd-networkd (see `networkctl status`).
|
||||
|
||||
==== Manual TUN device creation / configuration
|
||||
|
||||
If you chose to go for custom shell/init scripts, you may use the `ip` program which is the standard
|
||||
tool for network interface configuration on Linux, part of the `iproute2` package. In order to
|
||||
create a tun device, you must call it like this:
|
||||
|
||||
.Example: iproute2 command to create a tun device
|
||||
----
|
||||
# ip tuntap add dev apn0 mode tun user username group groupname
|
||||
----
|
||||
|
||||
Where _username_ and _groupname_ correspond to the User and Group that will have ownership over the
|
||||
device, i.e. the privileges which you intend to run osmo-ggsn under, and _apn0_ will be the
|
||||
name of the network device created. After creating the interface, you can configure its addresses
|
||||
using standard means like `ip addr add` or your distribution-specific utilities/tools
|
||||
to match the `ip prefix dynamic` config item, and activate the link, for example:
|
||||
|
||||
----
|
||||
# ip addr add 192.168.7.0/24 dev apn0
|
||||
# ip link set apn0 up
|
||||
----
|
||||
|
||||
==== systemd based TUN device creation+configuration
|
||||
|
||||
If you want to have systemd take care of creating and configuring a tun device for you,
|
||||
you can use the below example config files.
|
||||
|
||||
.Example: device config via systemd-networkd using apn0.netdev
|
||||
----
|
||||
[NetDev]
|
||||
Name=apn0 <1>
|
||||
Kind=tun
|
||||
|
||||
[Tun]
|
||||
User=username <2>
|
||||
Group=username <3>
|
||||
----
|
||||
<1> The network interface name of the newly-created device
|
||||
<2> The username under which you will run OsmoGGSN
|
||||
<3> The group name under which you will run OsmoGGSN
|
||||
|
||||
.Example: network settings via systemd-networkd using ggsn.network
|
||||
----
|
||||
[Match]
|
||||
Name=apn0 <1>
|
||||
|
||||
[Network]
|
||||
Address=192.168.7.1 <2>
|
||||
IPMasquerade=yes <3>
|
||||
----
|
||||
<1> The netowrk device name, which must match the one in the apn0.netdev unit file above
|
||||
<2> The local IP address configured on the device
|
||||
<3> Requesting systemd to configure IP masquerading for this interface. Depending on your needs,
|
||||
You may not want this if you have proper end-to-end routing set up, and want to have transparent
|
||||
inbound IP access to your GPRS-attached devices.
|
||||
|
||||
==== Config Changes
|
||||
|
||||
With the tun device pre-configured in one of the ways outlined above, the main
|
||||
changes in your osmo-ggsn.cfg file are:
|
||||
|
||||
* remove `ip ifconfig` directive,
|
||||
* make sure that `no shutdown` is present in the `apn` section as well as
|
||||
`no shutdown ggsn` in the `ggsn` section.
|
||||
|
||||
.Example: using externally configured tun device `apn0` as non-root
|
||||
----
|
||||
ggsn ggsn0
|
||||
gtp state-dir /tmp
|
||||
gtp bind-ip 127.0.0.6
|
||||
apn internet
|
||||
gtpu-mode tun
|
||||
tun-device apn0
|
||||
type-support v4
|
||||
ip prefix dynamic 192.168.7.0/24
|
||||
ip dns 0 192.168.100.1
|
||||
ip dns 1 8.8.8.8
|
||||
no shutdown
|
||||
default-apn internet
|
||||
no shutdown ggsn
|
||||
----
|
||||
145
doc/manuals/chapters/overview.adoc
Normal file
145
doc/manuals/chapters/overview.adoc
Normal file
@@ -0,0 +1,145 @@
|
||||
[[chapter_introduction]]
|
||||
== Overview
|
||||
|
||||
[[intro_overview]]
|
||||
=== About OsmoGGSN
|
||||
|
||||
OsmoGGSN is a Free / Open Source Software implementation of the GPRS
|
||||
GGSN (Gateway GPRS support node) element in side the packet switched
|
||||
core network of 2G and 3G cellular networks.
|
||||
|
||||
The GGSN function is the tunnel endpoint on the core network side,
|
||||
from where the external (IP) packet data network
|
||||
|
||||
=== Software Components
|
||||
|
||||
==== GTP Implementation (libgtp)
|
||||
|
||||
The OsmoGGSN source code includes a shared library implementation of
|
||||
the GTP protocol used on the GGSN-SGSN interface. This library
|
||||
and associated header files are installed system-wide and are
|
||||
available to other programs/applications.
|
||||
|
||||
In fact, libgtp is what the OsmoSGSN also uses for its use of GTP.
|
||||
|
||||
==== sgsnemu
|
||||
|
||||
In order to test OsmoGGSN without running a SGSN and other elements
|
||||
of a cellular network, there is a small command-line utility called
|
||||
*sgsnemu* which is able to simulate the customary operations of a SGSN
|
||||
towards the GGSN, such as a PDP Context Activation.
|
||||
|
||||
*sgsnemu* can even be used for testing against other GGSNs, as the GTP
|
||||
protocol is standardized across implementations.
|
||||
|
||||
==== osmo-ggsn
|
||||
|
||||
*osmo-ggsn* is the actual name of the OsmoGGSN executable program. It
|
||||
implements the GGSN functionality. All parameters are set using the
|
||||
configuration file, by default located in *./osmo-ggsn.cfg*
|
||||
|
||||
==== systemd service file
|
||||
|
||||
In *contrib/osmo-ggsn.service* you can find a sample service file for
|
||||
OsmoGGSN which can be used with systemd.
|
||||
|
||||
==== init script
|
||||
|
||||
In *contrib/osmo-ggsn.init* you can find a sample init script to be used
|
||||
on systems with classic init process.
|
||||
|
||||
=== Limitations
|
||||
|
||||
OsmoGGSN supports both GTP0 (GSM 09.60) and GTP1 (3GPP 29.060). In the
|
||||
following tables the support of each individual message type is
|
||||
detailed. The numbers before each feature indicates the relevant
|
||||
section in the standard.
|
||||
|
||||
==== GSM 09.60 (GTPv0)
|
||||
|
||||
[options="header",cols="50%,15%,15%,15%,5%"]
|
||||
|===
|
||||
| Feature | gtplib | osmo-ggsn | sgsnemu | notes
|
||||
5+<|*7.4 Path Management Messages*
|
||||
|7.4.1 Echo Request |Supported |Supported |Supported |
|
||||
|7.4.2 Echo Response |Supported |Supported |Supported |
|
||||
|7.4.3 Version Not Supported |Supported |Supported |Supported |
|
||||
5+<| *7.5 Tunnel Management Messages*
|
||||
|7.5.1 Create PDP Context Request|Supported |Supported |Supported |
|
||||
|7.5.2 Create PDP Context Response|Supported |Supported |Supported |
|
||||
|7.5.3 Update PDP Context Request|Supported |Supported |Not |
|
||||
|7.5.4 Update PDP Context Response|Supported |Supported |Not |
|
||||
|7.5.5 Delete PDP Context Request|Supported |Supported |Supported |
|
||||
|7.5.6 Delete PDP Context Response|Supported |Supported |Supported |
|
||||
|7.5.7 Create AA PDP Context Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.8 Create AA PDP Response|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.9 Delete AA PDP Context Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.10 Delete AA PDP Context Response|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.11 Error Indication |Supported |Supported |Supported |
|
||||
|7.5.12 PDU Notification Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.13 PDU Notification Response|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.14 PDU Notification Reject Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.5.15 PDU Notification Reject Response|Unsupported |Unsupported |Unsupported |
|
||||
5+<| *7.6 Location Management Messages*
|
||||
|7.6.1 Send Routeing Information for GPRS Request|Unsupported |Unsupported |Not applicable |
|
||||
|7.6.2 Send Routeing Information for GPRS Response|Unsupported |Unsupported |Not applicable |
|
||||
|7.6.3 Failure Report Request|Unsupported |Unsupported |Not applicable |
|
||||
|7.6.3 Failure Report Response|Unsupported |Unsupported |Not applicable |
|
||||
|7.6.5 Note MS GPRS Present Request|Unsupported |Unsupported |Not applicable|
|
||||
|7.6.6 Note MS GPRS Present Response|Unsupported |Unsupported |Not applicable|
|
||||
5+<| *7.5 Mobility Management Messages*
|
||||
|7.5.1 Identification Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.2 Identification Response|Unsupported |Not applicable|Not applicable |
|
||||
|7.5.3 SGSN Context Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.4 SGSN Context Response|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.5 SGSN Context Acknowledge|Unsupported |Not applicable|Not applicable|
|
||||
|===
|
||||
|
||||
==== 3GPP 29.060 (GTPv1)
|
||||
|
||||
[options="header",cols="50%,15%,15%,15%,5%"]
|
||||
|===
|
||||
|Feature |gtplib |osmo-ggsn |sgsnemu |notes
|
||||
5+<|*7.2 Path Management Messages*
|
||||
|7.2.1 Echo Request |Supported |Supported |Supported |
|
||||
|7.2.2 Echo Response |Supported |Supported |Supported |
|
||||
|7.2.3 Version Not Supported|Supported |Supported |Supported |
|
||||
|7.2.4 Extension Headers Notification|Supported |Supported |Supported |
|
||||
5+<|*7.3 Tunnel Management Messages*
|
||||
|7.3.1 Create PDP Context Request|Supported |Supported |Supported |1
|
||||
|7.3.2 Create PDP Context Response|Supported |Supported |Supported |
|
||||
|7.3.3 Update PDP Context Request|Supported |Supported |Not applicable|1
|
||||
|7.3.4 Update PDP Context Response|Supported |Supported |Not applicable|
|
||||
|7.3.5 Delete PDP Context Request|Supported |Supported |Supported |
|
||||
|7.3.6 Delete PDP Context Response|Supported |Supported |Supported |
|
||||
|7.3.7 Error Indication |Supported |Supported |Supported |
|
||||
|7.3.8 PDU Notification Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.3.9 PDU Notification Response|Unsupported |Unsupported |Unsupported |
|
||||
|7.3.10 PDU Notification Reject Request|Unsupported |Unsupported |Unsupported |
|
||||
|7.3.10 PDU Notification Reject Response|Unsupported |Unsupported |Unsupported |
|
||||
5+<|*7.4 Location Management Messages*
|
||||
|7.4.1 Send Routeing Information for GPRS Request|Unsupported |Unsupported |Not applicable |
|
||||
|7.4.2 Send Routeing Information for GPRS Response|Unsupported |Unsupported |Not applicable |
|
||||
|7.4.3 Failure Report Request|Unsupported |Unsupported |Not applicable|
|
||||
|7.4.3 Failure Report Response|Unsupported |Unsupported |Not applicable|
|
||||
|7.4.5 Note MS GPRS Present Request|Unsupported |Unsupported |Not applicable|
|
||||
|7.4.6 Note MS GPRS Present Response|Unsupported |Unsupported |Not applicable|
|
||||
5+<|*7.5 Mobility Management Messages*
|
||||
|7.5.1 Identification Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.2 Identification Response|Unsupported |Not applicable |Not applicable|
|
||||
|7.5.3 SGSN Context Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.4 SGSN Context Response|Unsupported |Not applicable |Not applicable|
|
||||
|7.5.5 SGSN Context Acknowledge|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.6 Forward Relocation Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.7 Forward Relocation Response|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.8 Forward Relocation Complete|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.9 Relocation Cancel Request|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.10 Relocation Cancel Response|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.11 Forward Relocation Complete |Unsupported |Not applicable |Not applicable |
|
||||
|7.5.12 Forward SRNS Context Acknowledge|Unsupported |Not applicable|Not applicable|
|
||||
|7.5.13 Forward SRNS Context|Unsupported |Not applicable|Not applicable|
|
||||
|===
|
||||
|
||||
Notes
|
||||
|
||||
1) The "Secondary PDP Context Activation Procedure" is not supported.
|
||||
82
doc/manuals/chapters/running.adoc
Normal file
82
doc/manuals/chapters/running.adoc
Normal file
@@ -0,0 +1,82 @@
|
||||
== Running OsmoGGSN
|
||||
|
||||
The OsmoGGSN executable (`osmo-ggsn`) offers the following command-line
|
||||
arguments:
|
||||
|
||||
=== SYNOPSIS
|
||||
|
||||
*osmo-ggsn* [-h|-V] [-D] [-c 'CONFIGFILE']
|
||||
|
||||
=== OPTIONS
|
||||
|
||||
*-h, --help*::
|
||||
Print a short help message about the supported options
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the OsmoBTS program
|
||||
*-D, --daemonize*::
|
||||
Fork the process as a daemon into background.
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
Specify the file and path name of the configuration file to be
|
||||
used. If none is specified, use `osmo-ggsn.cfg` in the current
|
||||
working directory.
|
||||
|
||||
=== Routing
|
||||
|
||||
Operating the OpenGGSN tun device naturally creates a network setup with
|
||||
multiple interfaces. Consider:
|
||||
|
||||
* Typical Linux setups prevent forwarding of packets between separate
|
||||
interfaces by default. To let subscribers reach the internet uplink from the
|
||||
tun device, it may be required to enable IP forwarding.
|
||||
|
||||
* Having a locally defined address range assigned to the tun device requires
|
||||
either sensible routing for this address range, or that masquerading is
|
||||
enabled to allow your single uplink IP address to "proxy" for the tun.
|
||||
|
||||
These are decisions to be made on a network administration level.
|
||||
|
||||
In a trivial case where you have a single box serving GPRS to few subscribers
|
||||
on an arbitrary IP address range not known in the larger network, the easiest
|
||||
way to enable GPRS uplink would be to enable IP forwarding and masquerading.
|
||||
|
||||
To manually enable IPv4 forwarding and masquerading ad-hoc, you can do:
|
||||
|
||||
----
|
||||
sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
|
||||
iptables -t nat -A POSTROUTING -o '*' -j MASQUERADE
|
||||
----
|
||||
|
||||
(You may want to replace `*` with the network device name, like `-o eth0`)
|
||||
|
||||
There are various ways to enable these settings persistently, please refer to
|
||||
your distribution's documentation -- e.g. look for @net.ipv4.ip_forward=1@ in
|
||||
@/etc/sysctl.d/@, and https://wiki.debian.org/iptables for masquerading.
|
||||
|
||||
=== Multiple instances
|
||||
|
||||
Running multiple instances of `osmo-ggsn` is possible if all GGSN instances
|
||||
are binding to different local IP addresse and all other interfaces (VTY,
|
||||
OML) are separated using the appropriate configuration options. The IP based
|
||||
interfaces are binding to local host by default. In order to separate the
|
||||
processes, the user has to bind those services to specific but different
|
||||
IP addresses.
|
||||
|
||||
The VTY and the control interface can be bound to IP addresses from the loopback
|
||||
address range.
|
||||
|
||||
.Example: Binding VTY and control interface to a specific ip-address
|
||||
----
|
||||
line vty
|
||||
bind 127.0.0.2
|
||||
ctrl
|
||||
bind 127.0.0.2
|
||||
----
|
||||
|
||||
Also make sure to place each instance's GTP bind on a separate IP address (GTP
|
||||
uses a port number that is fixed in the GTP specifications, so it will not be
|
||||
possible to pick differing ports on the same IP address), like:
|
||||
|
||||
----
|
||||
ggsn ggsn0
|
||||
gtp bind-ip 127.0.0.2
|
||||
----
|
||||
46
doc/manuals/osmoggsn-usermanual-docinfo.xml
Normal file
46
doc/manuals/osmoggsn-usermanual-docinfo.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>1</revnumber>
|
||||
<date>August 2017</date>
|
||||
<authorinitials>HW</authorinitials>
|
||||
<revremark>
|
||||
Initial version.
|
||||
</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Harald</firstname>
|
||||
<surname>Welte</surname>
|
||||
<email>hwelte@sysmocom.de</email>
|
||||
<authorinitials>HW</authorinitials>
|
||||
<affiliation>
|
||||
<shortaffil>sysmocom</shortaffil>
|
||||
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
|
||||
<jobtitle>Managing Director</jobtitle>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2013-2017</year>
|
||||
<holder>sysmocom - s.f.m.c. GmbH</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
Permission is granted to copy, distribute and/or modify this
|
||||
document under the terms of the GNU Free Documentation License,
|
||||
Version 1.3 or any later version published by the Free Software
|
||||
Foundation; with no Invariant Sections, no Front-Cover Texts,
|
||||
and no Back-Cover Texts. A copy of the license is included in
|
||||
the section entitled "GNU Free Documentation License".
|
||||
</para>
|
||||
<para>
|
||||
The Asciidoc source code of this manual can be found at
|
||||
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
|
||||
http://git.osmocom.org/osmo-gsm-manuals/
|
||||
</ulink>
|
||||
</para>
|
||||
</legalnotice>
|
||||
29
doc/manuals/osmoggsn-usermanual.adoc
Normal file
29
doc/manuals/osmoggsn-usermanual.adoc
Normal file
@@ -0,0 +1,29 @@
|
||||
OsmoGGSN User Manual
|
||||
====================
|
||||
Harald Welte <hwelte@sysmocom.de>
|
||||
|
||||
|
||||
include::./common/chapters/preface.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/overview.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/running.adoc[]
|
||||
|
||||
//include::{srcdir}/chapters/control.adoc[]
|
||||
|
||||
include::./common/chapters/vty.adoc[]
|
||||
|
||||
include::./common/chapters/logging.adoc[]
|
||||
|
||||
|
||||
include::{srcdir}/chapters/configuration.adoc[]
|
||||
|
||||
include::./common/chapters/control_if.adoc[]
|
||||
|
||||
include::./common/chapters/port_numbers.adoc[]
|
||||
|
||||
include::./common/chapters/bibliography.adoc[]
|
||||
|
||||
include::./common/chapters/glossary.adoc[]
|
||||
|
||||
include::./common/chapters/gfdl.adoc[]
|
||||
38
doc/manuals/osmoggsn-vty-reference.xml
Normal file
38
doc/manuals/osmoggsn-vty-reference.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
ex:ts=2:sw=42sts=2:et
|
||||
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
-->
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
|
||||
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
|
||||
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
|
||||
<!ENTITY sections-vty SYSTEM "generated/docbook_vty.xml" >
|
||||
]>
|
||||
|
||||
<book>
|
||||
<info>
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>v1</revnumber>
|
||||
<date>06th September 2017</date>
|
||||
<authorinitials>hw</authorinitials>
|
||||
<revremark>Initial version as of OsmoGGSN v1.0.0</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<title>OsmoGGSN VTY Reference</title>
|
||||
|
||||
<copyright>
|
||||
<year>2017</year>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</info>
|
||||
|
||||
<!-- Main chapters-->
|
||||
&chapter-vty;
|
||||
</book>
|
||||
|
||||
30
doc/manuals/vty/ggsn_vty_additions.xml
Normal file
30
doc/manuals/vty/ggsn_vty_additions.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
||||
<node id='config-line'>
|
||||
<child_of nodeid='config' />
|
||||
<name>Telnet/VTY Configuration Node</name>
|
||||
<description>
|
||||
Configure parameters of the Telnet/VTY Interface, such as to which IP address it should bind/listen to.
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ctrl'>
|
||||
<child_of nodeid='config' />
|
||||
<name>CTRL Configuration Node</name>
|
||||
<description>
|
||||
Configure parameters of the CTRL Interface, such as to which IP address it should bind/listen to.
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ggsn'>
|
||||
<child_of nodeid='config' />
|
||||
<name>GGSN Instance Configuration Node</name>
|
||||
<description>
|
||||
Configure an Instance of a (virtual) GGSN
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ggsn-apn'>
|
||||
<child_of nodeid='config-ggsn' />
|
||||
<name>APN Configuration Node</name>
|
||||
<description>
|
||||
Configure an Access Point Name (APN) inside a GGSN Instance
|
||||
</description>
|
||||
</node>
|
||||
</vtydoc>
|
||||
1447
doc/manuals/vty/ggsn_vty_reference.xml
Normal file
1447
doc/manuals/vty/ggsn_vty_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
|
||||
.\" * OpenGGSN - Gateway GPRS Support Node
|
||||
.\" * OsmoGGSN - Gateway GPRS Support Node
|
||||
.\" * Copyright (C) 2002, 2003 Mondru AB.
|
||||
.\" *
|
||||
.\" * The contents of this file may be used under the terms of the GNU
|
||||
@@ -12,57 +12,37 @@
|
||||
.\" *
|
||||
.\" * Contributor(s):
|
||||
.\" *
|
||||
.\" Manual page for ggsn
|
||||
.\" Manual page for osmo-ggsn
|
||||
.\" SH section heading
|
||||
.\" SS subsection heading
|
||||
.\" LP paragraph
|
||||
.\" IP indented paragraph
|
||||
.\" TP hanging label
|
||||
|
||||
.TH ggsn 8 "July 2003"
|
||||
.TH osmo-ggsn 8 "August 2017"
|
||||
.SH NAME
|
||||
ggsn \- Gateway GPRS Support Node.
|
||||
osmo-ggsn \- Gateway GPRS Support Node.
|
||||
.SH SYNOPSIS
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
\-\-help
|
||||
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
\-\-version
|
||||
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
[
|
||||
.BI \-\-fg
|
||||
.BI \-\-help
|
||||
] [
|
||||
.BI \-\-debug
|
||||
.BI \-\-daemonize
|
||||
] [
|
||||
.BI \-\-conf " file"
|
||||
.BI \-\-config-file " file"
|
||||
] [
|
||||
.BI \-\-pidfile " file"
|
||||
] [
|
||||
.BI \-\-statedir " file"
|
||||
] [
|
||||
.BI \-\-listen " host"
|
||||
] [
|
||||
.BI \-\-net " net"
|
||||
] [
|
||||
.BI \-\-ipup " script"
|
||||
] [
|
||||
.BI \-\-ipdown " script"
|
||||
] [
|
||||
.BI \-\-dynip " net"
|
||||
] [
|
||||
.BI \-\-statip " net"
|
||||
] [
|
||||
.BI \-\-pcodns1 " host"
|
||||
] [
|
||||
.BI \-\-pcodns2 " host"
|
||||
] [
|
||||
.BI \-\-timelimit " seconds"
|
||||
.BI \-\-version
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
is part of the
|
||||
.B OpenGGSN
|
||||
.B OsmoGGSN
|
||||
project, and implements a Gateway GPRS Support Node. It is used by
|
||||
mobile operators as the interface between the Internet and the rest of
|
||||
the mobile network infrastructure.
|
||||
@@ -82,14 +62,14 @@ over IP.
|
||||
The other interface can be thought of as the uplink interface, and
|
||||
interfaces the GGSN to an external data network. Gi is most often an
|
||||
interface to the Internet.
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
uses the
|
||||
.B TUN/TAP driver
|
||||
for the Gi interface. A tun network interface is established when the
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
is started.
|
||||
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
will accept incoming connections from mobile stations through the
|
||||
radio access network and the SGSN. When a connection request is
|
||||
received the ggsn will allocate a dynamic IP address for the mobile
|
||||
@@ -99,7 +79,7 @@ the SGSN. Runtime errors are reported using the Osmocom logging
|
||||
framework.
|
||||
|
||||
Typically
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
will be deployed with two Ethernet interfaces. One for the Gn/Gp
|
||||
interface, and one for the Gi interface. Policy routing and firewall
|
||||
rules should be used in order to separate Gi traffic from Gn/Gp
|
||||
@@ -115,104 +95,35 @@ Print help and exit.
|
||||
Print version and exit.
|
||||
|
||||
.TP
|
||||
.BI --fg
|
||||
Run in foreground (default = off)
|
||||
.BI --daemonize
|
||||
Run in background as a daemon (default = off)
|
||||
|
||||
.TP
|
||||
.BI --debug
|
||||
Run in debug mode (default = off)
|
||||
|
||||
.TP
|
||||
.BI --conf " file"
|
||||
.BI --config-file " file"
|
||||
Read configuration
|
||||
.I file
|
||||
(default = /etc/ggsn.conf) where each line corresponds to one command
|
||||
line option, but with the leading '--' removed. Command line options
|
||||
override the options given in the configuration file.
|
||||
|
||||
.TP
|
||||
.BI --pidfile " file"
|
||||
Filename of process id
|
||||
.I file
|
||||
(default = /var/run/ggsn.pid)
|
||||
|
||||
.TP
|
||||
.BI --statedir " path"
|
||||
.I path
|
||||
to directory of nonvolatile data (default = /var/lib/ggsn/)
|
||||
|
||||
.TP
|
||||
.BI --listen " host"
|
||||
Local interface IP address to use for the Gn/Gp interface. This option
|
||||
must be specified. For security issues it is not possible to use
|
||||
INADDR_ANY.
|
||||
|
||||
.TP
|
||||
.BI --net " net"
|
||||
Network address of the Gi interface (default = 192.168.0.0/24). The
|
||||
network address is set during initialisation when
|
||||
.B ggsn
|
||||
establishes a tun device for the Gi interface.
|
||||
|
||||
.TP
|
||||
.BI --ipup " script"
|
||||
Script executed after the Gi tun network interface has been brought
|
||||
up. Executed with the following parameters: <devicename> <ip address>
|
||||
|
||||
.TP
|
||||
.BI --ipdown " script"
|
||||
Script executed after the Gi tun network interface has been taken
|
||||
down. Executed with the following parameters: <devicename> <ip
|
||||
address>
|
||||
|
||||
.TP
|
||||
.BI --dynip " net"
|
||||
Dynamic IP address pool. Specifies a pool of dynamic IP addresses. If
|
||||
this option is omitted the network address specified by the
|
||||
.BI --net
|
||||
option is used for dynamic IP address allocation.
|
||||
|
||||
.TP
|
||||
.BI --pcodns1 " host"
|
||||
PCO DNS Server 1 (default = 0.0.0.0). PCO stands for Protocol
|
||||
Configuration options, and is part of the GPRS protocols. It is used
|
||||
to inform the mobile station about the DNS address to use for host
|
||||
name resolution.
|
||||
|
||||
.TP
|
||||
.BI --pcodns2 " host"
|
||||
PCO DNS Server 2 (default = 0.0.0.0). PCO stands for Protocol
|
||||
Configuration options, and is part of the GPRS protocols. It is used
|
||||
to inform the mobile station about the DNS address to use for host
|
||||
name resolution.
|
||||
|
||||
.TP
|
||||
.BI --timelimit " seconds"
|
||||
Exit
|
||||
.b ggsn
|
||||
after \fIseconds\fP. Used for debugging.
|
||||
|
||||
(default = ./openggsn.cfg)
|
||||
|
||||
.SH FILES
|
||||
.I /etc/ggsn.conf
|
||||
.I ./osmo-ggsn.cfg
|
||||
.RS
|
||||
The configuration file for
|
||||
.B ggsn.
|
||||
.B osmo-ggsn.
|
||||
.RE
|
||||
.I /var/run/ggsn.pid
|
||||
.I /var/run/osmo-ggsn.pid
|
||||
.RS
|
||||
Process ID file.
|
||||
.RE
|
||||
.I /var/lib/ggsn
|
||||
.I /var/lib/osmo-ggsn
|
||||
.RS
|
||||
Directory holding nonvolatile data.
|
||||
.RE
|
||||
|
||||
.SH BUGS
|
||||
Report all bugs to the OpenGGSN bug tracking list at
|
||||
.I http://sourceforge.net/projects/ggsn/
|
||||
Report all bugs to the OsmoGGSN bug tracking list at
|
||||
.I https://osmocom.org/projects/openggsn
|
||||
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
has very limited management support. Currently both SNMP as well as
|
||||
billing mechanisms are missing.
|
||||
|
||||
@@ -224,13 +135,13 @@ billing mechanisms are missing.
|
||||
.LP
|
||||
|
||||
Besides the long options documented in this man page
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
also accepts a number of short options with the same functionality. Use
|
||||
.B ggsn --help
|
||||
.B osmo-ggsn --help
|
||||
for a full list of all the available options.
|
||||
|
||||
The TUN/TAP driver is required for proper operation of
|
||||
.B ggsn.
|
||||
.B osmo-ggsn.
|
||||
For linux kernels later than 2.4.7 the TUN/TAP driver is included in the kernel, but typically needs to be loaded manually with
|
||||
.B modprobe tun.
|
||||
For automatic loading the line
|
||||
@@ -241,7 +152,7 @@ For other platforms see
|
||||
.I http://vtun.sourceforge.net/tun/
|
||||
for information on how to install and configure the tun driver.
|
||||
|
||||
.B ggsn
|
||||
.B osmo-ggsn
|
||||
uses the GPRS Tunneling Protocol (GTP) as specified by the Third
|
||||
Generation Partnership Project (3GPP). 3GPP protocols specifications
|
||||
can be found at
|
||||
@@ -250,6 +161,7 @@ can be found at
|
||||
.SH COPYRIGHT
|
||||
|
||||
Copyright (C) 2002, 2003 by Mondru AB.
|
||||
Copyright (C) 2017 Harald Welte
|
||||
|
||||
The contents of this file may be used under the terms of the GNU
|
||||
General Public License Version 2, provided that the above copyright
|
||||
@@ -258,3 +170,4 @@ substantial portions of the software.
|
||||
|
||||
.SH AUTHORS
|
||||
Jens Jakobsen <jj@openggsn.org>
|
||||
Harald Welte <laforge@gnumonks.org>
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
.\" * OpenGGSN - Gateway GPRS Support Node
|
||||
.\" * OsmoGGSN - Gateway GPRS Support Node
|
||||
.\" * Copyright (C) 2002, 2003 Mondru AB.
|
||||
.\" *
|
||||
.\" * The contents of this file may be used under the terms of the GNU
|
||||
@@ -90,7 +90,7 @@ sgsnemu \- Serving GPRS Support Node Emulator
|
||||
.SH DESCRIPTION
|
||||
.B sgsnemu
|
||||
is part of the
|
||||
.B OpenGGSN
|
||||
.B OsmoGGSN
|
||||
project, and implements a Serving GPRS Support Node (SGSN)
|
||||
emulator. It can be used for testing Gateway GPRS Support Nodes
|
||||
(GGSNs), GPRS core networks as well as GPRS roaming connections.
|
||||
@@ -329,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
|
||||
@@ -348,8 +348,8 @@ Directory holding nonvolatile data.
|
||||
.RE
|
||||
|
||||
.SH BUGS
|
||||
Report all bugs to the OpenGGSN bug tracking list at
|
||||
.I http://sourceforge.net/projects/sgsnemu/
|
||||
Report all bugs to the OsmoGGSN bug tracking list at
|
||||
.I http://osmocom.org/projects/openggsn/issues
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Sample ggsn configuration file
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# TAG: fg
|
||||
# Include this flag if process is to run in the foreground
|
||||
#
|
||||
#fg
|
||||
|
||||
# TAG: debug
|
||||
# Include this flag to include debug information.
|
||||
#debug
|
||||
|
||||
|
||||
# TAG: conf
|
||||
# Configuration file to use. This file is the configuration file,
|
||||
# so changing this parameter in the configuration file does not make
|
||||
# sense. Use it on the command line instead.
|
||||
|
||||
# TAG: pidfile
|
||||
# File to store information about the process id of the program.
|
||||
# The program must have write access to this file/directory.
|
||||
#pidfile /var/run/ggsn.pid
|
||||
|
||||
# TAG: statedir
|
||||
# Directory to use for nonvolatile storage.
|
||||
# The program must have write access to this directory.
|
||||
#statedir /var/lib/ggsn/
|
||||
|
||||
|
||||
# TAG: listen
|
||||
# Specifies the local IP address to listen to
|
||||
#listen 10.0.0.240
|
||||
|
||||
# TAG: net
|
||||
# IP network address of external packet data network
|
||||
# Used to set up network interface.
|
||||
#net 192.168.0.0/24
|
||||
|
||||
# TAG: ipup
|
||||
# Script executed after network interface has been brought up.
|
||||
# Executed with the following parameters: <devicename> <ip address>
|
||||
#ipup /etc/ggsn/ip-up
|
||||
|
||||
# TAG: ipdown
|
||||
# Script executed after network interface has been taken down.
|
||||
# Executed with the following parameters: <devicename> <ip address>
|
||||
#ipdown /etc/ggsn/ip-down
|
||||
|
||||
# TAG: dynip
|
||||
# Dynamic IP address pool.
|
||||
# Used for allocation of dynamic IP address when address is not given
|
||||
# by HLR.
|
||||
# If this option is not given then the net option is used as a substitute.
|
||||
#dynip 192.168.0.0/24
|
||||
|
||||
# TAG: statip
|
||||
# Use of this tag is currently UNSUPPORTED
|
||||
# Static IP address pool.
|
||||
# Used for allocation of static IP address by means of HLR.
|
||||
#statip 192.168.1.0/24
|
||||
|
||||
# TAG: pcodns1
|
||||
# Protocol configuration option domain name system server 1.
|
||||
#pcodns1 0.0.0.0
|
||||
|
||||
# TAG: pcodns2
|
||||
# Protocol configuration option domain name system server 2.
|
||||
#pcodns2 0.0.0.0
|
||||
|
||||
# TAG: timelimit
|
||||
# Exit after timelimit seconds.
|
||||
# Setting timelimit to zero will cause the program not to exit.
|
||||
#timelimit 0
|
||||
|
||||
# TAG: apn
|
||||
# Use of this tag is EXPERIMENTAL
|
||||
# Access point name to connect to when run in client mode.
|
||||
#apn internet
|
||||
|
||||
# TAG: qos
|
||||
# Use of this tag is EXPERIMENTAL
|
||||
# Requested Quality of Service used when run in client mode.
|
||||
# 3 bytes corresponding to ????
|
||||
#qos 0x0b921f
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
bin_PROGRAMS = ggsn
|
||||
bin_PROGRAMS = osmo-ggsn
|
||||
|
||||
AM_LDFLAGS = @EXEC_LDFLAGS@
|
||||
|
||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||
|
||||
ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
|
||||
ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
|
||||
ggsn_SOURCES = ggsn.c cmdline.c cmdline.h
|
||||
osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
|
||||
|
||||
if ENABLE_GTP_KERNEL
|
||||
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
|
||||
osmo_ggsn_LDADD += $(LIBGTPNL_LIBS)
|
||||
endif
|
||||
|
||||
osmo_ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
|
||||
osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h icmpv6.c icmpv6.h checksum.c checksum.h
|
||||
|
||||
211
ggsn/checksum.c
Normal file
211
ggsn/checksum.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
*
|
||||
* INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* IP/TCP/UDP checksumming routines
|
||||
*
|
||||
* Authors: Jorge Cwik, <jorge@laser.satlink.net>
|
||||
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
|
||||
* Tom May, <ftom@netcom.com>
|
||||
* Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
|
||||
* Lots of code moved from tcp.c and ip.c; see those files
|
||||
* for more names.
|
||||
*
|
||||
* 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek:
|
||||
* Fixed some nasty bugs, causing some horrible crashes.
|
||||
* A: At some points, the sum (%0) was used as
|
||||
* length-counter instead of the length counter
|
||||
* (%1). Thanks to Roman Hodek for pointing this out.
|
||||
* B: GCC seems to mess up if one uses too many
|
||||
* data-registers to hold input values and one tries to
|
||||
* specify d0 and d1 as scratch registers. Letting gcc
|
||||
* choose these registers itself solves the problem.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
|
||||
kills, so most of the assembly has to go. */
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#define _KERNEL /* needed on FreeBSD 10.x for s6_addr32 */
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#include "checksum.h"
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static inline unsigned short from32to16(unsigned int x)
|
||||
{
|
||||
/* add up 16-bit and 16-bit for 16+c bit */
|
||||
x = (x & 0xffff) + (x >> 16);
|
||||
/* add up carry.. */
|
||||
x = (x & 0xffff) + (x >> 16);
|
||||
return x;
|
||||
}
|
||||
|
||||
static unsigned int do_csum(const unsigned char *buff, int len)
|
||||
{
|
||||
int odd;
|
||||
unsigned int result = 0;
|
||||
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
odd = 1 & (unsigned long) buff;
|
||||
if (odd) {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
result += (*buff << 8);
|
||||
#else
|
||||
result = *buff;
|
||||
#endif
|
||||
len--;
|
||||
buff++;
|
||||
}
|
||||
if (len >= 2) {
|
||||
if (2 & (unsigned long) buff) {
|
||||
result += *(unsigned short *) buff;
|
||||
len -= 2;
|
||||
buff += 2;
|
||||
}
|
||||
if (len >= 4) {
|
||||
const unsigned char *end = buff + ((unsigned)len & ~3);
|
||||
unsigned int carry = 0;
|
||||
do {
|
||||
unsigned int w = *(unsigned int *) buff;
|
||||
buff += 4;
|
||||
result += carry;
|
||||
result += w;
|
||||
carry = (w > result);
|
||||
} while (buff < end);
|
||||
result += carry;
|
||||
result = (result & 0xffff) + (result >> 16);
|
||||
}
|
||||
if (len & 2) {
|
||||
result += *(unsigned short *) buff;
|
||||
buff += 2;
|
||||
}
|
||||
}
|
||||
if (len & 1)
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
result += *buff;
|
||||
#else
|
||||
result += (*buff << 8);
|
||||
#endif
|
||||
result = from32to16(result);
|
||||
if (odd)
|
||||
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of ip_compute_csum() optimized for IP headers,
|
||||
* which always checksum on 4 octet boundaries.
|
||||
*/
|
||||
uint16_t ip_fast_csum(const void *iph, unsigned int ihl)
|
||||
{
|
||||
return (uint16_t)~do_csum(iph, ihl*4);
|
||||
}
|
||||
|
||||
/*
|
||||
* computes the checksum of a memory block at buff, length len,
|
||||
* and adds in "sum" (32-bit)
|
||||
*
|
||||
* returns a 32-bit number suitable for feeding into itself
|
||||
* or csum_tcpudp_magic
|
||||
*
|
||||
* this function must be called with even lengths, except
|
||||
* for the last fragment, which may be odd
|
||||
*
|
||||
* it's best to have buff aligned on a 32-bit boundary
|
||||
*/
|
||||
uint32_t csum_partial(const void *buff, int len, uint32_t wsum)
|
||||
{
|
||||
unsigned int sum = (unsigned int)wsum;
|
||||
unsigned int result = do_csum(buff, len);
|
||||
|
||||
/* add in old sum, and carry.. */
|
||||
result += sum;
|
||||
if (sum > result)
|
||||
result += 1;
|
||||
return (uint32_t)result;
|
||||
}
|
||||
|
||||
/*
|
||||
* this routine is used for miscellaneous IP-like checksums, mainly
|
||||
* in icmp.c
|
||||
*/
|
||||
uint16_t ip_compute_csum(const void *buff, int len)
|
||||
{
|
||||
return (uint16_t)~do_csum(buff, len);
|
||||
}
|
||||
|
||||
uint16_t csum_ipv6_magic(const struct in6_addr *saddr,
|
||||
const struct in6_addr *daddr,
|
||||
uint32_t len, uint8_t proto, uint32_t csum)
|
||||
{
|
||||
int carry;
|
||||
uint32_t ulen;
|
||||
uint32_t uproto;
|
||||
uint32_t sum = (uint32_t)csum;
|
||||
|
||||
sum += (uint32_t)saddr->s6_addr32[0];
|
||||
carry = (sum < (uint32_t)saddr->s6_addr32[0]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)saddr->s6_addr32[1];
|
||||
carry = (sum < (uint32_t)saddr->s6_addr32[1]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)saddr->s6_addr32[2];
|
||||
carry = (sum < (uint32_t)saddr->s6_addr32[2]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)saddr->s6_addr32[3];
|
||||
carry = (sum < (uint32_t)saddr->s6_addr32[3]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)daddr->s6_addr32[0];
|
||||
carry = (sum < (uint32_t)daddr->s6_addr32[0]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)daddr->s6_addr32[1];
|
||||
carry = (sum < (uint32_t)daddr->s6_addr32[1]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)daddr->s6_addr32[2];
|
||||
carry = (sum < (uint32_t)daddr->s6_addr32[2]);
|
||||
sum += carry;
|
||||
|
||||
sum += (uint32_t)daddr->s6_addr32[3];
|
||||
carry = (sum < (uint32_t)daddr->s6_addr32[3]);
|
||||
sum += carry;
|
||||
|
||||
ulen = (uint32_t)htonl((uint32_t) len);
|
||||
sum += ulen;
|
||||
carry = (sum < ulen);
|
||||
sum += carry;
|
||||
|
||||
uproto = (uint32_t)htonl(proto);
|
||||
sum += uproto;
|
||||
carry = (sum < uproto);
|
||||
sum += carry;
|
||||
|
||||
return csum_fold((uint32_t)sum);
|
||||
}
|
||||
|
||||
/* fold a partial checksum */
|
||||
uint16_t csum_fold(uint32_t csum)
|
||||
{
|
||||
uint32_t sum = (uint32_t)csum;
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
return (uint16_t)~sum;
|
||||
}
|
||||
13
ggsn/checksum.h
Normal file
13
ggsn/checksum.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
uint16_t ip_fast_csum(const void *iph, unsigned int ihl);
|
||||
uint32_t csum_partial(const void *buff, int len, uint32_t wsum);
|
||||
uint16_t ip_compute_csum(const void *buff, int len);
|
||||
|
||||
uint16_t csum_ipv6_magic(const struct in6_addr *saddr,
|
||||
const struct in6_addr *daddr,
|
||||
uint32_t len, uint8_t proto, uint32_t csum);
|
||||
|
||||
uint16_t csum_fold(uint32_t csum);
|
||||
1145
ggsn/cmdline.c
1145
ggsn/cmdline.c
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
# OpenGGSN - Gateway GPRS Support Node
|
||||
# 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.
|
||||
#
|
||||
# Use "gengetopt --conf-parser < cmdline.ggo"
|
||||
# to generate cmdline.c and cmdline.h
|
||||
|
||||
option "fg" f "Run in foreground" flag off
|
||||
option "debug" d "Run in debug mode" flag off
|
||||
|
||||
option "conf" c "Read configuration file" string default="/etc/ggsn.conf" no
|
||||
option "pidfile" - "Filename of process id file" string default="/var/run/ggsn.pid" no
|
||||
option "statedir" - "Directory of nonvolatile data" string default="/var/lib/ggsn/" no
|
||||
|
||||
option "listen" l "Local interface" string no
|
||||
option "net" n "Network" string default="192.168.0.0/24" no
|
||||
option "ipup" - "Script to run after link-up" string no
|
||||
option "ipdown" - "Script to run after link-down" string no
|
||||
|
||||
option "dynip" - "Dynamic IP address pool" string no
|
||||
option "statip" - "Static IP address pool" string no
|
||||
|
||||
option "pcodns1" - "PCO DNS Server 1" string default="0.0.0.0" no
|
||||
option "pcodns2" - "PCO DNS Server 2" string default="0.0.0.0" no
|
||||
|
||||
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
|
||||
272
ggsn/cmdline.h
272
ggsn/cmdline.h
@@ -1,272 +0,0 @@
|
||||
/** @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
|
||||
|
||||
/* If we use autoconf. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#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; /**< @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. */
|
||||
|
||||
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. */
|
||||
|
||||
} ;
|
||||
|
||||
/** @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[];
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
1523
ggsn/ggsn.c
1523
ggsn/ggsn.c
File diff suppressed because it is too large
Load Diff
143
ggsn/ggsn.h
Normal file
143
ggsn/ggsn.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
|
||||
#include "../lib/tun.h"
|
||||
#include "../lib/ippool.h"
|
||||
#include "../lib/syserr.h"
|
||||
#include "../lib/in46_addr.h"
|
||||
#include "../gtp/gtp.h"
|
||||
|
||||
#define APN_TYPE_IPv4 0x01 /* v4-only */
|
||||
#define APN_TYPE_IPv6 0x02 /* v6-only */
|
||||
#define APN_TYPE_IPv4v6 0x04 /* v4v6 dual-stack */
|
||||
|
||||
struct ggsn_ctx;
|
||||
|
||||
struct apn_ctx_ip {
|
||||
struct {
|
||||
struct in46_prefix ifconfig_prefix;
|
||||
struct in46_prefix ll_prefix;
|
||||
struct in46_prefix static_prefix;
|
||||
struct in46_prefix dynamic_prefix;
|
||||
/* v4 DNS server names */
|
||||
struct in46_addr dns[2];
|
||||
} cfg;
|
||||
|
||||
/* v4 address pool */
|
||||
struct ippool_t *pool;
|
||||
};
|
||||
|
||||
struct apn_name {
|
||||
struct llist_head list;
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum apn_gtpu_mode {
|
||||
APN_GTPU_MODE_TUN = 0, /* default */
|
||||
APN_GTPU_MODE_KERNEL_GTP,
|
||||
};
|
||||
|
||||
struct apn_ctx {
|
||||
/* list of APNs inside GGSN */
|
||||
struct llist_head list;
|
||||
/* back-pointer to GGSN */
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
bool started;
|
||||
|
||||
struct {
|
||||
/* Primary name */
|
||||
char *name;
|
||||
/* Description string */
|
||||
char *description;
|
||||
/* List of secondary APN names */
|
||||
struct llist_head name_list;
|
||||
/* types supported address types on this APN */
|
||||
uint32_t apn_type_mask;
|
||||
/* GTP-U via TUN device or in Linux kernel */
|
||||
enum apn_gtpu_mode gtpu_mode;
|
||||
/* administratively shut-down (true) or not (false) */
|
||||
bool shutdown;
|
||||
/* transmit G-PDU sequeence numbers (true) or not (false) */
|
||||
bool tx_gpdu_seq;
|
||||
} cfg;
|
||||
|
||||
/* corresponding tun device */
|
||||
struct {
|
||||
struct {
|
||||
/* name of the network device */
|
||||
char *dev_name;
|
||||
/* ip-up and ip-down script names/paths */
|
||||
char *ipup_script;
|
||||
char *ipdown_script;
|
||||
} cfg;
|
||||
struct tun_t *tun;
|
||||
struct osmo_fd fd;
|
||||
} tun;
|
||||
|
||||
/* ipv6 link-local address */
|
||||
struct in6_addr v6_lladdr;
|
||||
|
||||
struct apn_ctx_ip v4;
|
||||
struct apn_ctx_ip v6;
|
||||
};
|
||||
|
||||
struct ggsn_ctx {
|
||||
/* global list of GGSNs */
|
||||
struct llist_head list;
|
||||
|
||||
/* list of APNs in this GGSN */
|
||||
struct llist_head apn_list;
|
||||
|
||||
bool started;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
/* Description string */
|
||||
char *description;
|
||||
/* an APN that shall be used as default for any non-matching APN */
|
||||
struct apn_ctx *default_apn;
|
||||
/* ADdress to which we listen for GTP */
|
||||
struct in46_addr listen_addr;
|
||||
/* Local GTP-C address advertised in GTP */
|
||||
struct in46_addr gtpc_addr;
|
||||
/* Local GTP-U address advertised in GTP */
|
||||
struct in46_addr gtpu_addr;
|
||||
/* directory for state file */
|
||||
char *state_dir;
|
||||
/* administratively shut-down (true) or not (false) */
|
||||
bool shutdown;
|
||||
} cfg;
|
||||
|
||||
/* The libgtp (G)GSN instance, i.e. what listens to GTP */
|
||||
struct gsn_t *gsn;
|
||||
|
||||
/* osmo-fd for gsn */
|
||||
struct osmo_fd gtp_fd0;
|
||||
struct osmo_fd gtp_fd1c;
|
||||
struct osmo_fd gtp_fd1u;
|
||||
|
||||
struct osmo_timer_list gtp_timer;
|
||||
};
|
||||
|
||||
/* ggsn_vty.c */
|
||||
extern struct llist_head g_ggsn_list;
|
||||
extern struct vty_app_info g_vty_info;
|
||||
extern int ggsn_vty_init(void);
|
||||
struct ggsn_ctx *ggsn_find(const char *name);
|
||||
struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name);
|
||||
struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name);
|
||||
struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name);
|
||||
|
||||
/* ggsn.c */
|
||||
extern void *tall_ggsn_ctx;
|
||||
extern int ggsn_start(struct ggsn_ctx *ggsn);
|
||||
extern int ggsn_stop(struct ggsn_ctx *ggsn);
|
||||
extern int apn_start(struct apn_ctx *apn);
|
||||
extern int apn_stop(struct apn_ctx *apn, bool force);
|
||||
975
ggsn/ggsn_vty.c
Normal file
975
ggsn/ggsn_vty.c
Normal file
@@ -0,0 +1,975 @@
|
||||
/*
|
||||
* (C) 2017 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
|
||||
#include "../gtp/gtp.h"
|
||||
#include "../gtp/pdp.h"
|
||||
|
||||
#include "ggsn.h"
|
||||
|
||||
#define PREFIX_STR "Prefix (Network/Netmask)\n"
|
||||
#define IFCONFIG_STR "GGSN-based interface configuration\n"
|
||||
#define GGSN_STR "Gateway GPRS Support NODE (GGSN)\n"
|
||||
|
||||
LLIST_HEAD(g_ggsn_list);
|
||||
|
||||
enum ggsn_vty_node {
|
||||
GGSN_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
APN_NODE,
|
||||
};
|
||||
|
||||
struct ggsn_ctx *ggsn_find(const char *name)
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
llist_for_each_entry(ggsn, &g_ggsn_list, list) {
|
||||
if (!strcmp(ggsn->cfg.name, name))
|
||||
return ggsn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name)
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
ggsn = ggsn_find(name);
|
||||
if (ggsn)
|
||||
return ggsn;
|
||||
|
||||
ggsn = talloc_zero(ctx, struct ggsn_ctx);
|
||||
if (!ggsn)
|
||||
return NULL;
|
||||
|
||||
ggsn->cfg.name = talloc_strdup(ggsn, name);
|
||||
ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
|
||||
ggsn->cfg.shutdown = true;
|
||||
INIT_LLIST_HEAD(&ggsn->apn_list);
|
||||
|
||||
llist_add_tail(&ggsn->list, &g_ggsn_list);
|
||||
return ggsn;
|
||||
}
|
||||
|
||||
struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name)
|
||||
{
|
||||
struct apn_ctx *apn;
|
||||
|
||||
llist_for_each_entry(apn, &ggsn->apn_list, list) {
|
||||
if (!strcmp(apn->cfg.name, name))
|
||||
return apn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name)
|
||||
{
|
||||
struct apn_ctx *apn = ggsn_find_apn(ggsn, name);
|
||||
if (apn)
|
||||
return apn;
|
||||
|
||||
apn = talloc_zero(ggsn, struct apn_ctx);
|
||||
if (!apn)
|
||||
return NULL;
|
||||
apn->ggsn = ggsn;
|
||||
apn->cfg.name = talloc_strdup(apn, name);
|
||||
apn->cfg.shutdown = true;
|
||||
apn->cfg.tx_gpdu_seq = true;
|
||||
INIT_LLIST_HEAD(&apn->cfg.name_list);
|
||||
|
||||
llist_add_tail(&apn->list, &ggsn->apn_list);
|
||||
return apn;
|
||||
}
|
||||
|
||||
/* GGSN Node */
|
||||
|
||||
static struct cmd_node ggsn_node = {
|
||||
GGSN_NODE,
|
||||
"%s(config-ggsn)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_ggsn, cfg_ggsn_cmd,
|
||||
"ggsn NAME",
|
||||
"Configure the Gateway GPRS Support Node\n" "GGSN Name (has only local significance)\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
ggsn = ggsn_find_or_create(tall_ggsn_ctx, argv[0]);
|
||||
if (!ggsn)
|
||||
return CMD_WARNING;
|
||||
|
||||
vty->node = GGSN_NODE;
|
||||
vty->index = ggsn;
|
||||
vty->index_sub = &ggsn->cfg.description;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_ggsn, cfg_no_ggsn_cmd,
|
||||
"no ggsn NAME",
|
||||
NO_STR "Remove the named Gateway GPRS Support Node\n"
|
||||
"GGSN Name (has only local significance)\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
ggsn = ggsn_find(argv[0]);
|
||||
if (!ggsn) {
|
||||
vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!ggsn->cfg.shutdown) {
|
||||
vty_out(vty, "%% GGSN %s is still active, please shutdown first%s",
|
||||
ggsn->cfg.name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!llist_empty(&ggsn->apn_list)) {
|
||||
vty_out(vty, "%% GGSN %s still has APNs configured, please remove first%s",
|
||||
ggsn->cfg.name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_del(&ggsn->list);
|
||||
talloc_free(ggsn);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_bind_ip, cfg_ggsn_bind_ip_cmd,
|
||||
"gtp bind-ip A.B.C.D",
|
||||
"GTP Parameters\n"
|
||||
"Set the IP address for the local GTP bind\n"
|
||||
"IPv4 Address\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
size_t t;
|
||||
|
||||
ippool_aton(&ggsn->cfg.listen_addr, &t, argv[0], 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_gtpc_ip, cfg_ggsn_gtpc_ip_cmd,
|
||||
"gtp control-ip A.B.C.D",
|
||||
"GTP Parameters\n"
|
||||
"Set the IP address states as local IP in GTP-C messages\n"
|
||||
"IPv4 Address\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
size_t t;
|
||||
|
||||
ippool_aton(&ggsn->cfg.gtpc_addr, &t, argv[0], 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_gtpu_ip, cfg_ggsn_gtpu_ip_cmd,
|
||||
"gtp user-ip A.B.C.D",
|
||||
"GTP Parameters\n"
|
||||
"Set the IP address states as local IP in GTP-U messages\n"
|
||||
"IPv4 Address\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
size_t t;
|
||||
|
||||
ippool_aton(&ggsn->cfg.gtpu_addr, &t, argv[0], 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_state_dir, cfg_ggsn_state_dir_cmd,
|
||||
"gtp state-dir PATH",
|
||||
"GTP Parameters\n"
|
||||
"Set the directory for the GTP State file\n"
|
||||
"Local Directory\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
|
||||
osmo_talloc_replace_string(ggsn, &ggsn->cfg.state_dir, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_apn, cfg_ggsn_apn_cmd,
|
||||
"apn NAME", "APN Configuration\n" "APN Name\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
struct apn_ctx *apn;
|
||||
|
||||
apn = ggsn_find_or_create_apn(ggsn, argv[0]);
|
||||
if (!apn)
|
||||
return CMD_WARNING;
|
||||
|
||||
vty->node = APN_NODE;
|
||||
vty->index = apn;
|
||||
vty->index_sub = &ggsn->cfg.description;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_no_apn, cfg_ggsn_no_apn_cmd,
|
||||
"no apn NAME",
|
||||
NO_STR "Remove APN Configuration\n" "APN Name\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
struct apn_ctx *apn;
|
||||
|
||||
apn = ggsn_find_apn(ggsn, argv[0]);
|
||||
if (!apn) {
|
||||
vty_out(vty, "%% No such APN '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!apn->cfg.shutdown) {
|
||||
vty_out(vty, "%% APN %s still active, please shutdown first%s",
|
||||
apn->cfg.name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_del(&apn->list);
|
||||
talloc_free(apn);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_default_apn, cfg_ggsn_default_apn_cmd,
|
||||
"default-apn NAME",
|
||||
"Set a default-APN to be used if no other APN matches\n"
|
||||
"APN Name\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
struct apn_ctx *apn;
|
||||
|
||||
apn = ggsn_find_apn(ggsn, argv[0]);
|
||||
if (!apn) {
|
||||
vty_out(vty, "%% No APN of name '%s' found%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
ggsn->cfg.default_apn = apn;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd,
|
||||
"no default-apn",
|
||||
NO_STR "Remove default-APN to be used if no other APN matches\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
ggsn->cfg.default_apn = NULL;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
|
||||
"shutdown ggsn",
|
||||
"Put the GGSN in administrative shut-down\n" GGSN_STR)
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
|
||||
if (!ggsn->cfg.shutdown) {
|
||||
if (ggsn_stop(ggsn)) {
|
||||
vty_out(vty, "%% Failed to shutdown GGSN%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ggsn->cfg.shutdown = true;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
|
||||
"no shutdown ggsn",
|
||||
NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
|
||||
|
||||
if (ggsn->cfg.shutdown) {
|
||||
if (ggsn_start(ggsn) < 0) {
|
||||
vty_out(vty, "%% Failed to start GGSN, check log for details%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ggsn->cfg.shutdown = false;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* APN Node */
|
||||
|
||||
static struct cmd_node apn_node = {
|
||||
APN_NODE,
|
||||
"%s(config-ggsn-apn)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
static const struct value_string pdp_type_names[] = {
|
||||
{ APN_TYPE_IPv4, "v4" },
|
||||
{ APN_TYPE_IPv6, "v6" },
|
||||
{ APN_TYPE_IPv4v6, "v4v6" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct value_string apn_gtpu_mode_names[] = {
|
||||
{ APN_GTPU_MODE_TUN, "tun" },
|
||||
{ APN_GTPU_MODE_KERNEL_GTP, "kernel-gtp" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
#define V4V6V46_STRING "IPv4(-only) PDP Type\n" \
|
||||
"IPv6(-only) PDP Type\n" \
|
||||
"IPv4v6 (dual-stack) PDP Type\n"
|
||||
|
||||
DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd,
|
||||
"type-support (v4|v6|v4v6)",
|
||||
"Enable support for PDP Type\n"
|
||||
V4V6V46_STRING)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
uint32_t type = get_string_value(pdp_type_names, argv[0]);
|
||||
|
||||
apn->cfg.apn_type_mask |= type;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_type_support, cfg_apn_no_type_support_cmd,
|
||||
"no type-support (v4|v6|v4v6)",
|
||||
NO_STR "Disable support for PDP Type\n"
|
||||
V4V6V46_STRING)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
uint32_t type = get_string_value(pdp_type_names, argv[0]);
|
||||
|
||||
apn->cfg.apn_type_mask &= ~type;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_gtpu_mode, cfg_apn_gtpu_mode_cmd,
|
||||
"gtpu-mode (tun|kernel-gtp)",
|
||||
"Set the Mode for this APN (tun or Linux Kernel GTP)\n"
|
||||
"GTP-U in userspace using TUN device\n"
|
||||
"GTP-U in kernel using Linux Kernel GTP\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
|
||||
apn->cfg.gtpu_mode = get_string_value(apn_gtpu_mode_names, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_tun_dev_name, cfg_apn_tun_dev_name_cmd,
|
||||
"tun-device NAME",
|
||||
"Configure tun device name\n"
|
||||
"TUN device name")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
osmo_talloc_replace_string(apn, &apn->tun.cfg.dev_name, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipup_script, cfg_apn_ipup_script_cmd,
|
||||
"ipup-script PATH",
|
||||
"Configure name/path of ip-up script\n"
|
||||
"File/Path name of ip-up script\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
osmo_talloc_replace_string(apn, &apn->tun.cfg.ipup_script, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ipup_script, cfg_apn_no_ipup_script_cmd,
|
||||
"no ipup-script",
|
||||
NO_STR "Disable ip-up script\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
talloc_free(apn->tun.cfg.ipup_script);
|
||||
apn->tun.cfg.ipup_script = NULL;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipdown_script, cfg_apn_ipdown_script_cmd,
|
||||
"ipdown-script PATH",
|
||||
"Configure name/path of ip-down script\n"
|
||||
"File/Path name of ip-down script\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
osmo_talloc_replace_string(apn, &apn->tun.cfg.ipdown_script, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* convert prefix from "A.B.C.D/M" notation to in46_prefix */
|
||||
static void str2prefix(struct in46_prefix *pfx, const char *in)
|
||||
{
|
||||
size_t t;
|
||||
|
||||
ippool_aton(&pfx->addr, &t, in, 0);
|
||||
pfx->prefixlen = t;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ipdown_script, cfg_apn_no_ipdown_script_cmd,
|
||||
"no ipdown-script",
|
||||
NO_STR "Disable ip-down script\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
talloc_free(apn->tun.cfg.ipdown_script);
|
||||
apn->tun.cfg.ipdown_script = NULL;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
|
||||
"ip prefix (static|dynamic) A.B.C.D/M",
|
||||
IP_STR PREFIX_STR "IPv4 Adress/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
struct in46_prefix *pfx;
|
||||
|
||||
/* first update our parsed prefix */
|
||||
if (!strcmp(argv[0], "static"))
|
||||
pfx = &apn->v4.cfg.static_prefix;
|
||||
else
|
||||
pfx = &apn->v4.cfg.dynamic_prefix;
|
||||
str2prefix(pfx, argv[1]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ip_ifconfig, cfg_apn_ip_ifconfig_cmd,
|
||||
"ip ifconfig A.B.C.D/M",
|
||||
IP_STR IFCONFIG_STR "IPv4 Adress/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
str2prefix(&apn->v4.cfg.ifconfig_prefix, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ip_ifconfig, cfg_apn_no_ip_ifconfig_cmd,
|
||||
"no ip ifconfig",
|
||||
NO_STR IP_STR IFCONFIG_STR)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
memset(&apn->v4.cfg.ifconfig_prefix, 0, sizeof(apn->v4.cfg.ifconfig_prefix));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
|
||||
"ipv6 prefix (static|dynamic) X:X::X:X/M",
|
||||
IP6_STR PREFIX_STR "IPv6 Address/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
struct in46_prefix *pfx;
|
||||
|
||||
if (!strcmp(argv[0], "static"))
|
||||
pfx = &apn->v6.cfg.static_prefix;
|
||||
else
|
||||
pfx = &apn->v6.cfg.dynamic_prefix;
|
||||
str2prefix(pfx, argv[1]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipv6_ifconfig, cfg_apn_ipv6_ifconfig_cmd,
|
||||
"ipv6 ifconfig X:X::X:X/M",
|
||||
IP6_STR IFCONFIG_STR "IPv6 Adress/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
str2prefix(&apn->v6.cfg.ifconfig_prefix, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
|
||||
"no ipv6 ifconfig",
|
||||
NO_STR IP6_STR IFCONFIG_STR)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
memset(&apn->v6.cfg.ifconfig_prefix, 0, sizeof(apn->v6.cfg.ifconfig_prefix));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipv6_linklocal, cfg_apn_ipv6_linklocal_cmd,
|
||||
"ipv6 link-local X:X::X:X/M",
|
||||
IP6_STR IFCONFIG_STR "IPv6 Link-local Adress/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
str2prefix(&apn->v6.cfg.ll_prefix, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ipv6_linklocal, cfg_apn_no_ipv6_linklocal_cmd,
|
||||
"no ipv6 link-local",
|
||||
NO_STR IP6_STR IFCONFIG_STR)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
memset(&apn->v6.cfg.ll_prefix, 0, sizeof(apn->v6.cfg.ll_prefix));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
|
||||
|
||||
DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
|
||||
"ip dns <0-1> A.B.C.D",
|
||||
IP_STR DNS_STRINGS)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
int idx = atoi(argv[0]);
|
||||
size_t dummy;
|
||||
|
||||
ippool_aton(&apn->v4.cfg.dns[idx], &dummy, argv[1], 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd,
|
||||
"ipv6 dns <0-1> X:X::X:X",
|
||||
IP6_STR DNS_STRINGS)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
int idx = atoi(argv[0]);
|
||||
size_t dummy;
|
||||
|
||||
ippool_aton(&apn->v6.cfg.dns[idx], &dummy, argv[1], 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_dns, cfg_apn_no_dns_cmd,
|
||||
"no (ip|ipv6) dns <0-1>",
|
||||
NO_STR IP_STR IP6_STR "Disable DNS Server\n" "primary/secondary DNS\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
struct in46_addr *a;
|
||||
int idx = atoi(argv[1]);
|
||||
|
||||
if (!strcmp(argv[0], "ip"))
|
||||
a = &apn->v4.cfg.dns[idx];
|
||||
else
|
||||
a = &apn->v6.cfg.dns[idx];
|
||||
|
||||
memset(a, 0, sizeof(*a));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_gpdu_seq, cfg_apn_gpdu_seq_cmd,
|
||||
"g-pdu tx-sequence-numbers",
|
||||
"G-PDU Configuration\n" "Enable transmission of G-PDU sequence numbers\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
apn->cfg.tx_gpdu_seq = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_gpdu_seq, cfg_apn_no_gpdu_seq_cmd,
|
||||
"no g-pdu tx-sequence-numbers",
|
||||
NO_STR "G-PDU Configuration\n" "Disable transmission of G-PDU sequence numbers\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
apn->cfg.tx_gpdu_seq = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
|
||||
"shutdown",
|
||||
"Put the APN in administrative shut-down\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
|
||||
if (!apn->cfg.shutdown) {
|
||||
if (apn_stop(apn, false)) {
|
||||
vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
apn->cfg.shutdown = true;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
|
||||
"no shutdown",
|
||||
NO_STR "Remove the APN from administrative shut-down\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
|
||||
if (apn->cfg.shutdown) {
|
||||
if (apn_start(apn) < 0) {
|
||||
vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
apn->cfg.shutdown = false;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void vty_dump_prefix(struct vty *vty, const char *pre, const struct in46_prefix *pfx)
|
||||
{
|
||||
vty_out(vty, "%s %s%s", pre, in46p_ntoa(pfx), VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
vty_out(vty, " apn %s%s", apn->cfg.name, VTY_NEWLINE);
|
||||
if (apn->cfg.description)
|
||||
vty_out(vty, " description %s%s", apn->cfg.description, VTY_NEWLINE);
|
||||
vty_out(vty, " gtpu-mode %s%s", get_value_string(apn_gtpu_mode_names, apn->cfg.gtpu_mode),
|
||||
VTY_NEWLINE);
|
||||
if (apn->tun.cfg.dev_name)
|
||||
vty_out(vty, " tun-device %s%s", apn->tun.cfg.dev_name, VTY_NEWLINE);
|
||||
if (apn->tun.cfg.ipup_script)
|
||||
vty_out(vty, " ipup-script %s%s", apn->tun.cfg.ipup_script, VTY_NEWLINE);
|
||||
if (apn->tun.cfg.ipdown_script)
|
||||
vty_out(vty, " ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (!(apn->cfg.apn_type_mask & (1 << i)))
|
||||
continue;
|
||||
vty_out(vty, " type-support %s%s", get_value_string(pdp_type_names, (1 << i)),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (!apn->cfg.tx_gpdu_seq)
|
||||
vty_out(vty, " no g-pdu tx-sequence-numbers%s", VTY_NEWLINE);
|
||||
|
||||
/* IPv4 prefixes + DNS */
|
||||
if (apn->v4.cfg.static_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ip prefix static", &apn->v4.cfg.static_prefix);
|
||||
if (apn->v4.cfg.dynamic_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ip prefix dynamic", &apn->v4.cfg.dynamic_prefix);
|
||||
for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
|
||||
if (!apn->v4.cfg.dns[i].len)
|
||||
continue;
|
||||
vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v4.cfg.dns[i]), VTY_NEWLINE);
|
||||
}
|
||||
if (apn->v4.cfg.ifconfig_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ip ifconfig", &apn->v4.cfg.ifconfig_prefix);
|
||||
|
||||
/* IPv6 prefixes + DNS */
|
||||
if (apn->v6.cfg.static_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ipv6 prefix static", &apn->v6.cfg.static_prefix);
|
||||
if (apn->v6.cfg.dynamic_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ipv6 prefix dynamic", &apn->v6.cfg.dynamic_prefix);
|
||||
for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
|
||||
if (!apn->v6.cfg.dns[i].len)
|
||||
continue;
|
||||
vty_out(vty, " ipv6 dns %u %s%s", i, in46a_ntoa(&apn->v6.cfg.dns[i]), VTY_NEWLINE);
|
||||
}
|
||||
if (apn->v6.cfg.ifconfig_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ipv6 ifconfig", &apn->v6.cfg.ifconfig_prefix);
|
||||
if (apn->v6.cfg.ll_prefix.addr.len)
|
||||
vty_dump_prefix(vty, " ipv6 link-local", &apn->v6.cfg.ll_prefix);
|
||||
|
||||
/* must be last */
|
||||
vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static int config_write_ggsn(struct vty *vty)
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
llist_for_each_entry(ggsn, &g_ggsn_list, list) {
|
||||
struct apn_ctx *apn;
|
||||
vty_out(vty, "ggsn %s%s", ggsn->cfg.name, VTY_NEWLINE);
|
||||
if (ggsn->cfg.description)
|
||||
vty_out(vty, " description %s%s", ggsn->cfg.description, VTY_NEWLINE);
|
||||
vty_out(vty, " gtp state-dir %s%s", ggsn->cfg.state_dir, VTY_NEWLINE);
|
||||
vty_out(vty, " gtp bind-ip %s%s", in46a_ntoa(&ggsn->cfg.listen_addr), VTY_NEWLINE);
|
||||
if (ggsn->cfg.gtpc_addr.v4.s_addr)
|
||||
vty_out(vty, " gtp control-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpc_addr), VTY_NEWLINE);
|
||||
if (ggsn->cfg.gtpu_addr.v4.s_addr)
|
||||
vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE);
|
||||
llist_for_each_entry(apn, &ggsn->apn_list, list)
|
||||
config_write_apn(vty, apn);
|
||||
if (ggsn->cfg.default_apn)
|
||||
vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
|
||||
/* must be last */
|
||||
vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *print_gsnaddr(const struct ul16_t *in)
|
||||
{
|
||||
struct in46_addr in46;
|
||||
|
||||
in46.len = in->l;
|
||||
OSMO_ASSERT(in->l <= sizeof(in46.v6));
|
||||
memcpy(&in46.v6, in->v, in->l);
|
||||
|
||||
return in46a_ntoa(&in46);
|
||||
}
|
||||
|
||||
static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
|
||||
{
|
||||
struct in46_addr eua46;
|
||||
|
||||
vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
|
||||
osmo_hexdump_nospc(pdp->msisdn.v, pdp->msisdn.l), VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
|
||||
vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
|
||||
vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
|
||||
|
||||
in46a_from_eua(&pdp->eua, &eua46);
|
||||
vty_out(vty, " End-User Address: %s%s", in46a_ntoa(&eua46), VTY_NEWLINE);
|
||||
vty_out(vty, " Transmit GTP Sequence Number for G-PDU: %s%s",
|
||||
pdp->tx_gpdu_seq ? "Yes" : "No", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
|
||||
"show pdp-context imsi IMSI [<0-15>]",
|
||||
SHOW_STR "Display information on PDP Context\n"
|
||||
"PDP contexts for given IMSI\n"
|
||||
"PDP context for given NSAPI\n")
|
||||
{
|
||||
uint64_t imsi = strtoull(argv[0], NULL, 10);
|
||||
unsigned int nsapi;
|
||||
struct pdp_t *pdp;
|
||||
int num_found = 0;
|
||||
|
||||
if (argc > 1) {
|
||||
nsapi = atoi(argv[1]);
|
||||
if (pdp_getimsi(&pdp, imsi, nsapi)) {
|
||||
show_one_pdp(vty, pdp);
|
||||
num_found++;
|
||||
}
|
||||
} else {
|
||||
for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
|
||||
if (pdp_getimsi(&pdp, imsi, nsapi))
|
||||
continue;
|
||||
show_one_pdp(vty, pdp);
|
||||
num_found++;
|
||||
}
|
||||
}
|
||||
if (num_found == 0) {
|
||||
vty_out(vty, "%% No such PDP context found%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
} else
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* show all (active) PDP contexts within a pool */
|
||||
static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pool->listsize; i++) {
|
||||
struct ippoolm_t *member = &pool->member[i];
|
||||
if (member->inuse == 0)
|
||||
continue;
|
||||
show_one_pdp(vty, member->peer);
|
||||
}
|
||||
}
|
||||
|
||||
/* show all (active) PDP contexts within an APN */
|
||||
static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
|
||||
{
|
||||
ippool_show_pdp_contexts(vty, apn->v4.pool);
|
||||
ippool_show_pdp_contexts(vty, apn->v6.pool);
|
||||
}
|
||||
|
||||
DEFUN(show_pdpctx, show_pdpctx_cmd,
|
||||
"show pdp-context ggsn NAME [apn APN]",
|
||||
SHOW_STR "Show PDP Context Information\n"
|
||||
GGSN_STR "GGSN Name\n") // FIXME
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
struct apn_ctx *apn;
|
||||
|
||||
ggsn = ggsn_find(argv[0]);
|
||||
if (!ggsn) {
|
||||
vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (argc < 2) {
|
||||
llist_for_each_entry(apn, &ggsn->apn_list, list)
|
||||
apn_show_pdp_contexts(vty, apn);
|
||||
} else {
|
||||
apn = ggsn_find_apn(ggsn, argv[1]);
|
||||
if (!apn) {
|
||||
vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
apn_show_pdp_contexts(vty, apn);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void show_apn(struct vty *vty, struct apn_ctx *apn)
|
||||
{
|
||||
vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
|
||||
{
|
||||
struct apn_ctx *apn;
|
||||
vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
|
||||
VTY_NEWLINE);
|
||||
/* FIXME */
|
||||
|
||||
llist_for_each_entry(apn, &ggsn->apn_list, list)
|
||||
show_apn(vty, apn);
|
||||
}
|
||||
|
||||
DEFUN(show_ggsn, show_ggsn_cmd,
|
||||
"show ggsn [NAME]",
|
||||
SHOW_STR "Display information on the GGSN\n")
|
||||
{
|
||||
struct ggsn_ctx *ggsn;
|
||||
|
||||
if (argc == 0) {
|
||||
llist_for_each_entry(ggsn, &g_ggsn_list, list)
|
||||
show_one_ggsn(vty, ggsn);
|
||||
} else {
|
||||
ggsn = ggsn_find(argv[0]);
|
||||
if (!ggsn)
|
||||
return CMD_WARNING;
|
||||
show_one_ggsn(vty, ggsn);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int ggsn_vty_init(void)
|
||||
{
|
||||
install_element_ve(&show_pdpctx_cmd);
|
||||
install_element_ve(&show_pdpctx_imsi_cmd);
|
||||
install_element_ve(&show_ggsn_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_ggsn_cmd);
|
||||
install_element(CONFIG_NODE, &cfg_no_ggsn_cmd);
|
||||
|
||||
install_node(&ggsn_node, config_write_ggsn);
|
||||
install_element(GGSN_NODE, &cfg_description_cmd);
|
||||
install_element(GGSN_NODE, &cfg_no_description_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_shutdown_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_no_shutdown_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_bind_ip_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_gtpc_ip_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_gtpu_ip_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_state_dir_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_apn_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
|
||||
install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
|
||||
|
||||
install_node(&apn_node, NULL);
|
||||
install_element(APN_NODE, &cfg_description_cmd);
|
||||
install_element(APN_NODE, &cfg_no_description_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_shutdown_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_shutdown_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_gtpu_mode_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_type_support_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_type_support_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_tun_dev_name_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipup_script_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipup_script_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipdown_script_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipdown_script_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ip_prefix_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ip_dns_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_dns_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ip_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_linklocal_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipv6_linklocal_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ggsn_vty_is_config_node(struct vty *vty, int node)
|
||||
{
|
||||
switch (node) {
|
||||
case GGSN_NODE:
|
||||
case APN_NODE:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ggsn_vty_go_parent(struct vty *vty)
|
||||
{
|
||||
switch (vty->node) {
|
||||
case GGSN_NODE:
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
vty->index_sub = NULL;
|
||||
break;
|
||||
case APN_NODE:
|
||||
vty->node = GGSN_NODE;
|
||||
{
|
||||
struct apn_ctx *apn = vty->index;
|
||||
vty->index = apn->ggsn;
|
||||
vty->index_sub = &apn->ggsn->cfg.description;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
vty->index_sub = NULL;
|
||||
}
|
||||
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
static const char ggsn_copyright[] =
|
||||
"Copyright (C) 2011-2017 Harald Welte <laforge@gnumonks.org>\r\n"
|
||||
"Copyright (C) 2012-2017 Holger Hans Peter Freyther <holger@moiji-mobile.com>\r\n"
|
||||
"Copyright (C) 2012-2017 sysmocom - s.f.m.c. GmbH\r\n"
|
||||
"Copyright (C) 2002-2005 Mondru AB\r\n"
|
||||
"License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl-2.0.html>\r\n"
|
||||
"This is free software: you are free to change and redistribute it.\r\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||
|
||||
struct vty_app_info g_vty_info = {
|
||||
.name = "OsmoGGSN",
|
||||
.version = PACKAGE_VERSION,
|
||||
.copyright = ggsn_copyright,
|
||||
.go_parent_cb = ggsn_vty_go_parent,
|
||||
.is_config_node = ggsn_vty_is_config_node,
|
||||
};
|
||||
232
ggsn/icmpv6.c
Normal file
232
ggsn/icmpv6.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* handle incoming packets to the all-routers multicast address */
|
||||
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
const struct in6_addr *pdp_prefix,
|
||||
const struct in6_addr *own_ll_addr,
|
||||
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));
|
||||
struct msgb *msg;
|
||||
|
||||
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;
|
||||
}
|
||||
/* Send router advertisement from GGSN link-local
|
||||
* address to MS link-local address, including prefix
|
||||
* allocated to this PDP context */
|
||||
msg = icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, pdp_prefix);
|
||||
/* 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;
|
||||
}
|
||||
9
ggsn/icmpv6.h
Normal file
9
ggsn/icmpv6.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gtp/gtp.h"
|
||||
#include "../gtp/pdp.h"
|
||||
|
||||
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
const struct in6_addr *pdp_prefix,
|
||||
const struct in6_addr *own_ll_addr,
|
||||
const uint8_t *pack, unsigned len);
|
||||
151
git-version-gen
Executable file
151
git-version-gen
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2010-01-28.01
|
||||
|
||||
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
|
||||
# It may be run two ways:
|
||||
# - from a git repository in which the "git describe" command below
|
||||
# produces useful output (thus requiring at least one signed tag)
|
||||
# - from a non-git-repo directory containing a .tarball-version file, which
|
||||
# presumes this script is invoked like "./git-version-gen .tarball-version".
|
||||
|
||||
# In order to use intra-version strings in your project, you will need two
|
||||
# separate generated version string files:
|
||||
#
|
||||
# .tarball-version - present only in a distribution tarball, and not in
|
||||
# a checked-out repository. Created with contents that were learned at
|
||||
# the last time autoconf was run, and used by git-version-gen. Must not
|
||||
# be present in either $(srcdir) or $(builddir) for git-version-gen to
|
||||
# give accurate answers during normal development with a checked out tree,
|
||||
# but must be present in a tarball when there is no version control system.
|
||||
# Therefore, it cannot be used in any dependencies. GNUmakefile has
|
||||
# hooks to force a reconfigure at distribution time to get the value
|
||||
# correct, without penalizing normal development with extra reconfigures.
|
||||
#
|
||||
# .version - present in a checked-out repository and in a distribution
|
||||
# tarball. Usable in dependencies, particularly for files that don't
|
||||
# want to depend on config.h but do want to track version changes.
|
||||
# Delete this file prior to any autoconf run where you want to rebuild
|
||||
# files to pick up a version string change; and leave it stale to
|
||||
# minimize rebuild time after unrelated changes to configure sources.
|
||||
#
|
||||
# It is probably wise to add these two files to .gitignore, so that you
|
||||
# don't accidentally commit either generated file.
|
||||
#
|
||||
# Use the following line in your configure.ac, so that $(VERSION) will
|
||||
# automatically be up-to-date each time configure is run (and note that
|
||||
# since configure.ac no longer includes a version string, Makefile rules
|
||||
# should not depend on configure.ac for version updates).
|
||||
#
|
||||
# AC_INIT([GNU project],
|
||||
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
# [bug-project@example])
|
||||
#
|
||||
# Then use the following lines in your Makefile.am, so that .version
|
||||
# will be present for dependencies, and so that .tarball-version will
|
||||
# exist in distribution tarballs.
|
||||
#
|
||||
# BUILT_SOURCES = $(top_srcdir)/.version
|
||||
# $(top_srcdir)/.version:
|
||||
# echo $(VERSION) > $@-t && mv $@-t $@
|
||||
# dist-hook:
|
||||
# echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
case $# in
|
||||
1) ;;
|
||||
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
|
||||
esac
|
||||
|
||||
tarball_version_file=$1
|
||||
nl='
|
||||
'
|
||||
|
||||
# First see if there is a tarball-only version file.
|
||||
# then try "git describe", then default.
|
||||
if test -f $tarball_version_file
|
||||
then
|
||||
v=`cat $tarball_version_file` || exit 1
|
||||
case $v in
|
||||
*$nl*) v= ;; # reject multi-line output
|
||||
[0-9]*) ;;
|
||||
*) v= ;;
|
||||
esac
|
||||
test -z "$v" \
|
||||
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
|
||||
fi
|
||||
|
||||
if test -n "$v"
|
||||
then
|
||||
: # use $v
|
||||
elif
|
||||
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||
&& case $v in
|
||||
[0-9]*) ;;
|
||||
v[0-9]*) ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
# Is this a new git that lists number of commits since the last
|
||||
# tag or the previous older version that did not?
|
||||
# Newer: v6.10-77-g0f8faeb
|
||||
# Older: v6.10-g0f8faeb
|
||||
case $v in
|
||||
*-*-*) : git describe is okay three part flavor ;;
|
||||
*-*)
|
||||
: git describe is older two part flavor
|
||||
# Recreate the number of commits and rewrite such that the
|
||||
# result is the same as if we were using the newer version
|
||||
# of git describe.
|
||||
vtag=`echo "$v" | sed 's/-.*//'`
|
||||
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
|
||||
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change the first '-' to a '.', so version-comparing tools work properly.
|
||||
# Remove the "g" in git describe's output string, to save a byte.
|
||||
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
|
||||
else
|
||||
v=UNKNOWN
|
||||
fi
|
||||
|
||||
v=`echo "$v" |sed 's/^v//'`
|
||||
|
||||
# Don't declare a version "dirty" merely because a time stamp has changed.
|
||||
git status > /dev/null 2>&1
|
||||
|
||||
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
|
||||
case "$dirty" in
|
||||
'') ;;
|
||||
*) # Append the suffix only if there isn't one already.
|
||||
case $v in
|
||||
*-dirty) ;;
|
||||
*) v="$v-dirty" ;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
|
||||
echo "$v" | tr -d '\012'
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
@@ -1,12 +1,15 @@
|
||||
# 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
|
||||
# If major=current-age is increased, remember to update the dh_strip line in debian/rules!
|
||||
LIBVERSION=3: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 $(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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
33
gtp/gtp.h
33
gtp/gtp.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
@@ -12,6 +12,9 @@
|
||||
#ifndef _GTP_H
|
||||
#define _GTP_H
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/defs.h>
|
||||
|
||||
#define GTP_MODE_GGSN 1
|
||||
#define GTP_MODE_SGSN 2
|
||||
|
||||
@@ -85,6 +88,10 @@
|
||||
/* 242-254 For future use. */
|
||||
#define GTP_GPDU 255 /* G-PDU */
|
||||
|
||||
extern const struct value_string gtp_type_names[];
|
||||
static inline const char *gtp_type_name(uint8_t val)
|
||||
{ return get_value_string(gtp_type_names, val); }
|
||||
|
||||
/* GTP information element cause codes from 29.060 v3.9.0 7.7 */
|
||||
/* */
|
||||
#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */
|
||||
@@ -133,6 +140,7 @@
|
||||
|
||||
struct ul66_t;
|
||||
struct ul16_t;
|
||||
struct pdp_t;
|
||||
|
||||
/* GTP 0 header.
|
||||
* Explanation to some of the fields:
|
||||
@@ -161,6 +169,13 @@ struct gtp0_header { /* Descriptions from 3GPP 09.60 */
|
||||
uint64_t tid; /* 13 Tunnel ID */
|
||||
} __attribute__((packed)); /* 20 */
|
||||
|
||||
#define GTP1HDR_F_NPDU 0x01
|
||||
#define GTP1HDR_F_SEQ 0x02
|
||||
#define GTP1HDR_F_EXT 0x04
|
||||
#define GTP1HDR_F_GTP1 0x10
|
||||
#define GTPHDR_F_VER(n) ((n) << 5)
|
||||
#define GTPHDR_F_GET_VER(flags) ((flags)>>5)
|
||||
|
||||
struct gtp1_header_short { /* Descriptions from 3GPP 29060 */
|
||||
uint8_t flags; /* 01 bitfield, with typical values */
|
||||
/* 001..... Version: 1 */
|
||||
@@ -244,7 +259,7 @@ struct gsn_t {
|
||||
|
||||
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 */
|
||||
|
||||
@@ -256,6 +271,7 @@ struct gsn_t {
|
||||
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);
|
||||
int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
|
||||
|
||||
/* Counters */
|
||||
|
||||
@@ -309,7 +325,10 @@ 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,
|
||||
void *cbp, int teardown);
|
||||
void *cbp, int teardown)
|
||||
OSMO_DEPRECATED("Use gtp_delete_context_req2() instead, to avoid freeing pdp ctx before reply");
|
||||
extern int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
void *cbp, int teardown);
|
||||
|
||||
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
void *pack, unsigned len);
|
||||
@@ -343,8 +362,15 @@ extern int gtp_set_cb_conf(struct gsn_t *gsn,
|
||||
|
||||
int gtp_set_cb_recovery(struct gsn_t *gsn,
|
||||
int (*cb) (struct sockaddr_in * peer,
|
||||
uint8_t recovery))
|
||||
OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
|
||||
int gtp_set_cb_recovery2(struct gsn_t *gsn,
|
||||
int (*cb) (struct sockaddr_in * peer,
|
||||
struct pdp_t * pdp,
|
||||
uint8_t recovery));
|
||||
|
||||
void gtp_clear_queues(struct gsn_t *gsn);
|
||||
|
||||
/* Internal functions (not part of the API */
|
||||
|
||||
extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
|
||||
@@ -399,5 +425,6 @@ 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 */
|
||||
|
||||
346
gtp/gtpie.c
346
gtp/gtpie.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002 Mondru AB.
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
@@ -39,8 +39,16 @@
|
||||
|
||||
#include "gtpie.h"
|
||||
|
||||
/*! Encode a TLV type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] l Length of value \a v in bytes
|
||||
* \param[in] v Pointer to input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
int l, void *v)
|
||||
int l, const void *v)
|
||||
{
|
||||
if ((*length + 3 + l) >= size)
|
||||
return 1;
|
||||
@@ -51,8 +59,16 @@ int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode a TV0 (Tag + value) type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] l Length of value \a v in bytes
|
||||
* \param[in] v Pointer to input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
int l, uint8_t * v)
|
||||
int l, const uint8_t * v)
|
||||
{
|
||||
if ((*length + 1 + l) >= size)
|
||||
return 1;
|
||||
@@ -62,6 +78,13 @@ int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode a TV1 (Tag + 8bit value) type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] v Input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
uint8_t v)
|
||||
{
|
||||
@@ -73,6 +96,13 @@ int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode a TV2 (Tag + 16bit value) type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] v Input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
uint16_t v)
|
||||
{
|
||||
@@ -84,6 +114,13 @@ int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode a TV4 (Tag + 32bit value) type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] v Input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
uint32_t v)
|
||||
{
|
||||
@@ -95,6 +132,13 @@ int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode a TV8 (Tag + 64bit value) type Information Element.
|
||||
* \param[inout] p Pointer to output packet to which IE is appended
|
||||
* \param[inout] length Up to which byte length is \a p used/filled
|
||||
* \param[in] size Total size of \a p in bytes
|
||||
* \param[in] t Tag / Information Element Identifier
|
||||
* \param[in] v Input value
|
||||
* \returns 0 on success, 1 on error */
|
||||
int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
uint64_t v)
|
||||
{
|
||||
@@ -106,6 +150,11 @@ int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain a GTP IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \returns index into \a ie on success; -1 if not found */
|
||||
int gtpie_getie(union gtpie_member *ie[], int type, int instance)
|
||||
{
|
||||
int j;
|
||||
@@ -118,6 +167,11 @@ int gtpie_getie(union gtpie_member *ie[], int type, int instance)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! Determine if IE for a given tag/IEI exists in a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \returns 1 if IEI instance present in \a ie; 0 if not */
|
||||
int gtpie_exist(union gtpie_member *ie[], int type, int instance)
|
||||
{
|
||||
int j;
|
||||
@@ -130,6 +184,14 @@ int gtpie_exist(union gtpie_member *ie[], int type, int instance)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TLV-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[out] length Length of IE
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \param[in] size Size of \a dst in bytes
|
||||
* \returns 0 on sucess; EOF in case value is larger than \a size */
|
||||
int gtpie_gettlv(union gtpie_member *ie[], int type, int instance,
|
||||
unsigned int *length, void *dst, unsigned int size)
|
||||
{
|
||||
@@ -145,6 +207,13 @@ int gtpie_gettlv(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TV0-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \param[in] size Size of value in bytes
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_gettv0(union gtpie_member *ie[], int type, int instance,
|
||||
void *dst, unsigned int size)
|
||||
{
|
||||
@@ -157,6 +226,12 @@ int gtpie_gettv0(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TV1-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_gettv1(union gtpie_member *ie[], int type, int instance,
|
||||
uint8_t * dst)
|
||||
{
|
||||
@@ -169,6 +244,12 @@ int gtpie_gettv1(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TV2-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_gettv2(union gtpie_member *ie[], int type, int instance,
|
||||
uint16_t * dst)
|
||||
{
|
||||
@@ -181,6 +262,12 @@ int gtpie_gettv2(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TV4-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_gettv4(union gtpie_member *ie[], int type, int instance,
|
||||
uint32_t * dst)
|
||||
{
|
||||
@@ -193,6 +280,12 @@ int gtpie_gettv4(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain Value of TV8-type IE for a given tag/IEI from a list/array.
|
||||
* \param[in] ie Array of GTPIE
|
||||
* \param[in] type Tag/IEI for which we're looking
|
||||
* \param[in] instance Instance (number of occurence) of this IEI
|
||||
* \param[inout] dst Caller-allocated buffer where to store value
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_gettv8(union gtpie_member *ie[], int type, int instance,
|
||||
uint64_t * dst)
|
||||
{
|
||||
@@ -205,13 +298,19 @@ int gtpie_gettv8(union gtpie_member *ie[], int type, int instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gtpie_decaps(union gtpie_member *ie[], int version, void *pack,
|
||||
/*! Parse an incoming GTP packet into its Information Elements.
|
||||
* \param[out] ie Caller-allocated Array of GTPIE
|
||||
* \param[in] version GTP protocol version
|
||||
* \param[in] pack Pointer to raw GTP packet (payload part)
|
||||
* \param[in] len Length of \a pack in bytes
|
||||
* \returns 0 on sucess; EOF in case IE not found */
|
||||
int gtpie_decaps(union gtpie_member *ie[], int version, const void *pack,
|
||||
unsigned len)
|
||||
{
|
||||
int i;
|
||||
int j = 0;
|
||||
unsigned char *p;
|
||||
unsigned char *end;
|
||||
const unsigned char *p;
|
||||
const unsigned char *end;
|
||||
|
||||
end = (unsigned char *)pack + len;
|
||||
p = pack;
|
||||
@@ -243,6 +342,7 @@ int gtpie_decaps(union gtpie_member *ie[], int version, void *pack,
|
||||
case GTPIE_RP_SMS:
|
||||
case GTPIE_RP:
|
||||
case GTPIE_MS_NOT_REACH:
|
||||
case GTPIE_BCM:
|
||||
if (j < GTPIE_SIZE) {
|
||||
ie[j] = (union gtpie_member *)p;
|
||||
if (GTPIE_DEBUG)
|
||||
@@ -390,11 +490,76 @@ int gtpie_decaps(union gtpie_member *ie[], int version, void *pack,
|
||||
case GTPIE_RAB_SETUP:
|
||||
case GTPIE_TRIGGER_ID:
|
||||
case GTPIE_OMC_ID:
|
||||
case GTPIE_CHARGING_ADDR:
|
||||
case GTPIE_RAN_T_CONTAIN:
|
||||
case GTPIE_PDP_CTX_PRIO:
|
||||
case GTPIE_ADDL_RAB_S_I:
|
||||
case GTPIE_SGSN_NUMBER:
|
||||
case GTPIE_COMMON_FLAGS:
|
||||
case GTPIE_APN_RESTR:
|
||||
case GTPIE_R_PRIO_LCS:
|
||||
case GTPIE_RAT_TYPE:
|
||||
case GTPIE_USER_LOC:
|
||||
case GTPIE_MS_TZ:
|
||||
case GTPIE_IMEI_SV:
|
||||
case GTPIE_CML_CHG_I_CT:
|
||||
case GTPIE_MBMS_UE_CTX:
|
||||
case GTPIE_TMGI:
|
||||
case GTPIE_RIM_ROUT_ADDR:
|
||||
case GTPIE_MBMS_PCO:
|
||||
case GTPIE_MBMS_SA:
|
||||
case GTPIE_SRNC_PDCP_CTX:
|
||||
case GTPIE_ADDL_TRACE:
|
||||
case GTPIE_HOP_CTR:
|
||||
case GTPIE_SEL_PLMN_ID:
|
||||
case GTPIE_MBMS_SESS_ID:
|
||||
case GTPIE_MBMS_2_3G_IND:
|
||||
case GTPIE_ENH_NSAPI:
|
||||
case GTPIE_MBMS_SESS_DUR:
|
||||
case GTPIE_A_MBMS_TRAC_I:
|
||||
case GTPIE_MBMS_S_REP_N:
|
||||
case GTPIE_MBMS_TTDT:
|
||||
case GTPIE_PS_HO_REQ_CTX:
|
||||
case GTPIE_BSS_CONTAINER:
|
||||
case GTPIE_CELL_ID:
|
||||
case GTPIE_PDU_NUMBERS:
|
||||
case GTPIE_BSSGP_CAUSE:
|
||||
case GTPIE_RQD_MBMS_BCAP:
|
||||
case GTPIE_RIM_RA_DISCR:
|
||||
case GTPIE_L_SETUP_PFCS:
|
||||
case GTPIE_PS_HO_XID_PAR:
|
||||
case GTPIE_MS_CHG_REP_A:
|
||||
case GTPIE_DIR_TUN_FLAGS:
|
||||
case GTPIE_CORREL_ID:
|
||||
case GTPIE_MBMS_FLOWI:
|
||||
case GTPIE_MBMS_MC_DIST:
|
||||
case GTPIE_MBMS_DIST_ACK:
|
||||
case GTPIE_R_IRAT_HO_INF:
|
||||
case GTPIE_RFSP_IDX:
|
||||
case GTPIE_FQDN:
|
||||
case GTPIE_E_ALL_PRIO_1:
|
||||
case GTPIE_E_ALL_PRIO_2:
|
||||
case GTPIE_E_CMN_FLAGS:
|
||||
case GTPIE_U_CSG_INFO:
|
||||
case GTPIE_CSG_I_REP_ACT:
|
||||
case GTPIE_CSG_ID:
|
||||
case GTPIE_CSG_MEMB_IND:
|
||||
case GTPIE_AMBR:
|
||||
case GTPIE_UE_NET_CAPA:
|
||||
case GTPIE_UE_AMBR:
|
||||
case GTPIE_APN_AMBR_NS:
|
||||
case GTPIE_GGSN_BACKOFF:
|
||||
case GTPIE_S_PRIO_IND:
|
||||
case GTPIE_S_PRIO_IND_NS:
|
||||
case GTPIE_H_BR_16MBPS_F:
|
||||
case GTPIE_A_MMCTX_SRVCC:
|
||||
case GTPIE_A_FLAGS_SRVCC:
|
||||
case GTPIE_STN_SR:
|
||||
case GTPIE_C_MSISDN:
|
||||
case GTPIE_E_RANAP_CAUSE:
|
||||
case GTPIE_ENODEB_ID:
|
||||
case GTPIE_SEL_MODE_NS:
|
||||
case GTPIE_ULI_TIMESTAMP:
|
||||
case GTPIE_CHARGING_ADDR:
|
||||
case GTPIE_PRIVATE:
|
||||
if (j < GTPIE_SIZE) {
|
||||
ie[j] = (union gtpie_member *)p;
|
||||
@@ -429,12 +594,16 @@ int gtpie_decaps(union gtpie_member *ie[], int version, void *pack,
|
||||
}
|
||||
}
|
||||
|
||||
/*! Encode GTP packet payload from Array of Information Elements.
|
||||
* \param[out] ie Input Array of GTPIE
|
||||
* \param[out] pack Pointer to caller-allocated buffer for raw GTP packet (GTPIE_MAX length)
|
||||
* \param[out] len Encoded length of \a pack in bytes
|
||||
* \returns 0 on sucess; 2 for out-of-space */
|
||||
int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p;
|
||||
unsigned char *end;
|
||||
union gtpie_member *m;
|
||||
int iesize;
|
||||
|
||||
p = pack;
|
||||
@@ -445,7 +614,6 @@ int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
if (ie[i] != 0) {
|
||||
if (GTPIE_DEBUG)
|
||||
printf("gtpie_encaps. Type %d\n", i);
|
||||
m = (union gtpie_member *)p;
|
||||
switch (i) {
|
||||
case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */
|
||||
case GTPIE_REORDER:
|
||||
@@ -459,6 +627,7 @@ int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
case GTPIE_RP_SMS:
|
||||
case GTPIE_RP:
|
||||
case GTPIE_MS_NOT_REACH:
|
||||
case GTPIE_BCM:
|
||||
iesize = 2;
|
||||
break;
|
||||
case GTPIE_FL_DI: /* TV GTPIE types with value length 2 */
|
||||
@@ -483,11 +652,13 @@ int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */
|
||||
iesize = 6;
|
||||
break;
|
||||
case GTPIE_RAI: /* TV GTPIE types with value length 6 */
|
||||
iesize = 7;
|
||||
break;
|
||||
case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */
|
||||
iesize = 8;
|
||||
break;
|
||||
case GTPIE_IMSI: /* TV GTPIE types with value length 8 */
|
||||
case GTPIE_RAI:
|
||||
iesize = 9;
|
||||
break;
|
||||
case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */
|
||||
@@ -511,6 +682,75 @@ int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
case GTPIE_RAB_SETUP:
|
||||
case GTPIE_TRIGGER_ID:
|
||||
case GTPIE_OMC_ID:
|
||||
case GTPIE_RAN_T_CONTAIN:
|
||||
case GTPIE_PDP_CTX_PRIO:
|
||||
case GTPIE_ADDL_RAB_S_I:
|
||||
case GTPIE_SGSN_NUMBER:
|
||||
case GTPIE_COMMON_FLAGS:
|
||||
case GTPIE_APN_RESTR:
|
||||
case GTPIE_R_PRIO_LCS:
|
||||
case GTPIE_RAT_TYPE:
|
||||
case GTPIE_USER_LOC:
|
||||
case GTPIE_MS_TZ:
|
||||
case GTPIE_IMEI_SV:
|
||||
case GTPIE_CML_CHG_I_CT:
|
||||
case GTPIE_MBMS_UE_CTX:
|
||||
case GTPIE_TMGI:
|
||||
case GTPIE_RIM_ROUT_ADDR:
|
||||
case GTPIE_MBMS_PCO:
|
||||
case GTPIE_MBMS_SA:
|
||||
case GTPIE_SRNC_PDCP_CTX:
|
||||
case GTPIE_ADDL_TRACE:
|
||||
case GTPIE_HOP_CTR:
|
||||
case GTPIE_SEL_PLMN_ID:
|
||||
case GTPIE_MBMS_SESS_ID:
|
||||
case GTPIE_MBMS_2_3G_IND:
|
||||
case GTPIE_ENH_NSAPI:
|
||||
case GTPIE_MBMS_SESS_DUR:
|
||||
case GTPIE_A_MBMS_TRAC_I:
|
||||
case GTPIE_MBMS_S_REP_N:
|
||||
case GTPIE_MBMS_TTDT:
|
||||
case GTPIE_PS_HO_REQ_CTX:
|
||||
case GTPIE_BSS_CONTAINER:
|
||||
case GTPIE_CELL_ID:
|
||||
case GTPIE_PDU_NUMBERS:
|
||||
case GTPIE_BSSGP_CAUSE:
|
||||
case GTPIE_RQD_MBMS_BCAP:
|
||||
case GTPIE_RIM_RA_DISCR:
|
||||
case GTPIE_L_SETUP_PFCS:
|
||||
case GTPIE_PS_HO_XID_PAR:
|
||||
case GTPIE_MS_CHG_REP_A:
|
||||
case GTPIE_DIR_TUN_FLAGS:
|
||||
case GTPIE_CORREL_ID:
|
||||
case GTPIE_MBMS_FLOWI:
|
||||
case GTPIE_MBMS_MC_DIST:
|
||||
case GTPIE_MBMS_DIST_ACK:
|
||||
case GTPIE_R_IRAT_HO_INF:
|
||||
case GTPIE_RFSP_IDX:
|
||||
case GTPIE_FQDN:
|
||||
case GTPIE_E_ALL_PRIO_1:
|
||||
case GTPIE_E_ALL_PRIO_2:
|
||||
case GTPIE_E_CMN_FLAGS:
|
||||
case GTPIE_U_CSG_INFO:
|
||||
case GTPIE_CSG_I_REP_ACT:
|
||||
case GTPIE_CSG_ID:
|
||||
case GTPIE_CSG_MEMB_IND:
|
||||
case GTPIE_AMBR:
|
||||
case GTPIE_UE_NET_CAPA:
|
||||
case GTPIE_UE_AMBR:
|
||||
case GTPIE_APN_AMBR_NS:
|
||||
case GTPIE_GGSN_BACKOFF:
|
||||
case GTPIE_S_PRIO_IND:
|
||||
case GTPIE_S_PRIO_IND_NS:
|
||||
case GTPIE_H_BR_16MBPS_F:
|
||||
case GTPIE_A_MMCTX_SRVCC:
|
||||
case GTPIE_A_FLAGS_SRVCC:
|
||||
case GTPIE_STN_SR:
|
||||
case GTPIE_C_MSISDN:
|
||||
case GTPIE_E_RANAP_CAUSE:
|
||||
case GTPIE_ENODEB_ID:
|
||||
case GTPIE_SEL_MODE_NS:
|
||||
case GTPIE_ULI_TIMESTAMP:
|
||||
case GTPIE_CHARGING_ADDR:
|
||||
case GTPIE_PRIVATE:
|
||||
iesize = 3 + hton16(ie[i]->tlv.l);
|
||||
@@ -528,13 +768,18 @@ int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Encode GTP packet payload from Array of Information Elements.
|
||||
* \param[out] ie Input Array of GTPIE
|
||||
* \param[in] size Size of ?
|
||||
* \param[out] pack Pointer to caller-allocated buffer for raw GTP packet (GTPIE_MAX length)
|
||||
* \param[out] len Encoded length of \a pack in bytes
|
||||
* \returns 0 on sucess; 2 for out-of-space */
|
||||
int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
void *pack, unsigned *len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned char *p;
|
||||
unsigned char *end;
|
||||
union gtpie_member *m;
|
||||
int iesize;
|
||||
|
||||
p = pack;
|
||||
@@ -548,7 +793,6 @@ int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
printf
|
||||
("gtpie_encaps. Number %d, Type %d\n",
|
||||
i, ie[i].t);
|
||||
m = (union gtpie_member *)p;
|
||||
switch (ie[i].t) {
|
||||
case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */
|
||||
case GTPIE_REORDER:
|
||||
@@ -562,6 +806,7 @@ int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
case GTPIE_RP_SMS:
|
||||
case GTPIE_RP:
|
||||
case GTPIE_MS_NOT_REACH:
|
||||
case GTPIE_BCM:
|
||||
iesize = 2;
|
||||
break;
|
||||
case GTPIE_PFI: /* TV GTPIE types with value length 2 */
|
||||
@@ -578,16 +823,19 @@ int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
case GTPIE_P_TMSI:
|
||||
case GTPIE_TEI_DI:
|
||||
case GTPIE_TEI_C:
|
||||
case GTPIE_CHARGING_ID:
|
||||
iesize = 5;
|
||||
break;
|
||||
case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */
|
||||
iesize = 6;
|
||||
break;
|
||||
case GTPIE_RAI: /* TV GTPIE types with value length 6 */
|
||||
iesize = 7;
|
||||
break;
|
||||
case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */
|
||||
iesize = 8;
|
||||
break;
|
||||
case GTPIE_IMSI: /* TV GTPIE types with value length 8 */
|
||||
case GTPIE_RAI:
|
||||
iesize = 9;
|
||||
break;
|
||||
case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */
|
||||
@@ -596,8 +844,7 @@ int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
case GTPIE_EXT_HEADER_T: /* GTP extension header */
|
||||
iesize = 2 + hton8(ie[i].ext.l);
|
||||
break;
|
||||
case GTPIE_CHARGING_ID: /* TLV GTPIE types with length length 2 */
|
||||
case GTPIE_EUA:
|
||||
case GTPIE_EUA: /* TLV GTPIE types with length length 2 */
|
||||
case GTPIE_MM_CONTEXT:
|
||||
case GTPIE_PDP_CONTEXT:
|
||||
case GTPIE_APN:
|
||||
@@ -612,6 +859,75 @@ int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
|
||||
case GTPIE_RAB_SETUP:
|
||||
case GTPIE_TRIGGER_ID:
|
||||
case GTPIE_OMC_ID:
|
||||
case GTPIE_RAN_T_CONTAIN:
|
||||
case GTPIE_PDP_CTX_PRIO:
|
||||
case GTPIE_ADDL_RAB_S_I:
|
||||
case GTPIE_SGSN_NUMBER:
|
||||
case GTPIE_COMMON_FLAGS:
|
||||
case GTPIE_APN_RESTR:
|
||||
case GTPIE_R_PRIO_LCS:
|
||||
case GTPIE_RAT_TYPE:
|
||||
case GTPIE_USER_LOC:
|
||||
case GTPIE_MS_TZ:
|
||||
case GTPIE_IMEI_SV:
|
||||
case GTPIE_CML_CHG_I_CT:
|
||||
case GTPIE_MBMS_UE_CTX:
|
||||
case GTPIE_TMGI:
|
||||
case GTPIE_RIM_ROUT_ADDR:
|
||||
case GTPIE_MBMS_PCO:
|
||||
case GTPIE_MBMS_SA:
|
||||
case GTPIE_SRNC_PDCP_CTX:
|
||||
case GTPIE_ADDL_TRACE:
|
||||
case GTPIE_HOP_CTR:
|
||||
case GTPIE_SEL_PLMN_ID:
|
||||
case GTPIE_MBMS_SESS_ID:
|
||||
case GTPIE_MBMS_2_3G_IND:
|
||||
case GTPIE_ENH_NSAPI:
|
||||
case GTPIE_MBMS_SESS_DUR:
|
||||
case GTPIE_A_MBMS_TRAC_I:
|
||||
case GTPIE_MBMS_S_REP_N:
|
||||
case GTPIE_MBMS_TTDT:
|
||||
case GTPIE_PS_HO_REQ_CTX:
|
||||
case GTPIE_BSS_CONTAINER:
|
||||
case GTPIE_CELL_ID:
|
||||
case GTPIE_PDU_NUMBERS:
|
||||
case GTPIE_BSSGP_CAUSE:
|
||||
case GTPIE_RQD_MBMS_BCAP:
|
||||
case GTPIE_RIM_RA_DISCR:
|
||||
case GTPIE_L_SETUP_PFCS:
|
||||
case GTPIE_PS_HO_XID_PAR:
|
||||
case GTPIE_MS_CHG_REP_A:
|
||||
case GTPIE_DIR_TUN_FLAGS:
|
||||
case GTPIE_CORREL_ID:
|
||||
case GTPIE_MBMS_FLOWI:
|
||||
case GTPIE_MBMS_MC_DIST:
|
||||
case GTPIE_MBMS_DIST_ACK:
|
||||
case GTPIE_R_IRAT_HO_INF:
|
||||
case GTPIE_RFSP_IDX:
|
||||
case GTPIE_FQDN:
|
||||
case GTPIE_E_ALL_PRIO_1:
|
||||
case GTPIE_E_ALL_PRIO_2:
|
||||
case GTPIE_E_CMN_FLAGS:
|
||||
case GTPIE_U_CSG_INFO:
|
||||
case GTPIE_CSG_I_REP_ACT:
|
||||
case GTPIE_CSG_ID:
|
||||
case GTPIE_CSG_MEMB_IND:
|
||||
case GTPIE_AMBR:
|
||||
case GTPIE_UE_NET_CAPA:
|
||||
case GTPIE_UE_AMBR:
|
||||
case GTPIE_APN_AMBR_NS:
|
||||
case GTPIE_GGSN_BACKOFF:
|
||||
case GTPIE_S_PRIO_IND:
|
||||
case GTPIE_S_PRIO_IND_NS:
|
||||
case GTPIE_H_BR_16MBPS_F:
|
||||
case GTPIE_A_MMCTX_SRVCC:
|
||||
case GTPIE_A_FLAGS_SRVCC:
|
||||
case GTPIE_STN_SR:
|
||||
case GTPIE_C_MSISDN:
|
||||
case GTPIE_E_RANAP_CAUSE:
|
||||
case GTPIE_ENODEB_ID:
|
||||
case GTPIE_SEL_MODE_NS:
|
||||
case GTPIE_ULI_TIMESTAMP:
|
||||
case GTPIE_CHARGING_ADDR:
|
||||
case GTPIE_PRIVATE:
|
||||
iesize = 3 + hton16(ie[i].tlv.l);
|
||||
|
||||
86
gtp/gtpie.h
86
gtp/gtpie.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
@@ -12,6 +12,8 @@
|
||||
#ifndef _GTPIE_H
|
||||
#define _GTPIE_H
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* Macroes for conversion between host and network byte order */
|
||||
#define hton8(x) (x)
|
||||
#define ntoh8(x) (x)
|
||||
@@ -48,7 +50,7 @@ static __inline uint64_t hton64(uint64_t q)
|
||||
|
||||
#define GTPIE_DEBUG 0 /* Print debug information */
|
||||
|
||||
/* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */
|
||||
/* GTP Information elements from 29.060 v11.8.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 */
|
||||
|
||||
@@ -84,7 +86,7 @@ static __inline uint64_t hton64(uint64_t q)
|
||||
#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) */
|
||||
/* 117-126 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15 / 32.295) */
|
||||
#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */
|
||||
#define GTPIE_EUA 128 /* End User Address */
|
||||
#define GTPIE_MM_CONTEXT 129 /* MM Context */
|
||||
@@ -102,13 +104,81 @@ static __inline uint64_t hton64(uint64_t q)
|
||||
#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_RAN_T_CONTAIN 144 /* RAN Transparent Container */
|
||||
#define GTPIE_PDP_CTX_PRIO 145 /* PDP Context Prioritization */
|
||||
#define GTPIE_ADDL_RAB_S_I 146 /* Additional RAB Setup Information */
|
||||
#define GTPIE_SGSN_NUMBER 147 /* SGSN Number */
|
||||
#define GTPIE_COMMON_FLAGS 148 /* Common Flags */
|
||||
#define GTPIE_APN_RESTR 149 /* APN Restriction */
|
||||
#define GTPIE_R_PRIO_LCS 150 /* Radio Priority LCS */
|
||||
#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 */
|
||||
/* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
|
||||
#define GTPIE_CML_CHG_I_CT 155 /* CAMEL Charging Information Container */
|
||||
#define GTPIE_MBMS_UE_CTX 156 /* MSMS UE Context */
|
||||
#define GTPIE_TMGI 157 /* Temporary Mobile Group Identity (TMGI) */
|
||||
#define GTPIE_RIM_ROUT_ADDR 158 /* RIM Routing Address */
|
||||
#define GTPIE_MBMS_PCO 159 /* MBMS Protocol Configuratin Options */
|
||||
#define GTPIE_MBMS_SA 160 /* MBMS Service Area */
|
||||
#define GTPIE_SRNC_PDCP_CTX 161 /* Source RNC PDCP Context Info */
|
||||
#define GTPIE_ADDL_TRACE 162 /* Additional Trace Info */
|
||||
#define GTPIE_HOP_CTR 163 /* Hop Counter */
|
||||
#define GTPIE_SEL_PLMN_ID 164 /* Selected PLMN ID */
|
||||
#define GTPIE_MBMS_SESS_ID 165 /* MBMS Session Identifier */
|
||||
#define GTPIE_MBMS_2_3G_IND 166 /* MBMS 2G/3G Indicator */
|
||||
#define GTPIE_ENH_NSAPI 167 /* Enhanced NSAPI */
|
||||
#define GTPIE_MBMS_SESS_DUR 168 /* MBMS Session Duration */
|
||||
#define GTPIE_A_MBMS_TRAC_I 169 /* Additional MBMS Trace Info */
|
||||
#define GTPIE_MBMS_S_REP_N 170 /* MBMS Session Repetition Number */
|
||||
#define GTPIE_MBMS_TTDT 171 /* MBMS Time To Data Transfer */
|
||||
#define GTPIE_PS_HO_REQ_CTX 172 /* PS Handover Request Context */
|
||||
#define GTPIE_BSS_CONTAINER 173 /* BSS Container */
|
||||
#define GTPIE_CELL_ID 174 /* Cell Identification */
|
||||
#define GTPIE_PDU_NUMBERS 175 /* PDU Numbers */
|
||||
#define GTPIE_BSSGP_CAUSE 176 /* BSSGP Cause */
|
||||
#define GTPIE_RQD_MBMS_BCAP 177 /* Required MBMS Bearer Capabilities */
|
||||
#define GTPIE_RIM_RA_DISCR 178 /* RIM Routing Address Discriminator */
|
||||
#define GTPIE_L_SETUP_PFCS 179 /* List of set-up PFCs */
|
||||
#define GTPIE_PS_HO_XID_PAR 180 /* PS Handover XID Parameters */
|
||||
#define GTPIE_MS_CHG_REP_A 181 /* MS Info Change Reporting Action */
|
||||
#define GTPIE_DIR_TUN_FLAGS 182 /* Direct Tunnel Flags */
|
||||
#define GTPIE_CORREL_ID 183 /* Correlation-ID */
|
||||
#define GTPIE_BCM 184 /* Bearer control mode */
|
||||
#define GTPIE_MBMS_FLOWI 185 /* MBMS Flow Identifier */
|
||||
#define GTPIE_MBMS_MC_DIST 186 /* MBMS IP Multicast Distribution */
|
||||
#define GTPIE_MBMS_DIST_ACK 187 /* MBMS Distribution Acknowledgement */
|
||||
#define GTPIE_R_IRAT_HO_INF 188 /* Reliable INTER RAT HANDOVER INFO */
|
||||
#define GTPIE_RFSP_IDX 189 /* RFSP Index */
|
||||
#define GTPIE_FQDN 190 /* FQDN */
|
||||
#define GTPIE_E_ALL_PRIO_1 191 /* Evolvd Allocation/Retention Priority I */
|
||||
#define GTPIE_E_ALL_PRIO_2 192 /* Evolvd Allocation/Retention Priority II */
|
||||
#define GTPIE_E_CMN_FLAGS 193 /* Extended Common Flags */
|
||||
#define GTPIE_U_CSG_INFO 194 /* User CSG Information (UCI) */
|
||||
#define GTPIE_CSG_I_REP_ACT 195 /* CSG Information Reporting Action */
|
||||
#define GTPIE_CSG_ID 196 /* CSG ID */
|
||||
#define GTPIE_CSG_MEMB_IND 197 /* CSG Membership Indication (CMI) */
|
||||
#define GTPIE_AMBR 198 /* Aggregate Maximum Bit Rate (AMBR) */
|
||||
#define GTPIE_UE_NET_CAPA 199 /* UE Network Capability */
|
||||
#define GTPIE_UE_AMBR 200 /* UE-AMBR */
|
||||
#define GTPIE_APN_AMBR_NS 201 /* APN-AMBR with NSAPI */
|
||||
#define GTPIE_GGSN_BACKOFF 202 /* GGSN Back-Off Time */
|
||||
#define GTPIE_S_PRIO_IND 203 /* Signalling Priority Indication */
|
||||
#define GTPIE_S_PRIO_IND_NS 204 /* Signalling Priority Indication with NSAPI */
|
||||
#define GTPIE_H_BR_16MBPS_F 205 /* Higher Bitrates than 16 Mbps flag */
|
||||
/* 206: Reserved */
|
||||
#define GTPIE_A_MMCTX_SRVCC 207 /* Additional MM context for SRVCC */
|
||||
#define GTPIE_A_FLAGS_SRVCC 208 /* Additional flags fro SRVC */
|
||||
#define GTPIE_STN_SR 209 /* STN-SR */
|
||||
#define GTPIE_C_MSISDN 210 /* C-MSISDN */
|
||||
#define GTPIE_E_RANAP_CAUSE 211 /* Extended RANAP Cause */
|
||||
#define GTPIE_ENODEB_ID 212 /* eNodeB ID */
|
||||
#define GTPIE_SEL_MODE_NS 213 /* Selection Mode with NSAPI */
|
||||
#define GTPIE_ULI_TIMESTAMP 214 /* ULI Timestamp */
|
||||
/* 215-238 Spare. For future use */
|
||||
/* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15 / 32.295) */
|
||||
#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */
|
||||
/* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
|
||||
/* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15 / 32.295) */
|
||||
#define GTPIE_PRIVATE 255 /* Private Extension */
|
||||
|
||||
/* GTP information element structs in network order */
|
||||
@@ -220,9 +290,9 @@ struct tlv2 {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern int gtpie_tlv(void *p, unsigned int *length, unsigned int size,
|
||||
uint8_t t, int l, void *v);
|
||||
uint8_t t, int l, const void *v);
|
||||
extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size,
|
||||
uint8_t t, int l, uint8_t * v);
|
||||
uint8_t t, int l, const 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,
|
||||
@@ -247,7 +317,7 @@ 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,
|
||||
void *pack, unsigned len);
|
||||
const 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);
|
||||
|
||||
104
gtp/pdp.c
104
gtp/pdp.c
@@ -1,16 +1,17 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
/*
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
*
|
||||
* Copyright (C) 2017 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* pdp.c:
|
||||
* pdp.c:
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -26,7 +27,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "pdp.h"
|
||||
#include "gtp.h"
|
||||
#include "lookupa.h"
|
||||
|
||||
/* ***********************************************************
|
||||
@@ -41,17 +44,17 @@ static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
* Functions related to PDP storage
|
||||
*
|
||||
* Lifecycle
|
||||
* For a GGSN pdp context life begins with the reception of a
|
||||
* For a GGSN pdp context life begins with the reception of a
|
||||
* create pdp context request. It normally ends with the reception
|
||||
* of a delete pdp context request, but will also end with the
|
||||
* reception of an error indication message.
|
||||
* reception of an error indication message.
|
||||
* Provisions should probably be made for terminating pdp contexts
|
||||
* based on either idle timeout, or by sending downlink probe
|
||||
* based on either idle timeout, or by sending downlink probe
|
||||
* messages (ping?) to see if the MS is still responding.
|
||||
*
|
||||
*
|
||||
* For an SGSN pdp context life begins with the application just
|
||||
* before sending off a create pdp context request. It normally
|
||||
* ends when a delete pdp context response message is received
|
||||
* ends when a delete pdp context response message is received
|
||||
* from the GGSN, but should also end when with the reception of
|
||||
* an error indication message.
|
||||
*
|
||||
@@ -61,15 +64,15 @@ static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
* Downlink packets received in the GGSN are identified only by their
|
||||
* network interface together with their destination IP address (Two
|
||||
* network interfaces can use the same private IP address). Each IMSI
|
||||
* (mobile station) can have several PDP contexts using the same IP
|
||||
* (mobile station) can have several PDP contexts using the same IP
|
||||
* address. In this case the traffic flow template (TFT) is used to
|
||||
* determine the correct PDP context for a particular IMSI. Also it
|
||||
* determine the correct PDP context for a particular IMSI. Also it
|
||||
* should be possible for each PDP context to use several IP adresses
|
||||
* For fixed wireless access a mobile station might need a full class
|
||||
* C network. Even in the case of several IP adresses the PDP context
|
||||
* should be determined on the basis of the network IP address.
|
||||
* Thus we need a hash table based on network interface + IP address.
|
||||
*
|
||||
*
|
||||
* Uplink packets are for GTP0 identified by their IMSI and NSAPI, which
|
||||
* is collectively called the tunnel identifier. There is also a 16 bit
|
||||
* flow label that can be used for identification of uplink packets. This
|
||||
@@ -82,7 +85,7 @@ static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
* Thus we need a hash table based on TID (IMSI and NSAPI). The TEID will
|
||||
* be used for directly addressing the PDP context.
|
||||
|
||||
* pdp_newpdp
|
||||
* pdp_newpdp
|
||||
* Gives you a pdp context with no hash references In some way
|
||||
* this should have a limited lifetime.
|
||||
*
|
||||
@@ -146,6 +149,8 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
1].secondary_tei[(*pdp)->nsapi & 0x0f] =
|
||||
(*pdp)->teid_own;
|
||||
}
|
||||
/* Default: Generate G-PDU sequence numbers on Tx */
|
||||
(*pdp)->tx_gpdu_seq = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -201,6 +206,24 @@ int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
|
||||
}
|
||||
}
|
||||
|
||||
/* get a PDP based on the *peer* address + TEI-Data. Used for matching inbound Error Ind */
|
||||
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* 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_tidhash(uint64_t tid)
|
||||
{
|
||||
return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
|
||||
@@ -211,7 +234,7 @@ 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 = %llx\n", tid);
|
||||
DEBUGP(DLGTP, "Begin pdp_tidset tid = %"PRIx64"\n", tid);
|
||||
pdp->tidnext = NULL;
|
||||
pdp->tid = tid;
|
||||
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
|
||||
@@ -229,7 +252,7 @@ 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 = %llx\n", pdp->tid);
|
||||
DEBUGP(DLGTP, "Begin pdp_tiddel tid = %"PRIx64"\n", pdp->tid);
|
||||
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
|
||||
if (pdp2 == pdp) {
|
||||
if (!pdp_prev)
|
||||
@@ -249,7 +272,7 @@ 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 = %llx\n", tid);
|
||||
DEBUGP(DLGTP, "Begin pdp_tidget tid = %"PRIx64"\n", tid);
|
||||
for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
|
||||
if (pdp2->tid == tid) {
|
||||
*pdp = pdp2;
|
||||
@@ -273,7 +296,7 @@ int pdp_iphash(void* ipif, struct ul66_t *eua) {
|
||||
/#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
|
||||
return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
|
||||
}
|
||||
|
||||
|
||||
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
|
||||
int hash;
|
||||
struct pdp_t *pdp2;
|
||||
@@ -281,7 +304,7 @@ int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
|
||||
|
||||
if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
|
||||
(unsigned) ipif, eua->l,
|
||||
eua->v[2], eua->v[3],
|
||||
eua->v[2], eua->v[3],
|
||||
eua->v[4], eua->v[5]);
|
||||
|
||||
pdp->ipnext = NULL;
|
||||
@@ -293,9 +316,9 @@ int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
|
||||
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
|
||||
pdp_prev = pdp2;
|
||||
if (!pdp_prev)
|
||||
if (!pdp_prev)
|
||||
haship[hash] = pdp;
|
||||
else
|
||||
else
|
||||
pdp_prev->ipnext = pdp;
|
||||
if (PDP_DEBUG) printf("End pdp_ipset\n");
|
||||
return 0;
|
||||
@@ -308,9 +331,9 @@ int pdp_ipdel(struct pdp_t *pdp) {
|
||||
if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
|
||||
if (pdp2 == pdp) {
|
||||
if (!pdp_prev)
|
||||
if (!pdp_prev)
|
||||
haship[hash] = pdp2->ipnext;
|
||||
else
|
||||
else
|
||||
pdp_prev->ipnext = pdp2->ipnext;
|
||||
if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
|
||||
return 0;
|
||||
@@ -324,41 +347,23 @@ int pdp_ipdel(struct pdp_t *pdp) {
|
||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
|
||||
int hash = pdp_iphash(ipif, eua);
|
||||
struct pdp_t *pdp2;
|
||||
/#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
|
||||
/#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
|
||||
eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
|
||||
if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
|
||||
if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
|
||||
(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
|
||||
*pdp = pdp2;
|
||||
/#printf("End pdp_ipget. Found\n");#/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
|
||||
if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
|
||||
(unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
|
||||
return EOF; /# End of linked list and not found #/
|
||||
}
|
||||
*/
|
||||
/* Various conversion functions */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi)
|
||||
{
|
||||
return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60);
|
||||
@@ -369,14 +374,3 @@ void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid)
|
||||
pdp->imsi = teid & 0x0fffffffffffffffull;
|
||||
pdp->nsapi = (teid & 0xf000000000000000ull) >> 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;
|
||||
}
|
||||
|
||||
41
gtp/pdp.h
41
gtp/pdp.h
@@ -1,20 +1,33 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
/*
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003 Mondru AB.
|
||||
*
|
||||
* Copyright (C) 2017 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 _PDP_H
|
||||
#define _PDP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct gsn_t;
|
||||
|
||||
#define LOGPDPX(ss, level, pdp, fmt, args...) \
|
||||
LOGP(ss, level, "PDP(%s:%u): " fmt, imsi_gtp2str(&(pdp)->imsi), (pdp)->nsapi, ## args)
|
||||
|
||||
#define PDP_MAX 1024 /* Max number of PDP contexts */
|
||||
#define PDP_MAXNSAPI 16 /* Max number of NSAPI */
|
||||
|
||||
#define PDP_EUA_ORG_IETF 0xF1
|
||||
#define PDP_EUA_TYPE_v4 0x21
|
||||
#define PDP_EUA_TYPE_v6 0x57
|
||||
#define PDP_EUA_TYPE_v4v6 0x8D
|
||||
|
||||
/* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */
|
||||
/* Also covers version 0. Note that version 0 6: QOS Profile was superceded *
|
||||
* by 135: QOS Profile in version 1 */
|
||||
@@ -59,16 +72,16 @@ struct ul255_t {
|
||||
* and 09.60.
|
||||
* 31 * 4 + 15 structs + = 120 + 15 structs ~ 2k / context
|
||||
* Structs: IP address 16+4 bytes (6), APN 255 bytes (2)
|
||||
* QOS: 255 bytes (3), msisdn 16 bytes (1),
|
||||
* QOS: 255 bytes (3), msisdn 16 bytes (1),
|
||||
*
|
||||
* TODO: We need to consider who manages the pdp_t hash tables
|
||||
* Is it gtp_lib, or is it the application?
|
||||
* I suppose that it will be gtp_lib.
|
||||
* I suppose that it will be gtp_lib.
|
||||
* SGSN will ask gtplib for new pdp_t. Fill out the fields,
|
||||
* and pass it on to gtp_create_pdp_req.
|
||||
* GGSN will receive gtp_create_pdp_ind, create new pdp_t and
|
||||
* send responce to SGSN.
|
||||
* SGSN will receive response and gtplib will find the
|
||||
* SGSN will receive response and gtplib will find the
|
||||
* original pdp_t corresponding to the request. This will be
|
||||
* passed on to the application.
|
||||
* Eventually the SGSN will close the connection, and the
|
||||
@@ -76,10 +89,10 @@ struct ul255_t {
|
||||
* This means that gtplib need to have functions to
|
||||
* allocate, free, sort and find pdp_t
|
||||
* (newpdp, freepdp, getpdp)
|
||||
* Hash tables: TID, IMSI, IP etc.)
|
||||
* Hash tables: TID, IMSI, IP etc.)
|
||||
*
|
||||
*
|
||||
* Secondary PDP Context Activation Procedure
|
||||
* Secondary PDP Context Activation Procedure
|
||||
*
|
||||
* With GTP version 1 it is possible to establish multiple PDP
|
||||
* contexts with the same IP address. With this scheme the first
|
||||
@@ -109,7 +122,7 @@ struct pdp_t {
|
||||
/* Parameters shared by all PDP context belonging to the same MS */
|
||||
|
||||
void *ipif; /* IP network interface */
|
||||
void *peer; /* Pointer to peer protocol */
|
||||
void *peer[2]; /* Pointer to peer protocol */
|
||||
void *asap; /* Application specific service access point */
|
||||
|
||||
uint64_t imsi; /* International Mobile Subscriber Identity. */
|
||||
@@ -221,6 +234,10 @@ struct pdp_t {
|
||||
|
||||
/* to be used by libgtp callers/users (to attach their own private state) */
|
||||
void *priv;
|
||||
|
||||
struct gsn_t *gsn;
|
||||
|
||||
bool tx_gpdu_seq; /* Transmit (true) or suppress G-PDU sequence numbers */
|
||||
};
|
||||
|
||||
/* functions related to pdp_t management */
|
||||
@@ -232,6 +249,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);
|
||||
|
||||
@@ -249,9 +267,6 @@ int pdp_ipdel(struct pdp_t *pdp);
|
||||
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 */
|
||||
|
||||
35
gtp/queue.c
35
gtp/queue.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
* Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
|
||||
* Copyright (C) 2016 sysmocom - s.f.m.c. GmbH
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
@@ -78,7 +79,7 @@ static int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
|
||||
if (QUEUE_DEBUG)
|
||||
printf("Begin queue_seqset seq = %d\n", (int)seq);
|
||||
if (QUEUE_DEBUG)
|
||||
printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer),
|
||||
printf("SIZEOF PEER %zu, *PEER %zu\n", sizeof(peer),
|
||||
sizeof(*peer));
|
||||
|
||||
qmsg->seq = seq;
|
||||
@@ -105,8 +106,7 @@ static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
|
||||
printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq);
|
||||
|
||||
for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
|
||||
/* FIXME: this is always true !?! */
|
||||
if (qmsg == qmsg) {
|
||||
if (qmsg == qmsg2) {
|
||||
if (!qmsg_prev)
|
||||
queue->hashseq[hash] = qmsg2->seqnext;
|
||||
else
|
||||
@@ -127,16 +127,15 @@ 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;
|
||||
|
||||
if (QUEUE_DEBUG)
|
||||
queue_print(*queue);
|
||||
if (*queue)
|
||||
return 0;
|
||||
else
|
||||
return EOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Deallocates queue structure */
|
||||
@@ -251,26 +250,6 @@ int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Linear search over entire queue to get given peer + seq*/
|
||||
/* FIXME: unused, dead code! */
|
||||
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 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002 Mondru AB.
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
noinst_LIBRARIES = libmisc.a
|
||||
|
||||
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h
|
||||
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.h
|
||||
|
||||
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
|
||||
libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c
|
||||
libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c netdev.c
|
||||
|
||||
if ENABLE_GTP_KERNEL
|
||||
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
|
||||
libmisc_a_SOURCES += gtp-kernel.c
|
||||
endif
|
||||
|
||||
@@ -26,6 +26,11 @@ static const struct log_info_cat default_categories[] = {
|
||||
.description = "SGSN Emulator",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DICMP6] = {
|
||||
.name = "DICMP6",
|
||||
.description = "ICMPv6",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
};
|
||||
|
||||
const struct log_info log_info = {
|
||||
|
||||
160
lib/gtp-kernel.c
Normal file
160
lib/gtp-kernel.c
Normal file
@@ -0,0 +1,160 @@
|
||||
#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 <inttypes.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(const char *prefix, const char *devname, struct pdp_t *pdp)
|
||||
{
|
||||
struct in46_addr ia46;
|
||||
struct in_addr ia;
|
||||
|
||||
in46a_from_eua(&pdp->eua, &ia46);
|
||||
gsna2in_addr(&ia, &pdp->gsnrc);
|
||||
|
||||
LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=%s SGSN=%s\n", prefix,
|
||||
devname, pdp->version,
|
||||
pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
|
||||
in46a_ntoa(&ia46), inet_ntoa(ia));
|
||||
}
|
||||
|
||||
static struct {
|
||||
int genl_id;
|
||||
struct mnl_socket *nl;
|
||||
} gtp_nl;
|
||||
|
||||
static int gtp_kernel_init_once(void)
|
||||
{
|
||||
/* only initialize once */
|
||||
if (gtp_nl.nl)
|
||||
return 0;
|
||||
|
||||
gtp_nl.nl = genl_socket_open();
|
||||
if (gtp_nl.nl == NULL) {
|
||||
LOGP(DGGSN, LOGL_ERROR, "cannot create genetlink socket\n");
|
||||
return -1;
|
||||
}
|
||||
gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
|
||||
if (gtp_nl.genl_id < 0) {
|
||||
LOGP(DGGSN, LOGL_ERROR, "cannot lookup GTP genetlink ID\n");
|
||||
genl_socket_close(gtp_nl.nl);
|
||||
gtp_nl.nl = NULL;
|
||||
return -1;
|
||||
}
|
||||
LOGP(DGGSN, LOGL_NOTICE, "Initialized GTP kernel mode (genl ID is %d)\n", gtp_nl.genl_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
|
||||
{
|
||||
if (gtp_kernel_init_once() < 0)
|
||||
return -1;
|
||||
|
||||
return gtp_dev_create(dest_ns, devname, fd0, fd1u);
|
||||
}
|
||||
|
||||
int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u)
|
||||
{
|
||||
if (gtp_kernel_init_once() < 0)
|
||||
return -1;
|
||||
|
||||
return gtp_dev_create_sgsn(dest_ns, devname, fd0, fd1u);
|
||||
}
|
||||
|
||||
void gtp_kernel_stop(const char *devname)
|
||||
{
|
||||
gtp_dev_destroy(devname);
|
||||
}
|
||||
|
||||
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
|
||||
{
|
||||
struct in_addr ms, sgsn;
|
||||
struct gtp_tunnel *t;
|
||||
int ret;
|
||||
|
||||
pdp_debug(__func__, devname, 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(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, const char *devname)
|
||||
{
|
||||
struct gtp_tunnel *t;
|
||||
int ret;
|
||||
|
||||
pdp_debug(__func__, devname, pdp);
|
||||
|
||||
t = gtp_tunnel_alloc();
|
||||
if (t == NULL)
|
||||
return -1;
|
||||
|
||||
gtp_tunnel_set_ifidx(t, if_nametoindex(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;
|
||||
}
|
||||
38
lib/gtp-kernel.h
Normal file
38
lib/gtp-kernel.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef _GTP_KERNEL_H_
|
||||
#define _GTP_KERNEL_H_
|
||||
|
||||
struct gengetopt_args_info;
|
||||
|
||||
extern int debug;
|
||||
extern char *ipup;
|
||||
|
||||
#ifdef GTP_KERNEL
|
||||
int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u);
|
||||
int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u);
|
||||
void gtp_kernel_stop(const char *devname);
|
||||
|
||||
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname);
|
||||
int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname);
|
||||
|
||||
#else
|
||||
static inline int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
|
||||
{
|
||||
SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n");
|
||||
return -1;
|
||||
}
|
||||
#define gtp_kernel_create_sgsn gtp_kernel_create
|
||||
|
||||
static inline void gtp_kernel_stop(const char *devname) {}
|
||||
|
||||
static inline int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* _GTP_KERNEL_H_ */
|
||||
373
lib/in46_addr.c
Normal file
373
lib/in46_addr.c
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* 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 "../gtp/pdp.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_INET6;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int ipv4_netmasklen(const struct in_addr *netmask)
|
||||
{
|
||||
uint32_t bits = netmask->s_addr;
|
||||
uint8_t *b = (uint8_t*) &bits;
|
||||
unsigned int i, prefix = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
while (b[i] & 0x80) {
|
||||
prefix++;
|
||||
b[i] = b[i] << 1;
|
||||
}
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
static unsigned int ipv6_netmasklen(const struct in6_addr *netmask)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
#define ADDRFIELD(i) s6_addr32[i]
|
||||
#else
|
||||
#define ADDRFIELD(i) __u6_addr.__u6_addr32[i]
|
||||
#endif
|
||||
|
||||
unsigned int i, j, prefix = 0;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
uint32_t bits = netmask->ADDRFIELD(j);
|
||||
uint8_t *b = (uint8_t*) &bits;
|
||||
for (i = 0; i < 4; i++) {
|
||||
while (b[i] & 0x80) {
|
||||
prefix++;
|
||||
b[i] = b[i] << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef ADDRFIELD
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/*! Convert netmask to prefix length representation
|
||||
* \param[in] netmask in46_addr containing a netmask (consecutive list of 1-bit followed by consecutive list of 0-bit)
|
||||
* \returns prefix length representation of the netmask (count of 1-bit from the start of the netmask)
|
||||
*/
|
||||
unsigned int in46a_netmasklen(const struct in46_addr *netmask)
|
||||
{
|
||||
switch (netmask->len) {
|
||||
case 4:
|
||||
return ipv4_netmasklen(&netmask->v4);
|
||||
case 16:
|
||||
return ipv6_netmasklen(&netmask->v6);
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Convert given array of in46_addr to PDP End User Address
|
||||
* \param[in] src Array containing 1 or 2 in46_addr
|
||||
* \param[out] eua End User Address structure to fill
|
||||
* \returns 0 on success; negative on error
|
||||
*
|
||||
* In case size is 2, this function expects to find exactly one IPv4 and one
|
||||
* IPv6 addresses in src. */
|
||||
int in46a_to_eua(const struct in46_addr *src, unsigned int size, struct ul66_t *eua)
|
||||
{
|
||||
const struct in46_addr *src_v4, *src_v6;
|
||||
if (size == 1) {
|
||||
switch (src->len) {
|
||||
case 4:
|
||||
eua->l = 6;
|
||||
eua->v[0] = PDP_EUA_ORG_IETF;
|
||||
eua->v[1] = PDP_EUA_TYPE_v4;
|
||||
memcpy(&eua->v[2], &src->v4, 4); /* Copy a 4 byte address */
|
||||
break;
|
||||
case 8:
|
||||
case 16:
|
||||
eua->l = 18;
|
||||
eua->v[0] = PDP_EUA_ORG_IETF;
|
||||
eua->v[1] = PDP_EUA_TYPE_v6;
|
||||
memcpy(&eua->v[2], &src->v6, 16); /* Copy a 16 byte address */
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (src[0].len == src[1].len)
|
||||
return -1; /* we should have a v4 and a v6 address */
|
||||
|
||||
src_v4 = (src[0].len == 4) ? &src[0] : &src[1];
|
||||
src_v6 = (src[0].len == 4) ? &src[1] : &src[0];
|
||||
|
||||
eua->l = 22;
|
||||
eua->v[0] = PDP_EUA_ORG_IETF;
|
||||
eua->v[1] = PDP_EUA_TYPE_v4v6;
|
||||
memcpy(&eua->v[2], &src_v4->v4, 4);
|
||||
memcpy(&eua->v[6], &src_v6->v6, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Convert given PDP End User Address to an array of in46_addr
|
||||
* \param[in] eua End User Address structure to parse
|
||||
* \param[out] dst Array containing 2 in46_addr
|
||||
* \returns number of parsed addresses (1 or 2) on success; negative on error
|
||||
*
|
||||
* This function expects to receive an End User Address struct together with an
|
||||
* array of 2 zeroed in46_addr structs. The in46_addr structs are filled in
|
||||
* order, hence if the function returns 1 the parsed address will be stored in
|
||||
* the first struct and the second one will be left intact. If 2 is returned, it
|
||||
* is guaranteed that one of them is an IPv4 and the other one is an IPv6, but
|
||||
* the order in which they are presented is not specified and must be
|
||||
* discovered for instance by checking the len field of each address.
|
||||
*/
|
||||
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
|
||||
{
|
||||
if (eua->l < 2)
|
||||
goto default_to_dyn_v4;
|
||||
|
||||
if (eua->v[0] != 0xf1)
|
||||
return -1;
|
||||
|
||||
switch (eua->v[1]) {
|
||||
case PDP_EUA_TYPE_v4:
|
||||
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;
|
||||
return 1;
|
||||
case PDP_EUA_TYPE_v6:
|
||||
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);
|
||||
return 1;
|
||||
case PDP_EUA_TYPE_v4v6:
|
||||
/* 3GPP TS 29.060, section 7.7.27 */
|
||||
switch (eua->l) {
|
||||
case 2: /* v4 & v6 dynamic */
|
||||
dst[0].v4.s_addr = 0;
|
||||
memset(&dst[1].v6, 0, 16);
|
||||
break;
|
||||
case 6: /* v4 static, v6 dynamic */
|
||||
memcpy(&dst[0].v4, &eua->v[2], 4);
|
||||
memset(&dst[1].v6, 0, 16);
|
||||
break;
|
||||
case 18: /* v4 dynamic, v6 static */
|
||||
dst[0].v4.s_addr = 0;
|
||||
memcpy(&dst[1].v6, &eua->v[2], 16);
|
||||
break;
|
||||
case 22: /* v4 & v6 static */
|
||||
memcpy(&dst[0].v4, &eua->v[2], 4);
|
||||
memcpy(&dst[1].v6, &eua->v[6], 16);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
dst[0].len = 4;
|
||||
dst[1].len = 16;
|
||||
return 2;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
default_to_dyn_v4:
|
||||
/* assume dynamic IPv4 by default */
|
||||
dst->len = 4;
|
||||
dst->v4.s_addr = 0;
|
||||
return 1;
|
||||
}
|
||||
33
lib/in46_addr.h
Normal file
33
lib/in46_addr.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#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);
|
||||
unsigned int in46a_netmasklen(const struct in46_addr *netmask);
|
||||
|
||||
int in46a_to_eua(const struct in46_addr *src, unsigned int size, struct ul66_t *eua);
|
||||
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
|
||||
330
lib/ippool.c
330
lib/ippool.c
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* 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>
|
||||
@@ -16,6 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include "syserr.h"
|
||||
#include "ippool.h"
|
||||
#include "lookup.h"
|
||||
@@ -24,20 +26,21 @@ 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);
|
||||
printf("Firstdyn %td\n", this->firstdyn - this->member);
|
||||
printf("Lastdyn %td\n", this->lastdyn - this->member);
|
||||
printf("Firststat %td\n", this->firststat - this->member);
|
||||
printf("Laststat %td\n", this->laststat - this->member);
|
||||
printf("Listsize %u\n", this->listsize);
|
||||
|
||||
for (n = 0; n < this->listsize; n++) {
|
||||
printf("Unit %d inuse %d prev %d next %d addr %s %x\n",
|
||||
char s[256];
|
||||
in46a_ntop(&this->member[n].addr, s, sizeof(s));
|
||||
printf("Unit %d inuse %d prev %td next %td addr %s\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);
|
||||
s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -49,7 +52,7 @@ int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member)
|
||||
struct ippoolm_t *p_prev = NULL;
|
||||
|
||||
/* Insert into hash table */
|
||||
hash = ippool_hash4(&member->addr) & this->hashmask;
|
||||
hash = ippool_hash(&member->addr) & this->hashmask;
|
||||
for (p = this->hash[hash]; p; p = p->nexthash)
|
||||
p_prev = p;
|
||||
if (!p_prev)
|
||||
@@ -66,7 +69,7 @@ int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member)
|
||||
struct ippoolm_t *p_prev = NULL;
|
||||
|
||||
/* Find in hash table */
|
||||
hash = ippool_hash4(&member->addr) & this->hashmask;
|
||||
hash = ippool_hash(&member->addr) & this->hashmask;
|
||||
for (p = this->hash[hash]; p; p = p->nexthash) {
|
||||
if (p == member) {
|
||||
break;
|
||||
@@ -88,129 +91,156 @@ int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long int ippool_hash4(struct in_addr *addr)
|
||||
static 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)
|
||||
static unsigned long int ippool_hash6(struct in6_addr *addr, unsigned int len)
|
||||
{
|
||||
return lookup((unsigned char *)addr->u6_addr8, sizeof(addr->u6_addr8),
|
||||
0);
|
||||
/* 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get IP address and mask */
|
||||
int ippool_aton(struct in_addr *addr, struct in_addr *mask,
|
||||
char *pool, int number)
|
||||
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];
|
||||
|
||||
/* Parse only first instance of network for now */
|
||||
/* Eventually "number" will indicate the token which we want to parse */
|
||||
strcpy(pool, pool_in);
|
||||
|
||||
unsigned int a1, a2, a3, a4;
|
||||
unsigned int m1, m2, m3, m4;
|
||||
int c;
|
||||
int m;
|
||||
int masklog;
|
||||
int err;
|
||||
|
||||
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(DIP, LOGL_ERROR, 0, "Invalid mask");
|
||||
return -1; /* Invalid mask */
|
||||
/* 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;
|
||||
}
|
||||
mask->s_addr = htonl(0xffffffff << (32 - m1));
|
||||
break;
|
||||
case 8:
|
||||
if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 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(DIP, LOGL_ERROR, 0, "Invalid mask");
|
||||
return -1; /* Wrong mask format (not all ones followed by all zeros) */
|
||||
}
|
||||
mask->s_addr = htonl(m);
|
||||
break;
|
||||
default:
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0, "Invalid mask");
|
||||
return -1; /* Invalid mask */
|
||||
}
|
||||
|
||||
if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Wrong IP address format");
|
||||
/* convert address */
|
||||
if ((err = getaddrinfo(pool, NULL, &hints, &ai))) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0, "Bad address");
|
||||
return -1;
|
||||
} else
|
||||
addr->s_addr =
|
||||
htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
static bool addr_in_prefix_list(struct in46_addr *addr, struct in46_prefix *list, size_t list_size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < list_size; i++) {
|
||||
if (in46a_prefix_equal(addr, &list[i].addr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create new address pool */
|
||||
int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
int allowdyn, int allowstat, int flags)
|
||||
int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const struct in46_prefix *stat,
|
||||
int flags, struct in46_prefix *blacklist, size_t blacklist_size)
|
||||
{
|
||||
|
||||
/* 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;
|
||||
struct in46_addr addr = { 0 };
|
||||
size_t addrprefixlen;
|
||||
struct in46_addr stataddr;
|
||||
size_t stataddrprefixlen;
|
||||
int listsize;
|
||||
int dynsize;
|
||||
unsigned int statsize;
|
||||
|
||||
if (!allowdyn) {
|
||||
if (!dyn || dyn->addr.len == 0) {
|
||||
dynsize = 0;
|
||||
} else {
|
||||
if (ippool_aton(&addr, &mask, dyn, 0)) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Failed to parse dynamic pool");
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
m = ntohl(mask.s_addr);
|
||||
dynsize = ((~m) + 1);
|
||||
dynsize = (1 << (addr.len*8 - addrprefixlen));
|
||||
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--;
|
||||
/* Exclude included blacklist addresses from pool */
|
||||
for (i = 0; i < blacklist_size; i++) {
|
||||
if (in46a_within_mask(&blacklist[i].addr, &addr, addrprefixlen))
|
||||
dynsize--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowstat) {
|
||||
if (!stat || stat->addr.len == 0) {
|
||||
statsize = 0;
|
||||
stataddr.s_addr = 0;
|
||||
statmask.s_addr = 0;
|
||||
stataddr.len = 0;
|
||||
stataddrprefixlen = 0;
|
||||
} else {
|
||||
if (ippool_aton(&stataddr, &statmask, stat, 0)) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Failed to parse static range");
|
||||
return -1;
|
||||
}
|
||||
stataddr = stat->addr;
|
||||
stataddrprefixlen = stat->prefixlen;
|
||||
|
||||
m = ntohl(statmask.s_addr);
|
||||
statsize = ((~m) + 1);
|
||||
statsize = (1 << (stataddr.len*8 - stataddrprefixlen));
|
||||
if (statsize > IPPOOL_STATSIZE)
|
||||
statsize = IPPOOL_STATSIZE;
|
||||
}
|
||||
@@ -223,10 +253,11 @@ int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*this)->allowdyn = allowdyn;
|
||||
(*this)->allowstat = allowstat;
|
||||
(*this)->stataddr = stataddr;
|
||||
(*this)->statmask = statmask;
|
||||
(*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))) {
|
||||
@@ -245,9 +276,8 @@ int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
(*this)->hashmask = (*this)->hashsize - 1;
|
||||
|
||||
/* Allocate hash table */
|
||||
if (!
|
||||
((*this)->hash =
|
||||
calloc(sizeof(struct ippoolm_t), (*this)->hashsize))) {
|
||||
(*this)->hash = calloc((*this)->hashsize, sizeof(struct ippoolm_t *));
|
||||
if (!(*this)->hash) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Failed to allocate memory for hash members in ippool");
|
||||
return -1;
|
||||
@@ -255,19 +285,22 @@ int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
|
||||
(*this)->firstdyn = NULL;
|
||||
(*this)->lastdyn = NULL;
|
||||
if (flags & IPPOOL_NONETWORK) {
|
||||
in46a_inc(&addr);
|
||||
}
|
||||
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);
|
||||
if (addr_in_prefix_list(&addr, blacklist, blacklist_size)) {
|
||||
SYS_ERR(DIP, LOGL_DEBUG, 0,
|
||||
"addr blacklisted from pool: %s", in46a_ntoa(&addr));
|
||||
in46a_inc(&addr);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
(*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;
|
||||
@@ -285,9 +318,10 @@ int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
(*this)->firststat = NULL;
|
||||
(*this)->laststat = NULL;
|
||||
for (i = dynsize; i < listsize; i++) {
|
||||
|
||||
(*this)->member[i].addr.s_addr = 0;
|
||||
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;
|
||||
@@ -316,15 +350,15 @@ int ippool_free(struct ippool_t *this)
|
||||
|
||||
/* Find an IP address in the pool */
|
||||
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
struct in_addr *addr)
|
||||
struct in46_addr *addr)
|
||||
{
|
||||
struct ippoolm_t *p;
|
||||
uint32_t hash;
|
||||
|
||||
/* Find in hash table */
|
||||
hash = ippool_hash4(addr) & this->hashmask;
|
||||
hash = ippool_hash(addr) & this->hashmask;
|
||||
for (p = this->hash[hash]; p; p = p->nexthash) {
|
||||
if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
|
||||
if (in46a_prefix_equal(&p->addr, addr)) {
|
||||
if (member)
|
||||
*member = p;
|
||||
return 0;
|
||||
@@ -344,14 +378,14 @@ int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
* address space.
|
||||
**/
|
||||
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
struct in_addr *addr, int statip)
|
||||
struct in46_addr *addr, int statip)
|
||||
{
|
||||
struct ippoolm_t *p;
|
||||
struct ippoolm_t *p2 = NULL;
|
||||
uint32_t hash;
|
||||
|
||||
/* If static:
|
||||
* Look in dynaddr.
|
||||
* Look in dynaddr.
|
||||
* If found remove from firstdyn/lastdyn linked list.
|
||||
* Else allocate from stataddr.
|
||||
* Remove from firststat/laststat linked list.
|
||||
@@ -365,33 +399,39 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
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 ((addr) && (addr->s_addr) && statip) { /* IP address given */
|
||||
if (specified && statip) { /* IP address given */
|
||||
if (!this->allowstat) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Static IP address not allowed");
|
||||
return -1;
|
||||
return -GTPCAUSE_NOT_SUPPORTED;
|
||||
}
|
||||
if ((addr->s_addr & this->statmask.s_addr) !=
|
||||
this->stataddr.s_addr) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Static out of range");
|
||||
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 -1;
|
||||
return -GTPCAUSE_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* If IP address given try to find it in dynamic address pool */
|
||||
if ((addr) && (addr->s_addr)) { /* IP address given */
|
||||
if (specified) { /* IP address given */
|
||||
/* Find in hash table */
|
||||
hash = ippool_hash4(addr) & this->hashmask;
|
||||
hash = ippool_hash(addr) & this->hashmask;
|
||||
for (p = this->hash[hash]; p; p = p->nexthash) {
|
||||
if ((p->addr.s_addr == addr->s_addr)) {
|
||||
if (in46a_prefix_equal(&p->addr, addr)) {
|
||||
p2 = p;
|
||||
break;
|
||||
}
|
||||
@@ -408,7 +448,7 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
if (!this->firstdyn) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"No more IP addresses available");
|
||||
return -1;
|
||||
return -GTPCAUSE_ADDR_OCCUPIED;
|
||||
} else
|
||||
p2 = this->firstdyn;
|
||||
}
|
||||
@@ -417,7 +457,12 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
if (p2->inuse) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"IP address allready in use");
|
||||
return -1; /* Allready in use / Should not happen */
|
||||
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 */
|
||||
@@ -442,14 +487,19 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
/* 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 (specified && (statip)) { /* IP address given */
|
||||
if (!this->firststat) {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"No more IP addresses available");
|
||||
return -1; /* No more 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;
|
||||
@@ -462,7 +512,15 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
p2->next = NULL;
|
||||
p2->prev = NULL;
|
||||
p2->inuse = 2; /* Static address in use */
|
||||
memcpy(&p2->addr, addr, sizeof(addr));
|
||||
/* p2->addr.len and addr->len already match (see above). */
|
||||
if (p2->addr.len == sizeof(struct in_addr))
|
||||
p2->addr.v4 = addr->v4;
|
||||
else if (p2->addr.len == sizeof(struct in6_addr))
|
||||
p2->addr.v6 = addr->v6;
|
||||
else {
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
|
||||
return -GTPCAUSE_UNKNOWN_PDP;
|
||||
}
|
||||
*member = p2;
|
||||
(void)ippool_hashadd(this, *member);
|
||||
if (0)
|
||||
@@ -472,7 +530,7 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
||||
|
||||
SYS_ERR(DIP, LOGL_ERROR, 0,
|
||||
"Could not allocate IP address");
|
||||
return -1; /* Should never get here. TODO: Bad code */
|
||||
return -GTPCAUSE_SYS_FAIL; /* Should never get here. TODO: Bad code */
|
||||
}
|
||||
|
||||
int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
|
||||
@@ -518,7 +576,7 @@ int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
|
||||
this->laststat = member;
|
||||
|
||||
member->inuse = 0;
|
||||
member->addr.s_addr = 0;
|
||||
memset(&member->addr, 0, sizeof(member->addr));
|
||||
member->peer = NULL;
|
||||
member->nexthash = NULL;
|
||||
if (0)
|
||||
@@ -530,9 +588,3 @@ int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
|
||||
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
|
||||
|
||||
46
lib/ippool.h
46
lib/ippool.h
@@ -1,17 +1,20 @@
|
||||
/*
|
||||
/*
|
||||
* 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.
|
||||
|
||||
@@ -20,17 +23,14 @@
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -40,8 +40,8 @@ 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 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 */
|
||||
@@ -54,11 +54,8 @@ struct ippool_t {
|
||||
};
|
||||
|
||||
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
|
||||
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 */
|
||||
@@ -70,35 +67,32 @@ struct ippoolm_t {
|
||||
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);
|
||||
extern unsigned long int ippool_hash(struct in46_addr *addr);
|
||||
|
||||
/* Create new address pool */
|
||||
extern int ippool_new(struct ippool_t **this, char *dyn, char *stat,
|
||||
int allowdyn, int allowstat, int flags);
|
||||
extern int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn,
|
||||
const struct in46_prefix *stat, int flags,
|
||||
struct in46_prefix *blacklist, size_t blacklist_size);
|
||||
|
||||
/* 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);
|
||||
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 in_addr *addr, int statip);
|
||||
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 */
|
||||
extern int ippool_aton(struct in_addr *addr, struct in_addr *mask,
|
||||
char *pool, int number);
|
||||
int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const 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
|
||||
/* Increase IPv4/IPv6 address by 1 */
|
||||
extern void in46a_inc(struct in46_addr *addr);
|
||||
|
||||
#endif /* !_IPPOOL_H */
|
||||
|
||||
@@ -37,7 +37,6 @@ register unsigned long int level; /* the previous hash, or an arbitrary value */
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
727
lib/netdev.c
Normal file
727
lib/netdev.c
Normal file
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* TUN interface functions.
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
* Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* netdev.c: Contains generic network device related functionality.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#elif defined (__FreeBSD__)
|
||||
#include <net/if_var.h>
|
||||
#include <netinet/in_var.h>
|
||||
|
||||
#elif defined (__APPLE__)
|
||||
#include <net/if.h>
|
||||
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
#endif
|
||||
|
||||
#include "netdev.h"
|
||||
#include "syserr.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <linux/ipv6.h>
|
||||
|
||||
static int netdev_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
||||
{
|
||||
int len = RTA_LENGTH(dlen);
|
||||
int alen = NLMSG_ALIGN(n->nlmsg_len);
|
||||
struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
|
||||
if (alen + len > nsize)
|
||||
return -1;
|
||||
rta->rta_len = len;
|
||||
rta->rta_type = type;
|
||||
memcpy(RTA_DATA(rta), d, dlen);
|
||||
n->nlmsg_len = alen + len;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int netdev_sifflags(const char *devname, int flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, '\0', sizeof(ifr));
|
||||
ifr.ifr_flags = flags;
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFFLAGS) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_setaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, '\0', sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
ifr.ifr_dstaddr.sa_family = AF_INET;
|
||||
|
||||
#if defined(__linux__)
|
||||
ifr.ifr_netmask.sa_family = AF_INET;
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
|
||||
sizeof(struct sockaddr_in);
|
||||
((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
|
||||
sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr) { /* Set the interface address */
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
|
||||
sizeof(*addr));
|
||||
if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
|
||||
if (errno != EEXIST) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFADDR) failed");
|
||||
} else {
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, errno,
|
||||
"ioctl(SIOCSIFADDR): Address already exists");
|
||||
}
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dstaddr) { /* Set the destination address */
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
|
||||
dstaddr, sizeof(*dstaddr));
|
||||
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFDSTADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (netmask) { /* Set the netmask */
|
||||
#if defined(__linux__)
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
|
||||
netmask, sizeof(*netmask));
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
|
||||
netmask->s_addr;
|
||||
#endif
|
||||
|
||||
if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFNETMASK) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
|
||||
/* On linux the route to the interface is set automatically
|
||||
on FreeBSD we have to do this manually */
|
||||
#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
netdev_addroute(dstaddr, addr, &this->netmask);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen)
|
||||
{
|
||||
struct in6_ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
#if defined(__linux__)
|
||||
ifr.ifr6_prefixlen = prefixlen;
|
||||
ifr.ifr6_ifindex = if_nametoindex(devname);
|
||||
if (ifr.ifr6_ifindex == 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", devname);
|
||||
return -1;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
#endif
|
||||
|
||||
/* Create a channel to the NET kernel */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (addr) {
|
||||
memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
|
||||
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
|
||||
if (errno != EEXIST) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
|
||||
} else {
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists");
|
||||
}
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* FIXME: looks like this is not possible/necessary for IPv6? */
|
||||
if (dstaddr) {
|
||||
memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
|
||||
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
if (addr)
|
||||
memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
|
||||
if (dstaddr)
|
||||
memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
|
||||
|
||||
if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
|
||||
netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
|
||||
/* On linux the route to the interface is set automatically
|
||||
on FreeBSD we have to do this manually */
|
||||
#if 0 /* FIXME */
|
||||
//#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
netdev_addroute6(dstaddr, addr, prefixlen);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_addaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
int fd;
|
||||
#if defined(__linux__)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg i;
|
||||
char buf[TUN_NLBUFSIZE];
|
||||
} req;
|
||||
|
||||
struct sockaddr_nl local;
|
||||
socklen_t addr_len;
|
||||
int status;
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req.n.nlmsg_type = RTM_NEWADDR;
|
||||
req.i.ifa_family = AF_INET;
|
||||
req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
|
||||
req.i.ifa_flags = 0;
|
||||
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
|
||||
req.i.ifa_index = if_nametoindex(devname);
|
||||
if (!req.i.ifa_index) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = 0;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof(local);
|
||||
if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"getsockname() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_len != sizeof(local)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address length %d", addr_len);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local.nl_family != AF_NETLINK) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address family %d", local.nl_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov.iov_base = (void *)&req.n;
|
||||
iov.iov_len = req.n.nlmsg_len;
|
||||
|
||||
msg.msg_name = (void *)&nladdr;
|
||||
msg.msg_namelen = sizeof(nladdr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
req.n.nlmsg_seq = 0;
|
||||
req.n.nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
status = sendmsg(fd, &msg, 0);
|
||||
if (status != req.n.nlmsg_len) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
if (status == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
|
||||
struct ifaliasreq areq;
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
/* Set up interface name */
|
||||
strncpy(areq.ifra_name, devname, IFNAMSIZ);
|
||||
areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
|
||||
sizeof(areq.ifra_addr);
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
|
||||
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
|
||||
sizeof(areq.ifra_mask);
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
|
||||
netmask->s_addr;
|
||||
|
||||
/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
|
||||
sizeof(areq.ifra_broadaddr);
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
|
||||
dstaddr->s_addr;
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCAIFADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_addaddr6(const char *devname, struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen)
|
||||
{
|
||||
int fd;
|
||||
#if defined(__linux__)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg i;
|
||||
char buf[TUN_NLBUFSIZE];
|
||||
} req;
|
||||
|
||||
struct sockaddr_nl local;
|
||||
socklen_t addr_len;
|
||||
int status;
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req.n.nlmsg_type = RTM_NEWADDR;
|
||||
req.i.ifa_family = AF_INET6;
|
||||
req.i.ifa_prefixlen = 64; /* 64 FOR IPv6 */
|
||||
req.i.ifa_flags = 0;
|
||||
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
|
||||
req.i.ifa_index = if_nametoindex(devname);
|
||||
if (!req.i.ifa_index) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = 0;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof(local);
|
||||
if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"getsockname() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_len != sizeof(local)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address length %d", addr_len);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local.nl_family != AF_NETLINK) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address family %d", local.nl_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov.iov_base = (void *)&req.n;
|
||||
iov.iov_len = req.n.nlmsg_len;
|
||||
|
||||
msg.msg_name = (void *)&nladdr;
|
||||
msg.msg_namelen = sizeof(nladdr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
req.n.nlmsg_seq = 0;
|
||||
req.n.nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
status = sendmsg(fd, &msg, 0);
|
||||
if (status != req.n.nlmsg_len) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
if (status == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
|
||||
struct ifaliasreq areq;
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
/* Set up interface name */
|
||||
strncpy(areq.ifra_name, devname, IFNAMSIZ);
|
||||
areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_len = sizeof(areq.ifra_addr);
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_addr.s6_addr = addr->s6_addr;
|
||||
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_len = sizeof(areq.ifra_mask);
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_addr.s6_addr = netmask->s6_addr;
|
||||
|
||||
/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_len = sizeof(areq.ifra_broadaddr);
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_addr.s6_addr = dstaddr->s6_addr;
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCAIFADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_route(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask, int delete)
|
||||
{
|
||||
int fd;
|
||||
#if defined(__linux__)
|
||||
struct rtentry r;
|
||||
|
||||
memset(&r, '\0', sizeof(r));
|
||||
r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r.rt_dst.sa_family = AF_INET;
|
||||
r.rt_gateway.sa_family = AF_INET;
|
||||
r.rt_genmask.sa_family = AF_INET;
|
||||
memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
|
||||
memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
|
||||
sizeof(*gateway));
|
||||
memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
|
||||
sizeof(*mask));
|
||||
|
||||
if (delete) {
|
||||
if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCDELRT) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCADDRT) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
struct {
|
||||
struct rt_msghdr rt;
|
||||
struct sockaddr_in dst;
|
||||
struct sockaddr_in gate;
|
||||
struct sockaddr_in mask;
|
||||
} req;
|
||||
struct rt_msghdr *rtm;
|
||||
|
||||
if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&req, 0x00, sizeof(req));
|
||||
|
||||
rtm = &req.rt;
|
||||
|
||||
rtm->rtm_msglen = sizeof(req);
|
||||
rtm->rtm_version = RTM_VERSION;
|
||||
if (delete) {
|
||||
rtm->rtm_type = RTM_DELETE;
|
||||
} else {
|
||||
rtm->rtm_type = RTM_ADD;
|
||||
}
|
||||
rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
|
||||
rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
|
||||
rtm->rtm_pid = getpid();
|
||||
rtm->rtm_seq = 0044; /* TODO */
|
||||
|
||||
req.dst.sin_family = AF_INET;
|
||||
req.dst.sin_len = sizeof(req.dst);
|
||||
req.mask.sin_family = AF_INET;
|
||||
req.mask.sin_len = sizeof(req.mask);
|
||||
req.gate.sin_family = AF_INET;
|
||||
req.gate.sin_len = sizeof(req.gate);
|
||||
|
||||
req.dst.sin_addr.s_addr = dst->s_addr;
|
||||
req.mask.sin_addr.s_addr = mask->s_addr;
|
||||
req.gate.sin_addr.s_addr = gateway->s_addr;
|
||||
|
||||
if (write(fd, rtm, rtm->rtm_msglen) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_addroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
|
||||
{
|
||||
return netdev_route(dst, gateway, mask, 0);
|
||||
}
|
||||
|
||||
int netdev_delroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)
|
||||
{
|
||||
return netdev_route(dst, gateway, mask, 1);
|
||||
}
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
/*! Obtain the local address of a network device
|
||||
* \param[in] devname Target device owning the IP
|
||||
* \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
|
||||
* \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
|
||||
* \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
|
||||
* \returns The number of ips found following the criteria specified by flags, -1 on error.
|
||||
*
|
||||
* This function will fill prefix_list with up to prefix_size IPs following the
|
||||
* criteria specified by flags parameter. It returns the number of IPs matching
|
||||
* the criteria. As a result, the number returned can be bigger than
|
||||
* prefix_size. It can be used with prefix_size=0 to get an estimate of the size
|
||||
* needed for prefix_list.
|
||||
*/
|
||||
int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
|
||||
{
|
||||
static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
struct in46_addr netmask;
|
||||
size_t count = 0;
|
||||
bool is_ipv6_ll;
|
||||
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(ifa->ifa_name, devname))
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET && (flags & IP_TYPE_IPv4)) {
|
||||
struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
|
||||
struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
|
||||
|
||||
if (count < prefix_size) {
|
||||
netmask.len = sizeof(netmask4->sin_addr);
|
||||
netmask.v4 = netmask4->sin_addr;
|
||||
prefix_list[count].addr.len = sizeof(sin4->sin_addr);
|
||||
prefix_list[count].addr.v4 = sin4->sin_addr;
|
||||
prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
|
||||
struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
|
||||
|
||||
is_ipv6_ll = !memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix));
|
||||
if ((flags & IP_TYPE_IPv6_NONLINK) && is_ipv6_ll)
|
||||
continue;
|
||||
if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll)
|
||||
continue;
|
||||
|
||||
if (count < prefix_size) {
|
||||
netmask.len = sizeof(netmask6->sin6_addr);
|
||||
netmask.v6 = netmask6->sin6_addr;
|
||||
prefix_list[count].addr.len = sizeof(sin6->sin6_addr);
|
||||
prefix_list[count].addr.v6 = sin6->sin6_addr;
|
||||
prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return count;
|
||||
}
|
||||
72
lib/netdev.h
Normal file
72
lib/netdev.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
/*
|
||||
* TUN interface functions.
|
||||
* Copyright (C) 2002, 2003 Mondru AB.
|
||||
* Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "../lib/in46_addr.h"
|
||||
|
||||
#define TUN_NLBUFSIZE 1024
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* ipv6 ip type flags for tun_ipv6_local_get() */
|
||||
enum {
|
||||
IP_TYPE_IPv4 = 1,
|
||||
IP_TYPE_IPv6_LINK = 2,
|
||||
IP_TYPE_IPv6_NONLINK = 4,
|
||||
};
|
||||
#define IP_TYPE_IPv6 (IP_TYPE_IPv6_LINK | IP_TYPE_IPv6_NONLINK)
|
||||
|
||||
|
||||
#ifndef HAVE_IPHDR
|
||||
struct iphdr
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ihl:4;
|
||||
unsigned int version:4;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
unsigned int version:4;
|
||||
unsigned int ihl:4;
|
||||
#else
|
||||
# error "Please fix <bits/endian.h>"
|
||||
#endif
|
||||
u_int8_t tos;
|
||||
u_int16_t tot_len;
|
||||
u_int16_t id;
|
||||
u_int16_t frag_off;
|
||||
u_int8_t ttl;
|
||||
u_int8_t protocol;
|
||||
u_int16_t check;
|
||||
u_int32_t saddr;
|
||||
u_int32_t daddr;
|
||||
/*The options start here. */
|
||||
};
|
||||
#endif /* !HAVE_IPHDR */
|
||||
|
||||
extern int netdev_setaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask);
|
||||
|
||||
extern int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen);
|
||||
|
||||
extern int netdev_addaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask);
|
||||
|
||||
extern int netdev_addaddr6(const char *devname, struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen);
|
||||
|
||||
extern int netdev_addroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
|
||||
extern int netdev_delroute(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
|
||||
|
||||
extern int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list,
|
||||
size_t prefix_size, int flags);
|
||||
@@ -19,6 +19,7 @@ enum {
|
||||
DTUN,
|
||||
DGGSN,
|
||||
DSGSN,
|
||||
DICMP6,
|
||||
};
|
||||
|
||||
#define SYS_ERR(sub, pri, en, fmt, args...) \
|
||||
|
||||
857
lib/tun.c
857
lib/tun.c
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
/*
|
||||
* TUN interface functions.
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
*
|
||||
* Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -37,600 +39,123 @@
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.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>
|
||||
#include <net/if_var.h>
|
||||
#include <netinet/in_var.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"
|
||||
#include "gtp-kernel.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
||||
static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
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 rc;
|
||||
rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
int tun_gifindex(struct tun_t *this, __u32 * 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(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
if (addr) {
|
||||
this->addr.len = sizeof(struct in_addr);
|
||||
this->addr.v4.s_addr = addr->s_addr;
|
||||
}
|
||||
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
if (dstaddr) {
|
||||
this->dstaddr.len = sizeof(struct in_addr);
|
||||
this->dstaddr.v4.s_addr = dstaddr->s_addr;
|
||||
}
|
||||
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(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;
|
||||
}
|
||||
|
||||
/* 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(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); * 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(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_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(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;
|
||||
|
||||
#elif defined (__sun__)
|
||||
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 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(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 */
|
||||
if (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;
|
||||
|
||||
#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(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, netmask);
|
||||
this->routes = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tun_route(struct tun_t *this,
|
||||
struct in_addr *dst,
|
||||
struct in_addr *gateway, struct in_addr *mask, int delete)
|
||||
static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen)
|
||||
{
|
||||
|
||||
/* 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(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
int rc;
|
||||
rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (dstaddr) {
|
||||
this->dstaddr.len = sizeof(*dstaddr);
|
||||
memcpy(&this->dstaddr.v6, dstaddr, sizeof(*dstaddr));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#elif defined(__sun__)
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, errno,
|
||||
"Could not set up routing on Solaris. Please add route manually.");
|
||||
return 0;
|
||||
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
this->addrs++;
|
||||
#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
this->routes = 1;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tun_addroute(struct tun_t *this,
|
||||
struct in_addr *dst,
|
||||
struct in_addr *gateway, struct in_addr *mask)
|
||||
static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
return tun_route(this, dst, gateway, mask, 0);
|
||||
int rc;
|
||||
|
||||
/* 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 */
|
||||
|
||||
rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
this->addrs++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tun_delroute(struct tun_t *this,
|
||||
struct in_addr *dst,
|
||||
struct in_addr *gateway, struct in_addr *mask)
|
||||
static int tun_addaddr6(struct tun_t *this,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen)
|
||||
{
|
||||
return tun_route(this, dst, gateway, mask, 1);
|
||||
int rc;
|
||||
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr6(this, addr, dstaddr, prefixlen);
|
||||
|
||||
rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
this->addrs++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tun_new(struct tun_t **tun)
|
||||
int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
|
||||
{
|
||||
struct in_addr netmask;
|
||||
switch (addr->len) {
|
||||
case 4:
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
|
||||
return tun_addaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
|
||||
case 16:
|
||||
return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u)
|
||||
{
|
||||
|
||||
#if defined(__linux__)
|
||||
@@ -641,15 +166,6 @@ int tun_new(struct tun_t **tun)
|
||||
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)))) {
|
||||
@@ -662,30 +178,53 @@ int tun_new(struct tun_t **tun)
|
||||
(*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");
|
||||
return -1;
|
||||
if (!use_kernel) {
|
||||
/* 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));
|
||||
if (dev_name)
|
||||
strcpy(ifr.ifr_name, dev_name);
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
|
||||
if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
||||
(*tun)->devname[IFNAMSIZ - 1] = 0;
|
||||
|
||||
/* Disable checksums */
|
||||
if (ioctl((*tun)->fd, TUNSETNOCSUM, 1) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable checksum on %s", (*tun)->devname);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
strncpy((*tun)->devname, dev_name, IFNAMSIZ);
|
||||
(*tun)->devname[IFNAMSIZ - 1] = 0;
|
||||
(*tun)->fd = -1;
|
||||
|
||||
if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) {
|
||||
LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set device flags. For some weird reason this is also the method
|
||||
used to obtain the network interface name */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
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");
|
||||
close((*tun)->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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__)
|
||||
|
||||
if (use_kernel) {
|
||||
LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find suitable device */
|
||||
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
|
||||
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
|
||||
@@ -697,11 +236,11 @@ int tun_new(struct tun_t **tun)
|
||||
if ((*tun)->fd < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"Can't find tunnel device");
|
||||
return -1;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
|
||||
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
||||
(*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 */
|
||||
@@ -715,7 +254,7 @@ int tun_new(struct tun_t **tun)
|
||||
/* 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;
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
/* Delete any IP addresses until SIOCDIFADDR fails */
|
||||
@@ -723,91 +262,31 @@ int tun_new(struct tun_t **tun)
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
#elif defined(__sun__)
|
||||
|
||||
if ((ip_fd = open("/dev/udp", O_RDWR, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"Can't open /dev/udp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 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(DTUN, LOGL_ERROR, errno,
|
||||
"Can't assign new interface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"Can't open /dev/tun (2)");
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(if_fd, I_PUSH, "ip") < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 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(DTUN, LOGL_ERROR, 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(DTUN, LOGL_ERROR, 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(DTUN, LOGL_ERROR, 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
|
||||
|
||||
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);
|
||||
netdev_delroute(&tun->dstaddr.v4, &tun->addr.v4, &tun->netmask);
|
||||
}
|
||||
|
||||
if (close(tun->fd)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
|
||||
if (tun->fd >= 0) {
|
||||
if (close(tun->fd)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
|
||||
}
|
||||
}
|
||||
|
||||
gtp_kernel_stop(tun->devname);
|
||||
|
||||
/* TODO: For solaris we need to unlink streams */
|
||||
|
||||
free(tun);
|
||||
@@ -823,9 +302,6 @@ int tun_set_cb_ind(struct tun_t *this,
|
||||
|
||||
int tun_decaps(struct tun_t *this)
|
||||
{
|
||||
|
||||
#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
|
||||
|
||||
unsigned char buffer[PACKET_MAX];
|
||||
int status;
|
||||
|
||||
@@ -838,44 +314,11 @@ int tun_decaps(struct tun_t *this)
|
||||
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(DTUN, LOGL_ERROR, 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)
|
||||
@@ -886,7 +329,7 @@ int tun_runscript(struct tun_t *tun, char *script)
|
||||
char smask[TUN_ADDRSIZE];
|
||||
int rc;
|
||||
|
||||
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
|
||||
strncpy(snet, inet_ntoa(tun->addr.v4), sizeof(snet));
|
||||
snet[sizeof(snet) - 1] = 0;
|
||||
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
|
||||
smask[sizeof(smask) - 1] = 0;
|
||||
@@ -903,3 +346,21 @@ int tun_runscript(struct tun_t *tun, char *script)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Obtain the local address of the tun device.
|
||||
* \param[in] tun Target device owning the IP
|
||||
* \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
|
||||
* \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
|
||||
* \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
|
||||
* \returns The number of ips found following the criteria specified by flags, -1 on error.
|
||||
*
|
||||
* This function will fill prefix_list with up to prefix_size IPs following the
|
||||
* criteria specified by flags parameter. It returns the number of IPs matching
|
||||
* the criteria. As a result, the number returned can be bigger than
|
||||
* prefix_size. It can be used with prefix_size=0 to get an estimate of the size
|
||||
* needed for prefix_list.
|
||||
*/
|
||||
int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
|
||||
{
|
||||
return netdev_ip_local_get(tun->devname, prefix_list, prefix_size, flags);
|
||||
}
|
||||
|
||||
51
lib/tun.h
51
lib/tun.h
@@ -1,37 +1,29 @@
|
||||
/*
|
||||
/*
|
||||
* TUN interface functions.
|
||||
* Copyright (C) 2002, 2003 Mondru AB.
|
||||
*
|
||||
* Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUN_H
|
||||
#define _TUN_H
|
||||
|
||||
#include <stdbool.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
|
||||
|
||||
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;
|
||||
};
|
||||
#include "config.h"
|
||||
#include "netdev.h"
|
||||
|
||||
/* ***********************************************************
|
||||
* Information storage for each tun instance
|
||||
@@ -39,28 +31,24 @@ struct tun_packet_t {
|
||||
|
||||
struct tun_t {
|
||||
int fd; /* File descriptor to tun interface */
|
||||
struct in_addr addr;
|
||||
struct in_addr dstaddr;
|
||||
struct in46_addr addr;
|
||||
struct in46_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_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u);
|
||||
extern int tun_free(struct tun_t *tun);
|
||||
extern int tun_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_addaddr(struct tun_t *this, struct in46_addr *addr,
|
||||
struct in46_addr *dstaddr, size_t prefixlen);
|
||||
|
||||
extern int tun_set_cb_ind(struct tun_t *this,
|
||||
int (*cb_ind) (struct tun_t * tun, void *pack,
|
||||
@@ -68,4 +56,7 @@ extern int tun_set_cb_ind(struct tun_t *this,
|
||||
|
||||
extern int tun_runscript(struct tun_t *tun, char *script);
|
||||
|
||||
int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list,
|
||||
size_t prefix_size, int flags);
|
||||
|
||||
#endif /* !_TUN_H */
|
||||
|
||||
@@ -3,7 +3,7 @@ exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: OpenGGSN STP Library
|
||||
Name: OsmoGGSN GTP Library
|
||||
Description: C Utility Library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lgtp
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
Summary: Open Source Gateway GPRS Support Node (GGSN)
|
||||
Summary: Osmocom Gateway GPRS Support Node (GGSN)
|
||||
Name: @PACKAGE@
|
||||
Version: @VERSION@
|
||||
Release: 1
|
||||
URL: http://sourceforge.net/projects/ggsn/
|
||||
URL: https://osmocom.org/projects/openggsn
|
||||
Source0: http://prdownloads.sourceforge.net/ggsn/%{name}-%{version}.tar.gz
|
||||
License: GPL
|
||||
Group: System Environment/Daemons
|
||||
BuildRoot: %{_tmppath}/%{name}-root
|
||||
|
||||
%description
|
||||
OpenGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
OsmoGGSN is a Gateway GPRS Support Node (GGSN). It is used by mobile
|
||||
operators as the interface between the Internet and the rest of the
|
||||
mobile network infrastructure. The project also provides an SGSN
|
||||
emulator suitable for GPRS core network testing.
|
||||
@@ -26,21 +26,21 @@ make
|
||||
%install
|
||||
|
||||
make install prefix=$RPM_BUILD_ROOT/usr
|
||||
strip $RPM_BUILD_ROOT/usr/bin/ggsn
|
||||
strip $RPM_BUILD_ROOT/usr/bin/osmo-ggsn
|
||||
strip $RPM_BUILD_ROOT/usr/bin/sgsnemu
|
||||
|
||||
#Copy ggsn init script in place
|
||||
#Copy osmo-ggsn init script in place
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
|
||||
install -m755 examples/ggsn.init \
|
||||
$RPM_BUILD_ROOT/etc/rc.d/init.d/ggsn
|
||||
install -m755 examples/osmo-ggsn.init \
|
||||
$RPM_BUILD_ROOT/etc/rc.d/init.d/osmo-ggsn
|
||||
|
||||
#Copy ggsn.conf in place
|
||||
install -m755 examples/ggsn.conf \
|
||||
$RPM_BUILD_ROOT/etc/ggsn.conf
|
||||
#Copy osmo-ggsn.conf in place
|
||||
install -m755 examples/osmo-ggsn.cfg \
|
||||
$RPM_BUILD_ROOT/etc/osmo-ggsn.cfg
|
||||
|
||||
#Copy gsn_restart file in place
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/ggsn
|
||||
echo "0" > $RPM_BUILD_ROOT/var/lib/ggsn/gsn_restart
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/osmo-ggsn
|
||||
echo "0" > $RPM_BUILD_ROOT/var/lib/osmo-ggsn/gsn_restart
|
||||
|
||||
#Clean up unwanted library files
|
||||
rm -rf $RPM_BUILD_ROOT/usr/include/*
|
||||
@@ -52,26 +52,26 @@ rm -rf $RPM_BUILD_ROOT
|
||||
make clean
|
||||
|
||||
%post
|
||||
/sbin/chkconfig --add ggsn
|
||||
/sbin/chkconfig --add osmo-ggsn
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
|
||||
/usr/bin/ggsn
|
||||
/usr/bin/osmo-ggsn
|
||||
/usr/bin/sgsnemu
|
||||
/etc/rc.d/init.d/ggsn
|
||||
%dir /var/lib/ggsn
|
||||
/var/lib/ggsn/gsn_restart
|
||||
/etc/rc.d/init.d/osmo-ggsn
|
||||
%dir /var/lib/osmo-ggsn
|
||||
/var/lib/osmo-ggsn/gsn_restart
|
||||
|
||||
%doc AUTHORS ChangeLog COPYING INSTALL NEWS README
|
||||
%doc examples/ggsn.conf
|
||||
%doc AUTHORS COPYING INSTALL NEWS README.md
|
||||
%doc examples/osmo-ggsn.conf
|
||||
%doc examples/sgsnemu.conf
|
||||
%doc examples/ggsn.init
|
||||
%doc examples/osmo-ggsn.init
|
||||
%doc examples/firewall
|
||||
%doc /usr/man/man8/ggsn.8.gz
|
||||
%doc /usr/man/man8/osmo-ggsn.8.gz
|
||||
%doc /usr/man/man8/sgsnemu.8.gz
|
||||
|
||||
%config /etc/ggsn.conf
|
||||
%config /etc/osmo-ggsn.cfg
|
||||
|
||||
|
||||
#/usr/lib/libgtp.a
|
||||
@@ -83,5 +83,8 @@ make clean
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jun 30 2017 <laforge@gnumonks.org>
|
||||
- Update to OsmoGGSN
|
||||
|
||||
* Mon Jun 30 2003 <jj@openggsn.org>
|
||||
- Initial build.
|
||||
@@ -5,5 +5,11 @@ AM_LDFLAGS = @EXEC_LDFLAGS@
|
||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
|
||||
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
|
||||
|
||||
if ENABLE_GTP_KERNEL
|
||||
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
|
||||
sgsnemu_LDADD += $(LIBGTPNL_LIBS)
|
||||
endif
|
||||
|
||||
sgsnemu_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
|
||||
sgsnemu_SOURCES = sgsnemu.c cmdline.c cmdline.h
|
||||
|
||||
2575
sgsnemu/cmdline.c
2575
sgsnemu/cmdline.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
# OpenGGSN - Gateway GPRS Support Node
|
||||
# OsmoGGSN - Gateway GPRS Support Node
|
||||
# Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
#
|
||||
# The contents of this file may be used under the terms of the GNU
|
||||
@@ -6,9 +6,19 @@
|
||||
# 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"
|
||||
|
||||
defmode "createif" modedesc="any option of this mode is related to tun interface, \
|
||||
all payload going in and out via tunN interface"
|
||||
defmode "pinghost" modedesc="generate ICMP payload inside G-PDU without setting up tun interface"
|
||||
|
||||
option "debug" d "Run in debug mode" flag off
|
||||
|
||||
option "conf" c "Read configuration file" string no
|
||||
@@ -16,7 +26,7 @@ option "pidfile" - "Filename of process id file" string default="./sgsn
|
||||
option "statedir" - "Directory of nonvolatile data" string default="./" no
|
||||
|
||||
option "dns" - "DNS Server to use" string no
|
||||
option "listen" l "Local interface" string no
|
||||
option "listen" l "Local host" string no
|
||||
option "remote" r "Remote host" string no
|
||||
|
||||
option "contexts" - "Number of contexts" int default="1" no
|
||||
@@ -25,23 +35,36 @@ 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
|
||||
|
||||
option "createif" - "Create local network interface" flag off
|
||||
option "net" n "Network address for local interface" string no
|
||||
option "defaultroute" - "Create default route" flag off
|
||||
option "ipup" - "Script to run after link-up" string no
|
||||
option "ipdown" - "Script to run after link-down" string no
|
||||
modeoption "createif" - "Create local network interface" flag off mode="createif"
|
||||
modeoption "net" n "Network address for local interface" string dependon="createif" no mode="createif"
|
||||
modeoption "defaultroute" - "Create default route" flag dependon="createif" off mode="createif"
|
||||
modeoption "ipup" - "Script to run after link-up" string dependon="createif" no mode="createif"
|
||||
modeoption "ipdown" - "Script to run after link-down" string dependon="createif" no mode="createif"
|
||||
modeoption "tun-device" - "Name of the local network interface" string dependon="createif" no mode="createif"
|
||||
|
||||
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 "pingquiet" - "Do not print ping packet info" flag off
|
||||
modeoption "pinghost" - "Ping remote host" string no mode="pinghost"
|
||||
modeoption "pingrate" - "Number of ping req per second" int default="1" dependon="pinghost" no mode="pinghost"
|
||||
modeoption "pingsize" - "Number of ping data bytes" int default="56" dependon="pinghost" no mode="pinghost"
|
||||
modeoption "pingcount" - "Number of ping req to send" int default="0" dependon="pinghost" no mode="pinghost"
|
||||
modeoption "pingquiet" - "Do not print ping packet info" flag dependon="pinghost" off mode="pinghost"
|
||||
|
||||
option "no-tx-gpdu-seq" - "Don't transmit G-PDU sequence nums" flag off
|
||||
option "pdp-type" t "PDP Type" string default="v4" no typestr="(v4|v6)"
|
||||
|
||||
@@ -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,197 +13,517 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* for FILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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
|
||||
|
||||
/** @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 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 *rattype_arg; /* Radio Access Technology Type (optional). */
|
||||
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 host. */
|
||||
char *listen_orig;
|
||||
/**< @brief Local host original value given at command line. */
|
||||
const char *listen_help;
|
||||
/**< @brief Local host 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;
|
||||
char *rattype_help;
|
||||
char *userloc_arg; /* User Location Information (optional). */
|
||||
/**< @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;
|
||||
char *userloc_help;
|
||||
char *rai_arg; /* Routing Area Information (optional). */
|
||||
/**< @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;
|
||||
char *rai_help;
|
||||
char *mstz_arg; /* MS Time Zone (optional). */
|
||||
/**< @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;
|
||||
char *mstz_help;
|
||||
char *imeisv_arg; /* IMEI(SV) (optional). */
|
||||
/**< @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;
|
||||
char *imeisv_help;
|
||||
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. */
|
||||
unsigned long long int qose1_arg; /* Requested quality of service Extension 1 */
|
||||
char *qose1_orig; /* Requested quality of service Extension 1 original value given at command line. */
|
||||
int qose2_arg; /* Requested quality of service Extension 2 */
|
||||
char *qose2_orig; /* Requested quality of service Extension 2 original value given at command line. */
|
||||
int qose3_arg; /* Requested quality of service Extension 3 */
|
||||
char *qose3_orig; /* Requested quality of service Extension 3 original value given at command line. */
|
||||
int qose4_arg; /* Requested quality of service Extension 4 */
|
||||
char *qose4_orig; /* Requested quality of service Extension 4 original value given at command line. */
|
||||
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 norecovery_flag; /* Do not print ping packet info (default=off). */
|
||||
const char *norecovery_help; /* Do not print ping packet info help description. */
|
||||
/**< @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 *tun_device_arg;
|
||||
/**< @brief Name of the local network interface. */
|
||||
char *tun_device_orig;
|
||||
/**< @brief Name of the local network interface original value given at command line. */
|
||||
const char *tun_device_help;
|
||||
/**< @brief Name of the local network interface 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. */
|
||||
int no_tx_gpdu_seq_flag;
|
||||
/**< @brief Don't transmit G-PDU sequence nums (default=off). */
|
||||
const char *no_tx_gpdu_seq_help;
|
||||
/**< @brief Don't transmit G-PDU sequence nums help description. */
|
||||
char *pdp_type_arg;
|
||||
/**< @brief PDP Type (default='v4'). */
|
||||
char *pdp_type_orig;
|
||||
/**< @brief PDP Type original value given at command line. */
|
||||
const char *pdp_type_help;
|
||||
/**< @brief PDP Type 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 rattype_given; /* Whether rattype was given. */
|
||||
int userloc_given; /* Whether userloc was given. */
|
||||
int rai_given; /* Whether RAI was given. */
|
||||
int mstz_given; /* Whether mstz was given. */
|
||||
int imeisv_given; /* Whether imeisv 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 qose1_given; /* Whether qos Extension 1 was given. */
|
||||
int qose2_given; /* Whether qos Extension 2 was given. */
|
||||
int qose3_given; /* Whether qos Extension 3 was given. */
|
||||
int qose4_given; /* Whether qos Extension 4 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. */
|
||||
int norecovery_given; /* Whether norecovery was given. */
|
||||
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 tun_device_given;
|
||||
/**< @brief Whether tun-device 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. */
|
||||
unsigned int no_tx_gpdu_seq_given;
|
||||
/**< @brief Whether no-tx-gpdu-seq was given. */
|
||||
unsigned int pdp_type_given;
|
||||
/**< @brief Whether pdp-type was given. */
|
||||
|
||||
int createif_mode_counter;
|
||||
/**< @brief Counter for mode createif */
|
||||
int pinghost_mode_counter;
|
||||
/**< @brief Counter for mode pinghost */
|
||||
};
|
||||
|
||||
/** @brief The additional parameters to pass to parser functions */
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* OpenGGSN - Gateway GPRS Support Node
|
||||
/*
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
*
|
||||
* Copyright (C) 2017 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -19,6 +20,7 @@
|
||||
#endif
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
@@ -29,6 +31,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -58,7 +62,7 @@ struct iphash_t {
|
||||
uint8_t inuse; /* 0=free. 1=used by somebody */
|
||||
struct iphash_t *ipnext;
|
||||
struct pdp_t *pdp;
|
||||
struct in_addr addr;
|
||||
struct in46_addr addr;
|
||||
};
|
||||
struct iphash_t iparr[MAXCONTEXTS];
|
||||
struct iphash_t *iphash[MAXCONTEXTS];
|
||||
@@ -70,18 +74,21 @@ struct iphash_t *iphash[MAXCONTEXTS];
|
||||
/* 3: Done */
|
||||
/* 4: Wait_disconnect */
|
||||
/* 5: Disconnected */
|
||||
int state = 0;
|
||||
volatile sig_atomic_t state = 0;
|
||||
|
||||
struct gsn_t *gsn = NULL; /* GSN instance */
|
||||
struct tun_t *tun = NULL; /* TUN instance */
|
||||
int maxfd = 0; /* For select() */
|
||||
int echoversion = 1; /* First try this version */
|
||||
void *tall_sgsnemu_ctx; /* root talloc ctx */
|
||||
|
||||
/* Struct with local versions of gengetopt options */
|
||||
struct {
|
||||
int debug; /* Print debug messages */
|
||||
int createif; /* Create local network interface */
|
||||
struct in_addr netaddr, destaddr, net, mask; /* Network interface */
|
||||
char *tun_dev_name;
|
||||
struct in46_addr netaddr, destaddr, net; /* Network interface */
|
||||
size_t prefixlen;
|
||||
char *ipup, *ipdown; /* Filename of scripts */
|
||||
int defaultroute; /* Set up default route */
|
||||
struct in_addr pinghost; /* Remote ping host */
|
||||
@@ -115,6 +122,8 @@ struct {
|
||||
int imeisv_given;
|
||||
struct ul16_t msisdn;
|
||||
int norecovery_given;
|
||||
int tx_gpdu_seq;
|
||||
uint8_t pdp_type;
|
||||
} options;
|
||||
|
||||
/* Definitions to use for PING. Most of the ping code was derived from */
|
||||
@@ -154,13 +163,19 @@ int tsum = 0;
|
||||
int pingseq = 0; /* Ping sequence counter */
|
||||
struct timeval firstping;
|
||||
|
||||
int ipset(struct iphash_t *ipaddr, struct in_addr *addr)
|
||||
static void signal_handler(int signo)
|
||||
{
|
||||
int hash = ippool_hash4(addr) % MAXCONTEXTS;
|
||||
if (state == 2)
|
||||
state = 3; /* Tell main loop to finish. */
|
||||
}
|
||||
|
||||
static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
|
||||
{
|
||||
int hash = ippool_hash(addr) % MAXCONTEXTS;
|
||||
struct iphash_t *h;
|
||||
struct iphash_t *prev = NULL;
|
||||
ipaddr->ipnext = NULL;
|
||||
ipaddr->addr.s_addr = addr->s_addr;
|
||||
ipaddr->addr = *addr;
|
||||
for (h = iphash[hash]; h; h = h->ipnext)
|
||||
prev = h;
|
||||
if (!prev)
|
||||
@@ -170,9 +185,9 @@ int ipset(struct iphash_t *ipaddr, struct in_addr *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipdel(struct iphash_t *ipaddr)
|
||||
static int ipdel(struct iphash_t *ipaddr)
|
||||
{
|
||||
int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
|
||||
int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
|
||||
struct iphash_t *h;
|
||||
struct iphash_t *prev = NULL;
|
||||
for (h = iphash[hash]; h; h = h->ipnext) {
|
||||
@@ -188,12 +203,12 @@ int ipdel(struct iphash_t *ipaddr)
|
||||
return EOF; /* End of linked list and not found */
|
||||
}
|
||||
|
||||
int ipget(struct iphash_t **ipaddr, struct in_addr *addr)
|
||||
static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
|
||||
{
|
||||
int hash = ippool_hash4(addr) % MAXCONTEXTS;
|
||||
int hash = ippool_hash(addr) % MAXCONTEXTS;
|
||||
struct iphash_t *h;
|
||||
for (h = iphash[hash]; h; h = h->ipnext) {
|
||||
if ((h->addr.s_addr == addr->s_addr)) {
|
||||
if (in46a_equal(&h->addr, addr)) {
|
||||
*ipaddr = h;
|
||||
return 0;
|
||||
}
|
||||
@@ -202,7 +217,7 @@ int ipget(struct iphash_t **ipaddr, struct in_addr *addr)
|
||||
}
|
||||
|
||||
/* Used to write process ID to file. Assume someone else will delete */
|
||||
void log_pid(char *pidfile)
|
||||
static void log_pid(char *pidfile)
|
||||
{
|
||||
FILE *file;
|
||||
mode_t oldmask;
|
||||
@@ -216,7 +231,7 @@ void log_pid(char *pidfile)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
int process_options(int argc, char **argv)
|
||||
static int process_options(int argc, char **argv)
|
||||
{
|
||||
/* gengeopt declarations */
|
||||
struct gengetopt_args_info args_info;
|
||||
@@ -231,6 +246,7 @@ int process_options(int argc, char **argv)
|
||||
char *type;
|
||||
char *mcc;
|
||||
char *mnc;
|
||||
char *tok, *apn;
|
||||
char *lac;
|
||||
int lac_d;
|
||||
char *rest;
|
||||
@@ -276,6 +292,8 @@ int process_options(int argc, char **argv)
|
||||
printf("contexts: %d\n", args_info.contexts_arg);
|
||||
printf("timelimit: %d\n", args_info.timelimit_arg);
|
||||
printf("createif: %d\n", args_info.createif_flag);
|
||||
if (args_info.tun_device_arg)
|
||||
printf("tun-device: %s\n", args_info.tun_device_arg);
|
||||
if (args_info.ipup_arg)
|
||||
printf("ipup: %s\n", args_info.ipup_arg);
|
||||
if (args_info.ipdown_arg)
|
||||
@@ -288,6 +306,7 @@ int process_options(int argc, char **argv)
|
||||
printf("pingcount: %d\n", args_info.pingcount_arg);
|
||||
printf("pingquiet: %d\n", args_info.pingquiet_flag);
|
||||
printf("norecovery: %d\n", args_info.norecovery_flag);
|
||||
printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
|
||||
}
|
||||
|
||||
/* Try out our new parser */
|
||||
@@ -331,6 +350,8 @@ int process_options(int argc, char **argv)
|
||||
printf("contexts: %d\n", args_info.contexts_arg);
|
||||
printf("timelimit: %d\n", args_info.timelimit_arg);
|
||||
printf("createif: %d\n", args_info.createif_flag);
|
||||
if (args_info.tun_device_arg)
|
||||
printf("tun-device: %s\n", args_info.tun_device_arg);
|
||||
if (args_info.ipup_arg)
|
||||
printf("ipup: %s\n", args_info.ipup_arg);
|
||||
if (args_info.ipdown_arg)
|
||||
@@ -345,6 +366,7 @@ int process_options(int argc, char **argv)
|
||||
printf("pingcount: %d\n", args_info.pingcount_arg);
|
||||
printf("pingquiet: %d\n", args_info.pingquiet_flag);
|
||||
printf("norecovery: %d\n", args_info.norecovery_flag);
|
||||
printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,10 +374,10 @@ int process_options(int argc, char **argv)
|
||||
|
||||
/* foreground */
|
||||
/* If fg flag not given run as a daemon */
|
||||
/* Do not allow sgsnemu to run as deamon
|
||||
/* Do not allow sgsnemu to run as deamon
|
||||
if (!args_info.fg_flag)
|
||||
{
|
||||
closelog();
|
||||
closelog();
|
||||
freopen("/dev/null", "w", stdout);
|
||||
freopen("/dev/null", "w", stderr);
|
||||
freopen("/dev/null", "r", stdin);
|
||||
@@ -534,10 +556,19 @@ int process_options(int argc, char **argv)
|
||||
printf("Invalid APN\n");
|
||||
return -1;
|
||||
}
|
||||
options.apn.l = strlen(args_info.apn_arg);
|
||||
strncpy((char *)options.apn.v, args_info.apn_arg,
|
||||
sizeof(options.apn.v));
|
||||
options.apn.v[sizeof(options.apn.v) - 1] = 0;
|
||||
options.apn.l = strlen(args_info.apn_arg) + 1;
|
||||
|
||||
apn = (char *)options.apn.v;
|
||||
for (tok = strtok(args_info.apn_arg, ".");
|
||||
tok != NULL;
|
||||
tok = strtok(NULL, ".")) {
|
||||
size_t len = strlen(tok);
|
||||
|
||||
*apn++ = (char)len;
|
||||
strncpy(apn, tok, len);
|
||||
apn += len;
|
||||
}
|
||||
|
||||
printf("Using APN: %s\n", args_info.apn_arg);
|
||||
|
||||
/* selmode */
|
||||
@@ -547,9 +578,9 @@ int process_options(int argc, char **argv)
|
||||
/* rattype */
|
||||
if (args_info.rattype_given == 1) {
|
||||
options.rattype_given = 1;
|
||||
options.rattype.l = strlen(args_info.rattype_arg);
|
||||
options.rattype.v[0] = atoi(args_info.rattype_arg);
|
||||
printf("Using RAT Type: %s\n", args_info.rattype_arg);
|
||||
options.rattype.l = 1;
|
||||
options.rattype.v[0] = args_info.rattype_arg;
|
||||
printf("Using RAT Type: %d\n", args_info.rattype_arg);
|
||||
}
|
||||
|
||||
/* userloc */
|
||||
@@ -582,7 +613,7 @@ int process_options(int argc, char **argv)
|
||||
mcc = userloc_el[1];
|
||||
printf("->mcc : %s\n", mcc);
|
||||
if (strlen(mcc) != 3) {
|
||||
printf("Invalid MCC lenght\n");
|
||||
printf("Invalid MCC length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -601,7 +632,7 @@ int process_options(int argc, char **argv)
|
||||
a = (uint8_t) (mcc[2] - 48);
|
||||
|
||||
if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
|
||||
printf("Invalid MNC lenght\n");
|
||||
printf("Invalid MNC length\n");
|
||||
return -1;
|
||||
}
|
||||
if (strlen(mnc) == 2) {
|
||||
@@ -666,7 +697,7 @@ int process_options(int argc, char **argv)
|
||||
mcc = rai_el[0];
|
||||
printf("->mcc : %s\n", mcc);
|
||||
if (strlen(mcc) != 3) {
|
||||
printf("Invalid MCC lenght\n");
|
||||
printf("Invalid MCC length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -682,7 +713,7 @@ int process_options(int argc, char **argv)
|
||||
a = (uint8_t) (mcc[2] - 48);
|
||||
|
||||
if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
|
||||
printf("Invalid MNC lenght\n");
|
||||
printf("Invalid MNC length\n");
|
||||
return -1;
|
||||
}
|
||||
if (strlen(mnc) == 2) {
|
||||
@@ -839,30 +870,26 @@ int process_options(int argc, char **argv)
|
||||
|
||||
/* createif */
|
||||
options.createif = args_info.createif_flag;
|
||||
options.tun_dev_name = args_info.tun_device_arg;
|
||||
|
||||
/* net */
|
||||
/* Store net as in_addr net and mask */
|
||||
if (args_info.net_arg) {
|
||||
if (ippool_aton
|
||||
(&options.net, &options.mask, args_info.net_arg, 0)) {
|
||||
(&options.net, &options.prefixlen, args_info.net_arg, 0)) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Invalid network address: %s!",
|
||||
args_info.net_arg);
|
||||
exit(1);
|
||||
}
|
||||
#if defined (__sun__)
|
||||
options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
|
||||
options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
|
||||
#else
|
||||
options.netaddr.s_addr = options.net.s_addr;
|
||||
options.destaddr.s_addr = options.net.s_addr;
|
||||
#endif
|
||||
options.netaddr = options.net;
|
||||
options.destaddr = options.net;
|
||||
|
||||
} else {
|
||||
options.net.s_addr = 0;
|
||||
options.mask.s_addr = 0;
|
||||
options.netaddr.s_addr = 0;
|
||||
options.destaddr.s_addr = 0;
|
||||
memset(&options.net, 0, sizeof(options.net));
|
||||
options.prefixlen = 0;
|
||||
memset(&options.netaddr, 0, sizeof(options.netaddr));
|
||||
memset(&options.destaddr, 0, sizeof(options.destaddr));
|
||||
}
|
||||
|
||||
/* ipup */
|
||||
@@ -903,38 +930,77 @@ int process_options(int argc, char **argv)
|
||||
/* norecovery */
|
||||
options.norecovery_given = args_info.norecovery_flag;
|
||||
|
||||
if (args_info.no_tx_gpdu_seq_flag)
|
||||
options.tx_gpdu_seq = 0;
|
||||
else
|
||||
options.tx_gpdu_seq = 1;
|
||||
|
||||
/* PDP Type */
|
||||
if (!strcmp(args_info.pdp_type_arg, "v6"))
|
||||
options.pdp_type = PDP_EUA_TYPE_v6;
|
||||
else if (!strcmp(args_info.pdp_type_arg, "v4"))
|
||||
options.pdp_type = PDP_EUA_TYPE_v4;
|
||||
else {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
|
||||
args_info.pdp_type_arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
|
||||
static char *proc_read(const char *path)
|
||||
{
|
||||
unsigned int i;
|
||||
printf("The packet looks like this:\n");
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x ", (unsigned char)*(char *)(pack + i));
|
||||
if (!((i + 1) % 16))
|
||||
printf("\n");
|
||||
};
|
||||
printf("\n");
|
||||
return 0;
|
||||
char *ret = NULL;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(path, "r");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
ret = malloc(256);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (!fgets(ret, 256, f)) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *print_ipprot(int t)
|
||||
/* Read value of a /proc/sys/net/ipv6/conf file for given device.
|
||||
* Memory is dynamically allocated, caller must free it later. */
|
||||
static char *proc_ipv6_conf_read(const char *dev, const char *file)
|
||||
{
|
||||
switch (t) {
|
||||
case 1:
|
||||
return "ICMP";
|
||||
case 6:
|
||||
return "TCP";
|
||||
case 17:
|
||||
return "UDP";
|
||||
default:
|
||||
const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
|
||||
char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
|
||||
snprintf(path, sizeof(path), fmt, dev, file);
|
||||
return proc_read(path);
|
||||
}
|
||||
|
||||
static char *print_ipprot(int t)
|
||||
{
|
||||
struct protoent *pe = getprotobynumber(t);
|
||||
|
||||
if (!pe)
|
||||
return "Unknown";
|
||||
};
|
||||
else
|
||||
return pe->p_name;
|
||||
}
|
||||
|
||||
char *print_icmptype(int t)
|
||||
static char *print_icmptype(int t)
|
||||
{
|
||||
static char *ttab[] = {
|
||||
"Echo Reply",
|
||||
@@ -960,7 +1026,7 @@ char *print_icmptype(int t)
|
||||
return (ttab[t]);
|
||||
}
|
||||
|
||||
int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
|
||||
static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
|
||||
{
|
||||
unsigned int n;
|
||||
uint64_t i64 = 0;
|
||||
@@ -1004,7 +1070,7 @@ int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
|
||||
|
||||
}
|
||||
|
||||
int imsi_add(uint64_t src, uint64_t * dst, int add)
|
||||
static int imsi_add(uint64_t src, uint64_t * dst, int add)
|
||||
{
|
||||
/* TODO: big endian / small endian ??? */
|
||||
uint64_t i64 = 0;
|
||||
@@ -1039,7 +1105,7 @@ int imsi_add(uint64_t src, uint64_t * dst, int add)
|
||||
}
|
||||
|
||||
/* Calculate time left until we have to send off next ping packet */
|
||||
int ping_timeout(struct timeval *tp)
|
||||
static int ping_timeout(struct timeval *tp)
|
||||
{
|
||||
struct timezone tz;
|
||||
struct timeval tv;
|
||||
@@ -1061,7 +1127,7 @@ int ping_timeout(struct timeval *tp)
|
||||
}
|
||||
|
||||
/* Print out statistics when at the end of ping sequence */
|
||||
int ping_finish()
|
||||
static int ping_finish()
|
||||
{
|
||||
struct timezone tz;
|
||||
struct timeval tv;
|
||||
@@ -1094,7 +1160,7 @@ int ping_finish()
|
||||
}
|
||||
|
||||
/* Handle a received ping packet. Print out line and update statistics. */
|
||||
int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
{
|
||||
struct timezone tz;
|
||||
struct timeval tv;
|
||||
@@ -1163,8 +1229,8 @@ int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
}
|
||||
|
||||
/* Create a new ping packet and send it off to peer. */
|
||||
int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
struct in_addr *dst, int seq, unsigned int datasize)
|
||||
static int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
struct in_addr *dst, int seq, unsigned int datasize)
|
||||
{
|
||||
|
||||
struct ip_ping pack;
|
||||
@@ -1242,14 +1308,14 @@ int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
|
||||
}
|
||||
|
||||
int delete_context(struct pdp_t *pdp)
|
||||
static int delete_context(struct pdp_t *pdp)
|
||||
{
|
||||
|
||||
if (tun && options.ipdown)
|
||||
tun_runscript(tun, options.ipdown);
|
||||
|
||||
ipdel((struct iphash_t *)pdp->peer);
|
||||
memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
|
||||
ipdel((struct iphash_t *)pdp->peer[0]);
|
||||
memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
|
||||
|
||||
if (1 == options.contexts)
|
||||
state = 5; /* Disconnected */
|
||||
@@ -1257,17 +1323,46 @@ int delete_context(struct pdp_t *pdp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Link-Local address prefix fe80::/64 */
|
||||
static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
|
||||
|
||||
/* Callback for receiving messages from tun */
|
||||
int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
|
||||
static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
|
||||
{
|
||||
struct iphash_t *ipm;
|
||||
struct in_addr src;
|
||||
struct tun_packet_t *iph = (struct tun_packet_t *)pack;
|
||||
struct in46_addr src;
|
||||
struct iphdr *iph = (struct iphdr *)pack;
|
||||
struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
|
||||
|
||||
src.s_addr = iph->src;
|
||||
if (iph->version == 4) {
|
||||
if (len < sizeof(*iph) || len < 4*iph->ihl) {
|
||||
printf("Dropping packet with too short IP header\n");
|
||||
return 0;
|
||||
}
|
||||
src.len = 4;
|
||||
src.v4.s_addr = iph->saddr;
|
||||
} else if (iph->version == 6) {
|
||||
/* We only have a single entry in the hash table, and it consists of the link-local
|
||||
* address "fe80::prefix". So we need to make sure to convert non-link-local source
|
||||
* addresses to that format before looking up the hash table via ippool_getip() */
|
||||
src.len = 16;
|
||||
if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
|
||||
/* is a link-local address, we can do the hash lookup 1:1 */
|
||||
src.v6 = ip6h->ip6_src;
|
||||
} else {
|
||||
/* it is not a link-local address, so we must convert from the /64 prefix
|
||||
* to the link-local format that's used in the hash table */
|
||||
memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
|
||||
memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
|
||||
}
|
||||
} else {
|
||||
printf("Dropping packet with invalid IP version %u\n", iph->version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ipget(&ipm, &src)) {
|
||||
printf("Received packet without a valid source address!!!\n");
|
||||
printf("Dropping packet from invalid source address: %s\n",
|
||||
in46a_ntoa(&src));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1276,9 +1371,9 @@ int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
struct in_addr addr;
|
||||
struct in46_addr addr;
|
||||
|
||||
struct iphash_t *iph = (struct iphash_t *)cbp;
|
||||
|
||||
@@ -1307,7 +1402,7 @@ int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
return EOF; /* Not what we expected */
|
||||
}
|
||||
|
||||
if (pdp_euaton(&pdp->eua, &addr)) {
|
||||
if (in46a_from_eua(&pdp->eua, &addr) < 1) {
|
||||
printf
|
||||
("Received create PDP context response. Cause value: %d\n",
|
||||
cause);
|
||||
@@ -1318,41 +1413,71 @@ int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
}
|
||||
|
||||
printf("Received create PDP context response. IP address: %s\n",
|
||||
inet_ntoa(addr));
|
||||
in46a_ntoa(&addr));
|
||||
|
||||
if ((options.createif) && (!options.net.s_addr)) {
|
||||
struct in_addr m;
|
||||
#ifdef HAVE_INET_ATON
|
||||
inet_aton("255.255.255.255", &m);
|
||||
#else
|
||||
m.s_addr = -1;
|
||||
#endif
|
||||
switch (addr.len) {
|
||||
case 16: /* IPv6 */
|
||||
/* we have to enable the kernel to perform stateless autoconfiguration,
|
||||
* i.e. send a router solicitation using the lover 64bits of the allocated
|
||||
* EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
|
||||
memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
|
||||
printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
|
||||
break;
|
||||
case 4: /* IPv4 */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((options.createif) && (!options.net.len)) {
|
||||
size_t prefixlen = 32;
|
||||
if (addr.len == 16)
|
||||
prefixlen = 64;
|
||||
/* printf("Setting up interface and routing\n"); */
|
||||
tun_addaddr(tun, &addr, &addr, &m);
|
||||
tun_addaddr(tun, &addr, &addr, prefixlen);
|
||||
if (options.defaultroute) {
|
||||
struct in_addr rm;
|
||||
rm.s_addr = 0;
|
||||
tun_addroute(tun, &rm, &addr, &rm);
|
||||
netdev_addroute(&rm, &addr.v4, &rm);
|
||||
}
|
||||
if (options.ipup)
|
||||
tun_runscript(tun, options.ipup);
|
||||
}
|
||||
|
||||
ipset((struct iphash_t *)pdp->peer, &addr);
|
||||
/* now that ip-up has been executed, check if we are configured to
|
||||
* accept router advertisements */
|
||||
if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
|
||||
char *accept_ra, *forwarding;
|
||||
|
||||
accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
|
||||
forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
|
||||
if (!accept_ra || !forwarding)
|
||||
printf("Could not open proc file for %s ?!?\n", tun->devname);
|
||||
else {
|
||||
if (!strcmp(accept_ra, "0") ||
|
||||
(!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
|
||||
printf("%s is %s, i.e. your tun device is not configured to accept "
|
||||
"router advertisements; SLAAC will not suceed, please "
|
||||
"fix your setup!\n");
|
||||
}
|
||||
}
|
||||
free(accept_ra);
|
||||
free(forwarding);
|
||||
}
|
||||
|
||||
ipset(iph, &addr);
|
||||
|
||||
state = 2; /* Connected */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int delete_pdp_conf(struct pdp_t *pdp, int cause)
|
||||
static int delete_pdp_conf(struct pdp_t *pdp, int cause)
|
||||
{
|
||||
printf("Received delete PDP context response. Cause value: %d\n",
|
||||
cause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int echo_conf(int recovery)
|
||||
static int echo_conf(int recovery)
|
||||
{
|
||||
|
||||
if (recovery < 0) {
|
||||
@@ -1374,7 +1499,7 @@ int echo_conf(int recovery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
||||
static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
||||
{
|
||||
/* if (cause < 0) return 0; Some error occurred. We don't care */
|
||||
switch (type) {
|
||||
@@ -1391,7 +1516,7 @@ int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
||||
}
|
||||
}
|
||||
|
||||
int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
|
||||
{
|
||||
/* printf("encaps_tun. Packet received: forwarding to tun\n"); */
|
||||
return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
|
||||
@@ -1406,12 +1531,19 @@ int main(int argc, char **argv)
|
||||
int starttime = time(NULL); /* Time program was started */
|
||||
int stoptime = 0; /* Time to exit */
|
||||
int pingtimeout = 0; /* Time to print ping statistics */
|
||||
int signal_received; /* If select() on fd_set is interrupted by signal. */
|
||||
|
||||
struct timezone tz; /* Used for calculating ping times */
|
||||
struct timeval tv;
|
||||
int diff;
|
||||
|
||||
osmo_init_logging(&log_info);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
|
||||
msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
|
||||
osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
|
||||
|
||||
/* Process options given in configuration file and command line */
|
||||
if (process_options(argc, argv))
|
||||
@@ -1439,7 +1571,7 @@ int main(int argc, char **argv)
|
||||
if (options.createif) {
|
||||
printf("Setting up interface\n");
|
||||
/* Create a tunnel interface */
|
||||
if (tun_new((struct tun_t **)&tun)) {
|
||||
if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Failed to create tun");
|
||||
exit(1);
|
||||
@@ -1449,14 +1581,13 @@ int main(int argc, char **argv)
|
||||
maxfd = tun->fd;
|
||||
}
|
||||
|
||||
if ((options.createif) && (options.net.s_addr)) {
|
||||
if ((options.createif) && (options.net.len)) {
|
||||
/* printf("Setting up interface and routing\n"); */
|
||||
tun_addaddr(tun, &options.netaddr, &options.destaddr,
|
||||
&options.mask);
|
||||
tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
|
||||
if (options.defaultroute) {
|
||||
struct in_addr rm;
|
||||
rm.s_addr = 0;
|
||||
tun_addroute(tun, &rm, &options.destaddr, &rm);
|
||||
netdev_addroute(&rm, &options.destaddr.v4, &rm);
|
||||
}
|
||||
if (options.ipup)
|
||||
tun_runscript(tun, options.ipup);
|
||||
@@ -1485,7 +1616,7 @@ int main(int argc, char **argv)
|
||||
/* Otherwise it is deallocated by gtplib */
|
||||
pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
|
||||
|
||||
pdp->peer = &iparr[n];
|
||||
pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
|
||||
pdp->ipif = tun; /* TODO */
|
||||
iparr[n].pdp = pdp;
|
||||
|
||||
@@ -1549,7 +1680,10 @@ int main(int argc, char **argv)
|
||||
msisdn_add(&options.msisdn, &pdp->msisdn, n);
|
||||
}
|
||||
|
||||
ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
|
||||
/* Request dynamic IP address */
|
||||
pdp->eua.v[0] = PDP_EUA_ORG_IETF;
|
||||
pdp->eua.v[1] = options.pdp_type;
|
||||
pdp->eua.l = 2;
|
||||
|
||||
if (options.pco.l > sizeof(pdp->pco_req.v)) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
@@ -1565,9 +1699,11 @@ int main(int argc, char **argv)
|
||||
pdp->hisaddr0 = options.remote;
|
||||
pdp->hisaddr1 = options.remote;
|
||||
|
||||
pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
|
||||
pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
|
||||
512 = Flat rate, 256 = Hot billing */
|
||||
|
||||
pdp->tx_gpdu_seq = options.tx_gpdu_seq;
|
||||
|
||||
/* Create context */
|
||||
/* We send this of once. Retransmissions are handled by gtplib */
|
||||
gtp_create_context_req(gsn, pdp, &iparr[n]);
|
||||
@@ -1665,10 +1801,14 @@ int main(int argc, char **argv)
|
||||
printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
|
||||
(int)idleTime.tv_sec, (int)idleTime.tv_usec);
|
||||
|
||||
signal_received = 0;
|
||||
switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
|
||||
case -1:
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Select returned -1");
|
||||
if (errno == EINTR)
|
||||
signal_received = 1;
|
||||
else
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Select returned -1");
|
||||
break;
|
||||
case 0:
|
||||
gtp_retrans(gsn); /* Only retransmit if nothing else */
|
||||
@@ -1677,19 +1817,23 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"TUN decaps failed");
|
||||
if (!signal_received) {
|
||||
|
||||
if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"TUN decaps failed");
|
||||
}
|
||||
|
||||
if (FD_ISSET(gsn->fd0, &fds))
|
||||
gtp_decaps0(gsn);
|
||||
|
||||
if (FD_ISSET(gsn->fd1c, &fds))
|
||||
gtp_decaps1c(gsn);
|
||||
|
||||
if (FD_ISSET(gsn->fd1u, &fds))
|
||||
gtp_decaps1u(gsn);
|
||||
|
||||
}
|
||||
|
||||
if (FD_ISSET(gsn->fd0, &fds))
|
||||
gtp_decaps0(gsn);
|
||||
|
||||
if (FD_ISSET(gsn->fd1c, &fds))
|
||||
gtp_decaps1c(gsn);
|
||||
|
||||
if (FD_ISSET(gsn->fd1u, &fds))
|
||||
gtp_decaps1u(gsn);
|
||||
}
|
||||
|
||||
gtp_free(gsn); /* Clean up the gsn instance */
|
||||
|
||||
41
tests/Makefile.am
Normal file
41
tests/Makefile.am
Normal file
@@ -0,0 +1,41 @@
|
||||
SUBDIRS = \
|
||||
lib \
|
||||
gtp \
|
||||
$(NULL)
|
||||
|
||||
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
|
||||
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
:;{ \
|
||||
echo '# Signature of the current package.' && \
|
||||
echo 'm4_define([AT_PACKAGE_NAME],' && \
|
||||
echo ' [$(PACKAGE_NAME)])' && \
|
||||
echo 'm4_define([AT_PACKAGE_TARNAME],' && \
|
||||
echo ' [$(PACKAGE_TARNAME)])' && \
|
||||
echo 'm4_define([AT_PACKAGE_VERSION],' && \
|
||||
echo ' [$(PACKAGE_VERSION)])' && \
|
||||
echo 'm4_define([AT_PACKAGE_STRING],' && \
|
||||
echo ' [$(PACKAGE_STRING)])' && \
|
||||
echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \
|
||||
echo ' [$(PACKAGE_BUGREPORT)])'; \
|
||||
echo 'm4_define([AT_PACKAGE_URL],' && \
|
||||
echo ' [$(PACKAGE_URL)])'; \
|
||||
} >'$(srcdir)/package.m4'
|
||||
|
||||
EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
DISTCLEANFILES = atconfig $(NULL)
|
||||
|
||||
check-local: atconfig $(TESTSUITE)
|
||||
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
|
||||
|
||||
installcheck-local: atconfig $(TESTSUITE)
|
||||
$(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
|
||||
|
||||
clean-local:
|
||||
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
|
||||
|
||||
AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te
|
||||
AUTOTEST = $(AUTOM4TE) --language=autotest
|
||||
$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4
|
||||
$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
|
||||
mv $@.tmp $@
|
||||
19
tests/gtp/Makefile.am
Normal file
19
tests/gtp/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
|
||||
|
||||
EXTRA_DIST = \
|
||||
gtpie_test.ok \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
gtpie_test \
|
||||
$(NULL)
|
||||
|
||||
gtpie_test_SOURCES = \
|
||||
gtpie_test.c \
|
||||
$(NULL)
|
||||
|
||||
gtpie_test_LDADD = \
|
||||
$(top_builddir)/lib/debug.o \
|
||||
$(top_builddir)/gtp/libgtp.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
132
tests/gtp/gtpie_test.c
Normal file
132
tests/gtp/gtpie_test.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
#include "../../lib/syserr.h"
|
||||
#include "../../gtp/gtpie.h"
|
||||
|
||||
static const uint8_t in[] = { 1,2,3,4,5,6 };
|
||||
static uint8_t buf[256];
|
||||
static int rc;
|
||||
|
||||
static void test_gtpie_tlv()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tlv()\n");
|
||||
|
||||
/* normal / successful case */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tlv(buf, &len, sizeof(buf), 23, sizeof(in), in);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == sizeof(in) + 3);
|
||||
OSMO_ASSERT(buf[0] == 23);
|
||||
OSMO_ASSERT(osmo_load16be(&buf[1]) == sizeof(in));
|
||||
OSMO_ASSERT(!memcmp(buf+3, in, sizeof(in)));
|
||||
|
||||
/* overflow */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tlv(buf, &len, 4, 23, sizeof(in), in);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
}
|
||||
|
||||
static void test_gtpie_tv0()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tv0()\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tv0(buf, &len, sizeof(buf), 42, sizeof(in), in);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == sizeof(in) + 1);
|
||||
}
|
||||
|
||||
static void test_gtpie_tv1()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tv1()\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tv1(buf, &len, sizeof(buf), 42, 0xAD);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == 2);
|
||||
OSMO_ASSERT(buf[0] == 42);
|
||||
OSMO_ASSERT(buf[1] == 0xAD);
|
||||
}
|
||||
|
||||
static void test_gtpie_tv2()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tv2()\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tv2(buf, &len, sizeof(buf), 42, 0xABCD);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == 3);
|
||||
OSMO_ASSERT(buf[0] == 42);
|
||||
OSMO_ASSERT(osmo_load16be(&buf[1]) == 0xABCD);
|
||||
}
|
||||
|
||||
static void test_gtpie_tv4()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tv4()\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tv4(buf, &len, sizeof(buf), 42, 0xABCD0123);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == 5);
|
||||
OSMO_ASSERT(buf[0] == 42);
|
||||
OSMO_ASSERT(osmo_load32be(&buf[1]) == 0xABCD0123);
|
||||
}
|
||||
|
||||
static void test_gtpie_tv8()
|
||||
{
|
||||
unsigned int len = 0;
|
||||
|
||||
printf("Testing gtpie_tv8()\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rc = gtpie_tv8(buf, &len, sizeof(buf), 42, 0x0001020304050607ULL);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(len == 9);
|
||||
OSMO_ASSERT(buf[0] == 42);
|
||||
OSMO_ASSERT(osmo_load32be(&buf[1]) == 0x00010203);
|
||||
OSMO_ASSERT(osmo_load32be(&buf[5]) == 0x04050607);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
|
||||
msgb_talloc_ctx_init(tall_ctx, 0);
|
||||
osmo_init_logging2(tall_ctx, &log_info);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
test_gtpie_tlv();
|
||||
test_gtpie_tv0();
|
||||
test_gtpie_tv1();
|
||||
test_gtpie_tv2();
|
||||
test_gtpie_tv4();
|
||||
test_gtpie_tv8();
|
||||
|
||||
/* TODO: gtpie_decaps() */
|
||||
/* TODO: gtpie_encaps() */
|
||||
/* TODO: gtpie_encaps2() */
|
||||
/* TODO: gtpie_getie(), gtpie_exist(), gtpie_get*() */
|
||||
return 0;
|
||||
}
|
||||
6
tests/gtp/gtpie_test.ok
Normal file
6
tests/gtp/gtpie_test.ok
Normal file
@@ -0,0 +1,6 @@
|
||||
Testing gtpie_tlv()
|
||||
Testing gtpie_tv0()
|
||||
Testing gtpie_tv1()
|
||||
Testing gtpie_tv2()
|
||||
Testing gtpie_tv4()
|
||||
Testing gtpie_tv8()
|
||||
28
tests/lib/Makefile.am
Normal file
28
tests/lib/Makefile.am
Normal file
@@ -0,0 +1,28 @@
|
||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
|
||||
|
||||
EXTRA_DIST = ippool_test.ok \
|
||||
ippool_test.err \
|
||||
ippool_v6_test.ok \
|
||||
ippool_v6_test.err \
|
||||
in46a_test.ok \
|
||||
in46a_v6_test.ok
|
||||
|
||||
noinst_PROGRAMS = ippool_test in46a_test
|
||||
|
||||
ippool_test_SOURCES = \
|
||||
ippool_test.c \
|
||||
$(NULL)
|
||||
|
||||
ippool_test_LDADD = \
|
||||
$(top_builddir)/lib/libmisc.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
in46a_test_SOURCES = \
|
||||
in46a_test.c \
|
||||
$(NULL)
|
||||
|
||||
in46a_test_LDADD = \
|
||||
$(top_builddir)/lib/libmisc.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
460
tests/lib/in46a_test.c
Normal file
460
tests/lib/in46a_test.c
Normal file
@@ -0,0 +1,460 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
#include "../../lib/in46_addr.h"
|
||||
#include "../../lib/syserr.h"
|
||||
|
||||
static const struct in46_addr g_ia4 = {
|
||||
.len = 4,
|
||||
.v4.s_addr = 0x0d0c0b0a,
|
||||
};
|
||||
|
||||
static void test_in46a_to_af(void)
|
||||
{
|
||||
printf("Testing in46a_to_af() with IPv4 addresses\n");
|
||||
|
||||
OSMO_ASSERT(in46a_to_af(&g_ia4) == AF_INET);
|
||||
}
|
||||
|
||||
static void test_in46a_to_sas(void)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
|
||||
|
||||
printf("Testing in46a_to_sas() with IPv4 addresses\n");
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
OSMO_ASSERT(in46a_to_sas(&ss, &g_ia4) == 0);
|
||||
OSMO_ASSERT(sin->sin_family == AF_INET);
|
||||
OSMO_ASSERT(sin->sin_addr.s_addr == g_ia4.v4.s_addr);
|
||||
}
|
||||
|
||||
static void test_in46a_ntop(void)
|
||||
{
|
||||
struct in46_addr ia;
|
||||
char buf[256];
|
||||
const char *res;
|
||||
|
||||
printf("Testing in46a_ntop() with IPv4 addresses\n");
|
||||
|
||||
res = in46a_ntop(NULL, buf, sizeof(buf));
|
||||
OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
|
||||
printf("res = %s\n", res);
|
||||
|
||||
ia.len = 0;
|
||||
res = in46a_ntop(&ia, buf, sizeof(buf));
|
||||
printf("res = %s\n", res);
|
||||
OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
|
||||
|
||||
ia.len = 4;
|
||||
ia.v4.s_addr = htonl(0x01020304);
|
||||
res = in46a_ntop(&ia, buf, sizeof(buf));
|
||||
OSMO_ASSERT(res && !strcmp(res, "1.2.3.4"));
|
||||
printf("res = %s\n", res);
|
||||
}
|
||||
|
||||
static void test_in46p_ntoa(void)
|
||||
{
|
||||
const struct in46_prefix ip46 = {
|
||||
.prefixlen = 24,
|
||||
.addr = {
|
||||
.len = 4,
|
||||
.v4.s_addr = htonl(0x10203000),
|
||||
},
|
||||
};
|
||||
printf("in46p_ntoa() returns %s\n", in46p_ntoa(&ip46));
|
||||
}
|
||||
|
||||
static void test_in46a_equal(void)
|
||||
{
|
||||
struct in46_addr b;
|
||||
|
||||
printf("Testing in46a_equal() with IPv4 addresses\n");
|
||||
|
||||
memset(&b, 0xff, sizeof(b));
|
||||
b.len = g_ia4.len;
|
||||
b.v4.s_addr = g_ia4.v4.s_addr;
|
||||
OSMO_ASSERT(in46a_equal(&g_ia4, &b));
|
||||
}
|
||||
|
||||
static int log_in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
|
||||
size_t prefixlen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
printf("in46a_within_mask(%s, ", in46a_ntoa(addr));
|
||||
printf("%s, %lu) = ", in46a_ntoa(net), prefixlen);
|
||||
|
||||
rc = in46a_within_mask(addr, net, prefixlen);
|
||||
printf("%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void test_in46a_within_mask(void)
|
||||
{
|
||||
struct in46_addr addr, mask;
|
||||
|
||||
printf("Testing in46a_within_mask() with IPv4 addresses\n");
|
||||
|
||||
addr = g_ia4;
|
||||
mask = g_ia4;
|
||||
OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 32));
|
||||
|
||||
mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfffffffC );
|
||||
OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 30));
|
||||
|
||||
mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfff80000 );
|
||||
OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 13));
|
||||
|
||||
addr.v4.s_addr = htonl(ntohl(addr.v4.s_addr) + 1);
|
||||
mask = g_ia4;
|
||||
OSMO_ASSERT(!log_in46a_within_mask(&addr, &mask, 32));
|
||||
mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfffffffC );
|
||||
OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 30));
|
||||
}
|
||||
|
||||
static void test_in46a_to_eua(void)
|
||||
{
|
||||
struct ul66_t eua;
|
||||
|
||||
printf("testing in46a_to_eua() with IPv4 addresses\n");
|
||||
|
||||
#if 0 /* triggers assert in current implementation */
|
||||
const struct in46_addr ia_invalid = { .len = 3, };
|
||||
OSMO_ASSERT(in46a_to_eua(&ia_invalid, &eua) < 0);
|
||||
#endif
|
||||
|
||||
/* IPv4 address */
|
||||
OSMO_ASSERT(in46a_to_eua(&g_ia4, 1, &eua) == 0);
|
||||
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
|
||||
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4);
|
||||
OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
|
||||
}
|
||||
|
||||
static void test_in46a_from_eua(void)
|
||||
{
|
||||
struct in46_addr ia;
|
||||
struct ul66_t eua;
|
||||
const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 };
|
||||
const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 };
|
||||
memset(&eua, 0, sizeof(eua));
|
||||
|
||||
printf("Testing in46a_from_eua() with IPv4 addresses\n");
|
||||
|
||||
/* default: v4 unspec */
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
|
||||
OSMO_ASSERT(ia.len == 4);
|
||||
OSMO_ASSERT(ia.v4.s_addr == 0);
|
||||
|
||||
/* invalid */
|
||||
eua.v[0] = 0x23;
|
||||
eua.v[1] = PDP_EUA_TYPE_v4;
|
||||
eua.l = 6;
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
|
||||
|
||||
/* invalid */
|
||||
eua.v[0] = PDP_EUA_ORG_IETF;
|
||||
eua.v[1] = 0x23;
|
||||
eua.l = 6;
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
|
||||
|
||||
/* unspecified V4 */
|
||||
memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
|
||||
eua.l = sizeof(v4_unspec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
|
||||
OSMO_ASSERT(ia.len == 4);
|
||||
OSMO_ASSERT(ia.v4.s_addr == 0);
|
||||
|
||||
/* specified V4 */
|
||||
memcpy(eua.v, v4_spec, sizeof(v4_spec));
|
||||
eua.l = sizeof(v4_spec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
|
||||
OSMO_ASSERT(ia.len == 4);
|
||||
OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
|
||||
}
|
||||
|
||||
static void test_in46a_netmasklen(void)
|
||||
{
|
||||
struct in46_addr netmask;
|
||||
unsigned int len;
|
||||
|
||||
printf("Testing in46a_netmasklen() with IPv4 addresses\n");
|
||||
netmask.len = 4;
|
||||
|
||||
netmask.v4.s_addr = 0xffffffff;
|
||||
len = in46a_netmasklen(&netmask);
|
||||
OSMO_ASSERT(len == 32);
|
||||
|
||||
netmask.v4.s_addr = 0x00ffffff;
|
||||
len = in46a_netmasklen(&netmask);
|
||||
OSMO_ASSERT(len == 24);
|
||||
|
||||
netmask.v4.s_addr = 0x00f0ffff;
|
||||
len = in46a_netmasklen(&netmask);
|
||||
OSMO_ASSERT(len == 20);
|
||||
|
||||
netmask.v4.s_addr = 0x000000fe;
|
||||
len = in46a_netmasklen(&netmask);
|
||||
OSMO_ASSERT(len == 7);
|
||||
|
||||
netmask.v4.s_addr = 0x00000000;
|
||||
len = in46a_netmasklen(&netmask);
|
||||
OSMO_ASSERT(len == 0);
|
||||
}
|
||||
|
||||
/* IPv6 specific tests */
|
||||
|
||||
static const struct in46_addr g_ia6 = {
|
||||
.len = 16,
|
||||
.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
|
||||
};
|
||||
|
||||
static void test_in46a_to_af_v6(void)
|
||||
{
|
||||
struct in46_addr ia;
|
||||
|
||||
printf("Testing in46a_to_af() with IPv6 addresses\n");
|
||||
|
||||
OSMO_ASSERT(in46a_to_af(&g_ia6) == AF_INET6);
|
||||
|
||||
ia.len = 8;
|
||||
OSMO_ASSERT(in46a_to_af(&ia) == AF_INET6);
|
||||
}
|
||||
|
||||
static void test_in46a_to_sas_v6(void)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
|
||||
|
||||
printf("Testing in46a_to_sas() with IPv6 addresses\n");
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
OSMO_ASSERT(in46a_to_sas(&ss, &g_ia6) == 0);
|
||||
OSMO_ASSERT(sin6->sin6_family == AF_INET6);
|
||||
OSMO_ASSERT(!memcmp(&sin6->sin6_addr, &g_ia6.v6, sizeof(sin6->sin6_addr)));
|
||||
}
|
||||
|
||||
static void test_in46a_ntop_v6(void)
|
||||
{
|
||||
char buf[256];
|
||||
const char *res;
|
||||
|
||||
printf("Testing in46a_ntop() with IPv6 addresses\n");
|
||||
|
||||
res = in46a_ntop(&g_ia6, buf, sizeof(buf));
|
||||
OSMO_ASSERT(res && !strcmp(res, "102:304:506:708:90a:b0c:d0e:f10"));
|
||||
printf("res = %s\n", res);
|
||||
}
|
||||
|
||||
static void test_in46a_equal_v6(void)
|
||||
{
|
||||
struct in46_addr b;
|
||||
|
||||
printf("Testing in46a_equal() with IPv6 addresses\n");
|
||||
|
||||
memset(&b, 0xff, sizeof(b));
|
||||
b.len = g_ia6.len;
|
||||
b.v6 = g_ia6.v6;
|
||||
OSMO_ASSERT(in46a_equal(&g_ia6, &b));
|
||||
}
|
||||
|
||||
static void test_in46a_to_eua_v6(void)
|
||||
{
|
||||
const struct in46_addr ia_v6_8 = {
|
||||
.len = 8,
|
||||
.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
|
||||
};
|
||||
struct ul66_t eua;
|
||||
|
||||
printf("Testing in46a_to_eua() with IPv6 addresses\n");
|
||||
|
||||
/* IPv6 address */
|
||||
OSMO_ASSERT(in46a_to_eua(&g_ia6, 1, &eua) == 0);
|
||||
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
|
||||
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
|
||||
OSMO_ASSERT(!memcmp(&eua.v[2], &g_ia6.v6, 16));
|
||||
|
||||
/* IPv6 address with prefix / length 8 */
|
||||
OSMO_ASSERT(in46a_to_eua(&ia_v6_8, 1, &eua) == 0);
|
||||
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
|
||||
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
|
||||
OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16));
|
||||
}
|
||||
|
||||
static void test_in46a_to_eua_v4v6() {
|
||||
const struct in46_addr ia_v4v6[2] = {
|
||||
{
|
||||
.len = 16,
|
||||
.v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
|
||||
},
|
||||
{
|
||||
.len = 4,
|
||||
.v4.s_addr = 0x0d0c0b0a,
|
||||
}
|
||||
};
|
||||
struct ul66_t eua;
|
||||
printf("Testing in46a_to_eua() with IPv4v6 addresses\n");
|
||||
|
||||
/* IPv4 address */
|
||||
OSMO_ASSERT(in46a_to_eua(ia_v4v6, 2, &eua) == 0);
|
||||
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
|
||||
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4v6);
|
||||
OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
|
||||
OSMO_ASSERT(!memcmp(&eua.v[6], &g_ia6.v6, 16));
|
||||
}
|
||||
|
||||
static void test_in46a_from_eua_v6(void)
|
||||
{
|
||||
struct in46_addr ia;
|
||||
struct ul66_t eua;
|
||||
const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 };
|
||||
const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6,
|
||||
1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
|
||||
|
||||
memset(&eua, 0, sizeof(eua));
|
||||
|
||||
printf("Testing in46a_from_eua() with IPv6 addresses\n");
|
||||
|
||||
/* unspecified V6 */
|
||||
memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
|
||||
eua.l = sizeof(v6_unspec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
|
||||
OSMO_ASSERT(ia.len == 16);
|
||||
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
|
||||
|
||||
/* specified V6 */
|
||||
memcpy(eua.v, v6_spec, sizeof(v6_spec));
|
||||
eua.l = sizeof(v6_spec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
|
||||
OSMO_ASSERT(ia.len == 16);
|
||||
OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
|
||||
}
|
||||
|
||||
static void test_in46a_from_eua_v4v6(void) {
|
||||
struct in46_addr ia[2];
|
||||
struct ul66_t eua;
|
||||
const uint8_t v4_unspec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6 };
|
||||
const uint8_t v4_spec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4 };
|
||||
const uint8_t v4_unspec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
|
||||
const uint8_t v4_spec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
|
||||
|
||||
memset(&eua, 0, sizeof(eua));
|
||||
|
||||
printf("Testing in46a_from_eua() with IPv4v6 addresses\n");
|
||||
|
||||
/* unspecified V4 & V6 */
|
||||
memcpy(eua.v, v4_unspec_v6_unspec, sizeof(v4_unspec_v6_unspec));
|
||||
eua.l = sizeof(v4_unspec_v6_unspec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
|
||||
OSMO_ASSERT(ia[0].len == 4);
|
||||
OSMO_ASSERT(ia[1].len == 16);
|
||||
OSMO_ASSERT(ia[0].v4.s_addr == 0);
|
||||
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
|
||||
|
||||
/* specified V4, unspecified V6 */
|
||||
memcpy(eua.v, v4_spec_v6_unspec, sizeof(v4_spec_v6_unspec));
|
||||
eua.l = sizeof(v4_spec_v6_unspec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
|
||||
OSMO_ASSERT(ia[0].len == 4);
|
||||
OSMO_ASSERT(ia[1].len == 16);
|
||||
OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
|
||||
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
|
||||
|
||||
/* unspecified V4, specified V6 */
|
||||
memcpy(eua.v, v4_unspec_v6_spec, sizeof(v4_unspec_v6_spec));
|
||||
eua.l = sizeof(v4_unspec_v6_spec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
|
||||
OSMO_ASSERT(ia[0].len == 4);
|
||||
OSMO_ASSERT(ia[1].len == 16);
|
||||
OSMO_ASSERT(ia[0].v4.s_addr == 0);
|
||||
OSMO_ASSERT(!memcmp(&ia[1].v6, v4_unspec_v6_spec+2, ia[1].len));
|
||||
|
||||
/* specified V4, specified V6 */
|
||||
memcpy(eua.v, v4_spec_v6_spec, sizeof(v4_spec_v6_spec));
|
||||
eua.l = sizeof(v4_spec_v6_spec);
|
||||
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
|
||||
OSMO_ASSERT(ia[0].len == 4);
|
||||
OSMO_ASSERT(ia[1].len == 16);
|
||||
OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
|
||||
OSMO_ASSERT(!memcmp(&ia[1].v6, v4_spec_v6_spec+6, ia[1].len));
|
||||
}
|
||||
|
||||
static void test_in46a_netmasklen_v6(void)
|
||||
{
|
||||
unsigned int len;
|
||||
printf("Testing in46a_netmasklen() with IPv6 addresses\n");
|
||||
const struct in46_addr netmaskA = {
|
||||
.len = 16,
|
||||
.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
|
||||
};
|
||||
len = in46a_netmasklen(&netmaskA);
|
||||
OSMO_ASSERT(len == 128);
|
||||
|
||||
const struct in46_addr netmaskB = {
|
||||
.len = 16,
|
||||
.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00},
|
||||
};
|
||||
len = in46a_netmasklen(&netmaskB);
|
||||
OSMO_ASSERT(len == 104);
|
||||
|
||||
const struct in46_addr netmaskC = {
|
||||
.len = 16,
|
||||
.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00},
|
||||
};
|
||||
len = in46a_netmasklen(&netmaskC);
|
||||
OSMO_ASSERT(len == 103);
|
||||
|
||||
const struct in46_addr netmaskD = {
|
||||
.len = 16,
|
||||
.v6.s6_addr = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
};
|
||||
len = in46a_netmasklen(&netmaskD);
|
||||
OSMO_ASSERT(len == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
|
||||
msgb_talloc_ctx_init(tall_ctx, 0);
|
||||
osmo_init_logging2(tall_ctx, &log_info);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-v6")) {
|
||||
test_in46a_to_af();
|
||||
test_in46a_to_sas();
|
||||
test_in46a_ntop();
|
||||
test_in46p_ntoa();
|
||||
test_in46a_equal();
|
||||
test_in46a_within_mask();
|
||||
test_in46a_to_eua();
|
||||
test_in46a_from_eua();
|
||||
test_in46a_netmasklen();
|
||||
} else {
|
||||
test_in46a_to_af_v6();
|
||||
test_in46a_to_sas_v6();
|
||||
test_in46a_ntop_v6();
|
||||
test_in46a_equal_v6();
|
||||
test_in46a_to_eua_v6();
|
||||
test_in46a_from_eua_v6();
|
||||
test_in46a_to_eua_v4v6();
|
||||
test_in46a_from_eua_v4v6();
|
||||
test_in46a_netmasklen_v6();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
17
tests/lib/in46a_test.ok
Normal file
17
tests/lib/in46a_test.ok
Normal file
@@ -0,0 +1,17 @@
|
||||
Testing in46a_to_af() with IPv4 addresses
|
||||
Testing in46a_to_sas() with IPv4 addresses
|
||||
Testing in46a_ntop() with IPv4 addresses
|
||||
res = UNDEFINED
|
||||
res = UNDEFINED
|
||||
res = 1.2.3.4
|
||||
in46p_ntoa() returns 16.32.48.0/24
|
||||
Testing in46a_equal() with IPv4 addresses
|
||||
Testing in46a_within_mask() with IPv4 addresses
|
||||
in46a_within_mask(10.11.12.13, 10.11.12.13, 32) = 1
|
||||
in46a_within_mask(10.11.12.13, 10.11.12.12, 30) = 1
|
||||
in46a_within_mask(10.11.12.13, 10.8.0.0, 13) = 1
|
||||
in46a_within_mask(10.11.12.14, 10.11.12.13, 32) = 0
|
||||
in46a_within_mask(10.11.12.14, 10.11.12.12, 30) = 1
|
||||
testing in46a_to_eua() with IPv4 addresses
|
||||
Testing in46a_from_eua() with IPv4 addresses
|
||||
Testing in46a_netmasklen() with IPv4 addresses
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user