blob: 2a731e626fcb26c1b05842a6db979219ba093904 [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>
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010021
22#include <errno.h>
23
24#include <time.h>
25
26#include "../lib/tun.h"
27#include "../lib/syserr.h"
Pau Espin Pedrol1ef26212019-08-20 13:26:14 +020028#include "../lib/util.h"
29#include "../lib/ippool.h"
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010030#include "../gtp/pdp.h"
31#include "../gtp/gtp.h"
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010032
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010033#include "gtp-kernel.h"
34
Harald Weltefd30bd12017-11-12 18:26:59 +090035static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010036{
Pau Espin Pedrol1ef26212019-08-20 13:26:14 +020037 char buf4[INET_ADDRSTRLEN], buf6[INET6_ADDRSTRLEN];
38 struct ippoolm_t *peer;
Harald Welte51127ea2017-11-06 02:42:22 +090039 struct in_addr ia;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010040
Pau Espin Pedrol1ef26212019-08-20 13:26:14 +020041 buf4[0] = '\0';
42 if ((peer = pdp_get_peer_ipv(pdp, false)))
43 in46a_ntop(&peer->addr, buf4, sizeof(buf4));
44 buf6[0] = '\0';
45 if ((peer = pdp_get_peer_ipv(pdp, true)))
46 in46a_ntop(&peer->addr, buf6, sizeof(buf6));
47
Harald Welte51127ea2017-11-06 02:42:22 +090048 gsna2in_addr(&ia, &pdp->gsnrc);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010049
Pau Espin Pedrol1ef26212019-08-20 13:26:14 +020050 LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=(%s,%s) SGSN=%s\n", prefix,
Harald Weltefd30bd12017-11-12 18:26:59 +090051 devname, pdp->version,
Harald Welte51127ea2017-11-06 02:42:22 +090052 pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
Pau Espin Pedrol1ef26212019-08-20 13:26:14 +020053 buf4, buf6, inet_ntoa(ia));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010054}
55
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010056static struct {
57 int genl_id;
58 struct mnl_socket *nl;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010059} gtp_nl;
60
Harald Welte22e15732017-11-08 16:07:12 +090061static int gtp_kernel_init_once(void)
62{
63 /* only initialize once */
64 if (gtp_nl.nl)
65 return 0;
66
67 gtp_nl.nl = genl_socket_open();
68 if (gtp_nl.nl == NULL) {
Harald Welte3dad9512017-11-08 16:53:47 +090069 LOGP(DGGSN, LOGL_ERROR, "cannot create genetlink socket\n");
Harald Welte22e15732017-11-08 16:07:12 +090070 return -1;
71 }
72 gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
73 if (gtp_nl.genl_id < 0) {
Harald Welte3dad9512017-11-08 16:53:47 +090074 LOGP(DGGSN, LOGL_ERROR, "cannot lookup GTP genetlink ID\n");
Harald Welte31879562017-11-08 16:08:20 +090075 genl_socket_close(gtp_nl.nl);
76 gtp_nl.nl = NULL;
Harald Welte22e15732017-11-08 16:07:12 +090077 return -1;
78 }
Harald Welte3dad9512017-11-08 16:53:47 +090079 LOGP(DGGSN, LOGL_NOTICE, "Initialized GTP kernel mode (genl ID is %d)\n", gtp_nl.genl_id);
Harald Welte22e15732017-11-08 16:07:12 +090080
81 return 0;
82}
83
Harald Weltef2286392018-04-25 19:02:31 +020084int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010085{
Harald Weltef2286392018-04-25 19:02:31 +020086 if (gtp_kernel_init_once() < 0)
Harald Weltee3c59182017-11-08 14:08:24 +090087 return -1;
Harald Weltee3c59182017-11-08 14:08:24 +090088
Harald Weltef2286392018-04-25 19:02:31 +020089 return gtp_dev_create(dest_ns, devname, fd0, fd1u);
90}
91
92int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u)
93{
94 if (gtp_kernel_init_once() < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010095 return -1;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010096
Harald Weltef2286392018-04-25 19:02:31 +020097 return gtp_dev_create_sgsn(dest_ns, devname, fd0, fd1u);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010098}
99
Harald Welte698a2332017-11-08 15:09:58 +0900100void gtp_kernel_stop(const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100101{
Harald Welte698a2332017-11-08 15:09:58 +0900102 gtp_dev_destroy(devname);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100103}
104
Harald Welte698a2332017-11-08 15:09:58 +0900105int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100106{
107 struct in_addr ms, sgsn;
108 struct gtp_tunnel *t;
109 int ret;
110
Harald Weltefd30bd12017-11-12 18:26:59 +0900111 pdp_debug(__func__, devname, pdp);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100112
113 t = gtp_tunnel_alloc();
114 if (t == NULL)
115 return -1;
116
117 memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
118 memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
119
Harald Welte698a2332017-11-08 15:09:58 +0900120 gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100121 gtp_tunnel_set_version(t, pdp->version);
122 gtp_tunnel_set_ms_ip4(t, &ms);
123 gtp_tunnel_set_sgsn_ip4(t, &sgsn);
124 if (pdp->version == 0) {
125 gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
126 gtp_tunnel_set_flowid(t, pdp->flru);
127 } else {
Harald Welte875e4dc2017-02-23 20:26:19 +0100128 gtp_tunnel_set_i_tei(t, pdp->teid_own);
129 /* use the TEI advertised by SGSN when sending packets
130 * towards the SGSN */
131 gtp_tunnel_set_o_tei(t, pdp->teid_gn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100132 }
133
134 ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
135 gtp_tunnel_free(t);
136
137 return ret;
138}
139
Harald Welte698a2332017-11-08 15:09:58 +0900140int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100141{
142 struct gtp_tunnel *t;
143 int ret;
144
Harald Weltefd30bd12017-11-12 18:26:59 +0900145 pdp_debug(__func__, devname, pdp);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100146
147 t = gtp_tunnel_alloc();
148 if (t == NULL)
149 return -1;
150
Harald Welte698a2332017-11-08 15:09:58 +0900151 gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100152 gtp_tunnel_set_version(t, pdp->version);
153 if (pdp->version == 0) {
154 gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
155 gtp_tunnel_set_flowid(t, pdp->flru);
156 } else {
Harald Welte875e4dc2017-02-23 20:26:19 +0100157 gtp_tunnel_set_i_tei(t, pdp->teid_own);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100158 }
159
160 ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
161 gtp_tunnel_free(t);
162
163 return ret;
164}