Compare commits

...

35 Commits

Author SHA1 Message Date
Daniel Willmann
54fcd64fc7 WIP
Change-Id: Ia8d595095462c30a56b8a0b30c8d24632776e4cc
2024-03-06 11:53:37 +01:00
Daniel Willmann
6536376527 gtp: WIP SGSN Context Request/Response/Ack support
* SGSN Context Request parsing
* SGSN Context Response generation
* Link to libosmo-gsm

Change-Id: I3a5046b67f73a81eeb6b509777132857a9abcf0c
2024-03-06 11:26:19 +01:00
Daniel Willmann
6d85d2a3dd gtp: Add function gtp_resp2() which takes flow label and tei
Change-Id: Id9ff95e0e2a10a22e65ecf42b2a2b06a0f2d1a45
2024-03-06 11:24:49 +01:00
Daniel Willmann
cd970edee4 gtp: Make peer addr const in gtp_req/gtp_resp
Change-Id: I955b82ba8022754c3d23979d5c55bb61233047b1
2024-03-06 11:24:49 +01:00
Oliver Smith
19a506b705 Add clear error for kernel not supporting IPv6
Make it clear to the user, that if adding a tunnel fails with kernel GTP
and IPv6: the reason is that the kernel doesn't support IPv6 yet.

Related: OS#6096
Change-Id: I1d3c8cbb51212c91136292347dad9529a5c58a31
2024-03-04 11:15:07 +01:00
Oliver Smith
ea6c02ac1f doc: fix typo ndoe -> node
Change-Id: Ib78b5de45b93a7534163de2cd91211e9be75445d
2024-03-01 08:08:43 +00:00
Oliver Smith
ec357c5377 lib/gtp-kernel.c: check rc of in46a_from_eua
Fixes: b17fe7bf ("kernel-gtp: support IPv6 on inner layer")
Change-Id: I40e4de1517de8871224a45c173208810b42312ff
2024-02-27 16:04:42 +01:00
Oliver Smith
768d6d5be9 lib/gtp-kernel.c: initialize ret with 0
Fix -Werror=maybe-uninitialize found in Pau's build env:

/home/pespin/dev/sysmocom/git/osmo-ggsn/lib/gtp-kernel.c: In function ‘gtp_kernel_tunnel_add’:
/home/pespin/dev/sysmocom/git/osmo-ggsn/lib/gtp-kernel.c:111:13: error: ‘ret’ may be used uninitialized [-Werror=maybe-uninitialize]
  111 |         int ret;
      |             ^~~
/home/pespin/dev/sysmocom/git/osmo-ggsn/lib/gtp-kernel.c: In function ‘gtp_kernel_tunnel_del’:
/home/pespin/dev/sysmocom/git/osmo-ggsn/lib/gtp-kernel.c:167:13: error: ‘ret’ may be used uninitialized [-Werror=maybe-uninitialize]
  167 |         int ret;
      |             ^~~

Fixes: b17fe7bf ("kernel-gtp: support IPv6 on inner layer")
Change-Id: I19067ebe561d4c067b9ace7f5b201e15af6b342e
2024-02-27 15:00:59 +01:00
Oliver Smith
fa91a10498 Cosmetic: {lib,gtp}/Makefile.am: diff friendly
Change-Id: Ib1956794edc6e82cfa6c5419b2609565674d98a4
2024-02-23 13:25:32 +01:00
Oliver Smith
6929391ecf Cosmetic: AM_CFLAGS: make diff friendly
Change-Id: I3303cd8ba8c8b21ff267608833d9fb4833ffc471
2024-02-23 12:08:48 +01:00
Oliver Smith
9baac03927 Cosmetic: Makefile.am: make SUBDIRS diff friendly
Change-Id: I49e1b08e48dc324f313228e8c69679c37aa774f4
2024-02-23 12:08:48 +01:00
Oliver Smith
9bd2711f39 Revert "kernel-gtp: support IPv6 on outer layer"
This reverts commit 0917ce4e22,
as it breaks building osmo-sgsn. This needs to be reworked to be
backwards compatible.

Related: OS#6373
Change-Id: I2c2b2ff0875217e041d94c8e2cef030d2a86c2d8
2024-02-22 16:06:33 +01:00
Oliver Smith
b17fe7bfe9 kernel-gtp: support IPv6 on inner layer
Related: OS#6096
Change-Id: I3df47b6c209f1e2f8254ba139581d6e622c6b35f
2024-02-21 16:22:24 +01:00
Oliver Smith
0917ce4e22 kernel-gtp: support IPv6 on outer layer
Related: OS#1953, OS#6096
Change-Id: I257fff1dcd9d030a7f9ea936b2693a3f13208230
2024-02-21 16:22:21 +01:00
Oliver Smith
2a0d37cb1d gtp_new: deduplicate create_and_bind_socket code
Change-Id: Iff3cfdfb0c08033d869c51499754b3416c71732b
2024-02-21 13:06:04 +01:00
Oliver Smith
f3d541e353 Fix a typo
Change-Id: I508274a1a466651025c488ad897aeed739e4b799
2024-02-21 13:05:56 +01:00
Pau Espin Pedrol
8d976444b8 pco: Improve IPCP spec reference documentation
Change-Id: I1dd4a41bae491c61197e8e307efcfc8c63945a71
2024-01-26 16:12:08 +01:00
Daniel Willmann
77734ac81b libgtp: Remove defines for reserved causes in gtp.h
As discussed in Gerrit change I9c3bf64537ef2223e29f8082861fa32fde26bf68
remove defines that don't serve any purpose. These are defines for
reserved values and changing them later if a newer spec defined them
would break API.

Keep the comments to explain the missing values.

Change-Id: I8db0aa0ade59785443a407b51dea326144406dcf
2023-11-29 16:40:49 +01:00
Oliver Smith
848ec697e2 Bump version: 1.10.2.1-a625 → 1.11.0
Change-Id: I1f116e1cded135f231f22ebc9b817aebf3736fc2
2023-11-28 13:07:17 +00:00
Daniel Willmann
6a2e82542d libgtp: Use gtp_cause_successful() instead of GTPCAUSE_ACC_REQ
In some cases the phone requests a PDP context type that isn't available
no the PGW/GGSN, e.g. phone requests a combined IPv4/v6 context, but
only IPv4 is supported.

In that case the GGSN can send a Create PDP Context Response with cause
"New PDP type due to network preference" or "New PDP type due to single
address bearer only". libgtp should continue handling these cause values
like the "Request Accepted" cause. Use the new gtp_cause_successful()
function for that.

Related: OS#6268
Change-Id: I7dd1e0aa185530e1e2d0402742df833c61a787a7
2023-11-24 09:48:22 +01:00
Daniel Willmann
a625bdd136 gtp: Add net GTP cause values and a function to check for success
According to the spec the upf/pgw can accept a modified pdp context from
the request e.g. if an ipv4/6 context was requested, but only ipv4 is
availiable. Introduce a function that checks all cause values that are
considered successful.

See also: 3GPP TS 29.060 Ch 7.3.2

Related: OS#6268
Change-Id: I9c3bf64537ef2223e29f8082861fa32fde26bf68
2023-11-22 12:36:49 +01:00
Pau Espin Pedrol
08bb5182a4 Bump version: 1.10.1.8-4963-dirty → 1.10.2
Change-Id: I148375902975aba0a374e4507c97f1ff67d687bc
2023-09-12 14:36:11 +02:00
Oliver Smith
4963d1c2ea lib/in46_addr: add in46a_from_gsna
Prepare to use it in gtp-kernel.c in a future patch.

Related: OS#6096
Change-Id: I3e76eb7ee89ba338f085c617662d15cffa2a62d5
2023-07-24 15:06:03 +02:00
Oliver Smith
37daa5d003 doc: running: update kernel-gtp limitations
Related: OS#6096
Change-Id: Ie4f1452ecefbe0db0e4093caa8177f1c87bd3950
2023-07-21 12:59:41 +02:00
Oliver Smith
c4c4d90b85 README: update documentation section
Change-Id: I3320dc5eb3d183a18c2bd2fe3139f729978ea2a1
2023-07-21 11:19:14 +02:00
Oliver Smith
59f1539ece systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: I29e547242b2ed1cfc4750c7d7e5f8636c2e8f3dc
2023-05-26 14:10:45 +02:00
Oliver Smith
eff88c08e7 debian: set compat level to 10
Related: OS#5958
Change-Id: I4b2988fffba12cc84ff0834bb9ef0f3d9de2bcda
2023-04-25 16:48:22 +02:00
Oliver Smith
92ac7249f9 doc/manuals/chapters/configuration: fix typo
Change-Id: I0e9d2c77200c7c8b49aec669bc39ca91d5d4cf1f
2023-04-11 17:18:34 +02:00
Vadim Yanitskiy
5cf6b75dc9 tests: use -no-install libtool flag to avoid ./lt-* scripts
This option should be used for any executables which are used only
for testing, or for generating other files and are consequently never
installed.  By specifying this option, we are telling Libtool that
the executable it links will only ever be executed from where it is
built in the build tree.  Libtool is usually able to considerably
speed up the link process for such executables.

Change-Id: I2ca675e93dc5b34bb08d3b841adc115e93558137
2023-03-11 04:36:59 +07:00
Vadim Yanitskiy
4aa2e417c9 Do not hard-code -g and -O2 in CFLAGS
Let the user decide on the optimization level and debugging info.

Change-Id: I4b0b523b7dac4d67413bda37b546964262e5ea0d
2023-03-09 17:17:03 +07:00
Vadim Yanitskiy
f14c056310 Bump version: 1.10.0.4-bf69 → 1.10.1
Change-Id: Ibde9f259bccce29638d35efbd597669f5584e295
2023-02-27 22:35:47 +07:00
Vadim Yanitskiy
bf69ddbfef gtp: use OSMO_ASSERT() in gtp_new()
When using built-in static_assert() [1], gcc v12.2.1 fails:

In file included from gsn.c:27:
gsn.c: In function 'gtp_new':
gsn.c:444:54: error: expression in static assertion is not constant
  444 |         osmo_static_assert(gtp_T_defs[0].default_val != 0, first_default_val_not_zero);
      |                                                      ^

The reason is likely that gtp_T_defs[] is not const, so it cannot
be assert()ed statically.  With the current osmo_static_assert()
implementation, this assert does nothing.  One can change the
gtp_T_defs[0].default_val to 0 and the code will still compile.

Change-Id: Ia8af1736b63d501661046fe70befe5bbabc1045a
Related: [1] libosmocore.git I5ca34bc14c05e8c38c721d7df33feb1c6c41c76e
2023-02-27 17:07:26 +07:00
Vadim Yanitskiy
70a4e2e6f8 gtp/gsn.c: fix 'No newline at end of file'
git complains if it's missing, vim adds it automatically.

Change-Id: I3b4808a76da89e65b934d818e7ca280bc0651483
2023-02-27 17:07:26 +07:00
Vadim Yanitskiy
99afe979ef lib/icmpv6.h: fix struct icmpv6_{radv_hdr,opt_prefix}
Fix wrong field order in the big-endian variants.

Change-Id: Ifaa63bb5496e056805bd13b964c8b430fb11c24c
2023-02-27 17:07:05 +07:00
Oliver Smith
35066fb0b0 debian/libgtp6.shlibs: new file
List the most recent library version where new symbols where added, so
debian properly upgrades libgtp6 when upgrading osmo-sgsn from the
version that is currently in Debian to a version from the Osmocom
repositories.

Closes: OS#5318
Change-Id: Ida5dae4655c0acaeb377bc9d556a2ac333bca10a
2023-02-08 18:11:54 +01:00
30 changed files with 793 additions and 198 deletions

View File

@@ -1,5 +1,14 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = lib gtp ggsn sgsnemu doc contrib utils tests
SUBDIRS = \
lib \
gtp \
ggsn \
sgsnemu \
doc \
contrib \
utils \
tests \
$(NULL)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libgtp.pc

View File

@@ -27,9 +27,10 @@ There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/o
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.
The user manual and VTY reference are optionally built in PDF form
as part of the build process. Find pre-rendered versions here:
https://ftp.osmocom.org/docs/osmo-ggsn/master/
Mailing List
------------

View File

@@ -7,3 +7,5 @@
# 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
libgtp REMOVE remove GTP cause defines of reserved values
libgtpnl > 1.2.5 gtp_tunnel_set_family()

View File

@@ -154,9 +154,10 @@ adl_FUNC_GETOPT_LONG
AM_INIT_AUTOMAKE([foreign])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(

View File

@@ -30,9 +30,9 @@ BuildRequires: pkgconfig >= 0.20
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libgtpnl) >= 1.2.0
BuildRequires: pkgconfig(libosmocore) >= 1.8.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0
BuildRequires: pkgconfig(libosmovty) >= 1.8.0
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
Obsoletes: openggsn
%{?systemd_requires}

View File

@@ -1,6 +1,7 @@
[Unit]
Description=OsmoGGSN
After=networking.service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple

35
debian/changelog vendored
View File

@@ -1,3 +1,38 @@
osmo-ggsn (1.11.0) unstable; urgency=medium
[ Daniel Willmann ]
* gtp: Add net GTP cause values and a function to check for success
-- Oliver Smith <osmith@sysmocom.de> Tue, 28 Nov 2023 13:38:29 +0100
osmo-ggsn (1.10.2) unstable; urgency=medium
[ Vadim Yanitskiy ]
* Do not hard-code -g and -O2 in CFLAGS
* tests: use -no-install libtool flag to avoid ./lt-* scripts
[ Oliver Smith ]
* doc/manuals/chapters/configuration: fix typo
* debian: set compat level to 10
* systemd: depend on networking-online.target
* README: update documentation section
* doc: running: update kernel-gtp limitations
* lib/in46_addr: add in46a_from_gsna
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:36:10 +0200
osmo-ggsn (1.10.1) unstable; urgency=medium
[ Oliver Smith ]
* debian/libgtp6.shlibs: new file
[ Vadim Yanitskiy ]
* lib/icmpv6.h: fix struct icmpv6_{radv_hdr,opt_prefix}
* gtp/gsn.c: fix 'No newline at end of file'
* gtp: use OSMO_ASSERT() in gtp_new()
-- Vadim Yanitskiy <vyanitskiy@sysmocom.de> Mon, 27 Feb 2023 22:35:47 +0700
osmo-ggsn (1.10.0) unstable; urgency=medium
[ Max ]

2
debian/compat vendored
View File

@@ -1 +1 @@
9
10

4
debian/control vendored
View File

@@ -2,12 +2,12 @@ Source: osmo-ggsn
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Section: net
Priority: optional
Build-Depends: debhelper (>= 9),
Build-Depends: debhelper (>= 10),
autotools-dev,
pkg-config,
libdpkg-perl, git,
dh-autoreconf,
libosmocore-dev (>= 1.8.0),
libosmocore-dev (>= 1.9.0),
osmo-gsm-manuals-dev,
libgtpnl-dev (>= 1.2.0)
Standards-Version: 3.9.6

2
debian/libgtp6.shlibs vendored Normal file
View File

@@ -0,0 +1,2 @@
# Most recent version of the package that added new symbols (OS#5318)
libgtp 6 libgtp6 (>= 1.8.0)

View File

@@ -101,7 +101,7 @@ 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`
<3> Enter the config node of the GGSN instance `ggsn0`
<4> Take the GGSN instance out of shutdown
@@ -121,7 +121,7 @@ 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`
<3> Enter the config node of the GGSN instance `ggsn0`
<4> Shut down the GGSN instance
@@ -215,8 +215,8 @@ 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`
<3> Enter the config node of the GGSN instance `ggsn0`
<4> Enter the config node of the APN `internet`
<5> Take the APN out of shutdown
@@ -237,8 +237,8 @@ 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`
<3> Enter the config node of the GGSN instance `ggsn0`
<4> Enter the config node of the APN `internet`
<5> Shut down the APN
[[ggsn_no_root]]
@@ -302,7 +302,7 @@ Name=apn0 <1>
Address=192.168.7.1/24 <2>
IPMasquerade=yes <3>
----
<1> The netowrk device name, which must match the one in the apn0.netdev unit file above
<1> The network 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

View File

@@ -83,7 +83,12 @@ ggsn ggsn0
=== GTP-U kernel module
WARNING: As of writing, the kernel module does not support IPv6.
WARNING: As of writing, IPv6 support for the kernel module has not been
upstreamed yet (OS#1952).
WARNING: As of writing, it is not possible to configure multiple APNs with
gtpu-mode kernel-gpt. This is a limitation in OsmoGGSN, not in the
kernel module (OS#6106).
OsmoGGSN has support to use the Linux kernel GTP-U tunnel driver to accelerate
the data/user plane while still implementing the control plane (GTP-C) in

View File

@@ -2,7 +2,15 @@ bin_PROGRAMS = osmo-ggsn
AM_LDFLAGS = @EXEC_LDFLAGS@
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_CFLAGS = \
-D_GNU_SOURCE \
-fno-builtin \
-Wall \
-DSBINDIR='"$(sbindir)"' \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(NULL)
osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)

View File

@@ -193,7 +193,7 @@ int apn_start(struct apn_ctx *apn)
}
LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
/* Register with libosmcoore */
/* Register with libosmocore */
osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, OSMO_FD_READ, ggsn_tun_fd_cb, apn, 0);
osmo_fd_register(&apn->tun.fd);
@@ -202,11 +202,6 @@ int apn_start(struct apn_ctx *apn)
break;
case APN_GTPU_MODE_KERNEL_GTP:
LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
apn_stop(apn);
return -1;
}
if (gsn == NULL) {
/* skip bringing up the APN now if the GSN is not initialized yet.
* This happens during initial load of the config file, as the
@@ -536,10 +531,11 @@ int create_context_ind(struct pdp_t *pdp)
in46a_to_eua(addr, num_addr, &pdp->eua);
if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
/* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
if (addrv6 && errno == EINVAL)
LOGPPDP(LOGL_ERROR, pdp, "Maybe your kernel does not support GTP-U with IPv6 yet?\n");
gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
return 0;
}

View File

@@ -814,10 +814,7 @@ static const char *print_gsnaddr(const struct ul16_t *in)
{
struct in46_addr in46;
in46.len = in->l;
OSMO_ASSERT(in->l <= sizeof(in46.v6));
memcpy(&in46.v6, in->v, in->l);
in46a_from_gsna(in, &in46);
return in46a_ntoa(&in46);
}

View File

@@ -110,6 +110,7 @@ ret_broken:
osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
}
/* Handle IP Control Protocol, RFC 1332, extensions in RFC 1877 */
static void process_pco_element_ipcp(const struct pco_element *pco_elem, struct msgb *resp,
const struct apn_ctx *apn, struct pdp_t *pdp)
{

View File

@@ -42,12 +42,11 @@ struct pco_element {
uint8_t data[0];
} __attribute__((packed));
/* RFC 1332 */
/* RFC 1332 IP Control Protocol options, extensions in RFC 1877 */
enum ipcp_options {
IPCP_OPT_IPADDR = 3,
IPCP_OPT_PRIMARY_DNS = 129,
IPCP_OPT_SECONDARY_DNS = 131,
IPCP_OPT_IPADDR = 3, /* RFC 1332 3.3 */
IPCP_OPT_PRIMARY_DNS = 129, /* RFC 1877 1.1 */
IPCP_OPT_SECONDARY_DNS = 131, /* RFC 1877 1.2 */
};
struct ipcp_option_hdr {

View File

@@ -2,14 +2,34 @@
# 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=9:0:3
LIBVERSION=9:1:3
lib_LTLIBRARIES = libgtp.la
include_HEADERS = gtp.h gsn.h pdp.h gtpie.h
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
AM_CFLAGS = \
-fno-builtin \
-Wall \
-DSBINDIR='"$(sbindir)"' \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(NULL)
libgtp_la_SOURCES = \
gsn.c \
gsn.h \
gtp.c \
gtp.h \
gtpie.c \
gtpie.h \
lookupa.c \
lookupa.h \
pdp.c \
pdp.h \
queue.c \
queue.h \
$(NULL)
libgtp_la_SOURCES = gtp.c gtp.h gsn.c gsn.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)
libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)

134
gtp/gsn.c
View File

@@ -67,7 +67,7 @@
#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
LOGP(ss, level, "addr(%s:%d) " fmt, \
inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
##args);
##args)
static const struct rate_ctr_desc gsn_ctr_description[] = {
[GSN_CTR_ERR_SOCKET] = { "err:socket", "Socket error" },
@@ -244,6 +244,12 @@ int gtp_set_cb_data_ind(struct gsn_t *gsn,
gsn->cb_data_ind = cb_data_ind;
return 0;
}
int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie))
{
gsn->cb_sgsn_context_request_ind = cb;
return 0;
}
static int queue_timer_retrans(struct gsn_t *gsn)
{
@@ -423,11 +429,45 @@ free_filename:
talloc_free(filename);
}
static int create_and_bind_socket(const char *name, struct gsn_t *gsn, int *fd, int domain,
const struct in_addr *listen, int port)
{
struct sockaddr_in addr;
int type = SOCK_DGRAM;
int protocol = 0;
*fd = socket(domain, type, protocol);
if (*fd < 0) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
LOGP(DLGTP, LOGL_ERROR,
"%s socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
name, domain, type, protocol, strerror(errno));
return -errno;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = domain;
addr.sin_addr = *listen;
addr.sin_port = htons(port);
#if defined(__FreeBSD__) || defined(__APPLE__)
addr.sin_len = sizeof(addr);
#endif
if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
"%s bind(fd=%d) failed: Error = %s\n",
name, *fd, strerror(errno));
return -errno;
}
return 0;
}
int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
int mode)
{
struct sockaddr_in addr;
LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen));
*gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
@@ -441,7 +481,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
/* Initialize timers: */
(*gsn)->tdef = gtp_T_defs;
/* Small hack to properly reset tdef for old clients not using the tdef_group: */
osmo_static_assert(gtp_T_defs[0].default_val != 0, first_default_val_not_zero);
OSMO_ASSERT(gtp_T_defs[0].default_val != 0);
if (gtp_T_defs[0].val == 0)
osmo_tdefs_reset((*gsn)->tdef);
@@ -467,89 +507,35 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
(*gsn)->cb_data_ind = 0;
/* Store function parameters */
/* Same IP for user traffic and signalling */
(*gsn)->gsnc = *listen;
(*gsn)->gsnu = *listen;
(*gsn)->mode = mode;
(*gsn)->fd0 = -1;
(*gsn)->fd1c = -1;
(*gsn)->fd1u = -1;
/* Create GTP version 0 socket */
if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP(DLGTP, LOGL_ERROR,
"GTPv0 socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
AF_INET, SOCK_DGRAM, 0, strerror(errno));
return -errno;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
addr.sin_port = htons(GTP0_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
addr.sin_len = sizeof(addr);
#endif
if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
"bind(fd0=%d) failed: Error = %s\n",
(*gsn)->fd0, strerror(errno));
return -errno;
}
if (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, AF_INET, listen, GTP0_PORT) < 0)
goto error;
/* Create GTP version 1 control plane socket */
if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP(DLGTP, LOGL_ERROR,
"GTPv1 control plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
AF_INET, SOCK_DGRAM, 0, strerror(errno));
return -errno;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
addr.sin_port = htons(GTP1C_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
addr.sin_len = sizeof(addr);
#endif
if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
"bind(fd1c=%d) failed: Error = %s\n",
(*gsn)->fd1c, strerror(errno));
return -errno;
}
if (create_and_bind_socket("GTPv1 control plane", *gsn, &(*gsn)->fd1c, AF_INET, listen, GTP1C_PORT) < 0)
goto error;
/* Create GTP version 1 user plane socket */
if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP(DLGTP, LOGL_ERROR,
"GTPv1 user plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
AF_INET, SOCK_DGRAM, 0, strerror(errno));
return -errno;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
addr.sin_port = htons(GTP1U_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
addr.sin_len = sizeof(addr);
#endif
if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
"bind(fd1u=%d) failed: Error = %s\n",
(*gsn)->fd1u, strerror(errno));
return -errno;
}
if (create_and_bind_socket("GTPv1 user plane", *gsn, &(*gsn)->fd1u, AF_INET, listen, GTP1U_PORT) < 0)
goto error;
/* Start internal queue timer */
gtp_queue_timer_start(*gsn);
return 0;
error:
gtp_free(*gsn);
*gsn = NULL;
return -1;
}
int gtp_free(struct gsn_t *gsn)
@@ -593,4 +579,4 @@ int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
timeout->tv_usec = 0;
/* dummy API, deprecated. Return a huge timer to do nothing */
return 0;
}
}

View File

@@ -17,6 +17,8 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gsm/gsm48.h>
#include "pdp.h"
@@ -107,6 +109,7 @@ struct gsn_t {
int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
int (*cb_sgsn_context_request_ind) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie); /* Pass RAI and TLLI/TMSI/IMSI directly */
/* Counters */
struct rate_ctr_group *ctrg;
@@ -130,6 +133,8 @@ 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);
extern int gtp_create_sgsn_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp);
extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct
pdp_t *
@@ -152,6 +157,9 @@ extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
extern int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie));
extern int gtp_set_cb_conf(struct gsn_t *gsn,
int (*cb) (int type, int cause, struct pdp_t * pdp,
void *cbp));

460
gtp/gtp.c
View File

@@ -25,6 +25,8 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm23003.h>
#if defined(__FreeBSD__)
#include <sys/endian.h>
@@ -338,7 +340,7 @@ static uint32_t get_tei(void *pack)
static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
union gtp_packet *packet, int len,
struct in_addr *inetaddr, void *cbp)
const struct in_addr *inetaddr, void *cbp)
{
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
struct sockaddr_in addr;
@@ -451,9 +453,7 @@ static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer
return 0;
}
static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
union gtp_packet *packet, int len,
struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
static int gtp_resp2(struct gsn_t *gsn, union gtp_packet *packet, int len, struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid, uint16_t flow, uint32_t tei)
{
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
struct qmsg_t *qmsg;
@@ -462,18 +462,11 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
packet->gtp0.h.seq = hton16(seq);
packet->gtp0.h.tid = htobe64(tid);
if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
(packet->gtp0.h.type == GTP_ERROR)))
packet->gtp0.h.flow = hton16(pdp->flru);
else if (pdp)
packet->gtp0.h.flow = hton16(pdp->flrc);
packet->gtp0.h.flow = hton16(flow);
} else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
packet->gtp1l.h.seq = hton16(seq);
if (pdp && (fd == gsn->fd1u))
packet->gtp1l.h.tei = hton32(pdp->teid_gn);
else if (pdp)
packet->gtp1l.h.tei = hton32(pdp->teic_gn);
packet->gtp1l.h.tei = hton32(tei);
} else {
LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
return -1;
@@ -485,7 +478,7 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
}
if (sendto(fd, packet, len, 0,
(struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
(const struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
LOGP(DLGTP, LOGL_ERROR,
"Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
@@ -521,6 +514,32 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
return 0;
}
static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
union gtp_packet *packet, int len,
struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
{
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
uint16_t flow = 0, tei = 0;
if (ver == 0) { /* Version 0 */
if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
(packet->gtp0.h.type == GTP_ERROR)))
flow = pdp->flru;
else if (pdp)
flow = pdp->flrc;
} else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
if (pdp && (fd == gsn->fd1u))
tei = pdp->teid_gn;
else if (pdp)
tei = pdp->teic_gn;
} else {
LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
return -1;
}
return gtp_resp2(gsn, packet, len, peer, fd, seq, tid, flow, tei);
}
static int gtp_notification(struct gsn_t *gsn, uint8_t version,
union gtp_packet *packet, int len,
const struct sockaddr_in *peer, int fd, uint16_t seq)
@@ -820,6 +839,395 @@ int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
return gtp_notification(gsn, 1, &packet, length, peer, gsn->fd1c, 0);
}
#define GSM_MI_TYPE_TLLI 0x05
/* Send an SGSN Context Request for an MI */
int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp)
{
union gtp_packet packet;
/* GTP 1 is the highest supported protocol */
unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_REQ, &packet);
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI, rai->l, rai->v);
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, teic);
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, sgsn_addr->l, sgsn_addr->v);
switch (mi->type) {
case GSM_MI_TYPE_IMSI:
{
uint64_t imsi = gtp_imsi_str2gtp(mi->imsi);
imsi = ntoh64(imsi);
gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
break;
}
case GSM_MI_TYPE_TLLI:
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TLLI, mi->tmsi);
break;
case GSM_MI_TYPE_TMSI:
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_P_TMSI, mi->tmsi);
break;
default:
return -1;
/* TODO: Error */
break;
}
return gtp_req(gsn, 1, NULL, &packet, length, peer, cbp);
}
/* Handle an SGSN Context Request */
static int gtp_sgsn_context_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
void *pack, unsigned len)
{
/* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
struct osmo_mobile_identity mi = {0};
uint64_t imsi;
union gtpie_member *ie[GTPIE_SIZE];
uint32_t teic;
uint8_t seq = get_seq(pack);
struct ul16_t sgsn_addr;
struct ul255_t rai = { .l = 6 };
struct osmo_routing_area_id rai_parsed;
if (version != 1) {
LOGP(DLGTP, LOGL_NOTICE,
"SGSN Context Request expected only on GTPCv1: %u\n", version);
return -EINVAL;
}
int hlen = get_hlen(pack);
/* Decode information elements */
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Invalid message format\n");
return -EINVAL;
}
/* RAI */
if (gtpie_gettv0(ie, GTPIE_RAI, 0, &rai.v, 6)) {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing RAI\n");
goto missing_ie;
}
if (osmo_routing_area_id_decode(&rai_parsed, rai.v, 6) < 0) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Invalid RAI\n");
}
/* TEI-C */
if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &teic)) {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing TEI-C\n");
goto missing_ie;
}
/* SGSN address for signalling (mandatory) */
if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &sgsn_addr.l,
&sgsn_addr.v, sizeof(sgsn_addr.v))) {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing GSN Addr\n");
goto missing_ie;
}
/* Get PTMSI, TLLI or IMSI - only one IE allowed */
if (!gtpie_gettv4(ie, GTPIE_TLLI, 0, &mi.tmsi)) {
mi.type = GSM_MI_TYPE_TLLI;
goto done;
}
if (!gtpie_gettv4(ie, GTPIE_P_TMSI, 0, &mi.tmsi)) {
mi.type = GSM_MI_TYPE_TMSI;
goto done;
}
if (!gtpie_gettv8(ie, GTPIE_IMSI, 0, &imsi)) {
mi.type = GSM_MI_TYPE_IMSI;
/* NOTE: gtpie_gettv8 already converts to host byte order, but imsi_gtp2str seems to prefer big endian */
imsi = ntoh64(imsi);
const char *imsi_str = imsi_gtp2str(&imsi);
memcpy(mi.imsi, imsi_str, sizeof(mi.imsi));
} else {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing Identity information\n");
goto missing_ie;
}
done:
if (gsn->cb_sgsn_context_request_ind)
gsn->cb_sgsn_context_request_ind(gsn, peer, seq, &rai_parsed, teic, &mi, ie);
return 0;
missing_ie:
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory IE\n");
/* TODO: Send response with cause */
return -EINVAL;
}
static bool is_ext_ua(const struct pdp_t *pdp)
{
return pdp->eua.l > 0 && pdp->eua.v[0] == PDP_EUA_TYPE_v4v6;
}
static int gtp_pdp_ctx(uint8_t *buf, unsigned int size, const struct pdp_t *pdp, uint16_t sapi)
{
uint32_t tmp32;
uint16_t tmp16;
uint8_t *ptr = buf;
#define CHECK_SPACE_ERR(bytes) \
if ((ptr - buf) + (bytes) > size) { \
printf("Failed size check: %lu + %lu > %lu\n", (ptr- buf), bytes, size); \
return -1; \
}
#define MEMCPY_CHK(dst, src, len) \
CHECK_SPACE_ERR((len)) \
memcpy((dst), (uint8_t *)(src), (len)); \
(dst) += (len);
// Flags - FIXME: No ASI
*ptr++ = (is_ext_ua(pdp) << 7) | ((!!pdp->vplmn_allow) << 6) | ((!!pdp->reorder) << 4) | (pdp->nsapi & 0x0f);
// SAPI
*ptr++ = sapi & 0x0f;
// QoS Sub
if (pdp->qos_sub.l < 4) {
/* Work around qos_sub never being set */
*ptr++ = 4;
*ptr++ = 0;
*ptr++ = 0x23;
*ptr++ = 0x02;
*ptr++ = 0x00;
} else {
*ptr++ = pdp->qos_sub.l;
MEMCPY_CHK(ptr, pdp->qos_sub.v, pdp->qos_sub.l);
}
// QoS Req
*ptr++ = pdp->qos_req.l;
MEMCPY_CHK(ptr, pdp->qos_req.v, pdp->qos_req.l);
// QoS Neg
*ptr++ = pdp->qos_neg.l;
MEMCPY_CHK(ptr, pdp->qos_neg.v, pdp->qos_neg.l);
// SND
tmp16 = osmo_htons(pdp->pdcpsndd);
MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
// SNU
tmp16 = osmo_htons(pdp->pdcpsndu);
MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
// Send N-PDU
*ptr++ = pdp->gtpsntx;
// Recv N-PDU
*ptr++ = pdp->gtpsnrx;
// Uplink TEIC
tmp32 = osmo_htonl(pdp->teic_gn);
MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
// Uplink TEIDI
tmp32 = osmo_htonl(pdp->teid_gn);
MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
// PDP Ctx Id
*ptr++ = pdp->pdp_id;
// PDP Type Org
*ptr++ = PDP_EUA_ORG_IETF;
// PDP Type No.
// PDP Address
switch (pdp->eua.v[1]) {
case PDP_EUA_TYPE_v4:
case PDP_EUA_TYPE_v4v6:
/* v4v6 expects an IPv4 addr first followed by an IPv6 addr*/
*ptr++ = PDP_EUA_TYPE_v4;
if (pdp->eua.l < 6)
return -1;
*ptr++ = 4;
MEMCPY_CHK(ptr, &pdp->eua.v[2], 4);
break;
case PDP_EUA_TYPE_v6:
*ptr++ = PDP_EUA_TYPE_v6;
if (pdp->eua.l < 18)
return -1;
*ptr++ = 16;
MEMCPY_CHK(ptr, &pdp->eua.v[2], 16);
break;
default:
return -EINVAL;
//Panic
}
// GGSN Address Ctrl
*ptr++ = pdp->gsnrc.l;
MEMCPY_CHK(ptr, pdp->gsnrc.v, pdp->gsnrc.l);
// GGSN Address User
*ptr++ = pdp->gsnru.l;
MEMCPY_CHK(ptr, pdp->gsnru.v, pdp->gsnru.l);
// APN
*ptr++ = pdp->apn_use.l;
MEMCPY_CHK(ptr, pdp->apn_use.v, pdp->apn_use.l);
// TransId
*ptr++ = (pdp->ti >> 8) & 0x0f;
*ptr++ = pdp->ti & 0xff;
if (is_ext_ua(pdp)) {
*ptr++ = PDP_EUA_TYPE_v6;
if (pdp->eua.l < 22)
return -1;
*ptr++ = 16;
MEMCPY_CHK(ptr, &pdp->eua.v[6], 16);
}
return ptr - buf;
#undef CHECK_SPACE_ERR
#undef MEMCPY_CHK
}
int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp)
{
union gtp_packet packet;
struct ul255_t pdp;
/* GTP 1 is the highest supported protocol */
unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_RSP, &packet);
// Cause - TV1
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
if (cause != GTPCAUSE_ACC_REQ)
return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
// IMSI - TV8
gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
// TEIC - TV4
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, pdpctx->teic_own);
// MM Ctx - TLV
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MM_CONTEXT, mm_len, mmctx);
// PDP Ctx - TLV
if (pdpctx) {
int rc = gtp_pdp_ctx(pdp.v, 255, pdpctx, sapi);
if (rc > 0)
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PDP_CONTEXT, rc, pdp.v);
}
// SGSN Addr Ctrl - TLV
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, 4, &sgsn_addr->s_addr);
// Alt GGSN Addr Ctrl (per PDP Ctx)
// Alt GGSN Addr User (per PDP Ctx)
/* The encoding for this is a bit insane */
return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
}
/* Handle an SGSN Context Response */
static int gtp_sgsn_context_conf_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
void *pack, unsigned len)
{
/** If cause is "Request accepted": Send ACK,
else: Log and handle error */
/* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
void *cbp = NULL;
uint8_t type = 0;
uint8_t cause;
union gtpie_member *ie[GTPIE_SIZE];
struct pdp_t *pdp = NULL;
uint32_t teic;
struct ul16_t sgsn_addr;
if (version != 1) {
LOGP(DLGTP, LOGL_NOTICE,
"SGSN Context Request expected only on GTPCv1: %u\n", version);
return -EINVAL;
}
int hlen = get_hlen(pack);
/* Remove packet from queue */
if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
return EOF;
/* Extract information elements into a pointer array */
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Invalid message format\n");
if (gsn->cb_conf)
gsn->cb_conf(type, EOF, NULL, cbp);
return EOF;
}
/* Extract cause value (mandatory) */
if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory information field\n");
if (gsn->cb_conf)
gsn->cb_conf(type, EOF, NULL, cbp);
return EOF;
}
/* Check all conditional information elements */
if (!gtp_cause_successful(cause)) {
GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
"SGSN Context response with cause (%u)\n", cause);
if (gsn->cb_conf)
gsn->cb_conf(type, cause, NULL, cbp);
}
/* Gather UE context and PDP data, create pdp context */
//gtp_pdp_newpdp(gsn, &pdp, imsi, nsapi, NULL)
if (gsn->cb_conf)
gsn->cb_conf(type, cause, pdp, cbp);
return 0;
}
/* Handle an SGSN Context Acknowledge */
static int gtp_sgsn_context_ack(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
void *pack, unsigned len)
{
/* If cause is != Request accepted, log error */
return -ENOTSUP;
}
/* Handle an SGSN Context request */
int gtp_context_request(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
void *pack, unsigned len)
{
union gtpie_member *ie[GTPIE_SIZE];
if (version != 1) {
LOGP(DLGTP, LOGL_NOTICE,
"SGSN Context Request expected only on GTPCv1: %u\n", version);
return -EINVAL;
}
int hlen = get_hlen(pack);
/* Decode information elements */
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Invalid message format (AN Information Relay)\n");
return -EINVAL;
}
if (gsn->cb_ran_info_relay_ind)
gsn->cb_ran_info_relay_ind(peer, ie);
return 0;
}
/* ***********************************************************
* Session management messages
* Messages: create, update and delete PDP context
@@ -995,7 +1403,7 @@ int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
/* Now send off a reply to the peer */
gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
if (cause != GTPCAUSE_ACC_REQ)
if (!gtp_cause_successful(cause))
gtp_freepdp(gsn, pdp);
return 0;
@@ -1011,7 +1419,7 @@ int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
if (cause == GTPCAUSE_ACC_REQ) {
if (gtp_cause_successful(cause)) {
if (version == 0)
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
@@ -1445,7 +1853,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
}
/* Check all conditional information elements */
if (GTPCAUSE_ACC_REQ == cause) {
if (gtp_cause_successful(cause)) {
if (version == 0) {
if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
@@ -1667,7 +2075,7 @@ static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
if (cause == GTPCAUSE_ACC_REQ) {
if (gtp_cause_successful(cause)) {
if (version == 0)
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
@@ -1997,7 +2405,7 @@ static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
/* Check all conditional information elements */
/* TODO: This does not handle GGSN-initiated update responses */
if (cause == GTPCAUSE_ACC_REQ) {
if (gtp_cause_successful(cause)) {
if (version == 0) {
if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
&pdp->qos_neg0,
@@ -2172,7 +2580,7 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
get_seq(pack), get_tid(pack));
if (cause == GTPCAUSE_ACC_REQ) {
if (gtp_cause_successful(cause)) {
if ((teardown) || (version == 0)) { /* Remove all contexts */
gtp_freepdp_teardown(gsn, linked_pdp);
} else {
@@ -2198,7 +2606,6 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
}
}
}
/* if (cause == GTPCAUSE_ACC_REQ) */
return 0;
}
@@ -2350,7 +2757,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
}
/* Check the cause value (again) */
if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
if (!gtp_cause_successful(cause) && (GTPCAUSE_NON_EXIST != cause)) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNEXPECTED_CAUSE);
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Unexpected cause value received: %d\n", cause);
@@ -2827,6 +3234,15 @@ int gtp_decaps1c(struct gsn_t *gsn)
case GTP_RAN_INFO_RELAY:
gtp_ran_info_relay_ind(gsn, version, &peer, buffer, status);
break;
case GTP_SGSN_CONTEXT_REQ:
gtp_sgsn_context_ind(gsn, version, &peer, buffer, status);
break;
case GTP_SGSN_CONTEXT_RSP:
gtp_sgsn_context_conf_ind(gsn, version, &peer, buffer, status);
break;
case GTP_SGSN_CONTEXT_ACK:
gtp_sgsn_context_ack(gsn, version, &peer, buffer, status);
break;
default:
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,

View File

@@ -53,7 +53,7 @@
#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */
#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */
#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */
/* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */
/* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */
#define GTP_ERROR 26 /* Error Indication */
#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */
#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */
@@ -99,19 +99,21 @@ static inline const char *gtp_type_name(uint8_t val)
#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */
#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */
#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */
#define GTPCAUSE_006 6 /* For future use 6-48 */
#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */
#define GTPCAUSE_064 64 /* For future use 64-127 */
/* 6-48 For future use */
/* 49-63 Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) */
/* 64-127 For future use */
#define GTPCAUSE_ACC_REQ 128 /* Request accepted */
#define GTPCAUSE_129 129 /* For future use 129-176 */
#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */
#define GTPCAUSE_NEW_PDP_NET_PREF 129 /* New PDP type due to network preference */
#define GTPCAUSE_NEW_PDP_ADDR_BEAR 130 /* New PDP type due to single address bearer only */
/* 131-176 For future use */
/* 177-191 Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) */
#define GTPCAUSE_NON_EXIST 192 /* Non-existent */
#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */
#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */
#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */
#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */
#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */
#define GTPCAUSE_198 198 /* For future use */
/* 198 For future use */
#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */
#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */
#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */
@@ -134,8 +136,15 @@ static inline const char *gtp_type_name(uint8_t val)
#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */
#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN */
#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */
#define GTPCAUSE_221 221 /* For Future Use 221-240 */
#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */
/* 221-240 For future use */
/* 241-255 Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) */
static inline bool gtp_cause_successful(uint8_t cause)
{
return cause == GTPCAUSE_ACC_REQ ||
cause == GTPCAUSE_NEW_PDP_NET_PREF ||
cause == GTPCAUSE_NEW_PDP_ADDR_BEAR;
}
struct ul66_t;
struct ul16_t;
@@ -253,6 +262,12 @@ extern int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *p
const uint8_t *rim_route_addr, size_t rim_route_addr_len,
uint8_t rim_route_addr_discr);
extern int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp);
extern int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp);
extern int gtp_decaps0(struct gsn_t *gsn);
extern int gtp_decaps1c(struct gsn_t *gsn);
extern int gtp_decaps1u(struct gsn_t *gsn);

View File

@@ -1,10 +1,41 @@
noinst_LIBRARIES = libmisc.a
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.h netns.h util.h icmpv6.h checksum.h
noinst_HEADERS = \
checksum.h \
gnugetopt.h \
gtp-kernel.h \
icmpv6.h \
in46_addr.h \
ippool.h \
lookup.h \
netdev.h \
netns.h \
syserr.h \
tun.h \
util.h \
$(NULL)
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
AM_CFLAGS = \
-fno-builtin \
-Wall \
-DSBINDIR='"$(sbindir)"' \
$(LIBOSMOCORE_CFLAGS) \
$(NULL)
libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c netdev.c netns.c util.c icmpv6.c checksum.c
libmisc_a_SOURCES = \
checksum.c \
debug.c \
getopt.c \
getopt1.c \
icmpv6.c \
in46_addr.c \
ippool.c \
lookup.c \
netdev.c \
netns.c \
tun.c \
util.c \
$(NULL)
if ENABLE_GTP_KERNEL
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)

View File

@@ -104,61 +104,97 @@ void gtp_kernel_stop(const char *devname)
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
{
struct in_addr ms, sgsn;
int ms_addr_count;
struct in46_addr ms[2];
struct in46_addr sgsn;
struct gtp_tunnel *t;
int ret;
int ret = 0;
pdp_debug(__func__, devname, pdp);
t = gtp_tunnel_alloc();
if (t == NULL)
in46a_from_gsna(&pdp->gsnrc, &sgsn);
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
if (ms_addr_count < 0)
return -1;
memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
for (int i = 0; i < ms_addr_count; i++) {
t = gtp_tunnel_alloc();
if (t == NULL)
return -1;
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);
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
gtp_tunnel_set_version(t, pdp->version);
if (in46a_to_af(&ms[i]) == AF_INET)
gtp_tunnel_set_ms_ip4(t, &ms[i].v4);
else {
/* In IPv6, EUA doesn't contain the actual IP
* addr/prefix. Set higher bits to 0 to get the 64 bit
* netmask. */
memset(((void *)&ms[i].v6) + 8, 0, 8);
gtp_tunnel_set_ms_ip6(t, &ms[i].v6);
}
if (in46a_to_af(&sgsn) == AF_INET)
gtp_tunnel_set_sgsn_ip4(t, &sgsn.v4);
else
gtp_tunnel_set_sgsn_ip6(t, &sgsn.v6);
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);
if (ret != 0)
break;
}
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)
{
int ms_addr_count;
struct in46_addr ms[2];
struct gtp_tunnel *t;
int ret;
int ret = 0;
pdp_debug(__func__, devname, pdp);
t = gtp_tunnel_alloc();
if (t == NULL)
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
if (ms_addr_count < 0)
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);
}
for (int i = 0; i < ms_addr_count; i++) {
t = gtp_tunnel_alloc();
if (t == NULL)
return -1;
ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
gtp_tunnel_free(t);
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
gtp_tunnel_set_family(t, in46a_to_af(&ms[i]));
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);
if (ret != 0)
break;
}
return ret;
}

View File

@@ -44,10 +44,9 @@ struct icmpv6_radv_hdr {
uint8_t res:6,
m:1,
o:1;
#else
uint8_t m:1,
o:1,
res:6;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t o:1, m:1, res:6;
#endif
uint16_t router_lifetime;
uint32_t reachable_time;
@@ -72,10 +71,9 @@ struct icmpv6_opt_prefix {
uint8_t res:6,
a:1,
l:1;
#else
uint8_t l:1,
a:1,
res:6;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t l:1, a:1, res:6;
#endif
uint32_t valid_lifetime;
uint32_t preferred_lifetime;

View File

@@ -375,3 +375,10 @@ default_to_dyn_v4:
dst->v4.s_addr = 0;
return 1;
}
void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst)
{
dst->len = in->l;
OSMO_ASSERT(in->l <= sizeof(dst->v6));
memcpy(&dst->v6, in->v, in->l);
}

View File

@@ -39,3 +39,5 @@ static inline bool in46a_is_v6(const struct in46_addr *addr) {
static inline bool in46a_is_v4(const struct in46_addr *addr) {
return addr->len == sizeof(struct in_addr);
}
void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst);

View File

@@ -2,12 +2,21 @@ bin_PROGRAMS = sgsnemu
AM_LDFLAGS = @EXEC_LDFLAGS@
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
AM_CFLAGS = \
-D_GNU_SOURCE \
-fno-builtin \
-Wall \
-DSBINDIR='"$(sbindir)"' \
$(LIBOSMOCORE_CFLAGS) \
$(NULL)
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
if ENABLE_GTP_KERNEL
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
AM_CFLAGS += \
-DGTP_KERNEL \
$(LIBGTPNL_CFLAGS) \
$(NULL)
sgsnemu_LDADD += $(LIBGTPNL_LIBS)
endif

View File

@@ -1,4 +1,9 @@
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
AM_CFLAGS = \
-Wall \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \
$(NULL)
AM_LDFLAGS = -no-install
EXTRA_DIST = \
gtpie_test.ok \

View File

@@ -1,4 +1,9 @@
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
AM_CFLAGS = \
-Wall \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \
$(NULL)
AM_LDFLAGS = -no-install
EXTRA_DIST = ippool_test.ok \
ippool_test.err \