blob: bde7f4b01731c9f8f5c26cf91fc77f0202a76936 [file] [log] [blame]
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02001/*
Harald Welte632e8432017-09-05 18:12:14 +02002 * OsmoGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welte7bdc80d2019-04-11 18:47:59 +02004 * Copyright (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02005 *
jjakoa7cd2492003-04-11 09:40:12 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +020010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/* ggsn.c
14 *
15 */
16
17#ifdef __linux__
18#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
19#endif
20
jjako0fe0df02004-09-17 11:30:40 +000021#include "../config.h"
22
23#ifdef HAVE_STDINT_H
24#include <stdint.h>
25#endif
jjako52c24142002-12-16 13:33:51 +000026
Harald Weltedda21ed2017-08-12 15:07:02 +020027#include <getopt.h>
jjako52c24142002-12-16 13:33:51 +000028#include <ctype.h>
jjako52c24142002-12-16 13:33:51 +000029#include <signal.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020033#include <unistd.h>
34#include <inttypes.h>
35#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000036#include <sys/types.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020037#include <sys/ioctl.h>
38
39#include <net/if.h>
40#include <arpa/inet.h>
jjako52c24142002-12-16 13:33:51 +000041#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020042#include <netinet/ip.h>
Harald Weltea0d281d2017-08-02 21:48:16 +020043#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000044
Harald Weltedda21ed2017-08-12 15:07:02 +020045#include <osmocom/core/timer.h>
Max727417d2016-08-02 17:10:38 +020046#include <osmocom/ctrl/control_if.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020047#include <osmocom/gsm/apn.h>
Max727417d2016-08-02 17:10:38 +020048
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020049#include "../lib/tun.h"
50#include "../lib/ippool.h"
51#include "../lib/syserr.h"
Harald Welted12eab92017-08-02 19:49:47 +020052#include "../lib/in46_addr.h"
Harald Weltef2286392018-04-25 19:02:31 +020053#include "../lib/gtp-kernel.h"
Pau Espin Pedrolf612ffe2019-08-20 13:24:55 +020054#include "../lib/util.h"
jjako52c24142002-12-16 13:33:51 +000055#include "../gtp/pdp.h"
56#include "../gtp/gtp.h"
Pau Espin Pedrol1c8ae662020-04-09 18:51:05 +020057#include "../lib/icmpv6.h"
Pau Espin Pedrolf7884e82019-08-20 12:06:13 +020058#include "pco.h"
Harald Weltedda21ed2017-08-12 15:07:02 +020059#include "ggsn.h"
jjako52c24142002-12-16 13:33:51 +000060
Harald Weltedda21ed2017-08-12 15:07:02 +020061static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what);
62static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len);
63
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +020064void ggsn_close_one_pdp(struct pdp_t *pdp)
65{
66 LOGPPDP(LOGL_DEBUG, pdp, "Sending DELETE PDP CTX due to shutdown\n");
67 gtp_delete_context_req2(pdp->gsn, pdp, NULL, 1);
68 /* We have nothing more to do with pdp ctx, free it. Upon cb_delete_context
69 called during this call we'll clean up ggsn related stuff attached to this
70 pdp context. After this call, ippool member is cleared so
71 data is no longer valid and should not be accessed anymore. */
72 gtp_freepdp_teardown(pdp->gsn, pdp);
73}
74
Harald Weltedda21ed2017-08-12 15:07:02 +020075static void pool_close_all_pdp(struct ippool_t *pool)
Harald Weltebed35df2011-11-02 13:06:18 +010076{
Harald Weltedda21ed2017-08-12 15:07:02 +020077 unsigned int i;
jjako52c24142002-12-16 13:33:51 +000078
Harald Weltedda21ed2017-08-12 15:07:02 +020079 if (!pool)
Harald Weltebed35df2011-11-02 13:06:18 +010080 return;
Harald Weltedda21ed2017-08-12 15:07:02 +020081
82 for (i = 0; i < pool->listsize; i++) {
83 struct ippoolm_t *member = &pool->member[i];
84 struct pdp_t *pdp;
85
86 if (!member->inuse)
87 continue;
88 pdp = member->peer;
89 if (!pdp)
90 continue;
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +020091 ggsn_close_one_pdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +010092 }
jjako52c24142002-12-16 13:33:51 +000093}
94
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +020095int apn_stop(struct apn_ctx *apn)
Harald Weltebed35df2011-11-02 13:06:18 +010096{
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +020097 LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
Harald Weltedda21ed2017-08-12 15:07:02 +020098 /* check if pools have any active PDP contexts and bail out */
99 pool_close_all_pdp(apn->v4.pool);
100 pool_close_all_pdp(apn->v6.pool);
101
102 /* shutdown whatever old state might be left */
103 if (apn->tun.tun) {
104 /* run ip-down script */
105 if (apn->tun.cfg.ipdown_script) {
106 LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
107 tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
108 }
Harald Weltef2286392018-04-25 19:02:31 +0200109 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
110 /* release tun device */
111 LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
112 osmo_fd_unregister(&apn->tun.fd);
113 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200114 tun_free(apn->tun.tun);
115 apn->tun.tun = NULL;
116 }
117
118 if (apn->v4.pool) {
119 LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
120 ippool_free(apn->v4.pool);
121 apn->v4.pool = NULL;
122 }
123 if (apn->v6.pool) {
124 LOGPAPN(LOGL_INFO, apn, "Releasing IPv6 pool\n");
125 ippool_free(apn->v6.pool);
126 apn->v6.pool = NULL;
127 }
128
129 apn->started = false;
130 return 0;
131}
132
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200133
Harald Weltef55a0392017-11-08 14:33:55 +0900134static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blacklist, bool ipv6)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200135{
136
137 int flags, len, len2, i;
138
Harald Weltee2a1de52017-11-08 15:24:07 +0900139 *blacklist = NULL;
140
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200141 if (ipv6)
142 flags = IP_TYPE_IPv6_NONLINK;
143 else
144 flags = IP_TYPE_IPv4;
145
146 while (1) {
Harald Weltee2a1de52017-11-08 15:24:07 +0900147 len = netdev_ip_local_get(apn->tun.cfg.dev_name, NULL, 0, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200148 if (len < 1)
149 return len;
150
151 *blacklist = talloc_zero_size(apn, len * sizeof(struct in46_prefix));
Harald Weltee2a1de52017-11-08 15:24:07 +0900152 len2 = netdev_ip_local_get(apn->tun.cfg.dev_name, *blacklist, len, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200153 if (len2 < 1) {
154 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900155 *blacklist = NULL;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200156 return len2;
157 }
158
Harald Weltee2a1de52017-11-08 15:24:07 +0900159 if (len2 > len) { /* iface was added between 2 calls, repeat operation */
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200160 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900161 *blacklist = NULL;
162 } else
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200163 break;
164 }
165
166 for (i = 0; i < len2; i++)
167 LOGPAPN(LOGL_INFO, apn, "Blacklist tun IP %s\n",
168 in46p_ntoa(&(*blacklist)[i]));
169
170 return len2;
171}
172
Harald Weltedda21ed2017-08-12 15:07:02 +0200173/* actually start the APN with its current config */
174int apn_start(struct apn_ctx *apn)
175{
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200176 int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST;
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200177 struct in46_prefix ipv6_tun_linklocal_ip;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200178 struct in46_prefix *blacklist;
179 int blacklist_size;
Harald Weltef2286392018-04-25 19:02:31 +0200180 struct gsn_t *gsn = apn->ggsn->gsn;
Pau Espin Pedrolbffc3f92017-12-14 11:19:10 +0100181 int rc;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200182
Harald Weltedda21ed2017-08-12 15:07:02 +0200183 if (apn->started)
184 return 0;
185
186 LOGPAPN(LOGL_INFO, apn, "Starting\n");
187 switch (apn->cfg.gtpu_mode) {
188 case APN_GTPU_MODE_TUN:
189 LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
Harald Weltef2286392018-04-25 19:02:31 +0200190 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200191 LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
192 return -1;
193 }
194 LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
195
196 /* Register with libosmcoore */
Harald Welte1719abb2020-10-18 22:38:20 +0200197 osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, OSMO_FD_READ, ggsn_tun_fd_cb, apn, 0);
Harald Weltedda21ed2017-08-12 15:07:02 +0200198 osmo_fd_register(&apn->tun.fd);
199
200 /* Set TUN library callback */
201 tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
Harald Weltedda21ed2017-08-12 15:07:02 +0200202 break;
203 case APN_GTPU_MODE_KERNEL_GTP:
Harald Welte2fc2bc62017-11-08 15:50:53 +0900204 LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
Harald Welte490782d2017-11-08 14:09:51 +0900205 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
206 LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200207 apn_stop(apn);
Harald Welte490782d2017-11-08 14:09:51 +0900208 return -1;
209 }
Harald Weltef2286392018-04-25 19:02:31 +0200210 if (gsn == NULL) {
Harald Welte07575042018-02-14 01:04:04 +0100211 /* skip bringing up the APN now if the GSN is not initialized yet.
212 * This happens during initial load of the config file, as the
213 * "no shutdown" in the ggsn node only happens after the "apn" nodes
214 * are brought up */
215 LOGPAPN(LOGL_NOTICE, apn, "Skipping APN start\n");
216 return 0;
217 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200218 /* use GTP kernel module for data packet encapsulation */
Harald Weltef2286392018-04-25 19:02:31 +0200219 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) {
220 LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n");
Harald Welte490782d2017-11-08 14:09:51 +0900221 return -1;
222 }
Harald Weltebed35df2011-11-02 13:06:18 +0100223 break;
224 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200225 LOGPAPN(LOGL_ERROR, apn, "Unknown GTPU Mode %d\n", apn->cfg.gtpu_mode);
226 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100227 }
jjako0141d202004-01-09 15:19:20 +0000228
Harald Weltef2286392018-04-25 19:02:31 +0200229 /* common initialization below */
230
231 /* set back-pointer from TUN device to APN */
232 apn->tun.tun->priv = apn;
233
234 if (apn->v4.cfg.ifconfig_prefix.addr.len) {
235 LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
236 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
237 if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
238 apn->v4.cfg.ifconfig_prefix.prefixlen)) {
239 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
240 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200241 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200242 return -1;
243 }
244 }
245
246 if (apn->v6.cfg.ifconfig_prefix.addr.len) {
247 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
248 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
249 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
250 apn->v6.cfg.ifconfig_prefix.prefixlen)) {
251 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
252 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
253 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200254 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200255 return -1;
256 }
257 }
258
259 if (apn->v6.cfg.ll_prefix.addr.len) {
260 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
261 in46p_ntoa(&apn->v6.cfg.ll_prefix));
262 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
263 apn->v6.cfg.ll_prefix.prefixlen)) {
264 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
265 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
266 in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200267 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200268 return -1;
269 }
270 apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
271 }
272
273 if (apn->tun.cfg.ipup_script) {
274 LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
275 apn->tun.cfg.ipup_script);
276 tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
277 }
278
279 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
280 apn->v6.cfg.ll_prefix.addr.len == 0) {
281 rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
282 if (rc < 1) {
283 LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
284 rc ? strerror(errno) : "tun interface has no link-local IP assigned");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200285 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200286 return -1;
287 }
288 apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
289 }
290
Harald Weltedda21ed2017-08-12 15:07:02 +0200291 /* Create IPv4 pool */
292 if (apn->v4.cfg.dynamic_prefix.addr.len) {
293 LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
294 in46p_ntoa(&apn->v4.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900295 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, false)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200296 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv4 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200297 if (ippool_new(&apn->v4.pool, &apn->v4.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200298 &apn->v4.cfg.static_prefix, ippool_flags,
299 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200300 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv4 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200301 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200302 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200303 return -1;
304 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200305 talloc_free(blacklist);
Harald Weltebed35df2011-11-02 13:06:18 +0100306 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200307
308 /* Create IPv6 pool */
309 if (apn->v6.cfg.dynamic_prefix.addr.len) {
310 LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n",
311 in46p_ntoa(&apn->v6.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900312 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, true)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200313 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv6 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200314 if (ippool_new(&apn->v6.pool, &apn->v6.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200315 &apn->v6.cfg.static_prefix, ippool_flags,
316 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200317 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv6 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200318 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200319 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200320 return -1;
321 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200322 talloc_free(blacklist);
Harald Weltedda21ed2017-08-12 15:07:02 +0200323 }
324
325 LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
326 apn->started = true;
327 return 0;
jjako0141d202004-01-09 15:19:20 +0000328}
jjako0141d202004-01-09 15:19:20 +0000329
Max3142d8d2017-05-04 17:45:10 +0200330static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
331{
Harald Welted12eab92017-08-02 19:49:47 +0200332 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200333 char val[NAMESIZE];
334
Harald Welted12eab92017-08-02 19:49:47 +0200335 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
336
Harald Welteb10ee082017-08-12 19:29:16 +0200337 snprintf(val, sizeof(val), "%s,%s", imsi_gtp2str(&pdp->imsi), addrstr);
Max3142d8d2017-05-04 17:45:10 +0200338
Harald Weltedda21ed2017-08-12 15:07:02 +0200339 if (ctrl_cmd_send_trap(g_ctrlh, var, val) < 0) {
340 LOGPPDP(LOGL_ERROR, pdp, "Failed to create and send TRAP %s\n", var);
Max3142d8d2017-05-04 17:45:10 +0200341 return false;
342 }
343 return true;
344}
345
Harald Weltedda21ed2017-08-12 15:07:02 +0200346static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +0100347{
Harald Weltedda21ed2017-08-12 15:07:02 +0200348 struct gsn_t *gsn = pdp->gsn;
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200349 struct pdp_priv_t *pdp_priv = pdp->priv;
350 struct apn_ctx *apn;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100351 struct ippoolm_t *member;
352 int i;
Harald Weltedda21ed2017-08-12 15:07:02 +0200353
354 LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
Maxdbd70242016-10-14 13:38:05 +0200355
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100356 for (i = 0; i < 2; i++) {
357 if (pdp->peer[i]) {
358 member = pdp->peer[i];
359 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
360 ippool_freeip(member->pool, member);
Pau Espin Pedrol3eb05d22019-08-28 11:17:08 +0200361 } else if (i == 0) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100362 LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
Pau Espin Pedrol3eb05d22019-08-28 11:17:08 +0200363 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100364 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100365
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200366 if (!pdp_priv) {
367 LOGPPDP(LOGL_NOTICE, pdp, "Deleting PDP context: without private structure!\n");
368 return 0;
369 }
370
371 /* Remove from SGSN */
372 sgsn_peer_remove_pdp_priv(pdp_priv);
373
374 apn = pdp_priv->apn;
Pau Espin Pedrold9501342019-08-21 15:24:29 +0200375 if (apn && apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
Harald Welte546884d2018-04-25 21:13:06 +0200376 if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
377 LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
378 strerror(errno));
379 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100380 }
381
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200382 talloc_free(pdp_priv);
383
Harald Weltebed35df2011-11-02 13:06:18 +0100384 return 0;
jjako52c24142002-12-16 13:33:51 +0000385}
386
Harald Welte9d9d91b2017-10-14 16:22:16 +0200387static bool apn_supports_ipv4(const struct apn_ctx *apn)
388{
389 if (apn->v4.cfg.static_prefix.addr.len || apn->v4.cfg.dynamic_prefix.addr.len)
390 return true;
391 return false;
392}
393
394static bool apn_supports_ipv6(const struct apn_ctx *apn)
395{
396 if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len)
397 return true;
398 return false;
399}
400
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200401static struct sgsn_peer* ggsn_find_sgsn(struct ggsn_ctx *ggsn, struct in_addr *peer_addr)
402{
403 struct sgsn_peer *sgsn;
404
405 llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry) {
406 if (memcmp(&sgsn->addr, peer_addr, sizeof(*peer_addr)) == 0)
407 return sgsn;
408 }
409 return NULL;
410}
411
412static struct sgsn_peer* ggsn_find_or_create_sgsn(struct ggsn_ctx *ggsn, struct pdp_t *pdp)
413{
414 struct sgsn_peer *sgsn;
415 struct in_addr ia;
416
417 if (gsna2in_addr(&ia, &pdp->gsnrc)) {
418 LOGPPDP(LOGL_ERROR, pdp, "Failed parsing gsnrc (len=%u) to discover SGSN\n",
419 pdp->gsnrc.l);
420 return NULL;
421 }
422
423 if ((sgsn = ggsn_find_sgsn(ggsn, &ia)))
424 return sgsn;
425
426 sgsn = sgsn_peer_allocate(ggsn, &ia, pdp->version);
427 llist_add(&sgsn->entry, &ggsn->sgsn_list);
428 return sgsn;
429}
430
Harald Weltebed35df2011-11-02 13:06:18 +0100431int create_context_ind(struct pdp_t *pdp)
432{
Harald Weltedda21ed2017-08-12 15:07:02 +0200433 static char name_buf[256];
434 struct gsn_t *gsn = pdp->gsn;
435 struct ggsn_ctx *ggsn = gsn->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100436 struct in46_addr addr[2];
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100437 struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
438 char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700439 struct apn_ctx *apn = NULL;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100440 int rc, num_addr, i;
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700441 char *apn_name;
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200442 struct sgsn_peer *sgsn;
443 struct pdp_priv_t *pdp_priv;
jjako52c24142002-12-16 13:33:51 +0000444
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700445 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
446 LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
447 apn_name ? name_buf : "(NONE)");
Harald Weltedda21ed2017-08-12 15:07:02 +0200448
449 /* First find an exact APN name match */
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700450 if (apn_name != NULL)
451 apn = ggsn_find_apn(ggsn, name_buf);
Harald Welte2e84d2c2017-10-01 13:36:52 +0800452 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200453 if (apn && !apn->started)
Harald Welte2e84d2c2017-10-01 13:36:52 +0800454 apn = NULL;
Harald Welteb16c46b2017-10-01 18:28:18 +0800455
Harald Weltedda21ed2017-08-12 15:07:02 +0200456 /* then try default (if any) */
457 if (!apn)
458 apn = ggsn->cfg.default_apn;
Harald Welteb16c46b2017-10-01 18:28:18 +0800459 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200460 if (apn && !apn->started)
Harald Welteb16c46b2017-10-01 18:28:18 +0800461 apn = NULL;
462
Harald Weltedda21ed2017-08-12 15:07:02 +0200463 if (!apn) {
464 /* no APN found for what user requested */
465 LOGPPDP(LOGL_NOTICE, pdp, "Unknown APN '%s', rejecting\n", name_buf);
466 gtp_create_context_resp(gsn, pdp, GTPCAUSE_MISSING_APN);
467 return 0;
468 }
jjako52c24142002-12-16 13:33:51 +0000469
Harald Welteecef9202021-03-27 19:00:34 +0100470 /* FIXME: implement context request for static IP addresses! */
471 if (pdp->eua.l > 2) {
472 LOGPPDP(LOGL_ERROR, pdp, "Static IP addresses not supported: %s\n",
473 osmo_hexdump(pdp->eua.v, pdp->eua.l));
474 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NOT_SUPPORTED);
475 return 0;
476 }
jjako52c24142002-12-16 13:33:51 +0000477
Harald Weltebed35df2011-11-02 13:06:18 +0100478 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000479
Harald Weltebed35df2011-11-02 13:06:18 +0100480 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
481 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000482
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100483 memset(addr, 0, sizeof(addr));
484 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200485 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200486 osmo_hexdump(pdp->eua.v, pdp->eua.l));
487 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
488 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100489 }
jjakoa7cd2492003-04-11 09:40:12 +0000490
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700491 /* Store the actual APN for logging and the VTY */
492 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
493 if (rc < 0) /* Unlikely this would happen, but anyway... */
494 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
495 pdp->apn_use.l = rc;
496
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100497 /* Allocate dynamic addresses from the pool */
498 for (i = 0; i < num_addr; i++) {
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200499 if (in46a_is_v4(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100500 /* does this APN actually have an IPv4 pool? */
501 if (!apn_supports_ipv4(apn))
502 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200503
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100504 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
505 if (rc < 0)
506 goto err_pool_full;
507 /* copy back */
508 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000509
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100510 addrv4 = member;
511
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200512 } else if (in46a_is_v6(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100513
514 /* does this APN actually have an IPv6 pool? */
515 if (!apn_supports_ipv6(apn))
516 goto err_wrong_af;
517
518 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
519 if (rc < 0)
520 goto err_pool_full;
521
522 /* IPv6 doesn't really send the real/allocated address at this point, but just
523 * the link-identifier which the MS shall use for router solicitation */
524 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
525 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
526 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
527 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100528
529 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100530 } else
531 OSMO_ASSERT(0);
532
533 pdp->peer[i] = member;
534 member->peer = pdp;
535 }
536
537 in46a_to_eua(addr, num_addr, &pdp->eua);
538
Harald Welte546884d2018-04-25 21:13:06 +0200539 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200540 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900541 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200542 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
543 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
544 return 0;
545 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100546 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200547
Harald Weltedda21ed2017-08-12 15:07:02 +0200548 pdp->ipif = apn->tun.tun; /* TODO */
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200549
550 pdp_priv = talloc_zero(ggsn, struct pdp_priv_t);
551 pdp->priv = pdp_priv;
552 pdp_priv->lib = pdp;
553 /* Create sgsn and assign pdp to it */
554 sgsn = ggsn_find_or_create_sgsn(ggsn, pdp);
555 sgsn_peer_add_pdp_priv(sgsn, pdp_priv);
556 pdp_priv->apn = apn;
Max3142d8d2017-05-04 17:45:10 +0200557
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100558 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200559 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200560 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
561 return 0;
562 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100563
Harald Weltedda21ed2017-08-12 15:07:02 +0200564 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200565
Harald Welte93fed3b2017-09-24 11:43:17 +0800566 /* Transmit G-PDU sequence numbers (only) if configured in APN */
567 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
568
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100569 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
570 name_buf, apn->cfg.name, pdp->teic_own,
571 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
572 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100573 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
574 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200575
576err_pool_full:
577 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
578 gtp_create_context_resp(gsn, pdp, -rc);
579 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200580
581err_wrong_af:
582 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
583 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
584 return 0;
jjako52c24142002-12-16 13:33:51 +0000585}
586
Harald Weltedda21ed2017-08-12 15:07:02 +0200587/* Internet-originated IP packet, needs to be sent via GTP towards MS */
588static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100589{
Harald Weltedda21ed2017-08-12 15:07:02 +0200590 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100591 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200592 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200593 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200594 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200595 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100596 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100597 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000598
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100599 switch (iph->version) {
600 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200601 if (len < sizeof(*iph) || len < 4*iph->ihl)
602 return -1;
603 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200604 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200605 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100606 break;
607 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200608 /* Due to the fact that 3GPP requires an allocation of a
609 * /64 prefix to each MS, we must instruct
610 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100611 * prefix, i.e. the first 8 bytes of the address. If the ll addr
612 * is used, then the match should be done on the trailing 64
613 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200614 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100615 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
616 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200617 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100618 break;
619 default:
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200620 LOGTUN(LOGL_NOTICE, tun, "non-IPv%u packet received\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200621 return -1;
622 }
jjakoc6762cf2004-04-28 14:52:58 +0000623
Harald Weltedda21ed2017-08-12 15:07:02 +0200624 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
625 if (!pool)
626 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100627
Harald Weltedda21ed2017-08-12 15:07:02 +0200628 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200629 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s) with no PDP contex! (%s)\n",
630 apn->cfg.name,
631 iph->version == 4 ?
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100632 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
633 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100634 return 0;
635 }
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200636 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s)\n", apn->cfg.name);
Harald Weltebed35df2011-11-02 13:06:18 +0100637
638 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200639 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100640 return 0;
jjako52c24142002-12-16 13:33:51 +0000641}
642
Harald Weltedda21ed2017-08-12 15:07:02 +0200643/* MS-originated GTP1-U packet, needs to be sent via TUN device */
644static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100645{
Harald Welted46bcd22017-08-08 23:27:22 +0200646 struct iphdr *iph = (struct iphdr *)pack;
647 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800648 struct tun_t *tun = (struct tun_t *)pdp->ipif;
649 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100650 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100651 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100652 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800653
654 OSMO_ASSERT(tun);
655 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200656
Max427699e2017-12-05 16:30:37 +0100657 LOGPPDP(LOGL_DEBUG, pdp, "Packet received on APN(%s): forwarding to tun %s\n", apn->cfg.name, tun->devname);
Harald Welted46bcd22017-08-08 23:27:22 +0200658
659 switch (iph->version) {
660 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100661 peer = pdp_get_peer_ipv(pdp, true);
662 if (!peer) {
663 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
664 osmo_hexdump(pack, len));
665 return -1;
666 }
667
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100668 /* Validate packet comes from IPaddr assigned to the pdp ctx.
669 If packet is a LL addr, then EUA is in the lower 64 bits,
670 otherwise it's used as the 64 prefix */
671 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
672 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
673 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
674 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
675 return -1;
676 }
677
Harald Welted46bcd22017-08-08 23:27:22 +0200678 /* daddr: all-routers multicast addr */
679 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100680 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
681 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200682 break;
683 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100684 peer = pdp_get_peer_ipv(pdp, false);
685 if (!peer) {
686 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
687 osmo_hexdump(pack, len));
688 return -1;
689 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100690
691 /* Validate packet comes from IPaddr assigned to the pdp ctx */
692 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
693 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
694 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
695 return -1;
696 }
Harald Welted46bcd22017-08-08 23:27:22 +0200697 break;
698 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200699 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
700 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +0200701 return -1;
702 }
Harald Weltebed35df2011-11-02 13:06:18 +0100703 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000704}
705
Harald Weltedda21ed2017-08-12 15:07:02 +0200706/* callback for tun device osmocom select loop integration */
707static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
708{
709 struct apn_ctx *apn = fd->data;
710
Harald Welte1719abb2020-10-18 22:38:20 +0200711 OSMO_ASSERT(what & OSMO_FD_READ);
Harald Weltedda21ed2017-08-12 15:07:02 +0200712
713 return tun_decaps(apn->tun.tun);
714}
715
716/* callback for libgtp osmocom select loop integration */
717static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
718{
719 struct ggsn_ctx *ggsn = fd->data;
720 int rc;
721
Harald Welte1719abb2020-10-18 22:38:20 +0200722 OSMO_ASSERT(what & OSMO_FD_READ);
Harald Weltedda21ed2017-08-12 15:07:02 +0200723
724 switch (fd->priv_nr) {
725 case 0:
726 rc = gtp_decaps0(ggsn->gsn);
727 break;
728 case 1:
729 rc = gtp_decaps1c(ggsn->gsn);
730 break;
731 case 2:
732 rc = gtp_decaps1u(ggsn->gsn);
733 break;
734 default:
735 OSMO_ASSERT(0);
736 break;
737 }
738 return rc;
739}
740
Oliver Smith1cde2c12019-05-13 11:35:03 +0200741/* libgtp callback for confirmations */
742static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
743{
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200744 struct sgsn_peer *sgsn;
Oliver Smith1cde2c12019-05-13 11:35:03 +0200745 int rc = 0;
746
747 if (cause == EOF)
748 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
749 type, pdp, cbp);
750
751 switch (type) {
752 case GTP_DELETE_PDP_REQ:
753 /* Remark: We actually never reach this path nowadays because
754 only place where we call gtp_delete_context_req2() is during
Pau Espin Pedrol26e300f2019-08-29 14:02:28 +0200755 ggsn_close_one_pdp() path, and in that case we free all pdp
756 contexts immediatelly without waiting for confirmation
757 (through gtp_freepdp_teardown()) since we want to tear down
758 the whole APN anyways. As a result, DeleteCtxResponse will
759 never reach here since it will be dropped at some point in
760 lower layers in the Rx path. This code is nevertheless left
761 here in order to ease future developent and avoid possible
762 future memleaks once more scenarios where GGSN sends a
763 DeleteCtxRequest are introduced. */
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200764 if (pdp)
Pau Espin Pedrol26e300f2019-08-29 14:02:28 +0200765 rc = gtp_freepdp(pdp->gsn, pdp);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200766 break;
767 case GTP_ECHO_REQ:
768 sgsn = (struct sgsn_peer *)cbp;
769 sgsn_peer_echo_resp(sgsn, cause == EOF);
770 break;
Oliver Smith1cde2c12019-05-13 11:35:03 +0200771 }
772 return rc;
773}
Harald Weltedda21ed2017-08-12 15:07:02 +0200774
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200775static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
776{
777 struct ggsn_ctx *ggsn = (struct ggsn_ctx *)gsn->priv;
778 struct sgsn_peer *sgsn;
779
780 sgsn = ggsn_find_sgsn(ggsn, &peer->sin_addr);
781 if (!sgsn) {
782 LOGPGGSN(LOGL_NOTICE, ggsn, "Received Recovery IE for unknown SGSN (no PDP contexts active)\n");
783 return -EINVAL;
784 }
785
786 return sgsn_peer_handle_recovery(sgsn, pdp, recovery);
787}
788
Harald Weltedda21ed2017-08-12 15:07:02 +0200789/* Start a given GGSN */
790int ggsn_start(struct ggsn_ctx *ggsn)
791{
792 struct apn_ctx *apn;
793 int rc;
794
795 if (ggsn->started)
796 return 0;
797
798 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
799
800 /* Start libgtp listener */
801 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
802 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
803 return -1;
804 }
805 ggsn->gsn->priv = ggsn;
806
Harald Welte98146772017-09-05 17:41:20 +0200807 /* patch in different addresses to use (in case we're behind NAT, the listen
808 * address is different from what we advertise externally) */
809 if (ggsn->cfg.gtpc_addr.v4.s_addr)
810 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
811
812 if (ggsn->cfg.gtpu_addr.v4.s_addr)
813 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
814
Harald Weltedda21ed2017-08-12 15:07:02 +0200815 /* Register File Descriptors */
Harald Welte1719abb2020-10-18 22:38:20 +0200816 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
Harald Weltedda21ed2017-08-12 15:07:02 +0200817 rc = osmo_fd_register(&ggsn->gtp_fd0);
818 OSMO_ASSERT(rc == 0);
819
Harald Welte1719abb2020-10-18 22:38:20 +0200820 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
Harald Weltedda21ed2017-08-12 15:07:02 +0200821 rc = osmo_fd_register(&ggsn->gtp_fd1c);
822 OSMO_ASSERT(rc == 0);
823
Harald Welte1719abb2020-10-18 22:38:20 +0200824 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
Harald Weltedda21ed2017-08-12 15:07:02 +0200825 rc = osmo_fd_register(&ggsn->gtp_fd1u);
826 OSMO_ASSERT(rc == 0);
827
Harald Weltedda21ed2017-08-12 15:07:02 +0200828 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
829 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
830 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +0200831 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200832 gtp_set_cb_recovery3(ggsn->gsn, cb_recovery3);
Harald Weltedda21ed2017-08-12 15:07:02 +0200833
834 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
835 ggsn->started = true;
836
837 llist_for_each_entry(apn, &ggsn->apn_list, list)
838 apn_start(apn);
839
840 return 0;
841}
842
843/* Stop a given GGSN */
844int ggsn_stop(struct ggsn_ctx *ggsn)
845{
846 struct apn_ctx *apn;
847
848 if (!ggsn->started)
849 return 0;
850
851 /* iterate over all APNs and stop them */
852 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200853 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200854
Harald Weltedda21ed2017-08-12 15:07:02 +0200855 osmo_fd_unregister(&ggsn->gtp_fd1u);
856 osmo_fd_unregister(&ggsn->gtp_fd1c);
857 osmo_fd_unregister(&ggsn->gtp_fd0);
858
859 if (ggsn->gsn) {
860 gtp_free(ggsn->gsn);
861 ggsn->gsn = NULL;
862 }
863
864 ggsn->started = false;
865 return 0;
866}