blob: 48811bc9618430800f351b4f9c0cac956af7c128 [file] [log] [blame]
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +01001#ifdef __linux__
2#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
3#endif
4
5#include "../config.h"
6
7#ifdef HAVE_STDINT_H
8#include <stdint.h>
9#endif
10
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010011#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
Harald Welte51127ea2017-11-06 02:42:22 +090014#include <inttypes.h>
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010015#include <sys/types.h>
16#include <arpa/inet.h>
17#include <net/if.h>
18
19#include <libgtpnl/gtp.h>
20#include <libgtpnl/gtpnl.h>
21#include <libmnl/libmnl.h>
22
23#include <errno.h>
24
25#include <time.h>
26
27#include "../lib/tun.h"
28#include "../lib/syserr.h"
29#include "../gtp/pdp.h"
30#include "../gtp/gtp.h"
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010031
32#include <libgtpnl/gtp.h>
33#include <libgtpnl/gtpnl.h>
34#include <libmnl/libmnl.h>
35
36#include "gtp-kernel.h"
37
Harald Weltefd30bd12017-11-12 18:26:59 +090038static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010039{
Harald Welte51127ea2017-11-06 02:42:22 +090040 struct in46_addr ia46;
41 struct in_addr ia;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010042
Harald Welte51127ea2017-11-06 02:42:22 +090043 in46a_from_eua(&pdp->eua, &ia46);
44 gsna2in_addr(&ia, &pdp->gsnrc);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010045
Harald Weltefd30bd12017-11-12 18:26:59 +090046 LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=%s SGSN=%s\n", prefix,
47 devname, pdp->version,
Harald Welte51127ea2017-11-06 02:42:22 +090048 pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
49 in46a_ntoa(&ia46), inet_ntoa(ia));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010050}
51
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010052static struct {
53 int genl_id;
54 struct mnl_socket *nl;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010055} gtp_nl;
56
Harald Welte22e15732017-11-08 16:07:12 +090057static int gtp_kernel_init_once(void)
58{
59 /* only initialize once */
60 if (gtp_nl.nl)
61 return 0;
62
63 gtp_nl.nl = genl_socket_open();
64 if (gtp_nl.nl == NULL) {
Harald Welte3dad9512017-11-08 16:53:47 +090065 LOGP(DGGSN, LOGL_ERROR, "cannot create genetlink socket\n");
Harald Welte22e15732017-11-08 16:07:12 +090066 return -1;
67 }
68 gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
69 if (gtp_nl.genl_id < 0) {
Harald Welte3dad9512017-11-08 16:53:47 +090070 LOGP(DGGSN, LOGL_ERROR, "cannot lookup GTP genetlink ID\n");
Harald Welte31879562017-11-08 16:08:20 +090071 genl_socket_close(gtp_nl.nl);
72 gtp_nl.nl = NULL;
Harald Welte22e15732017-11-08 16:07:12 +090073 return -1;
74 }
Harald Welte3dad9512017-11-08 16:53:47 +090075 LOGP(DGGSN, LOGL_NOTICE, "Initialized GTP kernel mode (genl ID is %d)\n", gtp_nl.genl_id);
Harald Welte22e15732017-11-08 16:07:12 +090076
77 return 0;
78}
79
Harald Weltef2286392018-04-25 19:02:31 +020080int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010081{
Harald Weltef2286392018-04-25 19:02:31 +020082 if (gtp_kernel_init_once() < 0)
Harald Weltee3c59182017-11-08 14:08:24 +090083 return -1;
Harald Weltee3c59182017-11-08 14:08:24 +090084
Harald Weltef2286392018-04-25 19:02:31 +020085 return gtp_dev_create(dest_ns, devname, fd0, fd1u);
86}
87
88int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u)
89{
90 if (gtp_kernel_init_once() < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010091 return -1;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010092
Harald Weltef2286392018-04-25 19:02:31 +020093 return gtp_dev_create_sgsn(dest_ns, devname, fd0, fd1u);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010094}
95
Harald Welte698a2332017-11-08 15:09:58 +090096void gtp_kernel_stop(const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010097{
Harald Welte698a2332017-11-08 15:09:58 +090098 gtp_dev_destroy(devname);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010099}
100
Harald Welte698a2332017-11-08 15:09:58 +0900101int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100102{
103 struct in_addr ms, sgsn;
104 struct gtp_tunnel *t;
105 int ret;
106
Harald Weltefd30bd12017-11-12 18:26:59 +0900107 pdp_debug(__func__, devname, pdp);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100108
109 t = gtp_tunnel_alloc();
110 if (t == NULL)
111 return -1;
112
113 memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
114 memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
115
Harald Welte698a2332017-11-08 15:09:58 +0900116 gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100117 gtp_tunnel_set_version(t, pdp->version);
118 gtp_tunnel_set_ms_ip4(t, &ms);
119 gtp_tunnel_set_sgsn_ip4(t, &sgsn);
120 if (pdp->version == 0) {
121 gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
122 gtp_tunnel_set_flowid(t, pdp->flru);
123 } else {
Harald Welte875e4dc2017-02-23 20:26:19 +0100124 gtp_tunnel_set_i_tei(t, pdp->teid_own);
125 /* use the TEI advertised by SGSN when sending packets
126 * towards the SGSN */
127 gtp_tunnel_set_o_tei(t, pdp->teid_gn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100128 }
129
130 ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
131 gtp_tunnel_free(t);
132
133 return ret;
134}
135
Harald Welte698a2332017-11-08 15:09:58 +0900136int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100137{
138 struct gtp_tunnel *t;
139 int ret;
140
Harald Weltefd30bd12017-11-12 18:26:59 +0900141 pdp_debug(__func__, devname, pdp);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100142
143 t = gtp_tunnel_alloc();
144 if (t == NULL)
145 return -1;
146
Harald Welte698a2332017-11-08 15:09:58 +0900147 gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100148 gtp_tunnel_set_version(t, pdp->version);
149 if (pdp->version == 0) {
150 gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
151 gtp_tunnel_set_flowid(t, pdp->flru);
152 } else {
Harald Welte875e4dc2017-02-23 20:26:19 +0100153 gtp_tunnel_set_i_tei(t, pdp->teid_own);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100154 }
155
156 ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
157 gtp_tunnel_free(t);
158
159 return ret;
160}