blob: 94f47e3fa053e4d1333e1975703586ca73f07d57 [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"
Harald Welted46bcd22017-08-08 23:27:22 +020057#include "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
Harald Weltedda21ed2017-08-12 15:07:02 +020064static void pool_close_all_pdp(struct ippool_t *pool)
Harald Weltebed35df2011-11-02 13:06:18 +010065{
Harald Weltedda21ed2017-08-12 15:07:02 +020066 unsigned int i;
jjako52c24142002-12-16 13:33:51 +000067
Harald Weltedda21ed2017-08-12 15:07:02 +020068 if (!pool)
Harald Weltebed35df2011-11-02 13:06:18 +010069 return;
Harald Weltedda21ed2017-08-12 15:07:02 +020070
71 for (i = 0; i < pool->listsize; i++) {
72 struct ippoolm_t *member = &pool->member[i];
73 struct pdp_t *pdp;
74
75 if (!member->inuse)
76 continue;
77 pdp = member->peer;
78 if (!pdp)
79 continue;
80 LOGPPDP(LOGL_DEBUG, pdp, "Sending DELETE PDP CTX due to shutdown\n");
Oliver Smith1cde2c12019-05-13 11:35:03 +020081 gtp_delete_context_req2(pdp->gsn, pdp, NULL, 1);
82 /* We have nothing more to do with pdp ctx, free it. Upon cb_delete_context
83 called during this call we'll clean up ggsn related stuff attached to this
84 pdp context. After this call, ippool member is cleared so
85 data is no longer valid and should not be accessed anymore. */
86 gtp_freepdp_teardown(pdp->gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +010087 }
jjako52c24142002-12-16 13:33:51 +000088}
89
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +020090int apn_stop(struct apn_ctx *apn)
Harald Weltebed35df2011-11-02 13:06:18 +010091{
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +020092 LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
Harald Weltedda21ed2017-08-12 15:07:02 +020093 /* check if pools have any active PDP contexts and bail out */
94 pool_close_all_pdp(apn->v4.pool);
95 pool_close_all_pdp(apn->v6.pool);
96
97 /* shutdown whatever old state might be left */
98 if (apn->tun.tun) {
99 /* run ip-down script */
100 if (apn->tun.cfg.ipdown_script) {
101 LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
102 tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
103 }
Harald Weltef2286392018-04-25 19:02:31 +0200104 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
105 /* release tun device */
106 LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
107 osmo_fd_unregister(&apn->tun.fd);
108 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200109 tun_free(apn->tun.tun);
110 apn->tun.tun = NULL;
111 }
112
113 if (apn->v4.pool) {
114 LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
115 ippool_free(apn->v4.pool);
116 apn->v4.pool = NULL;
117 }
118 if (apn->v6.pool) {
119 LOGPAPN(LOGL_INFO, apn, "Releasing IPv6 pool\n");
120 ippool_free(apn->v6.pool);
121 apn->v6.pool = NULL;
122 }
123
124 apn->started = false;
125 return 0;
126}
127
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200128
Harald Weltef55a0392017-11-08 14:33:55 +0900129static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blacklist, bool ipv6)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200130{
131
132 int flags, len, len2, i;
133
Harald Weltee2a1de52017-11-08 15:24:07 +0900134 *blacklist = NULL;
135
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200136 if (ipv6)
137 flags = IP_TYPE_IPv6_NONLINK;
138 else
139 flags = IP_TYPE_IPv4;
140
141 while (1) {
Harald Weltee2a1de52017-11-08 15:24:07 +0900142 len = netdev_ip_local_get(apn->tun.cfg.dev_name, NULL, 0, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200143 if (len < 1)
144 return len;
145
146 *blacklist = talloc_zero_size(apn, len * sizeof(struct in46_prefix));
Harald Weltee2a1de52017-11-08 15:24:07 +0900147 len2 = netdev_ip_local_get(apn->tun.cfg.dev_name, *blacklist, len, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200148 if (len2 < 1) {
149 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900150 *blacklist = NULL;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200151 return len2;
152 }
153
Harald Weltee2a1de52017-11-08 15:24:07 +0900154 if (len2 > len) { /* iface was added between 2 calls, repeat operation */
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200155 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900156 *blacklist = NULL;
157 } else
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200158 break;
159 }
160
161 for (i = 0; i < len2; i++)
162 LOGPAPN(LOGL_INFO, apn, "Blacklist tun IP %s\n",
163 in46p_ntoa(&(*blacklist)[i]));
164
165 return len2;
166}
167
Harald Weltedda21ed2017-08-12 15:07:02 +0200168/* actually start the APN with its current config */
169int apn_start(struct apn_ctx *apn)
170{
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200171 int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST;
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200172 struct in46_prefix ipv6_tun_linklocal_ip;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200173 struct in46_prefix *blacklist;
174 int blacklist_size;
Harald Weltef2286392018-04-25 19:02:31 +0200175 struct gsn_t *gsn = apn->ggsn->gsn;
Pau Espin Pedrolbffc3f92017-12-14 11:19:10 +0100176 int rc;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200177
Harald Weltedda21ed2017-08-12 15:07:02 +0200178 if (apn->started)
179 return 0;
180
181 LOGPAPN(LOGL_INFO, apn, "Starting\n");
182 switch (apn->cfg.gtpu_mode) {
183 case APN_GTPU_MODE_TUN:
184 LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
Harald Weltef2286392018-04-25 19:02:31 +0200185 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200186 LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
187 return -1;
188 }
189 LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
190
191 /* Register with libosmcoore */
192 osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, BSC_FD_READ, ggsn_tun_fd_cb, apn, 0);
193 osmo_fd_register(&apn->tun.fd);
194
195 /* Set TUN library callback */
196 tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
Harald Weltedda21ed2017-08-12 15:07:02 +0200197 break;
198 case APN_GTPU_MODE_KERNEL_GTP:
Harald Welte2fc2bc62017-11-08 15:50:53 +0900199 LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
Harald Welte490782d2017-11-08 14:09:51 +0900200 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
201 LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200202 apn_stop(apn);
Harald Welte490782d2017-11-08 14:09:51 +0900203 return -1;
204 }
Harald Weltef2286392018-04-25 19:02:31 +0200205 if (gsn == NULL) {
Harald Welte07575042018-02-14 01:04:04 +0100206 /* skip bringing up the APN now if the GSN is not initialized yet.
207 * This happens during initial load of the config file, as the
208 * "no shutdown" in the ggsn node only happens after the "apn" nodes
209 * are brought up */
210 LOGPAPN(LOGL_NOTICE, apn, "Skipping APN start\n");
211 return 0;
212 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200213 /* use GTP kernel module for data packet encapsulation */
Harald Weltef2286392018-04-25 19:02:31 +0200214 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) {
215 LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n");
Harald Welte490782d2017-11-08 14:09:51 +0900216 return -1;
217 }
Harald Weltebed35df2011-11-02 13:06:18 +0100218 break;
219 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200220 LOGPAPN(LOGL_ERROR, apn, "Unknown GTPU Mode %d\n", apn->cfg.gtpu_mode);
221 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100222 }
jjako0141d202004-01-09 15:19:20 +0000223
Harald Weltef2286392018-04-25 19:02:31 +0200224 /* common initialization below */
225
226 /* set back-pointer from TUN device to APN */
227 apn->tun.tun->priv = apn;
228
229 if (apn->v4.cfg.ifconfig_prefix.addr.len) {
230 LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
231 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
232 if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
233 apn->v4.cfg.ifconfig_prefix.prefixlen)) {
234 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
235 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200236 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200237 return -1;
238 }
239 }
240
241 if (apn->v6.cfg.ifconfig_prefix.addr.len) {
242 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
243 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
244 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
245 apn->v6.cfg.ifconfig_prefix.prefixlen)) {
246 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
247 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
248 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200249 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200250 return -1;
251 }
252 }
253
254 if (apn->v6.cfg.ll_prefix.addr.len) {
255 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
256 in46p_ntoa(&apn->v6.cfg.ll_prefix));
257 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
258 apn->v6.cfg.ll_prefix.prefixlen)) {
259 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
260 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
261 in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200262 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200263 return -1;
264 }
265 apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
266 }
267
268 if (apn->tun.cfg.ipup_script) {
269 LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
270 apn->tun.cfg.ipup_script);
271 tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
272 }
273
274 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
275 apn->v6.cfg.ll_prefix.addr.len == 0) {
276 rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
277 if (rc < 1) {
278 LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
279 rc ? strerror(errno) : "tun interface has no link-local IP assigned");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200280 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200281 return -1;
282 }
283 apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
284 }
285
Harald Weltedda21ed2017-08-12 15:07:02 +0200286 /* Create IPv4 pool */
287 if (apn->v4.cfg.dynamic_prefix.addr.len) {
288 LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
289 in46p_ntoa(&apn->v4.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900290 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, false)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200291 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv4 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200292 if (ippool_new(&apn->v4.pool, &apn->v4.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200293 &apn->v4.cfg.static_prefix, ippool_flags,
294 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200295 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv4 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200296 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200297 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200298 return -1;
299 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200300 talloc_free(blacklist);
Harald Weltebed35df2011-11-02 13:06:18 +0100301 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200302
303 /* Create IPv6 pool */
304 if (apn->v6.cfg.dynamic_prefix.addr.len) {
305 LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n",
306 in46p_ntoa(&apn->v6.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900307 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, true)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200308 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv6 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200309 if (ippool_new(&apn->v6.pool, &apn->v6.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200310 &apn->v6.cfg.static_prefix, ippool_flags,
311 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200312 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv6 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200313 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200314 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200315 return -1;
316 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200317 talloc_free(blacklist);
Harald Weltedda21ed2017-08-12 15:07:02 +0200318 }
319
320 LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
321 apn->started = true;
322 return 0;
jjako0141d202004-01-09 15:19:20 +0000323}
jjako0141d202004-01-09 15:19:20 +0000324
Max3142d8d2017-05-04 17:45:10 +0200325static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
326{
Harald Welted12eab92017-08-02 19:49:47 +0200327 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200328 char val[NAMESIZE];
329
Harald Welted12eab92017-08-02 19:49:47 +0200330 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
331
Harald Welteb10ee082017-08-12 19:29:16 +0200332 snprintf(val, sizeof(val), "%s,%s", imsi_gtp2str(&pdp->imsi), addrstr);
Max3142d8d2017-05-04 17:45:10 +0200333
Harald Weltedda21ed2017-08-12 15:07:02 +0200334 if (ctrl_cmd_send_trap(g_ctrlh, var, val) < 0) {
335 LOGPPDP(LOGL_ERROR, pdp, "Failed to create and send TRAP %s\n", var);
Max3142d8d2017-05-04 17:45:10 +0200336 return false;
337 }
338 return true;
339}
340
Harald Weltedda21ed2017-08-12 15:07:02 +0200341static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +0100342{
Harald Weltedda21ed2017-08-12 15:07:02 +0200343 struct gsn_t *gsn = pdp->gsn;
Harald Welte698a2332017-11-08 15:09:58 +0900344 struct apn_ctx *apn = pdp->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100345 struct ippoolm_t *member;
346 int i;
Harald Weltedda21ed2017-08-12 15:07:02 +0200347
348 LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
Maxdbd70242016-10-14 13:38:05 +0200349
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100350 for (i = 0; i < 2; i++) {
351 if (pdp->peer[i]) {
352 member = pdp->peer[i];
353 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
354 ippool_freeip(member->pool, member);
355 } else if(i == 0)
356 LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
357 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100358
Pau Espin Pedrold9501342019-08-21 15:24:29 +0200359 if (apn && apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
Harald Welte546884d2018-04-25 21:13:06 +0200360 if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
361 LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
362 strerror(errno));
363 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100364 }
365
Harald Weltebed35df2011-11-02 13:06:18 +0100366 return 0;
jjako52c24142002-12-16 13:33:51 +0000367}
368
Harald Welte9d9d91b2017-10-14 16:22:16 +0200369static bool apn_supports_ipv4(const struct apn_ctx *apn)
370{
371 if (apn->v4.cfg.static_prefix.addr.len || apn->v4.cfg.dynamic_prefix.addr.len)
372 return true;
373 return false;
374}
375
376static bool apn_supports_ipv6(const struct apn_ctx *apn)
377{
378 if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len)
379 return true;
380 return false;
381}
382
Harald Weltebed35df2011-11-02 13:06:18 +0100383int create_context_ind(struct pdp_t *pdp)
384{
Harald Weltedda21ed2017-08-12 15:07:02 +0200385 static char name_buf[256];
386 struct gsn_t *gsn = pdp->gsn;
387 struct ggsn_ctx *ggsn = gsn->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100388 struct in46_addr addr[2];
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100389 struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
390 char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700391 struct apn_ctx *apn = NULL;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100392 int rc, num_addr, i;
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700393 char *apn_name;
jjako52c24142002-12-16 13:33:51 +0000394
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700395 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
396 LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
397 apn_name ? name_buf : "(NONE)");
Harald Weltedda21ed2017-08-12 15:07:02 +0200398
399 /* First find an exact APN name match */
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700400 if (apn_name != NULL)
401 apn = ggsn_find_apn(ggsn, name_buf);
Harald Welte2e84d2c2017-10-01 13:36:52 +0800402 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200403 if (apn && !apn->started)
Harald Welte2e84d2c2017-10-01 13:36:52 +0800404 apn = NULL;
Harald Welteb16c46b2017-10-01 18:28:18 +0800405
Harald Weltedda21ed2017-08-12 15:07:02 +0200406 /* then try default (if any) */
407 if (!apn)
408 apn = ggsn->cfg.default_apn;
Harald Welteb16c46b2017-10-01 18:28:18 +0800409 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200410 if (apn && !apn->started)
Harald Welteb16c46b2017-10-01 18:28:18 +0800411 apn = NULL;
412
Harald Weltedda21ed2017-08-12 15:07:02 +0200413 if (!apn) {
414 /* no APN found for what user requested */
415 LOGPPDP(LOGL_NOTICE, pdp, "Unknown APN '%s', rejecting\n", name_buf);
416 gtp_create_context_resp(gsn, pdp, GTPCAUSE_MISSING_APN);
417 return 0;
418 }
jjako52c24142002-12-16 13:33:51 +0000419
Harald Welted9d88622017-08-04 00:22:35 +0200420 /* FIXME: we manually force all context requests to dynamic here! */
421 if (pdp->eua.l > 2)
422 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000423
Harald Weltebed35df2011-11-02 13:06:18 +0100424 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000425
Harald Weltebed35df2011-11-02 13:06:18 +0100426 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
427 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000428
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100429 memset(addr, 0, sizeof(addr));
430 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200431 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200432 osmo_hexdump(pdp->eua.v, pdp->eua.l));
433 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
434 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100435 }
jjakoa7cd2492003-04-11 09:40:12 +0000436
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700437 /* Store the actual APN for logging and the VTY */
438 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
439 if (rc < 0) /* Unlikely this would happen, but anyway... */
440 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
441 pdp->apn_use.l = rc;
442
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100443 /* Allocate dynamic addresses from the pool */
444 for (i = 0; i < num_addr; i++) {
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200445 if (in46a_is_v4(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100446 /* does this APN actually have an IPv4 pool? */
447 if (!apn_supports_ipv4(apn))
448 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200449
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100450 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
451 if (rc < 0)
452 goto err_pool_full;
453 /* copy back */
454 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000455
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100456 addrv4 = member;
457
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200458 } else if (in46a_is_v6(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100459
460 /* does this APN actually have an IPv6 pool? */
461 if (!apn_supports_ipv6(apn))
462 goto err_wrong_af;
463
464 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
465 if (rc < 0)
466 goto err_pool_full;
467
468 /* IPv6 doesn't really send the real/allocated address at this point, but just
469 * the link-identifier which the MS shall use for router solicitation */
470 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
471 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
472 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
473 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100474
475 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100476 } else
477 OSMO_ASSERT(0);
478
479 pdp->peer[i] = member;
480 member->peer = pdp;
481 }
482
483 in46a_to_eua(addr, num_addr, &pdp->eua);
484
Harald Welte546884d2018-04-25 21:13:06 +0200485 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200486 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900487 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200488 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
489 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
490 return 0;
491 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100492 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200493
Harald Weltedda21ed2017-08-12 15:07:02 +0200494 pdp->ipif = apn->tun.tun; /* TODO */
Harald Welte698a2332017-11-08 15:09:58 +0900495 pdp->priv = apn;
Max3142d8d2017-05-04 17:45:10 +0200496
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100497 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200498 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200499 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
500 return 0;
501 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100502
Harald Weltedda21ed2017-08-12 15:07:02 +0200503 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200504
Harald Welte93fed3b2017-09-24 11:43:17 +0800505 /* Transmit G-PDU sequence numbers (only) if configured in APN */
506 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
507
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100508 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
509 name_buf, apn->cfg.name, pdp->teic_own,
510 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
511 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100512 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
513 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200514
515err_pool_full:
516 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
517 gtp_create_context_resp(gsn, pdp, -rc);
518 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200519
520err_wrong_af:
521 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
522 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
523 return 0;
jjako52c24142002-12-16 13:33:51 +0000524}
525
Harald Weltedda21ed2017-08-12 15:07:02 +0200526/* Internet-originated IP packet, needs to be sent via GTP towards MS */
527static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100528{
Harald Weltedda21ed2017-08-12 15:07:02 +0200529 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100530 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200531 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200532 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200533 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200534 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100535 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100536 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000537
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100538 switch (iph->version) {
539 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200540 if (len < sizeof(*iph) || len < 4*iph->ihl)
541 return -1;
542 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200543 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200544 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100545 break;
546 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200547 /* Due to the fact that 3GPP requires an allocation of a
548 * /64 prefix to each MS, we must instruct
549 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100550 * prefix, i.e. the first 8 bytes of the address. If the ll addr
551 * is used, then the match should be done on the trailing 64
552 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200553 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100554 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
555 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200556 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100557 break;
558 default:
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200559 LOGTUN(LOGL_NOTICE, tun, "non-IPv%u packet received\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200560 return -1;
561 }
jjakoc6762cf2004-04-28 14:52:58 +0000562
Harald Weltedda21ed2017-08-12 15:07:02 +0200563 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
564 if (!pool)
565 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100566
Harald Weltedda21ed2017-08-12 15:07:02 +0200567 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200568 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s) with no PDP contex! (%s)\n",
569 apn->cfg.name,
570 iph->version == 4 ?
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100571 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
572 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100573 return 0;
574 }
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200575 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s)\n", apn->cfg.name);
Harald Weltebed35df2011-11-02 13:06:18 +0100576
577 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200578 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100579 return 0;
jjako52c24142002-12-16 13:33:51 +0000580}
581
Harald Welted46bcd22017-08-08 23:27:22 +0200582/* RFC3307 link-local scope multicast address */
583static const struct in6_addr all_router_mcast_addr = {
584 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
585};
586
Harald Weltedda21ed2017-08-12 15:07:02 +0200587/* MS-originated GTP1-U packet, needs to be sent via TUN device */
588static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100589{
Harald Welted46bcd22017-08-08 23:27:22 +0200590 struct iphdr *iph = (struct iphdr *)pack;
591 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800592 struct tun_t *tun = (struct tun_t *)pdp->ipif;
593 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100594 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100595 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100596 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800597
598 OSMO_ASSERT(tun);
599 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200600
Max427699e2017-12-05 16:30:37 +0100601 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 +0200602
603 switch (iph->version) {
604 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100605 peer = pdp_get_peer_ipv(pdp, true);
606 if (!peer) {
607 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
608 osmo_hexdump(pack, len));
609 return -1;
610 }
611
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100612 /* Validate packet comes from IPaddr assigned to the pdp ctx.
613 If packet is a LL addr, then EUA is in the lower 64 bits,
614 otherwise it's used as the 64 prefix */
615 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
616 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
617 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
618 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
619 return -1;
620 }
621
Harald Welted46bcd22017-08-08 23:27:22 +0200622 /* daddr: all-routers multicast addr */
623 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100624 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
625 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200626 break;
627 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100628 peer = pdp_get_peer_ipv(pdp, false);
629 if (!peer) {
630 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
631 osmo_hexdump(pack, len));
632 return -1;
633 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100634
635 /* Validate packet comes from IPaddr assigned to the pdp ctx */
636 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
637 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
638 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
639 return -1;
640 }
Harald Welted46bcd22017-08-08 23:27:22 +0200641 break;
642 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200643 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
644 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +0200645 return -1;
646 }
Harald Weltebed35df2011-11-02 13:06:18 +0100647 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000648}
649
Harald Weltedda21ed2017-08-12 15:07:02 +0200650/* callback for tun device osmocom select loop integration */
651static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
652{
653 struct apn_ctx *apn = fd->data;
654
655 OSMO_ASSERT(what & BSC_FD_READ);
656
657 return tun_decaps(apn->tun.tun);
658}
659
660/* callback for libgtp osmocom select loop integration */
661static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
662{
663 struct ggsn_ctx *ggsn = fd->data;
664 int rc;
665
666 OSMO_ASSERT(what & BSC_FD_READ);
667
668 switch (fd->priv_nr) {
669 case 0:
670 rc = gtp_decaps0(ggsn->gsn);
671 break;
672 case 1:
673 rc = gtp_decaps1c(ggsn->gsn);
674 break;
675 case 2:
676 rc = gtp_decaps1u(ggsn->gsn);
677 break;
678 default:
679 OSMO_ASSERT(0);
680 break;
681 }
682 return rc;
683}
684
685static void ggsn_gtp_tmr_start(struct ggsn_ctx *ggsn)
686{
687 struct timeval next;
688
689 /* Retrieve next retransmission as timeval */
690 gtp_retranstimeout(ggsn->gsn, &next);
691
692 /* re-schedule the timer */
693 osmo_timer_schedule(&ggsn->gtp_timer, next.tv_sec, next.tv_usec/1000);
694}
695
696/* timer callback for libgtp retransmission and ping */
697static void ggsn_gtp_tmr_cb(void *data)
698{
699 struct ggsn_ctx *ggsn = data;
700
701 /* do all the retransmissions as needed */
702 gtp_retrans(ggsn->gsn);
703
704 ggsn_gtp_tmr_start(ggsn);
705}
706
Oliver Smith1cde2c12019-05-13 11:35:03 +0200707/* libgtp callback for confirmations */
708static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
709{
710 int rc = 0;
711
712 if (cause == EOF)
713 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
714 type, pdp, cbp);
715
716 switch (type) {
717 case GTP_DELETE_PDP_REQ:
718 /* Remark: We actually never reach this path nowadays because
719 only place where we call gtp_delete_context_req2() is during
720 apn_stop()->pool_close_all_pdp() path, and in that case we
721 free all pdp contexts immediatelly without waiting for
722 confirmation since we want to tear down the whole APN
723 anyways. As a result, DeleteCtxResponse will never reach here
724 since it will be dropped at some point in lower layers in the
725 Rx path. This code is nevertheless left here in order to ease
726 future developent and avoid possible future memleaks once more
727 scenarios where GGSN sends a DeleteCtxRequest are introduced. */
728 if (pdp)
729 rc = pdp_freepdp(pdp);
730 }
731 return rc;
732}
Harald Weltedda21ed2017-08-12 15:07:02 +0200733
734/* Start a given GGSN */
735int ggsn_start(struct ggsn_ctx *ggsn)
736{
737 struct apn_ctx *apn;
738 int rc;
739
740 if (ggsn->started)
741 return 0;
742
743 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
744
745 /* Start libgtp listener */
746 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
747 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
748 return -1;
749 }
750 ggsn->gsn->priv = ggsn;
751
Harald Welte98146772017-09-05 17:41:20 +0200752 /* patch in different addresses to use (in case we're behind NAT, the listen
753 * address is different from what we advertise externally) */
754 if (ggsn->cfg.gtpc_addr.v4.s_addr)
755 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
756
757 if (ggsn->cfg.gtpu_addr.v4.s_addr)
758 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
759
Harald Weltedda21ed2017-08-12 15:07:02 +0200760 /* Register File Descriptors */
761 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
762 rc = osmo_fd_register(&ggsn->gtp_fd0);
763 OSMO_ASSERT(rc == 0);
764
765 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
766 rc = osmo_fd_register(&ggsn->gtp_fd1c);
767 OSMO_ASSERT(rc == 0);
768
769 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
770 rc = osmo_fd_register(&ggsn->gtp_fd1u);
771 OSMO_ASSERT(rc == 0);
772
773 /* Start GTP re-transmission timer */
774 osmo_timer_setup(&ggsn->gtp_timer, ggsn_gtp_tmr_cb, ggsn);
Pau Espin Pedrolcd87c5f2019-05-27 16:35:00 +0200775 ggsn_gtp_tmr_start(ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200776
777 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
778 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
779 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +0200780 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Harald Weltedda21ed2017-08-12 15:07:02 +0200781
782 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
783 ggsn->started = true;
784
785 llist_for_each_entry(apn, &ggsn->apn_list, list)
786 apn_start(apn);
787
788 return 0;
789}
790
791/* Stop a given GGSN */
792int ggsn_stop(struct ggsn_ctx *ggsn)
793{
794 struct apn_ctx *apn;
795
796 if (!ggsn->started)
797 return 0;
798
799 /* iterate over all APNs and stop them */
800 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200801 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200802
803 osmo_timer_del(&ggsn->gtp_timer);
804
805 osmo_fd_unregister(&ggsn->gtp_fd1u);
806 osmo_fd_unregister(&ggsn->gtp_fd1c);
807 osmo_fd_unregister(&ggsn->gtp_fd0);
808
809 if (ggsn->gsn) {
810 gtp_free(ggsn->gsn);
811 ggsn->gsn = NULL;
812 }
813
814 ggsn->started = false;
815 return 0;
816}