mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-11-03 05:33:23 +00:00
Compare commits
369 Commits
neels/refa
...
1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67aebc9d1c | ||
|
|
ea1cb3fa33 | ||
|
|
0036a60c44 | ||
|
|
e47932976c | ||
|
|
f1e01517bc | ||
|
|
ad252e70aa | ||
|
|
08ca425bc2 | ||
|
|
1eeb113c34 | ||
|
|
d0ba664fec | ||
|
|
ec1d8c4004 | ||
|
|
36e12d4db8 | ||
|
|
2404c5b0b7 | ||
|
|
32b76ee1af | ||
|
|
7bdc80de00 | ||
|
|
83f5266f43 | ||
|
|
e725d87d13 | ||
|
|
8b90bce962 | ||
|
|
f0829ff34b | ||
|
|
e589c6544c | ||
|
|
d1a2ddfee6 | ||
|
|
7b52f00192 | ||
|
|
25ab381c0f | ||
|
|
9fbcb10568 | ||
|
|
eefa30dce8 | ||
|
|
5560001af5 | ||
|
|
a469a90d5e | ||
|
|
84515f4b8b | ||
|
|
1cde2c1691 | ||
|
|
93dd798a99 | ||
|
|
8651573632 | ||
|
|
0d0b0592f0 | ||
|
|
aad77a0acf | ||
|
|
9ee8d3264b | ||
|
|
de72d26f49 | ||
|
|
ceac078d77 | ||
|
|
cd87c5f963 | ||
|
|
154f93da51 | ||
|
|
742a6b55ce | ||
|
|
72ab4bc547 | ||
|
|
fb62504160 | ||
|
|
d7030d268c | ||
|
|
2e8e57a3de | ||
|
|
ca276e01eb | ||
|
|
977b339abe | ||
|
|
9272d212c3 | ||
|
|
f653c5bc33 | ||
|
|
549417e675 | ||
|
|
42c9fa4958 | ||
|
|
df404c4296 | ||
|
|
ffa227307c | ||
|
|
3fc9cc97de | ||
|
|
f5a268a96d | ||
|
|
6da888c5d0 | ||
|
|
33c537e5a7 | ||
|
|
aa69034c00 | ||
|
|
bf47f71785 | ||
|
|
2b7a860ffb | ||
|
|
932eeec240 | ||
|
|
6f7aabf6a3 | ||
|
|
a491e42129 | ||
|
|
1ce111f72b | ||
|
|
e010dea56e | ||
|
|
f4530447f6 | ||
|
|
e7361067ac | ||
|
|
606837597f | ||
|
|
5f8b332e6b | ||
|
|
43001cbc7a | ||
|
|
65d61c347b | ||
|
|
c8ca02b937 | ||
|
|
3ce5a3648a | ||
|
|
a4cb02699e | ||
|
|
f0fb2c2ddd | ||
|
|
8a1e7b8658 | ||
|
|
b7782d4d41 | ||
|
|
b0b9c28284 | ||
|
|
3730c550cd | ||
|
|
cc8181fefe | ||
|
|
7327360d10 | ||
|
|
e405c2f196 | ||
|
|
411ff3b984 | ||
|
|
aee905b790 | ||
|
|
fb75adfeda | ||
|
|
7b9230acfe | ||
|
|
5662cb2152 | ||
|
|
e1412d9493 | ||
|
|
d1e2342f91 | ||
|
|
381b723543 | ||
|
|
ee44b82b96 | ||
|
|
b5f93346df | ||
|
|
8e8c7ef3c7 | ||
|
|
57238889eb | ||
|
|
d70ab97fa4 | ||
|
|
d1bd6fce9c | ||
|
|
a32e4c4fb8 | ||
|
|
3b84e92ab3 | ||
|
|
3e0baa6146 | ||
|
|
b673d1c438 | ||
|
|
6a2856bab5 | ||
|
|
0d95ca59f9 | ||
|
|
906c2099da | ||
|
|
ac07625086 | ||
|
|
36c4fac9c9 | ||
|
|
a06b2d3877 | ||
|
|
546884d9a1 | ||
|
|
f2286395e9 | ||
|
|
9eebe15cd1 | ||
|
|
31e1dab2c0 | ||
|
|
db0366c9e4 | ||
|
|
47adad0817 | ||
|
|
c5efb5bccb | ||
|
|
9a6da455b9 | ||
|
|
b4c0828039 | ||
|
|
df3dcac439 | ||
|
|
0757504a86 | ||
|
|
042a445cf3 | ||
|
|
a16c7501a4 | ||
|
|
9f98822255 | ||
|
|
fc8357a2db | ||
|
|
3e443ca502 | ||
|
|
2c10211d60 | ||
|
|
5fdda13f89 | ||
|
|
dbeaa044f8 | ||
|
|
7ad4d5e8cb | ||
|
|
ab4db10750 | ||
|
|
dddbbaaee1 | ||
|
|
134855c45e | ||
|
|
a4942e6566 | ||
|
|
4e43ef5ab0 | ||
|
|
4ae8d8232d | ||
|
|
0bdd8bf5bc | ||
|
|
5b1ef9589c | ||
|
|
7d54ed48e7 | ||
|
|
07730bb9cc | ||
|
|
7b38af5cd3 | ||
|
|
85ef5833cb | ||
|
|
a2a08f7602 | ||
|
|
282d4e3dda | ||
|
|
42d3250d17 | ||
|
|
5aed8de11d | ||
|
|
5f5fcff5f3 | ||
|
|
a884a95a7b | ||
|
|
a4aada0b5f | ||
|
|
732131d4d0 | ||
|
|
36b940d1fe | ||
|
|
e661277b48 | ||
|
|
6f539aa259 | ||
|
|
1c8c62667f | ||
|
|
e5a082d64a | ||
|
|
37c45e3998 | ||
|
|
f5e40b7011 | ||
|
|
02e21af657 | ||
|
|
bffc3f9012 | ||
|
|
7c4de0776b | ||
|
|
077b903e11 | ||
|
|
2d6a69e69a | ||
|
|
4f0343233b | ||
|
|
bcab7fb4af | ||
|
|
427699e6eb | ||
|
|
9c0f4f49e9 | ||
|
|
ac51c7e68e | ||
|
|
55d639f0fb | ||
|
|
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>
|
||||
|
||||
9
TODO-RELEASE
Normal file
9
TODO-RELEASE
Normal file
@@ -0,0 +1,9 @@
|
||||
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
||||
# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
||||
# In short:
|
||||
# LIBVERSION=c:r:a
|
||||
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
|
||||
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
|
||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||
#library what description / commit summary line
|
||||
257
configure.ac
Normal file
257
configure.ac
Normal file
@@ -0,0 +1,257 @@
|
||||
# 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])
|
||||
AC_CONFIG_HEADERS([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_TARGET
|
||||
|
||||
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. Some versions of linux/if.h fail without sys/socket.h included beforehand:
|
||||
# see https://algorithmicallyrandom.blogspot.com/2012/07/error-on-including-include.html
|
||||
AC_CHECK_HEADERS([linux/if.h net/if.h], [], [], [#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
# endif
|
||||
])
|
||||
|
||||
# Check for tun header
|
||||
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 >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.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
|
||||
64
contrib/jenkins.sh
Executable file
64
contrib/jenkins.sh
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/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
|
||||
|
||||
$MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
@@ -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
|
||||
@@ -1,10 +1,11 @@
|
||||
[Unit]
|
||||
Description=OpenGGSN
|
||||
Description=OsmoGGSN
|
||||
After=networking.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/ggsn -c /etc/ggsn.conf -f
|
||||
ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
286
debian/changelog
vendored
286
debian/changelog
vendored
@@ -1,4 +1,288 @@
|
||||
openggsn (0.91+git34) UNRELEASED; urgency=medium
|
||||
osmo-ggsn (1.4.0) unstable; urgency=medium
|
||||
|
||||
[ Max ]
|
||||
* Don't return error on normal shutdown
|
||||
|
||||
[ Harald Welte ]
|
||||
* process_pco() const-ify 'apn' argument
|
||||
* ggsn: Remove magic numbers from pco_contains_proto()
|
||||
* ggsn: const-ify input / read-only arguments of PCO related functions
|
||||
* ggsn: Remove magic numbers from ipcp_contains_option()
|
||||
* ggsn: Fix build_ipcp_pco() in presence of invalid IPCP content
|
||||
* ggsn.c: Refactor PCO processing during PDP activation
|
||||
* ggsn: Add minimalistic PAP support
|
||||
* ggsn: More logging from PCO handling (e.g. in case of malconfiguration)
|
||||
* sgsnemu: Fix format string argument count
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* osmo-ggsn: fix VTY command for getting PDP contexts by APN
|
||||
* osmo-ggsn: add VTY command to show PDP context by IPv4
|
||||
* osmo-ggsn: check result of osmo_apn_to_str()
|
||||
* osmo-ggsn: print requested / actual APN in PDP info
|
||||
* osmo-ggsn: properly show subscriber's MSISDN in the VTY
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* ggsn: Drop unused param force in apn_stop()
|
||||
* gtp: Document spec reasoning drop of Rx DeleteCtxReq
|
||||
* ggsn: Start gtp retrans timer during startup
|
||||
* gtp: Take queue_resp into account to schedule retrans timer
|
||||
* gtp: Fix typo dublicate->duplicate
|
||||
* pdp: Introduce new API pdp_count_secondary
|
||||
* gtp_create_pdp_ind: simplify code by reordering and compacting parsing
|
||||
* gtp: Refactor code to use gtp_freepdp(_teardown) APIs
|
||||
* cosmetic: gtp: Document free pdp ctx in non-teardown scenario
|
||||
* gtp: Re-arrange free pdp ctx code in non-teardown scenario
|
||||
* pdp: Drop unused code for haship
|
||||
* cosmetic: gtp.h: Remove trailing whitespaces
|
||||
* ggsn: Fix undefined behaviour shifting beyond sign bit
|
||||
* gtp: Introduce new pdp APIs (and deprecate old ones) to support multiple GSN
|
||||
* gtp: Make use of new libgtp APIs with multi-gsn support
|
||||
* ggsn_vty_reference.xml: Update from last code changes
|
||||
* ggsn: vty: Require ggsn param in <show pdp-context> cmd
|
||||
* sgsnemu: Replace use of deprecated libgtp API pdp_newpdp with new one
|
||||
* cosmetic: gtp: queue: remove trailing whitespace
|
||||
* gtp: Add missing headers
|
||||
* gtp: queue.c: Document queue APIs
|
||||
* gtp: queue: Add unit test queue_test
|
||||
* ggsn: Avoid unaligned mem access reading PCO proto id
|
||||
* ggsn: Use structures instead of raw arrays when parsing ipcp_hdr
|
||||
* configure.ac: Replace obosolete macro AC_CANONICAL_SYSTEM
|
||||
* configure.ac: Use brackets in AC_INIT params
|
||||
* configure.ac: Use prefered AC_CONFIG_HEADERS over AM_CONFIG_HEADER
|
||||
* configure.ac: some versions of linux/if.h require including sys/socket.h
|
||||
* sgsnemu: Fix unaligned pointer access during ip/icmp checksum
|
||||
* Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
|
||||
* Require libosmocore 1.1.0
|
||||
|
||||
[ Oliver Smith ]
|
||||
* debian: create -doc subpackage with pdf manuals
|
||||
* ggsn: Use gtp_delete_context_req2() everywhere
|
||||
* contrib/jenkins.sh: run "make maintainer-clean"
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* manuals: Add script to regenerate vty/counter documentation
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 21:28:30 +0200
|
||||
|
||||
osmo-ggsn (1.3.0) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* ggsn: ctrl iface: listen on IP configured by VTY
|
||||
* gtp: Log type name of unexpected signalling message
|
||||
* gtp: Allow recv DEL CTX REQ in sgsn and DEL CTX RSP in ggsn
|
||||
* gtp: Log ignore CTX DEL REQ due to no teardown and only 1 ctx active
|
||||
* gtp: Add new API to avoid freeing pdp contexts during DEL CTX REQ
|
||||
* gtp: Add new replacement cb_recovery2 for cb_recovery
|
||||
* Install systemd services with autotools
|
||||
* Install sample cfg file to /etc/osmocom
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* fix unaligned access in build_ipcp_pco()
|
||||
* fix support for multiple IPCP in PDP protocol configuration options
|
||||
* check ioctl() call return value in tun_new()
|
||||
* fix allocation of ippool's hash table
|
||||
* replace bogus memcpy() call in ippool_newip()
|
||||
* initialize local variable addr in ippool_new()
|
||||
* fix format string error in ippool_printaddr()
|
||||
* fix a format string directives in queue_seqset()
|
||||
* properly store IPv6 addresses in struct tun_t
|
||||
|
||||
[ Harald Welte ]
|
||||
* debian/rules: Don't overwrite .tarball-version
|
||||
* osmo-ggsn.cfg: Ensure well-formed config file example
|
||||
* sgsnemu: Fix printing of tun device name
|
||||
* ippool.c: Use "%td" format string for ptrdiff_t
|
||||
* initial version of OsmoGGSN user manual
|
||||
* OsmoGGSN: Add VTY reference manual
|
||||
* GGSN: Document how 'ip tuntap' is used for non-root; call netdev 'apn0'
|
||||
* vty-ref: Update URI of docbook 5.0 schema
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* libgtp: implement gtp_clear_queues to clear req/resp queue
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* Importing history from osmo-gsm-manuals.git
|
||||
* refactor Makefile build rules, don't use the FORCE
|
||||
* GGSN: don't say 'NITB'
|
||||
* OsmoGGSN: more info on non-root operation / tun creation
|
||||
* OsmoGGSN: multiple instances: mention GTP port
|
||||
* OsmoGGSN: add Routing section for IP forward and masquerading
|
||||
* OsmoGGSN: typo: priveleges
|
||||
* OsmoGGSN VTY ref: prep: convert newlines to unix
|
||||
* OsmoGGSN vty: update VTY reference
|
||||
* OsmoGGSN: fix VTY additions' node IDs
|
||||
* OsmoGGSN: update vty reference
|
||||
* ggsn: update vty reference
|
||||
|
||||
[ Max ]
|
||||
* Expand OsmoGGSN manual
|
||||
|
||||
[ Oliver Smith ]
|
||||
* build manuals moved here from osmo-gsm-manuals.git
|
||||
* Fix DISTCHECK_CONFIGURE_FLAGS override
|
||||
* contrib/jenkins.sh: build and publish manuals
|
||||
* contrib: fix makedistcheck with disabled systemd
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Sun, 20 Jan 2019 21:34:22 +0100
|
||||
|
||||
osmo-ggsn (1.2.2) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* ggsn_vty.c: fix: use CONFIG_NODE as parent by default
|
||||
|
||||
[ Philipp Maier ]
|
||||
* ggsn: fix misinterpreted length field in ipcp_contains_option()
|
||||
* ggsn: make sure ipcp_option_hdr and and ipcp_hdr are packed
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 31 May 2018 12:44:54 +0200
|
||||
|
||||
osmo-ggsn (1.2.1) unstable; urgency=medium
|
||||
|
||||
* debian/rules: Fix debian packaging after 1.2.0 release
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 04 May 2018 12:19:58 +0200
|
||||
|
||||
osmo-ggsn (1.2.0) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix compiler warnings: return 0 in main(), in 3 tests
|
||||
* add --enable-sanitize config option
|
||||
* sanitize build: ensure uint16/32 alignment in gtpie_test and in46a_test
|
||||
* configure: add --enable-werror
|
||||
* jenkins.sh: use --enable-werror configure flag, not CFLAGS
|
||||
|
||||
[ Harald Welte ]
|
||||
* sgsnemu: Don't leak FILE handle in proc_read()
|
||||
* sgsnemu: Fix format string in printing tun-device name
|
||||
* sgsnemu: Make sure buffer has space for terminating-NUL
|
||||
* sgsnemu: Free strings in error path
|
||||
* gtp: Fix buffer overflow in imsi_gtp2str()
|
||||
* gtp: Explicit OSMO_ASSERT to ensure pdp variable is set
|
||||
* tun: Don't copy 16byte IPv6 address to 'struct in_addr'
|
||||
* ippool: Correctly compute size of static pool
|
||||
* remove unused argument to alloc_ippool_blacklist()
|
||||
* factor out netdev_ip_local_get() from tun_ip_local_get()
|
||||
* Properly NULL-out blacklist in alloc_ippool_blacklist()
|
||||
* gtp_kernel: Change gtp_kernel_init() function signature
|
||||
* gtp-kernel: Re-add support for kernel GTP-U acceleration
|
||||
* gtp-kernel: Get rid of hard-coded kernel GTP device name
|
||||
* gtp-kernel: shut down kernel GTP device in apn_down()
|
||||
* gtp-kernel: Align logging for APN start in kernel-gtp case with that of TUN
|
||||
* gtp-kernel: Avoid global state variable
|
||||
* gtp-kernel: Make sure repeated calls to gtp_kernel_init() are safe
|
||||
* gtp-kernel: proper cleanup in error path
|
||||
* gtp-kernel: Get rid of SYS_ERR where not applicable
|
||||
* gtp-kernel: Add function name to pdp_debug() function calls
|
||||
* gtp-kernel: Add device nime in pdp_debug() log statements
|
||||
* contrib/jenkins.sh: Allow jenkins job to specify if kernel GTP is used
|
||||
* ggsn.c: Fix byte order of IPCP IPv4 DNS servers
|
||||
* ggsn: Ignore PCO with length 0, don't abort processing
|
||||
* README.md: Remove misleading sentence on sgsnemu
|
||||
* Add talloc context introspection via VTY
|
||||
* fix segfault in case of kernel gtp-u
|
||||
* lib/tun.c: Generalize tun_sifflags() to netdev_sifflags
|
||||
* lib/tun.c: generalize tun_*route() to netdev_*route()
|
||||
* lib/tun.c: Generalize tun_{set,add}addr*() functions
|
||||
* lib/tun: split generic network device related stuff to lib/netdev
|
||||
* lib/netdev.c: Cosmetic changes (coding style / cleanups)
|
||||
* ggsn: Don't explicitly use tun_setaddr() API anymore
|
||||
* sgsnemu: Convert from tun_setaddr() to tun_addaddr()
|
||||
* lib/tun: Remove tun_setaddr() API, as everyone is using tun_addaddr() now
|
||||
* Move kernel GTP support from ggsn/ to lib/
|
||||
* ggsn: don't use gtp_kernel_tunnel_{add,del}() for userspace tun
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* ggsn_vty: Stop using deprecated API vty_install_default
|
||||
* contrib/jenkins.sh: Enable Werror in C(PP)FLAGS
|
||||
* examples: Add secondary ipv6 google DNS to osmo-ggsn.cfg
|
||||
* tun_setaddr6: Fix log typo
|
||||
* cosmetic: Reorder tun_addaddr to get rid of decl of tun_setaddr4
|
||||
* ggsn.c: Print version of unhandled ip packet
|
||||
* Remove unused empty src/Makefile.in
|
||||
* tests: Split ipv6 specific tests into a new test group
|
||||
* Add support for IPv4v6 End User Addresses
|
||||
* contrib: jenkins.sh: Build libgtpnl as dep when building with gtp kernel support
|
||||
* cosmetic: sgsnemu.c: Fix trailing whitespace
|
||||
* ggsn.c: Improve logging info on link-local ipv6 addr not found
|
||||
* tun.c: tun_addaddr: Fix segfault and wrong usage of tun_nlattr
|
||||
* Set tun_addaddr ipv agnostic and add support for ipv6
|
||||
* ggsn: Add 'ipv6 link-local' vty cmd
|
||||
* ggsn_vty.c: Print ipv6 link-local cmd when writing config to file
|
||||
* gtp.c: Fix trailing whitespace
|
||||
* gtp.c: Determine GTP version from header
|
||||
* gtp.c: Log unsupported GTP version number
|
||||
* gtp/pdp: Fix trailing whitespace
|
||||
* gtp/pdp: Remove unused APIs pdp_ntoeua pdp_euaton
|
||||
* gtp.c: gtp_gpdu_ind: Convert ifelse to switch statement
|
||||
* gtp.c: gtp_gpdu_ind: Early return to avoid use of uninitialized var
|
||||
* gtp/gtp.c: Remove unused function char2ul_t
|
||||
* gtp/gtp.c: Mark non exported functions as static
|
||||
* gtp/gtp.c: Use uint8_t for version param in static functions
|
||||
* ggsn: encaps_tun: Avoid forwarding packet if EUA is unassigned, fix crash
|
||||
* ggsn: Validate packet src addr from MS
|
||||
* ggsn: Parse PCO_IPCP
|
||||
* ggsn: Parse PCO_IPCP for IPv4v6 pdp ctx
|
||||
* ggsn: Print all addresses on successful pdp ctx creation
|
||||
* ggsn.c: cb_tun_ind: Convert ifelse to switch statement
|
||||
* ggsn.c: cb_tun_ind: log dst addr of packet without pdp ctx
|
||||
* ggsn.c: cb_tun_ind: Don't drop packets targeting pdp ctx ll addr
|
||||
* sgsnemu: Fix bad ptr during context deallocation
|
||||
* sgsnemu: listen param is a host, not an interface
|
||||
* use osmo_init_logging2
|
||||
|
||||
[ Max ]
|
||||
* Log APN and tun names for packets
|
||||
* Enable sanitize for CI tests
|
||||
* Fix stow-enabled jenkins build failure
|
||||
* Add GTP message names
|
||||
|
||||
[ Viktor Tsymbalyuk ]
|
||||
* sgsnemu: sgsnemu stopped after recieving "Request accepted" from ggsn
|
||||
* sgsnemu: created "pinghost" and "createif" modes for mutual exclusion
|
||||
* sgsnemu: fix: no outgoing GTP-U in "createif" mode
|
||||
|
||||
[ Martin Hauke ]
|
||||
* build: Remove AC_PROG_CXX, C++ is never used
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* remove the -f option from osmo-ggsn.service
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 03 May 2018 16:05:27 +0200
|
||||
|
||||
osmo-ggsn (1.1.0) unstable; urgency=medium
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
86
debian/control
vendored
86
debian/control
vendored
@@ -1,36 +1,86 @@
|
||||
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 (>= 1.1.0),
|
||||
osmo-gsm-manuals-dev
|
||||
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: libgtp5
|
||||
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},
|
||||
libgtp5 (= ${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}, libgtp5 (= ${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}, libgtp5 (= ${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.
|
||||
|
||||
Package: osmo-ggsn-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
Priority: optional
|
||||
Depends: ${misc:Depends}
|
||||
Description: ${misc:Package} PDF documentation
|
||||
Various manuals: user manual, VTY reference manual and/or
|
||||
protocol/interface manuals.
|
||||
|
||||
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/*
|
||||
1
debian/osmo-ggsn-doc.install
vendored
Normal file
1
debian/osmo-ggsn-doc.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
usr/share/doc/osmo-ggsn-doc/*.pdf
|
||||
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/*
|
||||
26
debian/rules
vendored
26
debian/rules
vendored
@@ -1,24 +1,26 @@
|
||||
#!/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 -plibgtp5 --dbg-package=libgtp-dbg
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
|
||||
|
||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
|
||||
override_dh_compress:
|
||||
dh_compress -X.pdf
|
||||
|
||||
@@ -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
|
||||
18
doc/manuals/Makefile.am
Normal file
18
doc/manuals/Makefile.am
Normal file
@@ -0,0 +1,18 @@
|
||||
EXTRA_DIST = osmoggsn-usermanual.adoc \
|
||||
osmoggsn-usermanual-docinfo.xml \
|
||||
osmoggsn-vty-reference.xml \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
if BUILD_MANUALS
|
||||
ASCIIDOC = osmoggsn-usermanual.adoc
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||
|
||||
VTY_REFERENCE = osmoggsn-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
OSMO_REPOSITORY=osmo-ggsn
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
|
||||
endif
|
||||
335
doc/manuals/chapters/configuration.adoc
Normal file
335
doc/manuals/chapters/configuration.adoc
Normal file
@@ -0,0 +1,335 @@
|
||||
== Configuring OsmoGGSN
|
||||
|
||||
All configuration of OsmoGGSN is performed using the VTY. For more
|
||||
general information on the VTY interface, see <<vty>>.
|
||||
|
||||
=== Configuring a virtual GGSN instance
|
||||
|
||||
OsmoGGSN can run multiple GGSN instances inside one program/process.
|
||||
Each GGSN instance binds to its own transport-layer GTP IP address and
|
||||
has its own set of APNs and associated IP address pools + tun/gtp
|
||||
devices.
|
||||
|
||||
In most usage cases, yo will only have a single GGSN instance inside
|
||||
your configuration file, like in below example:
|
||||
|
||||
.Example: Single GGSN configuration section
|
||||
----
|
||||
ggsn ggsn0
|
||||
gtp state-dir /tmp
|
||||
gtp bind-ip 127.0.0.6
|
||||
apn internet
|
||||
gtpu-mode tun
|
||||
tun-device tun4
|
||||
type-support v4
|
||||
ip prefix dynamic 176.16.222.0/24
|
||||
ip dns 0 192.168.100.1
|
||||
ip dns 1 8.8.8.8
|
||||
ip ifconfig 176.16.222.0/24
|
||||
no shutdown
|
||||
----
|
||||
|
||||
|
||||
==== Creating/Editing a GGSN instance
|
||||
|
||||
Creating/Editing a GGSN instance can be done by the following sequence
|
||||
of VTY commands:
|
||||
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Create or edit the GGSN instance `ggsn0`. The name can be any ASCII
|
||||
string, its significance is only to the local user.
|
||||
<4> Your prompt is now in the `ggsn` config node, where you can
|
||||
configure the properties of this GGSN instance.
|
||||
|
||||
NOTE:: After creating a new GGSN instance, it is in `shutdown` mode. See
|
||||
<<unshutdown_apn>> to take it out of shutdown, but make sure to configure it fully
|
||||
before taking it out of shutdown.
|
||||
|
||||
==== Configuring a GGSN instance
|
||||
|
||||
The following two mandatory configuration statements have to be given
|
||||
for every GGSN instance:
|
||||
|
||||
----
|
||||
OsmoGGSN(config-ggsn)# gtp state-dir /var/lib/ggsn/ggsn0 <1>
|
||||
OsmoGGSN(config-ggsn)# gtp bind-ip 127.0.0.6 <2>
|
||||
----
|
||||
<1> Store the GSN restart state in the specified directory
|
||||
<2> Bind the GGSN instance to the specified local IPv4 address
|
||||
|
||||
There are some further configuration statements that can be used at the
|
||||
GGSN node, some examples are given below. For a full list, see the
|
||||
_OsmoGGSN VTY reference manual_ <<vty-ref-osmoggsn>>.
|
||||
|
||||
----
|
||||
OsmoGGSN(config-ggsn)# default-apn foobar <1>
|
||||
----
|
||||
<1> Configure a default APN to be used if the user-requested APN is not
|
||||
found. The named APN must previously be configured
|
||||
|
||||
|
||||
==== Deleting a GGSN instance
|
||||
|
||||
A GGSN instance can be removed like this
|
||||
|
||||
.Example: Deleting a GGSN instance
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# no ggsn ggsn0 <3>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Delete the GGSN instance
|
||||
|
||||
|
||||
==== Taking a GGSN instance out of shutdown
|
||||
|
||||
.Example: Taking a GGSN instance out of shutdown
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# no shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Take the GGSN instance out of shutdown
|
||||
|
||||
|
||||
==== Shutting a GGSN instance down
|
||||
|
||||
If you would like to take a GGSN instance out of service, you can
|
||||
put it into shutdown mode. This will make the entire GGSN unavailable
|
||||
to user traffic and permit you to e.g. reconfigure it before taking it
|
||||
out of shutdown again.
|
||||
|
||||
.Example: Shutting down a GGSN instance
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Shut down the GGSN instance
|
||||
|
||||
|
||||
=== Configuring an Access Point Name
|
||||
|
||||
An Access Point Name (APN) represents a connection to an external packet
|
||||
data network, such as the public Internet or private corporate networsk.
|
||||
|
||||
APNs are selected by terminals (MS/UE) when establishing PDP contexts.
|
||||
|
||||
Each OsmoGGSN GGSN instance can have any number of APNs configured.
|
||||
Each APN is identified by a string name.
|
||||
|
||||
==== Creating/Editing an APN
|
||||
|
||||
.Example: Creating a new APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Create or Edit an APN called `internet`
|
||||
<5> Your prompt is now in the `ggsn` config node, where you can
|
||||
configure the properties of this GGSN instance.
|
||||
|
||||
NOTE:: The newly-create APN is created in `shutdown` mode. See <<unshutdown_apn>> to take it
|
||||
out of shutdown.
|
||||
|
||||
|
||||
==== Configuring an APN
|
||||
|
||||
.Example: Configuring an APN
|
||||
----
|
||||
OsmoGGSN(config-ggsn-apn)# gtpu-mode tun <1>
|
||||
OsmoGGSN(config-ggsn-apn)# type-support v4 <2>
|
||||
OsmoGGSN(config-ggsn-apn)# ip prefix dynamic 176.16.222.0/24 <3>
|
||||
OsmoGGSN(config-ggsn-apn)# ip dns 0 192.168.100.1 <4>
|
||||
OsmoGGSN(config-ggsn-apn)# ip dns 1 8.8.8.8 <5>
|
||||
OsmoGGSN(config-ggsn-apn)# ip ifconfig 176.16.222.0/24 <6>
|
||||
----
|
||||
<1> Use the userspace GTP-U handling using a TUN device
|
||||
<2> Support (only) IPv4 Addresses
|
||||
<3> Specify the pool of dynamic IPv4 addresses to be allocated to PDP
|
||||
contexts
|
||||
<4> Specify the primary DNS server to be provided using IPCP/PCO
|
||||
<5> Specify the secondary DNS server to be provided using IPCP/PCO
|
||||
<6> Request OsmoGGSN to configure the `tun4` device network/netmask
|
||||
|
||||
NOTE:: If you use the optional `ip ifconfig` command to set the network
|
||||
device address/mask, OsmoGGSN must run with root or `CAP_NET_ADMIN`
|
||||
support. It might be better to configure related tun devices at system
|
||||
startup and run OsmoGGSN as non-privileged user. See <<ggsn_no_root>> for more
|
||||
details.
|
||||
|
||||
|
||||
==== Deleting an APN
|
||||
|
||||
An APN configuration can be removed like this
|
||||
|
||||
.Example: Deleting an APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# no apn internet <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Delete the APN `internet`
|
||||
|
||||
[[unshutdown_apn]]
|
||||
==== Taking an APN out of shutdown
|
||||
|
||||
In order to bring a deactived APN in `shutdown` state into active
|
||||
operation, use the `no shutdown` command at the APN node as explained in
|
||||
the following example:
|
||||
|
||||
.Example: Taking an APN out of shutdown
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# no shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<5> Take the APN out of shutdown
|
||||
|
||||
|
||||
==== Shutting an APN down
|
||||
|
||||
If you would like to take an APN instance out of service, you can
|
||||
put it into shutdown mode. This will make the APN unavailable
|
||||
to user traffic and permit you to e.g. reconfigure it before taking it
|
||||
out of shutdown again.
|
||||
|
||||
.Example: Shutting down an APN
|
||||
----
|
||||
OsmoGGSN> enable <1>
|
||||
OsmoGGSN# configure terminal <2>
|
||||
OsmoGGSN(config)# ggsn ggsn0 <3>
|
||||
OsmoGGSN(config-ggsn)# apn internet <4>
|
||||
OsmoGGSN(config-ggsn-apn)# shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<5> Shut down the APN
|
||||
|
||||
[[ggsn_no_root]]
|
||||
=== Configuring for running without root privileges
|
||||
|
||||
It's possible to run OsmoGGSN without root privileges if the tun devices are already configured.
|
||||
|
||||
The interface creation + configuration must then happen before osmo-ggsn starting up. This can be
|
||||
achieved by means such as
|
||||
|
||||
* a custom shell script run as root before starting osmo-ggsn (e.g. as init script)
|
||||
* systemd .netdev and .network files, if your system is using systemd-networkd (see `networkctl status`).
|
||||
|
||||
==== Manual TUN device creation / configuration
|
||||
|
||||
If you chose to go for custom shell/init scripts, you may use the `ip` program which is the standard
|
||||
tool for network interface configuration on Linux, part of the `iproute2` package. In order to
|
||||
create a tun device, you must call it like this:
|
||||
|
||||
.Example: iproute2 command to create a tun device
|
||||
----
|
||||
# ip tuntap add dev apn0 mode tun user username group groupname
|
||||
----
|
||||
|
||||
Where _username_ and _groupname_ correspond to the User and Group that will have ownership over the
|
||||
device, i.e. the privileges which you intend to run osmo-ggsn under, and _apn0_ will be the
|
||||
name of the network device created. After creating the interface, you can configure its addresses
|
||||
using standard means like `ip addr add` or your distribution-specific utilities/tools
|
||||
to match the `ip prefix dynamic` config item, and activate the link, for example:
|
||||
|
||||
----
|
||||
# ip addr add 192.168.7.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>
|
||||
|
||||
17
doc/manuals/regen_doc.sh
Executable file
17
doc/manuals/regen_doc.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
|
||||
OSMO_GGSN_BRANCH=$COMMIT ./regen_doc.sh osmo-ggsn 4260 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/ggsn_vty_reference.xml"
|
||||
30
doc/manuals/vty/ggsn_vty_additions.xml
Normal file
30
doc/manuals/vty/ggsn_vty_additions.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
||||
<node id='config-line'>
|
||||
<child_of nodeid='config' />
|
||||
<name>Telnet/VTY Configuration Node</name>
|
||||
<description>
|
||||
Configure parameters of the Telnet/VTY Interface, such as to which IP address it should bind/listen to.
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ctrl'>
|
||||
<child_of nodeid='config' />
|
||||
<name>CTRL Configuration Node</name>
|
||||
<description>
|
||||
Configure parameters of the CTRL Interface, such as to which IP address it should bind/listen to.
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ggsn'>
|
||||
<child_of nodeid='config' />
|
||||
<name>GGSN Instance Configuration Node</name>
|
||||
<description>
|
||||
Configure an Instance of a (virtual) GGSN
|
||||
</description>
|
||||
</node>
|
||||
<node id='config-ggsn-apn'>
|
||||
<child_of nodeid='config-ggsn' />
|
||||
<name>APN Configuration Node</name>
|
||||
<description>
|
||||
Configure an Access Point Name (APN) inside a GGSN Instance
|
||||
</description>
|
||||
</node>
|
||||
</vtydoc>
|
||||
1492
doc/manuals/vty/ggsn_vty_reference.xml
Normal file
1492
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 */
|
||||
1685
ggsn/ggsn.c
1685
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);
|
||||
1067
ggsn/ggsn_vty.c
Normal file
1067
ggsn/ggsn_vty.c
Normal file
File diff suppressed because it is too large
Load Diff
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=5: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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
55
gtp/gtp.h
55
gtp/gtp.h
@@ -1,17 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 _GTP_H
|
||||
#define _GTP_H
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/defs.h>
|
||||
|
||||
#include "pdp.h"
|
||||
|
||||
#define GTP_MODE_GGSN 1
|
||||
#define GTP_MODE_SGSN 2
|
||||
|
||||
@@ -85,6 +90,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,8 +142,9 @@
|
||||
|
||||
struct ul66_t;
|
||||
struct ul16_t;
|
||||
struct pdp_t;
|
||||
|
||||
/* GTP 0 header.
|
||||
/* GTP 0 header.
|
||||
* Explanation to some of the fields:
|
||||
* SNDCP NPDU Number flag = 0 except for inter SGSN handover situations
|
||||
* SNDCP N-PDU LCC Number 0 = 0xff except for inter SGSN handover situations
|
||||
@@ -161,6 +171,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 */
|
||||
@@ -216,13 +233,13 @@ union gtp_packet {
|
||||
* Information storage for each gsn instance
|
||||
*
|
||||
* Normally each instance of the application corresponds to
|
||||
* one instance of a gsn.
|
||||
*
|
||||
* one instance of a gsn.
|
||||
*
|
||||
* In order to avoid global variables in the application, and
|
||||
* also in order to allow several instances of a gsn in the same
|
||||
* application this struct is provided in order to store all
|
||||
* relevant information related to the gsn.
|
||||
*
|
||||
*
|
||||
* Note that this does not include information storage for '
|
||||
* each pdp context. This is stored in another struct.
|
||||
*************************************************************/
|
||||
@@ -244,10 +261,13 @@ 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 */
|
||||
|
||||
struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
|
||||
struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
|
||||
/* Call back functions */
|
||||
int (*cb_delete_context) (struct pdp_t *);
|
||||
int (*cb_create_context_ind) (struct pdp_t *);
|
||||
@@ -256,6 +276,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 */
|
||||
|
||||
@@ -291,8 +312,9 @@ extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
|
||||
extern int gtp_free(struct gsn_t *gsn);
|
||||
|
||||
extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
|
||||
uint64_t imsi, uint8_t nsapi);
|
||||
uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
|
||||
extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
|
||||
extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp);
|
||||
|
||||
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
void *cbp);
|
||||
@@ -309,7 +331,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 +368,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 +431,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);
|
||||
|
||||
233
gtp/pdp.c
233
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,32 +27,26 @@
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "pdp.h"
|
||||
#include "gtp.h"
|
||||
#include "lookupa.h"
|
||||
|
||||
/* ***********************************************************
|
||||
* Global variables TODO: most should be moved to gsn_t
|
||||
*************************************************************/
|
||||
|
||||
static struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
|
||||
static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
/* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */
|
||||
|
||||
/* ***********************************************************
|
||||
* Functions related to PDP storage
|
||||
*
|
||||
* 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 +56,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 +77,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.
|
||||
*
|
||||
@@ -109,11 +104,16 @@ static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
int pdp_init()
|
||||
static struct gsn_t *g_gsn;
|
||||
|
||||
int pdp_init(struct gsn_t *gsn)
|
||||
{
|
||||
memset(&pdpa, 0, sizeof(pdpa));
|
||||
memset(&hashtid, 0, sizeof(hashtid));
|
||||
/* memset(&haship, 0, sizeof(haship)); */
|
||||
if(!g_gsn) {
|
||||
g_gsn = gsn;
|
||||
} else {
|
||||
LOGP(DLGTP, LOGL_FATAL, "This interface is depreacted and doesn't support multiple GGSN!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -121,6 +121,13 @@ int pdp_init()
|
||||
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
struct pdp_t *pdp_old)
|
||||
{
|
||||
return gtp_pdp_newpdp(g_gsn, pdp, imsi, nsapi, pdp_old);
|
||||
}
|
||||
|
||||
int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
struct pdp_t *pdp_old)
|
||||
{
|
||||
struct pdp_t *pdpa = gsn->pdpa;
|
||||
int n;
|
||||
for (n = 0; n < PDP_MAX; n++) { /* TODO: Need to do better than linear search */
|
||||
if (pdpa[n].inuse == 0) {
|
||||
@@ -130,6 +137,7 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
else
|
||||
memset(*pdp, 0, sizeof(struct pdp_t));
|
||||
(*pdp)->inuse = 1;
|
||||
(*pdp)->gsn = gsn;
|
||||
(*pdp)->imsi = imsi;
|
||||
(*pdp)->nsapi = nsapi;
|
||||
(*pdp)->fllc = (uint16_t) n + 1;
|
||||
@@ -146,6 +154,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;
|
||||
}
|
||||
@@ -155,6 +165,8 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
|
||||
int pdp_freepdp(struct pdp_t *pdp)
|
||||
{
|
||||
struct pdp_t *pdpa = pdp->gsn->pdpa;
|
||||
|
||||
pdp_tiddel(pdp);
|
||||
|
||||
/* Remove any references in primary context */
|
||||
@@ -169,12 +181,20 @@ int pdp_freepdp(struct pdp_t *pdp)
|
||||
|
||||
int pdp_getpdp(struct pdp_t **pdp)
|
||||
{
|
||||
*pdp = &pdpa[0];
|
||||
*pdp = &g_gsn->pdpa[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
|
||||
{
|
||||
return gtp_pdp_getgtp0(g_gsn, pdp, fl);
|
||||
}
|
||||
|
||||
|
||||
int gtp_pdp_getgtp0(struct gsn_t *gsn, struct pdp_t **pdp, uint16_t fl)
|
||||
{
|
||||
struct pdp_t *pdpa = gsn->pdpa;
|
||||
|
||||
if ((fl > PDP_MAX) || (fl < 1)) {
|
||||
return EOF; /* Not found */
|
||||
} else {
|
||||
@@ -189,6 +209,13 @@ int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
|
||||
|
||||
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
|
||||
{
|
||||
return gtp_pdp_getgtp1(g_gsn, pdp, tei);
|
||||
}
|
||||
|
||||
int gtp_pdp_getgtp1(struct gsn_t *gsn, struct pdp_t **pdp, uint32_t tei)
|
||||
{
|
||||
struct pdp_t *pdpa = gsn->pdpa;
|
||||
|
||||
if ((tei > PDP_MAX) || (tei < 1)) {
|
||||
return EOF; /* Not found */
|
||||
} else {
|
||||
@@ -201,6 +228,30 @@ 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)
|
||||
{
|
||||
return gtp_pdp_getgtp1_peer_d(g_gsn, pdp, peer, teid_gn);
|
||||
}
|
||||
|
||||
int gtp_pdp_getgtp1_peer_d(struct gsn_t *gsn, struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn)
|
||||
{
|
||||
struct pdp_t *pdpa = gsn->pdpa;
|
||||
unsigned int i;
|
||||
|
||||
/* 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);
|
||||
@@ -208,10 +259,11 @@ int pdp_tidhash(uint64_t tid)
|
||||
|
||||
int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
|
||||
{
|
||||
struct pdp_t **hashtid = pdp->gsn->hashtid;
|
||||
int hash = pdp_tidhash(tid);
|
||||
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)
|
||||
@@ -226,10 +278,11 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
|
||||
|
||||
int pdp_tiddel(struct pdp_t *pdp)
|
||||
{
|
||||
struct pdp_t **hashtid = pdp->gsn->hashtid;
|
||||
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)
|
||||
@@ -247,9 +300,15 @@ int pdp_tiddel(struct pdp_t *pdp)
|
||||
|
||||
int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
|
||||
{
|
||||
return gtp_pdp_tidget(g_gsn, pdp, tid);
|
||||
}
|
||||
|
||||
int gtp_pdp_tidget(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t tid)
|
||||
{
|
||||
struct pdp_t **hashtid = gsn->hashtid;
|
||||
int hash = pdp_tidhash(tid);
|
||||
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;
|
||||
@@ -263,102 +322,19 @@ int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
|
||||
|
||||
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
|
||||
{
|
||||
return pdp_tidget(pdp,
|
||||
return gtp_pdp_getimsi(g_gsn, pdp, imsi, nsapi);
|
||||
}
|
||||
|
||||
int gtp_pdp_getimsi(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
|
||||
{
|
||||
return gtp_pdp_tidget(gsn, pdp,
|
||||
(imsi & 0x0fffffffffffffffull) +
|
||||
((uint64_t) nsapi << 60));
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
struct pdp_t *pdp_prev = NULL;
|
||||
|
||||
if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
|
||||
(unsigned) ipif, eua->l,
|
||||
eua->v[2], eua->v[3],
|
||||
eua->v[4], eua->v[5]);
|
||||
|
||||
pdp->ipnext = NULL;
|
||||
pdp->ipif = ipif;
|
||||
pdp->eua.l = eua->l;
|
||||
memcpy(pdp->eua.v, eua->v, eua->l);
|
||||
|
||||
hash = pdp_iphash(pdp->ipif, &pdp->eua);
|
||||
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
|
||||
pdp_prev = pdp2;
|
||||
if (!pdp_prev)
|
||||
haship[hash] = pdp;
|
||||
else
|
||||
pdp_prev->ipnext = pdp;
|
||||
if (PDP_DEBUG) printf("End pdp_ipset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pdp_ipdel(struct pdp_t *pdp) {
|
||||
int hash = pdp_iphash(pdp->ipif, &pdp->eua);
|
||||
struct pdp_t *pdp2;
|
||||
struct pdp_t *pdp_prev = NULL;
|
||||
if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
|
||||
if (pdp2 == pdp) {
|
||||
if (!pdp_prev)
|
||||
haship[hash] = pdp2->ipnext;
|
||||
else
|
||||
pdp_prev->ipnext = pdp2->ipnext;
|
||||
if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
|
||||
return 0;
|
||||
}
|
||||
pdp_prev = pdp2;
|
||||
}
|
||||
if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
|
||||
return EOF; /# End of linked list and not found #/
|
||||
}
|
||||
|
||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
|
||||
int hash = pdp_iphash(ipif, eua);
|
||||
struct pdp_t *pdp2;
|
||||
/#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
|
||||
eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
|
||||
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
|
||||
if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
|
||||
(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
|
||||
*pdp = pdp2;
|
||||
/#printf("End pdp_ipget. Found\n");#/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
|
||||
(unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
|
||||
return EOF; /# End of linked list and not found #/
|
||||
}
|
||||
*/
|
||||
/* Various conversion functions */
|
||||
|
||||
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);
|
||||
@@ -370,13 +346,16 @@ void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid)
|
||||
pdp->nsapi = (teid & 0xf000000000000000ull) >> 60;
|
||||
}
|
||||
|
||||
int ulcpy(void *dst, void *src, size_t size)
|
||||
/* Count amount of secondary PDP contexts linked to this primary PDP context
|
||||
* (itself included). Must be called on a primary PDP context. */
|
||||
unsigned int pdp_count_secondary(struct pdp_t *pdp)
|
||||
{
|
||||
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;
|
||||
unsigned int n;
|
||||
unsigned int count = 0;
|
||||
OSMO_ASSERT(!pdp->secondary);
|
||||
|
||||
for (n = 0; n < PDP_MAXNSAPI; n++)
|
||||
if (pdp->secondary_tei[n])
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
80
gtp/pdp.h
80
gtp/pdp.h
@@ -1,20 +1,36 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osmocom/core/defs.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 +75,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 +92,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 +125,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,37 +237,41 @@ struct pdp_t {
|
||||
|
||||
/* to be used by libgtp callers/users (to attach their own private state) */
|
||||
void *priv;
|
||||
|
||||
struct gsn_t *gsn; /* Back pointer to GSN where this pdp ctx belongs to */
|
||||
|
||||
bool tx_gpdu_seq; /* Transmit (true) or suppress G-PDU sequence numbers */
|
||||
};
|
||||
|
||||
/* functions related to pdp_t management */
|
||||
int pdp_init();
|
||||
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
struct pdp_t *pdp_old);
|
||||
int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi,
|
||||
uint8_t nsapi, struct pdp_t *pdp_old);
|
||||
int pdp_freepdp(struct pdp_t *pdp);
|
||||
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_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi);
|
||||
int gtp_pdp_getgtp0(struct gsn_t *gsn, struct pdp_t **pdp, uint16_t fl);
|
||||
int gtp_pdp_getgtp1(struct gsn_t *gsn, struct pdp_t **pdp, uint32_t tei);
|
||||
int gtp_pdp_getgtp1_peer_d(struct gsn_t *gsn, struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn);
|
||||
int gtp_pdp_getimsi(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi);
|
||||
int gtp_pdp_tidget(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t tid);
|
||||
|
||||
int pdp_tidhash(uint64_t tid);
|
||||
int pdp_tidset(struct pdp_t *pdp, uint64_t tid);
|
||||
int pdp_tiddel(struct pdp_t *pdp);
|
||||
int pdp_tidget(struct pdp_t **pdp, uint64_t tid);
|
||||
|
||||
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
|
||||
void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid);
|
||||
|
||||
/*
|
||||
int pdp_iphash(void* ipif, struct ul66_t *eua);
|
||||
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua);
|
||||
int pdp_ipdel(struct pdp_t *pdp);
|
||||
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua);
|
||||
*/
|
||||
unsigned int pdp_count_secondary(struct pdp_t *pdp);
|
||||
|
||||
/* Deprecated APIs (support for only 1 GSN per process). Must be used only after first call to gtp_new() and until it is freed. */
|
||||
int pdp_init(struct gsn_t *gsn); /* Use only allowed inside libgtp to keep compatiblity with deprecated APIs defined here. */
|
||||
int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
|
||||
struct pdp_t *pdp_old) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
|
||||
int pdp_getpdp(struct pdp_t **pdp) OSMO_DEPRECATED("Use gsn_t->pdpa field instead");
|
||||
int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl) OSMO_DEPRECATED("Use gtp_pdp_getgtp0() instead");
|
||||
int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei) OSMO_DEPRECATED("Use gtp_pdp_getgtp1() instead");
|
||||
int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn) OSMO_DEPRECATED("Use gtp_pdp_getgtp1_peer_d() instead");
|
||||
int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_getimsi() instead");
|
||||
int pdp_tidget(struct pdp_t **pdp, uint64_t tid) OSMO_DEPRECATED("Use gtp_pdp_tidget() instead");
|
||||
|
||||
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua);
|
||||
int pdp_euaton(struct ul66_t *eua, struct in_addr *dst);
|
||||
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
|
||||
int ulcpy(void *dst, void *src, size_t size);
|
||||
|
||||
#endif /* !_PDP_H */
|
||||
|
||||
96
gtp/queue.c
96
gtp/queue.c
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
* 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
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -61,7 +62,7 @@ static int queue_seqhash(struct sockaddr_in *peer, uint16_t seq)
|
||||
return seq % QUEUE_HASH_SIZE;
|
||||
}
|
||||
|
||||
/*! \brief Insert a message with given sequence number into the hash
|
||||
/*! \brief Insert a message with given sequence number into the hash.
|
||||
*
|
||||
* This function sets the peer and the seq of the qmsg and then inserts
|
||||
* the qmsg into the queue hash. To do so, it does a hashtable lookup
|
||||
@@ -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
|
||||
@@ -121,25 +121,30 @@ static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
|
||||
return EOF; /* End of linked list and not found */
|
||||
}
|
||||
|
||||
/*! \brief Allocates and initialises new queue structure */
|
||||
/*! Allocates and initialises new queue structure.
|
||||
* \param[out] queue pointer where to store the allocated object. Must be freed with queue_free
|
||||
* \returns zero on success, non-zero on error
|
||||
*/
|
||||
int queue_new(struct queue_t **queue)
|
||||
{
|
||||
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 */
|
||||
/*! Deallocates queue structure.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_free(struct queue_t *queue)
|
||||
{
|
||||
if (QUEUE_DEBUG)
|
||||
@@ -150,7 +155,13 @@ int queue_free(struct queue_t *queue)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Add a new message to the queue */
|
||||
/*! Add a new message to the queue.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[out] qmsg first message from the queue (if succeeds)
|
||||
* \param[in] peer who sent the message to add
|
||||
* \param[in] seq sequence number of the message to add
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
|
||||
struct sockaddr_in *peer, uint16_t seq)
|
||||
{
|
||||
@@ -177,7 +188,11 @@ int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Simply remoev a given qmsg_t from the queue
|
||||
|
||||
/*! Remove an element from the queue.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[in] qmsg message to free
|
||||
* \returns zero on success, non-zero on error.
|
||||
*
|
||||
* Internally, we first delete the entry from the queue, and then update
|
||||
* up our global queue->first / queue->last pointers. Finally,
|
||||
@@ -211,7 +226,11 @@ int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Move a given qmsg_t to the end of the queue ?!? */
|
||||
/*! Move a given qmsg_t to the end of the queue.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[in] qmsg message to move to the end of the queue
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
|
||||
{
|
||||
if (QUEUE_DEBUG)
|
||||
@@ -237,7 +256,11 @@ int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Get the first element in the entire queue */
|
||||
/*! Get the first element in the entire queue.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[out] qmsg first message from the queue (if succeeds)
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
|
||||
{
|
||||
/*printf("queue_getfirst\n"); */
|
||||
@@ -251,27 +274,13 @@ 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 */
|
||||
/*! Get a queue entry for a given peer + seq.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[out] qmsg first message from the queue (if succeeds)
|
||||
* \param[in] peer who sent the message to retrieve
|
||||
* \param[in] seq sequence number of the message to retrive
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
|
||||
struct sockaddr_in *peer, uint16_t seq)
|
||||
{
|
||||
@@ -293,7 +302,14 @@ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
|
||||
return EOF; /* End of linked list and not found */
|
||||
}
|
||||
|
||||
/*! \brief look-up a given seq/peer, return cbp + type and free entry */
|
||||
/*! look-up a given seq/peer, return cbp + type and free entry.
|
||||
* \param[in] queue pointer previously allocated by queue_new
|
||||
* \param[in] peer who sent the message to retrieve
|
||||
* \param[in] seq sequence number of the message to retrive
|
||||
* \param[out] type GTP message type
|
||||
* \param[out] type callback pointer of the message
|
||||
* \returns zero on success, non-zero on error.
|
||||
*/
|
||||
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
|
||||
uint16_t seq, uint8_t * type, void **cbp)
|
||||
{
|
||||
|
||||
10
gtp/queue.h
10
gtp/queue.h
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef _QUEUE_H
|
||||
#define _QUEUE_H
|
||||
|
||||
#include "gtp.h"
|
||||
|
||||
#define QUEUE_DEBUG 0 /* Print debug information */
|
||||
|
||||
#define QUEUE_SIZE 1024 /* Size of retransmission queue */
|
||||
|
||||
@@ -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,12 +1229,12 @@ 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;
|
||||
uint16_t *p = (uint16_t *) & pack;
|
||||
uint16_t v16;
|
||||
uint8_t *p8 = (uint8_t *) & pack;
|
||||
struct in_addr src;
|
||||
unsigned int n;
|
||||
@@ -1204,7 +1270,7 @@ int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
pack.seq = htons(seq);
|
||||
|
||||
/* Generate ICMP payload */
|
||||
p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
|
||||
p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
|
||||
for (n = 0; n < (datasize); n++)
|
||||
p8[n] = n;
|
||||
|
||||
@@ -1212,11 +1278,13 @@ int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
gettimeofday(tp, &tz);
|
||||
|
||||
/* Calculate IP header checksum */
|
||||
p = (uint16_t *) & pack;
|
||||
p8 = (uint8_t *) &pack;
|
||||
count = CREATEPING_IP;
|
||||
sum = 0;
|
||||
while (count > 1) {
|
||||
sum += *p++;
|
||||
memcpy(&v16, p8, 2);
|
||||
sum += v16;
|
||||
p8 += 2;
|
||||
count -= 2;
|
||||
}
|
||||
while (sum >> 16)
|
||||
@@ -1226,14 +1294,16 @@ int create_ping(void *gsn, struct pdp_t *pdp,
|
||||
/* Calculate ICMP checksum */
|
||||
count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
|
||||
sum = 0;
|
||||
p = (uint16_t *) & pack;
|
||||
p += CREATEPING_IP / 2;
|
||||
p8 = (uint8_t *) &pack;
|
||||
p8 += CREATEPING_IP;
|
||||
while (count > 1) {
|
||||
sum += *p++;
|
||||
memcpy(&v16, p8, 2);
|
||||
sum += v16;
|
||||
p8 += 2;
|
||||
count -= 2;
|
||||
}
|
||||
if (count > 0)
|
||||
sum += *(unsigned char *)p;
|
||||
sum += *(unsigned char *)p8;
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
pack.checksum = ~sum;
|
||||
@@ -1242,14 +1312,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 +1327,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 +1375,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 +1406,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 +1417,77 @@ 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")) {
|
||||
printf("accept_ra=0, i.e. your tun device is not configured to accept "
|
||||
"router advertisements; SLAAC will not succeed, please "
|
||||
"fix your setup!\n");
|
||||
}
|
||||
if (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1")) {
|
||||
printf("forwarding=1 and accept_ra=1, i.e. your tun device is not "
|
||||
"configured to accept router advertisements; SLAAC will not "
|
||||
"succeed, 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);
|
||||
if (pdp)
|
||||
pdp_freepdp(pdp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int echo_conf(int recovery)
|
||||
static int echo_conf(int recovery)
|
||||
{
|
||||
|
||||
if (recovery < 0) {
|
||||
@@ -1374,7 +1509,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) {
|
||||
@@ -1383,15 +1518,13 @@ int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
||||
case GTP_CREATE_PDP_REQ:
|
||||
return create_pdp_conf(pdp, cbp, cause);
|
||||
case GTP_DELETE_PDP_REQ:
|
||||
if (cause != 128)
|
||||
return 0; /* Request not accepted. We don't care */
|
||||
return delete_pdp_conf(pdp, cause);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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 +1539,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 +1579,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 +1589,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);
|
||||
@@ -1483,9 +1622,9 @@ int main(int argc, char **argv)
|
||||
/* Allocated here. */
|
||||
/* If create context failes we have to deallocate ourselves. */
|
||||
/* Otherwise it is deallocated by gtplib */
|
||||
pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
|
||||
gtp_pdp_newpdp(gsn, &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 +1688,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 +1707,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]);
|
||||
@@ -1620,8 +1764,7 @@ int main(int argc, char **argv)
|
||||
for (n = 0; n < options.contexts; n++) {
|
||||
/* Delete context */
|
||||
printf("Disconnecting PDP context #%d\n", n);
|
||||
gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
|
||||
1);
|
||||
gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
|
||||
if ((options.pinghost.s_addr != 0)
|
||||
&& ntransmitted)
|
||||
ping_finish();
|
||||
@@ -1665,10 +1808,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 +1824,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 $@
|
||||
31
tests/gtp/Makefile.am
Normal file
31
tests/gtp/Makefile.am
Normal file
@@ -0,0 +1,31 @@
|
||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
|
||||
|
||||
EXTRA_DIST = \
|
||||
gtpie_test.ok \
|
||||
queue_test.ok \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
gtpie_test \
|
||||
queue_test \
|
||||
$(NULL)
|
||||
|
||||
gtpie_test_SOURCES = \
|
||||
gtpie_test.c \
|
||||
$(NULL)
|
||||
|
||||
queue_test_SOURCES = \
|
||||
queue_test.c \
|
||||
$(NULL)
|
||||
|
||||
gtpie_test_LDADD = \
|
||||
$(top_builddir)/lib/debug.o \
|
||||
$(top_builddir)/gtp/libgtp.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
queue_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()
|
||||
232
tests/gtp/queue_test.c
Normal file
232
tests/gtp/queue_test.c
Normal file
@@ -0,0 +1,232 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
#include "../../lib/syserr.h"
|
||||
#include "../../gtp/queue.h"
|
||||
|
||||
static const struct qmsg_t qmsg_zero;
|
||||
|
||||
static void queue_print(struct queue_t *queue, char* str)
|
||||
{
|
||||
int n;
|
||||
printf("=== [Queue %s] Next: %d First: %d Last: %d\n", str,
|
||||
queue->next, queue->first, queue->last);
|
||||
printf("#\tseq\tnext\tprev\ttimeout\tretrans\ttype\tcbp\n");
|
||||
for (n = 0; n < QUEUE_SIZE; n++) {
|
||||
if (queue->qmsga[n].state == 0) {
|
||||
/* Nothing there, validate everything is zeroed */
|
||||
OSMO_ASSERT(memcmp(&qmsg_zero, &queue->qmsga[n], sizeof(qmsg_zero)) == 0);
|
||||
continue;
|
||||
}
|
||||
printf("%d\t%d\t%d\t%d\t%d\t%d\t%u\t%ld\n",
|
||||
n,
|
||||
queue->qmsga[n].seq,
|
||||
queue->qmsga[n].next,
|
||||
queue->qmsga[n].prev,
|
||||
(int)queue->qmsga[n].timeout,
|
||||
queue->qmsga[n].retrans,
|
||||
queue->qmsga[n].type,
|
||||
((uintptr_t)queue->qmsga[n].cbp & 0xFFFFFFFF)
|
||||
);
|
||||
}
|
||||
printf("======================================================\n");
|
||||
}
|
||||
|
||||
static void test_queue_empty()
|
||||
{
|
||||
printf("***** Testing %s()\n", __func__);
|
||||
struct queue_t *queue = NULL;
|
||||
struct qmsg_t *qmsg = NULL;
|
||||
uint16_t seq = 23;
|
||||
uint8_t type = 0;
|
||||
void *cbp = NULL;
|
||||
struct sockaddr_in peer;
|
||||
int rc;
|
||||
|
||||
rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
|
||||
OSMO_ASSERT(rc == 1);
|
||||
|
||||
rc = queue_new(&queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "created");
|
||||
|
||||
rc = queue_getfirst(queue, &qmsg);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
rc = queue_seqget(queue, &qmsg, &peer, seq);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
rc = queue_freemsg_seq(queue, &peer, seq, &type, &cbp);
|
||||
OSMO_ASSERT(rc==EOF);
|
||||
|
||||
queue_print(queue, "pre-delete");
|
||||
rc = queue_free(queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
static void test_queue_one()
|
||||
{
|
||||
printf("***** Testing %s()\n", __func__);
|
||||
struct queue_t *queue = NULL;
|
||||
struct qmsg_t *qmsg = NULL, *qmsg2 = NULL;;
|
||||
uint16_t seq = 23;
|
||||
uint8_t type = 0;
|
||||
void *cbp = NULL;
|
||||
struct sockaddr_in peer, peer2;
|
||||
int rc;
|
||||
|
||||
rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
|
||||
OSMO_ASSERT(rc == 1);
|
||||
rc = inet_pton(AF_INET, "127.0.0.2", &(peer2.sin_addr));
|
||||
OSMO_ASSERT(rc == 1);
|
||||
|
||||
rc = queue_new(&queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "created");
|
||||
|
||||
rc = queue_newmsg(queue, &qmsg, &peer, seq);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "first added");
|
||||
qmsg->type = GTP_ECHO_REQ;
|
||||
qmsg->cbp = (void*) 0x13243546;
|
||||
qmsg->seq = seq;
|
||||
|
||||
rc = queue_getfirst(queue, &qmsg2);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(qmsg == qmsg2);
|
||||
|
||||
rc = queue_seqget(queue, &qmsg2, &peer, seq);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(qmsg == qmsg2);
|
||||
rc = queue_seqget(queue, &qmsg, &peer2, seq);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
rc = queue_seqget(queue, &qmsg, &peer, seq + 1);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
queue_print(queue, "after-get");
|
||||
|
||||
rc = queue_back(queue, qmsg);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "after-back");
|
||||
|
||||
rc = queue_freemsg_seq(queue, &peer2, seq, &type, &cbp);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
rc = queue_freemsg_seq(queue, &peer, seq + 1, &type, &cbp);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
queue_print(queue, "pree-freemsg");
|
||||
rc = queue_freemsg_seq(queue, &peer, seq, &type, &cbp);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(type == GTP_ECHO_REQ);
|
||||
OSMO_ASSERT(cbp == (void*)0x13243546);
|
||||
|
||||
queue_print(queue, "pre-delete");
|
||||
rc = queue_free(queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
#define newmsg_fill(queue, qmsg_ptr, peer_ptr, seq) \
|
||||
do { \
|
||||
int rc = queue_newmsg(queue, &(qmsg_ptr), peer_ptr, seq); \
|
||||
OSMO_ASSERT(rc == 0); \
|
||||
OSMO_ASSERT(qmsg_ptr); \
|
||||
qmsg_ptr->type = GTP_CREATE_PDP_REQ; \
|
||||
qmsg_ptr->cbp = (void*)(uintptr_t)seq; \
|
||||
} while (0);
|
||||
|
||||
#define freemsg_verify(seq, type, cbp) \
|
||||
do { \
|
||||
OSMO_ASSERT(type == GTP_CREATE_PDP_REQ); \
|
||||
OSMO_ASSERT(cbp == (void*)(uintptr_t)seq); \
|
||||
} while (0);
|
||||
|
||||
static void test_queue_full()
|
||||
{
|
||||
/* queue_newmsg until we receive EOF. Try moving back then. */
|
||||
printf("***** Testing %s()\n", __func__);
|
||||
struct queue_t *queue = NULL;
|
||||
struct qmsg_t *qmsg = NULL;
|
||||
uint8_t type = 0;
|
||||
void *cbp = NULL;
|
||||
struct sockaddr_in peer;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = inet_pton(AF_INET, "127.0.0.1", &(peer.sin_addr));
|
||||
OSMO_ASSERT(rc == 1);
|
||||
|
||||
rc = queue_new(&queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "created");
|
||||
|
||||
for (i = 0; i < QUEUE_SIZE - 1; i++) {
|
||||
newmsg_fill(queue, qmsg, &peer, i);
|
||||
}
|
||||
queue_print(queue, "after-fill");
|
||||
|
||||
/* There's one slot left at the end, let's use first()->back() */
|
||||
rc = queue_getfirst(queue, &qmsg);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
rc = queue_back(queue, qmsg);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
queue_print(queue, "after-back");
|
||||
|
||||
/* Now let's fill last empty slot */
|
||||
newmsg_fill(queue, qmsg, &peer, QUEUE_SIZE - 1);
|
||||
queue_print(queue, "after-full");
|
||||
|
||||
/* queue is now full, it should fail */
|
||||
rc = queue_newmsg(queue, &qmsg, &peer, QUEUE_SIZE);
|
||||
OSMO_ASSERT(rc == EOF);
|
||||
queue_print(queue, "after-failing-full");
|
||||
|
||||
/* Remove 1before-last msg (the one moved back) and make sure we can
|
||||
re-add it at the end of the list */
|
||||
rc = queue_seqget(queue, &qmsg, &peer, 0);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
rc = queue_freemsg(queue, qmsg);
|
||||
queue_print(queue, "after-freeing-0");
|
||||
OSMO_ASSERT(rc == 0);
|
||||
/* Now let's fill last empty slot which should be at the end */
|
||||
newmsg_fill(queue, qmsg, &peer, 0);
|
||||
queue_print(queue, "after-refilling-0");
|
||||
|
||||
/* Now free first half seq set in increasing order */
|
||||
for (i = 0; i < QUEUE_SIZE / 2; i++) {
|
||||
rc = queue_freemsg_seq(queue, &peer, i, &type, &cbp);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
freemsg_verify(i, type, cbp);
|
||||
}
|
||||
queue_print(queue, "after-first-half-free");
|
||||
|
||||
/* Now free second half seq set in decreasing order */
|
||||
for (i = QUEUE_SIZE - 1; i >= QUEUE_SIZE / 2; i--) {
|
||||
rc = queue_freemsg_seq(queue, &peer, i, &type, &cbp);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
freemsg_verify(i, type, cbp);
|
||||
}
|
||||
queue_print(queue, "after-second-half-free");
|
||||
|
||||
rc = queue_free(queue);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "Root context");
|
||||
msgb_talloc_ctx_init(tall_ctx, 0);
|
||||
osmo_init_logging2(tall_ctx, &log_info);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
|
||||
test_queue_empty();
|
||||
test_queue_one();
|
||||
test_queue_full();
|
||||
|
||||
return 0;
|
||||
}
|
||||
6711
tests/gtp/queue_test.ok
Normal file
6711
tests/gtp/queue_test.ok
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user