mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-10-23 08:22:07 +00:00
Move all includes from /usr/include/….h to /usr/include/osmocom/gtp/….h to be more consistent with other Osmocom projects, and to not "pollute" the top include directory if we add more header files. Also the new directory structure makes more obvious, which headers are public and which ones aren't. Adjust libgtp.pc.in so both #include <gtp.h> (legacy) and #include <osmocom/gtp/gtp.h> can be used. Related: OS#6373 Change-Id: If7e01c61168819bf7120667344e40c857da5490b
202 lines
4.4 KiB
C
202 lines
4.4 KiB
C
#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 <errno.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <osmocom/gtp/pdp.h>
|
|
#include <osmocom/gtp/gtp.h>
|
|
|
|
#include "../lib/tun.h"
|
|
#include "../lib/syserr.h"
|
|
#include "../lib/util.h"
|
|
#include "../lib/ippool.h"
|
|
|
|
#include "gtp-kernel.h"
|
|
|
|
static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
|
|
{
|
|
char buf4[INET_ADDRSTRLEN], buf6[INET6_ADDRSTRLEN];
|
|
struct ippoolm_t *peer;
|
|
struct in_addr ia;
|
|
|
|
buf4[0] = '\0';
|
|
if ((peer = pdp_get_peer_ipv(pdp, false)))
|
|
in46a_ntop(&peer->addr, buf4, sizeof(buf4));
|
|
buf6[0] = '\0';
|
|
if ((peer = pdp_get_peer_ipv(pdp, true)))
|
|
in46a_ntop(&peer->addr, buf6, sizeof(buf6));
|
|
|
|
gsna2in_addr(&ia, &pdp->gsnrc);
|
|
|
|
LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=(%s,%s) SGSN=%s\n", prefix,
|
|
devname, pdp->version,
|
|
pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
|
|
buf4, buf6, 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)
|
|
{
|
|
int ms_addr_count;
|
|
struct in46_addr ms[2];
|
|
struct in46_addr sgsn;
|
|
struct gtp_tunnel *t;
|
|
int ret = 0;
|
|
|
|
pdp_debug(__func__, devname, pdp);
|
|
|
|
in46a_from_gsna(&pdp->gsnrc, &sgsn);
|
|
|
|
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
|
|
if (ms_addr_count < 0)
|
|
return -1;
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
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 = 0;
|
|
|
|
pdp_debug(__func__, devname, pdp);
|
|
|
|
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
|
|
if (ms_addr_count < 0)
|
|
return -1;
|
|
|
|
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_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;
|
|
}
|