blob: 968d4dd8a4f052a0f341f3e1d0e45f4a41e0bb68 [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/application.h>
Max727417d2016-08-02 17:10:38 +020046#include <osmocom/core/select.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020047#include <osmocom/core/stats.h>
48#include <osmocom/core/rate_ctr.h>
49#include <osmocom/core/timer.h>
Harald Welte7bdc80d2019-04-11 18:47:59 +020050#include <osmocom/core/utils.h>
Max727417d2016-08-02 17:10:38 +020051#include <osmocom/ctrl/control_if.h>
52#include <osmocom/ctrl/control_cmd.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020053#include <osmocom/ctrl/control_vty.h>
Max727417d2016-08-02 17:10:38 +020054#include <osmocom/ctrl/ports.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020055#include <osmocom/vty/telnet_interface.h>
56#include <osmocom/vty/logging.h>
57#include <osmocom/vty/stats.h>
58#include <osmocom/vty/ports.h>
59#include <osmocom/vty/command.h>
Harald Welte3e443ca2018-02-14 01:04:04 +010060#include <osmocom/vty/misc.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020061#include <osmocom/gsm/apn.h>
Max727417d2016-08-02 17:10:38 +020062
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020063#include "../lib/tun.h"
64#include "../lib/ippool.h"
65#include "../lib/syserr.h"
Harald Welted12eab92017-08-02 19:49:47 +020066#include "../lib/in46_addr.h"
Harald Weltef2286392018-04-25 19:02:31 +020067#include "../lib/gtp-kernel.h"
jjako52c24142002-12-16 13:33:51 +000068#include "../gtp/pdp.h"
69#include "../gtp/gtp.h"
Harald Welted46bcd22017-08-08 23:27:22 +020070#include "icmpv6.h"
Harald Weltedda21ed2017-08-12 15:07:02 +020071#include "ggsn.h"
jjako52c24142002-12-16 13:33:51 +000072
Harald Weltedda21ed2017-08-12 15:07:02 +020073void *tall_ggsn_ctx;
jjakoa7cd2492003-04-11 09:40:12 +000074
Harald Weltedda21ed2017-08-12 15:07:02 +020075static int end = 0;
76static int daemonize = 0;
77static struct ctrl_handle *g_ctrlh;
78
jjakoa7cd2492003-04-11 09:40:12 +000079struct ul255_t qos;
80struct ul255_t apn;
81
Harald Weltedda21ed2017-08-12 15:07:02 +020082#define LOGPAPN(level, apn, fmt, args...) \
83 LOGP(DGGSN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args)
jjako52c24142002-12-16 13:33:51 +000084
Harald Weltedda21ed2017-08-12 15:07:02 +020085#define LOGPGGSN(level, ggsn, fmt, args...) \
86 LOGP(DGGSN, level, "GGSN(%s): " fmt, (ggsn)->cfg.name, ## args)
87
Max6a215272017-09-25 10:35:34 +020088#define LOGPPDP(level, pdp, fmt, args...) LOGPDPX(DGGSN, level, pdp, fmt, ## args)
Harald Weltedda21ed2017-08-12 15:07:02 +020089
90static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what);
91static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len);
92
93
94static void pool_close_all_pdp(struct ippool_t *pool)
Harald Weltebed35df2011-11-02 13:06:18 +010095{
Harald Weltedda21ed2017-08-12 15:07:02 +020096 unsigned int i;
jjako52c24142002-12-16 13:33:51 +000097
Harald Weltedda21ed2017-08-12 15:07:02 +020098 if (!pool)
Harald Weltebed35df2011-11-02 13:06:18 +010099 return;
Harald Weltedda21ed2017-08-12 15:07:02 +0200100
101 for (i = 0; i < pool->listsize; i++) {
102 struct ippoolm_t *member = &pool->member[i];
103 struct pdp_t *pdp;
104
105 if (!member->inuse)
106 continue;
107 pdp = member->peer;
108 if (!pdp)
109 continue;
110 LOGPPDP(LOGL_DEBUG, pdp, "Sending DELETE PDP CTX due to shutdown\n");
Oliver Smith1cde2c12019-05-13 11:35:03 +0200111 gtp_delete_context_req2(pdp->gsn, pdp, NULL, 1);
112 /* We have nothing more to do with pdp ctx, free it. Upon cb_delete_context
113 called during this call we'll clean up ggsn related stuff attached to this
114 pdp context. After this call, ippool member is cleared so
115 data is no longer valid and should not be accessed anymore. */
116 gtp_freepdp_teardown(pdp->gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +0100117 }
jjako52c24142002-12-16 13:33:51 +0000118}
119
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200120int apn_stop(struct apn_ctx *apn)
Harald Weltebed35df2011-11-02 13:06:18 +0100121{
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200122 LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200123 /* check if pools have any active PDP contexts and bail out */
124 pool_close_all_pdp(apn->v4.pool);
125 pool_close_all_pdp(apn->v6.pool);
126
127 /* shutdown whatever old state might be left */
128 if (apn->tun.tun) {
129 /* run ip-down script */
130 if (apn->tun.cfg.ipdown_script) {
131 LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
132 tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
133 }
Harald Weltef2286392018-04-25 19:02:31 +0200134 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
135 /* release tun device */
136 LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
137 osmo_fd_unregister(&apn->tun.fd);
138 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200139 tun_free(apn->tun.tun);
140 apn->tun.tun = NULL;
141 }
142
143 if (apn->v4.pool) {
144 LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
145 ippool_free(apn->v4.pool);
146 apn->v4.pool = NULL;
147 }
148 if (apn->v6.pool) {
149 LOGPAPN(LOGL_INFO, apn, "Releasing IPv6 pool\n");
150 ippool_free(apn->v6.pool);
151 apn->v6.pool = NULL;
152 }
153
154 apn->started = false;
155 return 0;
156}
157
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200158
Harald Weltef55a0392017-11-08 14:33:55 +0900159static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blacklist, bool ipv6)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200160{
161
162 int flags, len, len2, i;
163
Harald Weltee2a1de52017-11-08 15:24:07 +0900164 *blacklist = NULL;
165
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200166 if (ipv6)
167 flags = IP_TYPE_IPv6_NONLINK;
168 else
169 flags = IP_TYPE_IPv4;
170
171 while (1) {
Harald Weltee2a1de52017-11-08 15:24:07 +0900172 len = netdev_ip_local_get(apn->tun.cfg.dev_name, NULL, 0, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200173 if (len < 1)
174 return len;
175
176 *blacklist = talloc_zero_size(apn, len * sizeof(struct in46_prefix));
Harald Weltee2a1de52017-11-08 15:24:07 +0900177 len2 = netdev_ip_local_get(apn->tun.cfg.dev_name, *blacklist, len, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200178 if (len2 < 1) {
179 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900180 *blacklist = NULL;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200181 return len2;
182 }
183
Harald Weltee2a1de52017-11-08 15:24:07 +0900184 if (len2 > len) { /* iface was added between 2 calls, repeat operation */
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200185 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900186 *blacklist = NULL;
187 } else
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200188 break;
189 }
190
191 for (i = 0; i < len2; i++)
192 LOGPAPN(LOGL_INFO, apn, "Blacklist tun IP %s\n",
193 in46p_ntoa(&(*blacklist)[i]));
194
195 return len2;
196}
197
Harald Weltedda21ed2017-08-12 15:07:02 +0200198/* actually start the APN with its current config */
199int apn_start(struct apn_ctx *apn)
200{
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200201 int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST;
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200202 struct in46_prefix ipv6_tun_linklocal_ip;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200203 struct in46_prefix *blacklist;
204 int blacklist_size;
Harald Weltef2286392018-04-25 19:02:31 +0200205 struct gsn_t *gsn = apn->ggsn->gsn;
Pau Espin Pedrolbffc3f92017-12-14 11:19:10 +0100206 int rc;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200207
Harald Weltedda21ed2017-08-12 15:07:02 +0200208 if (apn->started)
209 return 0;
210
211 LOGPAPN(LOGL_INFO, apn, "Starting\n");
212 switch (apn->cfg.gtpu_mode) {
213 case APN_GTPU_MODE_TUN:
214 LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
Harald Weltef2286392018-04-25 19:02:31 +0200215 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200216 LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
217 return -1;
218 }
219 LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
220
221 /* Register with libosmcoore */
222 osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, BSC_FD_READ, ggsn_tun_fd_cb, apn, 0);
223 osmo_fd_register(&apn->tun.fd);
224
225 /* Set TUN library callback */
226 tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
Harald Weltedda21ed2017-08-12 15:07:02 +0200227 break;
228 case APN_GTPU_MODE_KERNEL_GTP:
Harald Welte2fc2bc62017-11-08 15:50:53 +0900229 LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
Harald Welte490782d2017-11-08 14:09:51 +0900230 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
231 LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200232 apn_stop(apn);
Harald Welte490782d2017-11-08 14:09:51 +0900233 return -1;
234 }
Harald Weltef2286392018-04-25 19:02:31 +0200235 if (gsn == NULL) {
Harald Welte07575042018-02-14 01:04:04 +0100236 /* skip bringing up the APN now if the GSN is not initialized yet.
237 * This happens during initial load of the config file, as the
238 * "no shutdown" in the ggsn node only happens after the "apn" nodes
239 * are brought up */
240 LOGPAPN(LOGL_NOTICE, apn, "Skipping APN start\n");
241 return 0;
242 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200243 /* use GTP kernel module for data packet encapsulation */
Harald Weltef2286392018-04-25 19:02:31 +0200244 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) {
245 LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n");
Harald Welte490782d2017-11-08 14:09:51 +0900246 return -1;
247 }
Harald Weltebed35df2011-11-02 13:06:18 +0100248 break;
249 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200250 LOGPAPN(LOGL_ERROR, apn, "Unknown GTPU Mode %d\n", apn->cfg.gtpu_mode);
251 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100252 }
jjako0141d202004-01-09 15:19:20 +0000253
Harald Weltef2286392018-04-25 19:02:31 +0200254 /* common initialization below */
255
256 /* set back-pointer from TUN device to APN */
257 apn->tun.tun->priv = apn;
258
259 if (apn->v4.cfg.ifconfig_prefix.addr.len) {
260 LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
261 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
262 if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
263 apn->v4.cfg.ifconfig_prefix.prefixlen)) {
264 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
265 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200266 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200267 return -1;
268 }
269 }
270
271 if (apn->v6.cfg.ifconfig_prefix.addr.len) {
272 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
273 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
274 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
275 apn->v6.cfg.ifconfig_prefix.prefixlen)) {
276 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
277 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
278 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200279 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200280 return -1;
281 }
282 }
283
284 if (apn->v6.cfg.ll_prefix.addr.len) {
285 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
286 in46p_ntoa(&apn->v6.cfg.ll_prefix));
287 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
288 apn->v6.cfg.ll_prefix.prefixlen)) {
289 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
290 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
291 in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200292 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200293 return -1;
294 }
295 apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
296 }
297
298 if (apn->tun.cfg.ipup_script) {
299 LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
300 apn->tun.cfg.ipup_script);
301 tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
302 }
303
304 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
305 apn->v6.cfg.ll_prefix.addr.len == 0) {
306 rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
307 if (rc < 1) {
308 LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
309 rc ? strerror(errno) : "tun interface has no link-local IP assigned");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200310 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200311 return -1;
312 }
313 apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
314 }
315
Harald Weltedda21ed2017-08-12 15:07:02 +0200316 /* Create IPv4 pool */
317 if (apn->v4.cfg.dynamic_prefix.addr.len) {
318 LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
319 in46p_ntoa(&apn->v4.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900320 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, false)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200321 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv4 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200322 if (ippool_new(&apn->v4.pool, &apn->v4.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200323 &apn->v4.cfg.static_prefix, ippool_flags,
324 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200325 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv4 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200326 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200327 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200328 return -1;
329 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200330 talloc_free(blacklist);
Harald Weltebed35df2011-11-02 13:06:18 +0100331 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200332
333 /* Create IPv6 pool */
334 if (apn->v6.cfg.dynamic_prefix.addr.len) {
335 LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n",
336 in46p_ntoa(&apn->v6.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900337 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, true)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200338 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv6 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200339 if (ippool_new(&apn->v6.pool, &apn->v6.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200340 &apn->v6.cfg.static_prefix, ippool_flags,
341 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200342 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv6 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200343 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200344 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200345 return -1;
346 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200347 talloc_free(blacklist);
Harald Weltedda21ed2017-08-12 15:07:02 +0200348 }
349
350 LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
351 apn->started = true;
352 return 0;
jjako0141d202004-01-09 15:19:20 +0000353}
jjako0141d202004-01-09 15:19:20 +0000354
Max3142d8d2017-05-04 17:45:10 +0200355static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
356{
Harald Welted12eab92017-08-02 19:49:47 +0200357 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200358 char val[NAMESIZE];
359
Harald Welted12eab92017-08-02 19:49:47 +0200360 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
361
Harald Welteb10ee082017-08-12 19:29:16 +0200362 snprintf(val, sizeof(val), "%s,%s", imsi_gtp2str(&pdp->imsi), addrstr);
Max3142d8d2017-05-04 17:45:10 +0200363
Harald Weltedda21ed2017-08-12 15:07:02 +0200364 if (ctrl_cmd_send_trap(g_ctrlh, var, val) < 0) {
365 LOGPPDP(LOGL_ERROR, pdp, "Failed to create and send TRAP %s\n", var);
Max3142d8d2017-05-04 17:45:10 +0200366 return false;
367 }
368 return true;
369}
370
Harald Weltedda21ed2017-08-12 15:07:02 +0200371static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +0100372{
Harald Weltedda21ed2017-08-12 15:07:02 +0200373 struct gsn_t *gsn = pdp->gsn;
Harald Welte698a2332017-11-08 15:09:58 +0900374 struct apn_ctx *apn = pdp->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100375 struct ippoolm_t *member;
376 int i;
Harald Weltedda21ed2017-08-12 15:07:02 +0200377
378 LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
Maxdbd70242016-10-14 13:38:05 +0200379
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100380 for (i = 0; i < 2; i++) {
381 if (pdp->peer[i]) {
382 member = pdp->peer[i];
383 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
384 ippool_freeip(member->pool, member);
385 } else if(i == 0)
386 LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
387 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100388
Harald Welte546884d2018-04-25 21:13:06 +0200389 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
390 if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
391 LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
392 strerror(errno));
393 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100394 }
395
Harald Weltebed35df2011-11-02 13:06:18 +0100396 return 0;
jjako52c24142002-12-16 13:33:51 +0000397}
398
Harald Welte1ae98772017-08-09 20:28:52 +0200399#include <osmocom/gsm/tlv.h>
400
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100401/* RFC 1332 */
402enum ipcp_options {
403 IPCP_OPT_IPADDR = 3,
404 IPCP_OPT_PRIMARY_DNS = 129,
405 IPCP_OPT_SECONDARY_DNS = 131,
406};
407
408struct ipcp_option_hdr {
409 uint8_t type;
410 uint8_t len;
411 uint8_t data[0];
Philipp Maier6a2856b2018-05-28 17:50:09 +0200412} __attribute__ ((packed));
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100413
414struct ipcp_hdr {
415 uint8_t code;
416 uint8_t id;
417 uint16_t len;
418 uint8_t options[0];
Philipp Maier6a2856b2018-05-28 17:50:09 +0200419} __attribute__ ((packed));
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100420
421/* determine if IPCP contains given option */
Harald Welte42c9fa42019-04-10 15:19:04 +0200422static const uint8_t *ipcp_contains_option(const uint8_t *ipcp, size_t ipcp_len,
423 enum ipcp_options opt, size_t opt_minlen)
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100424{
Harald Welte42c9fa42019-04-10 15:19:04 +0200425 const uint8_t *cur_opt = ipcp + sizeof(struct ipcp_hdr);
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100426
427 /* iterate over Options and check if protocol contained */
Harald Welte549417e2019-04-10 15:26:08 +0200428 while (cur_opt + sizeof(struct ipcp_option_hdr) <= ipcp + ipcp_len) {
429 const struct ipcp_option_hdr *cur_opt_hdr = (const struct ipcp_option_hdr *)cur_opt;
430 /* length value includes 2 bytes type/length */
431 if (cur_opt_hdr->len < sizeof(struct ipcp_option_hdr))
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200432 return NULL;
Harald Welte549417e2019-04-10 15:26:08 +0200433 if (cur_opt_hdr->type == opt &&
434 cur_opt_hdr->len >= sizeof(struct ipcp_option_hdr) + opt_minlen)
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100435 return cur_opt;
Harald Welte549417e2019-04-10 15:26:08 +0200436 cur_opt += cur_opt_hdr->len;
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100437 }
438 return NULL;
439}
440
Harald Welte1ae98772017-08-09 20:28:52 +0200441/* 3GPP TS 24.008 10.6.5.3 */
442enum pco_protocols {
443 PCO_P_LCP = 0xC021,
444 PCO_P_PAP = 0xC023,
445 PCO_P_CHAP = 0xC223,
446 PCO_P_IPCP = 0x8021,
447 PCO_P_PCSCF_ADDR = 0x0001,
448 PCO_P_IM_CN_SS_F = 0x0002,
449 PCO_P_DNS_IPv6_ADDR = 0x0003,
450 PCO_P_POLICY_CTRL_REJ = 0x0004, /* only in Network->MS */
451 PCO_P_MS_SUP_NETREQ_BCI = 0x0005,
452 /* reserved */
453 PCO_P_DSMIPv6_HA_ADDR = 0x0007,
454 PCO_P_DSMIPv6_HN_PREF = 0x0008,
455 PCO_P_DSMIPv6_v4_HA_ADDR= 0x0009,
456 PCO_P_IP_ADDR_VIA_NAS = 0x000a, /* only MS->Network */
457 PCO_P_IPv4_ADDR_VIA_DHCP= 0x000b, /* only MS->Netowrk */
458 PCO_P_PCSCF_IPv4_ADDR = 0x000c,
459 PCO_P_DNS_IPv4_ADDR = 0x000d,
460 PCO_P_MSISDN = 0x000e,
461 PCO_P_IFOM_SUPPORT = 0x000f,
462 PCO_P_IPv4_LINK_MTU = 0x0010,
463 PCO_P_MS_SUPP_LOC_A_TFT = 0x0011,
464 PCO_P_PCSCF_RESEL_SUP = 0x0012, /* only MS->Network */
465 PCO_P_NBIFOM_REQ = 0x0013,
466 PCO_P_NBIFOM_MODE = 0x0014,
467 PCO_P_NONIP_LINK_MTU = 0x0015,
468 PCO_P_APN_RATE_CTRL_SUP = 0x0016,
469 PCO_P_PS_DATA_OFF_UE = 0x0017,
470 PCO_P_REL_DATA_SVC = 0x0018,
471};
472
Harald Weltedf404c42019-04-10 15:15:26 +0200473struct pco_element {
474 uint16_t protocol_id; /* network byte order */
475 uint8_t length; /* length of data below */
476 uint8_t data[0];
477} __attribute__((packed));
478
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100479/*! Get the peer of pdp based on IP version used.
480 * \param[in] pdp PDP context to select the peer from.
481 * \param[in] v4v6 IP version to select. Valid values are 4 and 6.
482 * \returns The selected peer matching the given IP version. NULL if not present.
483 */
484static struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
485 uint8_t len1, len2, i;
486
487 if (is_ipv6) {
488 len1 = 8;
489 len2 = 16;
490 } else {
491 len1 = sizeof(struct in_addr);
492 len2 = len1;
493 }
494
495 for (i = 0; i < 2; i++) {
496 struct ippoolm_t * ippool = pdp->peer[i];
497 if (ippool && (ippool->addr.len == len1 || ippool->addr.len == len2))
498 return ippool;
499 }
500 return NULL;
501}
502
Harald Welte7bdc80d2019-04-11 18:47:59 +0200503/* RFC 1334, section 3.2. Packet Format */
504struct pap_element {
505 uint8_t code;
506 uint8_t id;
507 uint16_t len; /* length including header */
508 uint8_t data[0];
509} __attribute__((packed));
510
511enum pap_code {
512 PAP_CODE_AUTH_REQ = 1,
513 PAP_CODE_AUTH_ACK = 2,
514 PAP_CODE_AUTH_NAK = 3,
515};
516
517static const char *pap_welcome = "Welcome to OsmoGGSN " PACKAGE_VERSION;
518
519/* Handle PAP protocol according to RFC 1334 */
520static void process_pco_element_pap(const struct pco_element *pco_in, struct msgb *resp,
521 const struct apn_ctx *apn, struct pdp_t *pdp)
522{
523 const struct pap_element *pap_in = (const struct pap_element *) pco_in->data;
524 uint16_t pap_in_len;
525 uint8_t peer_id_len;
526 const uint8_t *peer_id;
527 unsigned int pap_welcome_len;
528 uint8_t pap_out_size;
529 struct pap_element *pap_out;
530
531 if (pco_in->length < sizeof(struct pap_element))
532 goto ret_broken;
533
534 pap_in_len = osmo_load16be(&pap_in->len);
535 if (pco_in->length < pap_in_len)
536 goto ret_broken;
537 /* "pco_in->length > pap_in_len" is allowed: RFC1334 2.2 states:
538 "Octets outside the range of the Length field should be treated as
539 Data Link Layer padding and should be ignored on reception."
540 */
541
542 switch (pap_in->code) {
543 case PAP_CODE_AUTH_REQ:
544 if (pap_in_len < sizeof(struct pap_element) + 1)
545 goto ret_broken_auth;
546 peer_id_len = pap_in->data[0];
547 if (pap_in_len < sizeof(struct pap_element) + 1 + peer_id_len)
548 goto ret_broken_auth;
549 peer_id = &pap_in->data[1];
550 LOGPPDP(LOGL_DEBUG, pdp, "PCO PAP PeerId = %s, ACKing\n",
551 osmo_quote_str((const char *)peer_id, peer_id_len));
552 /* Password-Length + Password following here, but we don't care */
553
554 /* Prepare response, we ACK all of them: */
555 pap_welcome_len = strlen(pap_welcome);
556 /* +1: Length field of pap_welcome Message */
557 pap_out_size = sizeof(struct pap_element) + 1 + pap_welcome_len;
558 pap_out = alloca(pap_out_size);
559 pap_out->code = PAP_CODE_AUTH_ACK;
560 pap_out->id = pap_in->id;
561 pap_out->len = htons(pap_out_size);
562 pap_out->data[0] = pap_welcome_len;
563 memcpy(pap_out->data+1, pap_welcome, pap_welcome_len);
564 msgb_t16lv_put(resp, PCO_P_PAP, pap_out_size, (uint8_t *) pap_out);
565 break;
566 case PAP_CODE_AUTH_ACK:
567 case PAP_CODE_AUTH_NAK:
568 default:
569 LOGPPDP(LOGL_NOTICE, pdp, "Unsupported PAP PCO Code %u, ignoring\n", pap_in->code);
570 break;
571 }
572 return;
573
574ret_broken_auth:
575 LOGPPDP(LOGL_NOTICE, pdp, "Invalid PAP AuthenticateReq: %s, ignoring\n",
576 osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
577 return;
578
579ret_broken:
580 LOGPPDP(LOGL_NOTICE, pdp, "Invalid PAP PCO Length: %s, ignoring\n",
581 osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
582}
583
Harald Welte9272d212019-04-11 15:39:16 +0200584static void process_pco_element_ipcp(const struct pco_element *pco_elem, struct msgb *resp,
585 const struct apn_ctx *apn, struct pdp_t *pdp)
Harald Weltedda21ed2017-08-12 15:07:02 +0200586{
Harald Welte9272d212019-04-11 15:39:16 +0200587 struct ippoolm_t *peer_v4 = pdp_get_peer_ipv(pdp, false);
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100588 const struct in46_addr *dns1 = &apn->v4.cfg.dns[0];
589 const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
Harald Welte9272d212019-04-11 15:39:16 +0200590 uint8_t *start = resp->tail;
Harald Weltef653c5b2019-04-10 15:48:26 +0200591 const uint8_t *ipcp;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200592 uint16_t ipcp_len;
Harald Welte42c9fa42019-04-10 15:19:04 +0200593 uint8_t *len1, *len2;
Harald Weltedda21ed2017-08-12 15:07:02 +0200594 unsigned int len_appended;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200595 ptrdiff_t consumed;
Harald Welte9272d212019-04-11 15:39:16 +0200596 size_t remain;
Harald Weltedda21ed2017-08-12 15:07:02 +0200597
Harald Welte32b76ee2019-04-11 18:57:16 +0200598 if (!peer_v4) {
599 LOGPPDP(LOGL_ERROR, pdp, "IPCP but no IPv4 type ?!?\n");
Harald Welte9272d212019-04-11 15:39:16 +0200600 return;
Harald Welte32b76ee2019-04-11 18:57:16 +0200601 }
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200602
Harald Welte9272d212019-04-11 15:39:16 +0200603 ipcp = pco_elem->data;
604 consumed = (ipcp - &pdp->pco_req.v[0]);
605 remain = sizeof(pdp->pco_req.v) - consumed;
606 ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
Harald Welte32b76ee2019-04-11 18:57:16 +0200607 if (remain < 0 || remain < ipcp_len) {
608 LOGPPDP(LOGL_ERROR, pdp, "Malformed IPCP, ignoring\n");
Harald Welte9272d212019-04-11 15:39:16 +0200609 return;
Harald Welte32b76ee2019-04-11 18:57:16 +0200610 }
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100611
Harald Welte9272d212019-04-11 15:39:16 +0200612 /* Three byte T16L header */
613 msgb_put_u16(resp, 0x8021); /* IPCP */
614 len1 = msgb_put(resp, 1); /* Length of contents: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200615
Harald Welte9272d212019-04-11 15:39:16 +0200616 msgb_put_u8(resp, 0x02); /* ACK */
617 msgb_put_u8(resp, ipcp[1]); /* ID: Needs to match request */
618 msgb_put_u8(resp, 0x00); /* Length MSB */
619 len2 = msgb_put(resp, 1); /* Length LSB: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200620
Harald Welte9272d212019-04-11 15:39:16 +0200621 if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
622 msgb_put_u8(resp, 0x81); /* DNS1 Tag */
623 msgb_put_u8(resp, 2 + dns1->len); /* DNS1 Length, incl. TL */
624 msgb_put_u32(resp, ntohl(dns1->v4.s_addr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200625 }
626
Harald Welte9272d212019-04-11 15:39:16 +0200627 if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
628 msgb_put_u8(resp, 0x83); /* DNS2 Tag */
629 msgb_put_u8(resp, 2 + dns2->len); /* DNS2 Length, incl. TL */
630 msgb_put_u32(resp, ntohl(dns2->v4.s_addr));
631 }
632
633 /* patch in length values */
634 len_appended = resp->tail - start;
635 *len1 = len_appended - 3;
636 *len2 = len_appended - 3;
637}
638
639static void process_pco_element_dns_ipv6(const struct pco_element *pco_elem, struct msgb *resp,
640 const struct apn_ctx *apn, struct pdp_t *pdp)
641{
642 unsigned int i;
Harald Welte32b76ee2019-04-11 18:57:16 +0200643 const uint8_t *tail = resp->tail;
Harald Welte9272d212019-04-11 15:39:16 +0200644
645 for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
646 const struct in46_addr *i46a = &apn->v6.cfg.dns[i];
647 if (i46a->len != 16)
648 continue;
649 msgb_t16lv_put(resp, PCO_P_DNS_IPv6_ADDR, i46a->len, i46a->v6.s6_addr);
650 }
Harald Welte32b76ee2019-04-11 18:57:16 +0200651 if (resp->tail == tail)
652 LOGPPDP(LOGL_NOTICE, pdp, "MS requested IPv6 DNS, but APN has none configured\n");
Harald Welte9272d212019-04-11 15:39:16 +0200653}
654
655static void process_pco_element_dns_ipv4(const struct pco_element *pco_elem, struct msgb *resp,
656 const struct apn_ctx *apn, struct pdp_t *pdp)
657{
658 unsigned int i;
Harald Welte32b76ee2019-04-11 18:57:16 +0200659 const uint8_t *tail = resp->tail;
Harald Welte9272d212019-04-11 15:39:16 +0200660
661 for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
662 const struct in46_addr *i46a = &apn->v4.cfg.dns[i];
663 if (i46a->len != 4)
664 continue;
665 msgb_t16lv_put(resp, PCO_P_DNS_IPv4_ADDR, i46a->len, (uint8_t *)&i46a->v4);
666 }
Harald Welte32b76ee2019-04-11 18:57:16 +0200667 if (resp->tail == tail)
668 LOGPPDP(LOGL_NOTICE, pdp, "MS requested IPv4 DNS, but APN has none configured\n");
Harald Welte9272d212019-04-11 15:39:16 +0200669}
670
671static void process_pco_element(const struct pco_element *pco_elem, struct msgb *resp,
672 const struct apn_ctx *apn, struct pdp_t *pdp)
673{
Harald Welte32b76ee2019-04-11 18:57:16 +0200674 uint16_t protocol_id = ntohs(pco_elem->protocol_id);
675
676 LOGPPDP(LOGL_DEBUG, pdp, "PCO Protocol 0x%04x\n", protocol_id);
677 switch (protocol_id) {
Harald Welte7bdc80d2019-04-11 18:47:59 +0200678 case PCO_P_PAP:
679 process_pco_element_pap(pco_elem, resp, apn, pdp);
680 break;
Harald Welte9272d212019-04-11 15:39:16 +0200681 case PCO_P_IPCP:
682 process_pco_element_ipcp(pco_elem, resp, apn, pdp);
683 break;
684 case PCO_P_DNS_IPv6_ADDR:
685 process_pco_element_dns_ipv6(pco_elem, resp, apn, pdp);
686 break;
687 case PCO_P_DNS_IPv4_ADDR:
688 process_pco_element_dns_ipv4(pco_elem, resp, apn, pdp);
689 break;
690 default:
Harald Welte32b76ee2019-04-11 18:57:16 +0200691 LOGPPDP(LOGL_INFO, pdp, "Unknown/Unimplemented PCO Protocol 0x%04x: %s\n",
692 protocol_id, osmo_hexdump_nospc(pco_elem->data, pco_elem->length));
Harald Welte9272d212019-04-11 15:39:16 +0200693 break;
694 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200695}
696
Harald Welte1ae98772017-08-09 20:28:52 +0200697/* process one PCO request from a MS/UE, putting together the proper responses */
Harald Welteffa22732019-04-10 14:30:21 +0200698static void process_pco(const struct apn_ctx *apn, struct pdp_t *pdp)
Harald Welte1ae98772017-08-09 20:28:52 +0200699{
Harald Welte9272d212019-04-11 15:39:16 +0200700 struct msgb *resp = msgb_alloc(256, "PCO.resp");
701 const struct ul255_t *pco = &pdp->pco_req;
702 const struct pco_element *pco_elem;
703 const uint8_t *cur;
Harald Weltedda21ed2017-08-12 15:07:02 +0200704
Harald Welte9272d212019-04-11 15:39:16 +0200705 /* build the header of the PCO response */
706 OSMO_ASSERT(resp);
707 msgb_put_u8(resp, 0x80); /* ext-bit + configuration protocol byte */
Harald Welte1ae98772017-08-09 20:28:52 +0200708
Harald Welte9272d212019-04-11 15:39:16 +0200709 /* iterate over the PCO elements in the request; call process_pco_element() for each */
710 for (cur = pco->v + 1, pco_elem = (const struct pco_element *) cur;
711 cur + sizeof(struct pco_element) <= pco->v + pco->l;
712 cur += pco_elem->length + sizeof(*pco_elem), pco_elem = (const struct pco_element *) cur) {
713 process_pco_element(pco_elem, resp, apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200714 }
715
Harald Welte9272d212019-04-11 15:39:16 +0200716 /* copy the PCO response msgb and copy its contents over to the PDP context */
717 if (msgb_length(resp) > 1) {
718 memcpy(pdp->pco_neg.v, msgb_data(resp), msgb_length(resp));
719 pdp->pco_neg.l = msgb_length(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200720 } else
721 pdp->pco_neg.l = 0;
Harald Welte9272d212019-04-11 15:39:16 +0200722 msgb_free(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200723}
724
Harald Welte9d9d91b2017-10-14 16:22:16 +0200725static bool apn_supports_ipv4(const struct apn_ctx *apn)
726{
727 if (apn->v4.cfg.static_prefix.addr.len || apn->v4.cfg.dynamic_prefix.addr.len)
728 return true;
729 return false;
730}
731
732static bool apn_supports_ipv6(const struct apn_ctx *apn)
733{
734 if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len)
735 return true;
736 return false;
737}
738
Harald Weltebed35df2011-11-02 13:06:18 +0100739int create_context_ind(struct pdp_t *pdp)
740{
Harald Weltedda21ed2017-08-12 15:07:02 +0200741 static char name_buf[256];
742 struct gsn_t *gsn = pdp->gsn;
743 struct ggsn_ctx *ggsn = gsn->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100744 struct in46_addr addr[2];
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100745 struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
746 char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700747 struct apn_ctx *apn = NULL;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100748 int rc, num_addr, i;
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700749 char *apn_name;
jjako52c24142002-12-16 13:33:51 +0000750
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700751 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
752 LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
753 apn_name ? name_buf : "(NONE)");
Harald Weltedda21ed2017-08-12 15:07:02 +0200754
755 /* First find an exact APN name match */
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700756 if (apn_name != NULL)
757 apn = ggsn_find_apn(ggsn, name_buf);
Harald Welte2e84d2c2017-10-01 13:36:52 +0800758 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200759 if (apn && !apn->started)
Harald Welte2e84d2c2017-10-01 13:36:52 +0800760 apn = NULL;
Harald Welteb16c46b2017-10-01 18:28:18 +0800761
Harald Weltedda21ed2017-08-12 15:07:02 +0200762 /* then try default (if any) */
763 if (!apn)
764 apn = ggsn->cfg.default_apn;
Harald Welteb16c46b2017-10-01 18:28:18 +0800765 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200766 if (apn && !apn->started)
Harald Welteb16c46b2017-10-01 18:28:18 +0800767 apn = NULL;
768
Harald Weltedda21ed2017-08-12 15:07:02 +0200769 if (!apn) {
770 /* no APN found for what user requested */
771 LOGPPDP(LOGL_NOTICE, pdp, "Unknown APN '%s', rejecting\n", name_buf);
772 gtp_create_context_resp(gsn, pdp, GTPCAUSE_MISSING_APN);
773 return 0;
774 }
jjako52c24142002-12-16 13:33:51 +0000775
Harald Welted9d88622017-08-04 00:22:35 +0200776 /* FIXME: we manually force all context requests to dynamic here! */
777 if (pdp->eua.l > 2)
778 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000779
Harald Weltebed35df2011-11-02 13:06:18 +0100780 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000781
Harald Weltebed35df2011-11-02 13:06:18 +0100782 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
783 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000784
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100785 memset(addr, 0, sizeof(addr));
786 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200787 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200788 osmo_hexdump(pdp->eua.v, pdp->eua.l));
789 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
790 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100791 }
jjakoa7cd2492003-04-11 09:40:12 +0000792
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700793 /* Store the actual APN for logging and the VTY */
794 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
795 if (rc < 0) /* Unlikely this would happen, but anyway... */
796 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
797 pdp->apn_use.l = rc;
798
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100799 /* Allocate dynamic addresses from the pool */
800 for (i = 0; i < num_addr; i++) {
801 if (addr[i].len == sizeof(struct in_addr)) {
802 /* does this APN actually have an IPv4 pool? */
803 if (!apn_supports_ipv4(apn))
804 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200805
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100806 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
807 if (rc < 0)
808 goto err_pool_full;
809 /* copy back */
810 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000811
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100812 addrv4 = member;
813
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100814 } else if (addr[i].len == sizeof(struct in6_addr)) {
815
816 /* does this APN actually have an IPv6 pool? */
817 if (!apn_supports_ipv6(apn))
818 goto err_wrong_af;
819
820 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
821 if (rc < 0)
822 goto err_pool_full;
823
824 /* IPv6 doesn't really send the real/allocated address at this point, but just
825 * the link-identifier which the MS shall use for router solicitation */
826 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
827 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
828 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
829 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100830
831 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100832 } else
833 OSMO_ASSERT(0);
834
835 pdp->peer[i] = member;
836 member->peer = pdp;
837 }
838
839 in46a_to_eua(addr, num_addr, &pdp->eua);
840
Harald Welte546884d2018-04-25 21:13:06 +0200841 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200842 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900843 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200844 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
845 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
846 return 0;
847 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100848 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200849
Harald Weltedda21ed2017-08-12 15:07:02 +0200850 pdp->ipif = apn->tun.tun; /* TODO */
Harald Welte698a2332017-11-08 15:09:58 +0900851 pdp->priv = apn;
Max3142d8d2017-05-04 17:45:10 +0200852
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100853 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200854 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200855 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
856 return 0;
857 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100858
Harald Weltedda21ed2017-08-12 15:07:02 +0200859 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200860
Harald Welte93fed3b2017-09-24 11:43:17 +0800861 /* Transmit G-PDU sequence numbers (only) if configured in APN */
862 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
863
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100864 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
865 name_buf, apn->cfg.name, pdp->teic_own,
866 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
867 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100868 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
869 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200870
871err_pool_full:
872 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
873 gtp_create_context_resp(gsn, pdp, -rc);
874 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200875
876err_wrong_af:
877 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
878 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
879 return 0;
jjako52c24142002-12-16 13:33:51 +0000880}
881
Harald Weltedda21ed2017-08-12 15:07:02 +0200882/* Internet-originated IP packet, needs to be sent via GTP towards MS */
883static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100884{
Harald Weltedda21ed2017-08-12 15:07:02 +0200885 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100886 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200887 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200888 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200889 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200890 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100891 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100892 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000893
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100894 switch (iph->version) {
895 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200896 if (len < sizeof(*iph) || len < 4*iph->ihl)
897 return -1;
898 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200899 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200900 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100901 break;
902 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200903 /* Due to the fact that 3GPP requires an allocation of a
904 * /64 prefix to each MS, we must instruct
905 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100906 * prefix, i.e. the first 8 bytes of the address. If the ll addr
907 * is used, then the match should be done on the trailing 64
908 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200909 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100910 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
911 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200912 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100913 break;
914 default:
Pau Espin Pedrol55d639f2017-12-04 13:17:07 +0100915 LOGP(DTUN, LOGL_NOTICE, "non-IPv%u packet received from tun\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200916 return -1;
917 }
jjakoc6762cf2004-04-28 14:52:58 +0000918
Harald Weltedda21ed2017-08-12 15:07:02 +0200919 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
920 if (!pool)
921 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100922
Max427699e2017-12-05 16:30:37 +0100923 DEBUGP(DTUN, "Received packet for APN(%s) from tun %s", apn->cfg.name, tun->devname);
Harald Weltedda21ed2017-08-12 15:07:02 +0200924
925 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100926 DEBUGPC(DTUN, " with no PDP contex! (%s)\n", iph->version == 4 ?
927 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
928 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100929 return 0;
930 }
Max427699e2017-12-05 16:30:37 +0100931 DEBUGPC(DTUN, "\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100932
933 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200934 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100935 return 0;
jjako52c24142002-12-16 13:33:51 +0000936}
937
Harald Welted46bcd22017-08-08 23:27:22 +0200938/* RFC3307 link-local scope multicast address */
939static const struct in6_addr all_router_mcast_addr = {
940 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
941};
942
Harald Weltedda21ed2017-08-12 15:07:02 +0200943/* MS-originated GTP1-U packet, needs to be sent via TUN device */
944static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100945{
Harald Welted46bcd22017-08-08 23:27:22 +0200946 struct iphdr *iph = (struct iphdr *)pack;
947 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800948 struct tun_t *tun = (struct tun_t *)pdp->ipif;
949 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100950 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100951 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100952 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800953
954 OSMO_ASSERT(tun);
955 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200956
Max427699e2017-12-05 16:30:37 +0100957 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 +0200958
959 switch (iph->version) {
960 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100961 peer = pdp_get_peer_ipv(pdp, true);
962 if (!peer) {
963 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
964 osmo_hexdump(pack, len));
965 return -1;
966 }
967
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100968 /* Validate packet comes from IPaddr assigned to the pdp ctx.
969 If packet is a LL addr, then EUA is in the lower 64 bits,
970 otherwise it's used as the 64 prefix */
971 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
972 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
973 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
974 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
975 return -1;
976 }
977
Harald Welted46bcd22017-08-08 23:27:22 +0200978 /* daddr: all-routers multicast addr */
979 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100980 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
981 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200982 break;
983 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100984 peer = pdp_get_peer_ipv(pdp, false);
985 if (!peer) {
986 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
987 osmo_hexdump(pack, len));
988 return -1;
989 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100990
991 /* Validate packet comes from IPaddr assigned to the pdp ctx */
992 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
993 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
994 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
995 return -1;
996 }
Harald Welted46bcd22017-08-08 23:27:22 +0200997 break;
998 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200999 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
1000 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +02001001 return -1;
1002 }
Harald Weltebed35df2011-11-02 13:06:18 +01001003 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001004}
1005
Harald Welte632e8432017-09-05 18:12:14 +02001006static char *config_file = "osmo-ggsn.cfg";
Harald Weltedda21ed2017-08-12 15:07:02 +02001007
1008/* callback for tun device osmocom select loop integration */
1009static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
1010{
1011 struct apn_ctx *apn = fd->data;
1012
1013 OSMO_ASSERT(what & BSC_FD_READ);
1014
1015 return tun_decaps(apn->tun.tun);
1016}
1017
1018/* callback for libgtp osmocom select loop integration */
1019static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
1020{
1021 struct ggsn_ctx *ggsn = fd->data;
1022 int rc;
1023
1024 OSMO_ASSERT(what & BSC_FD_READ);
1025
1026 switch (fd->priv_nr) {
1027 case 0:
1028 rc = gtp_decaps0(ggsn->gsn);
1029 break;
1030 case 1:
1031 rc = gtp_decaps1c(ggsn->gsn);
1032 break;
1033 case 2:
1034 rc = gtp_decaps1u(ggsn->gsn);
1035 break;
1036 default:
1037 OSMO_ASSERT(0);
1038 break;
1039 }
1040 return rc;
1041}
1042
1043static void ggsn_gtp_tmr_start(struct ggsn_ctx *ggsn)
1044{
1045 struct timeval next;
1046
1047 /* Retrieve next retransmission as timeval */
1048 gtp_retranstimeout(ggsn->gsn, &next);
1049
1050 /* re-schedule the timer */
1051 osmo_timer_schedule(&ggsn->gtp_timer, next.tv_sec, next.tv_usec/1000);
1052}
1053
1054/* timer callback for libgtp retransmission and ping */
1055static void ggsn_gtp_tmr_cb(void *data)
1056{
1057 struct ggsn_ctx *ggsn = data;
1058
1059 /* do all the retransmissions as needed */
1060 gtp_retrans(ggsn->gsn);
1061
1062 ggsn_gtp_tmr_start(ggsn);
1063}
1064
1065/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
1066static void signal_handler(int s)
1067{
1068 LOGP(DGGSN, LOGL_NOTICE, "signal %d received\n", s);
1069 switch (s) {
1070 case SIGINT:
Harald Weltee8049472017-08-20 12:44:21 +02001071 case SIGTERM:
Harald Weltedda21ed2017-08-12 15:07:02 +02001072 LOGP(DGGSN, LOGL_NOTICE, "SIGINT received, shutting down\n");
1073 end = 1;
1074 break;
1075 case SIGABRT:
1076 case SIGUSR1:
1077 talloc_report(tall_vty_ctx, stderr);
1078 talloc_report_full(tall_ggsn_ctx, stderr);
1079 break;
1080 case SIGUSR2:
1081 talloc_report_full(tall_vty_ctx, stderr);
1082 break;
1083 default:
1084 break;
1085 }
1086}
1087
Oliver Smith1cde2c12019-05-13 11:35:03 +02001088/* libgtp callback for confirmations */
1089static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1090{
1091 int rc = 0;
1092
1093 if (cause == EOF)
1094 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
1095 type, pdp, cbp);
1096
1097 switch (type) {
1098 case GTP_DELETE_PDP_REQ:
1099 /* Remark: We actually never reach this path nowadays because
1100 only place where we call gtp_delete_context_req2() is during
1101 apn_stop()->pool_close_all_pdp() path, and in that case we
1102 free all pdp contexts immediatelly without waiting for
1103 confirmation since we want to tear down the whole APN
1104 anyways. As a result, DeleteCtxResponse will never reach here
1105 since it will be dropped at some point in lower layers in the
1106 Rx path. This code is nevertheless left here in order to ease
1107 future developent and avoid possible future memleaks once more
1108 scenarios where GGSN sends a DeleteCtxRequest are introduced. */
1109 if (pdp)
1110 rc = pdp_freepdp(pdp);
1111 }
1112 return rc;
1113}
Harald Weltedda21ed2017-08-12 15:07:02 +02001114
1115/* Start a given GGSN */
1116int ggsn_start(struct ggsn_ctx *ggsn)
1117{
1118 struct apn_ctx *apn;
1119 int rc;
1120
1121 if (ggsn->started)
1122 return 0;
1123
1124 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
1125
1126 /* Start libgtp listener */
1127 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
1128 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
1129 return -1;
1130 }
1131 ggsn->gsn->priv = ggsn;
1132
Harald Welte98146772017-09-05 17:41:20 +02001133 /* patch in different addresses to use (in case we're behind NAT, the listen
1134 * address is different from what we advertise externally) */
1135 if (ggsn->cfg.gtpc_addr.v4.s_addr)
1136 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
1137
1138 if (ggsn->cfg.gtpu_addr.v4.s_addr)
1139 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
1140
Harald Weltedda21ed2017-08-12 15:07:02 +02001141 /* Register File Descriptors */
1142 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
1143 rc = osmo_fd_register(&ggsn->gtp_fd0);
1144 OSMO_ASSERT(rc == 0);
1145
1146 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
1147 rc = osmo_fd_register(&ggsn->gtp_fd1c);
1148 OSMO_ASSERT(rc == 0);
1149
1150 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
1151 rc = osmo_fd_register(&ggsn->gtp_fd1u);
1152 OSMO_ASSERT(rc == 0);
1153
1154 /* Start GTP re-transmission timer */
1155 osmo_timer_setup(&ggsn->gtp_timer, ggsn_gtp_tmr_cb, ggsn);
Pau Espin Pedrolcd87c5f2019-05-27 16:35:00 +02001156 ggsn_gtp_tmr_start(ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001157
1158 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
1159 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
1160 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001161 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Harald Weltedda21ed2017-08-12 15:07:02 +02001162
1163 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
1164 ggsn->started = true;
1165
1166 llist_for_each_entry(apn, &ggsn->apn_list, list)
1167 apn_start(apn);
1168
1169 return 0;
1170}
1171
1172/* Stop a given GGSN */
1173int ggsn_stop(struct ggsn_ctx *ggsn)
1174{
1175 struct apn_ctx *apn;
1176
1177 if (!ggsn->started)
1178 return 0;
1179
1180 /* iterate over all APNs and stop them */
1181 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +02001182 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001183
1184 osmo_timer_del(&ggsn->gtp_timer);
1185
1186 osmo_fd_unregister(&ggsn->gtp_fd1u);
1187 osmo_fd_unregister(&ggsn->gtp_fd1c);
1188 osmo_fd_unregister(&ggsn->gtp_fd0);
1189
1190 if (ggsn->gsn) {
1191 gtp_free(ggsn->gsn);
1192 ggsn->gsn = NULL;
1193 }
1194
1195 ggsn->started = false;
1196 return 0;
1197}
1198
1199static void print_usage()
1200{
1201 printf("Usage: osmo-ggsn [-h] [-D] [-c configfile] [-V]\n");
1202}
1203
1204static void print_help()
1205{
1206 printf( " Some useful help...\n"
1207 " -h --help This help text\n"
1208 " -D --daemonize Fork the process into a background daemon\n"
1209 " -c --config-file filename The config file to use\n"
1210 " -V --version Print the version of OsmoGGSN\n"
1211 );
1212}
1213
1214static void handle_options(int argc, char **argv)
1215{
1216 while (1) {
1217 int option_index = 0, c;
1218 static struct option long_options[] = {
1219 { "help", 0, 0, 'h' },
1220 { "daemonize", 0, 0, 'D' },
1221 { "config-file", 1, 0, 'c' },
1222 { "version", 0, 0, 'V' },
1223 { 0, 0, 0, 0 }
1224 };
1225
1226 c = getopt_long(argc, argv, "hdc:V", long_options, &option_index);
1227 if (c == -1)
1228 break;
1229
1230 switch (c) {
1231 case 'h':
1232 print_usage();
1233 print_help();
1234 exit(0);
1235 case 'D':
1236 daemonize = 1;
1237 break;
1238 case 'c':
1239 config_file = optarg;
1240 break;
1241 case 'V':
1242 print_version(1);
1243 exit(0);
1244 break;
1245 }
1246 }
1247}
1248
jjako52c24142002-12-16 13:33:51 +00001249int main(int argc, char **argv)
1250{
Harald Weltedda21ed2017-08-12 15:07:02 +02001251 struct ggsn_ctx *ggsn;
1252 int rc;
jjako52c24142002-12-16 13:33:51 +00001253
Harald Welte632e8432017-09-05 18:12:14 +02001254 tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
Harald Weltedda21ed2017-08-12 15:07:02 +02001255 msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
Harald Welte3e443ca2018-02-14 01:04:04 +01001256 g_vty_info.tall_ctx = tall_ggsn_ctx;
jjako52c24142002-12-16 13:33:51 +00001257
Harald Weltee8049472017-08-20 12:44:21 +02001258 /* Handle keyboard interrupt SIGINT */
Harald Weltedda21ed2017-08-12 15:07:02 +02001259 signal(SIGINT, &signal_handler);
Harald Weltee8049472017-08-20 12:44:21 +02001260 signal(SIGTERM, &signal_handler);
Harald Weltedda21ed2017-08-12 15:07:02 +02001261 signal(SIGABRT, &signal_handler);
1262 signal(SIGUSR1, &signal_handler);
1263 signal(SIGUSR2, &signal_handler);
jjako52c24142002-12-16 13:33:51 +00001264
Harald Weltedda21ed2017-08-12 15:07:02 +02001265 osmo_init_ignore_signals();
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001266 osmo_init_logging2(tall_ggsn_ctx, &log_info);
Harald Weltedda21ed2017-08-12 15:07:02 +02001267 osmo_stats_init(tall_ggsn_ctx);
jjako0141d202004-01-09 15:19:20 +00001268
Harald Weltedda21ed2017-08-12 15:07:02 +02001269 vty_init(&g_vty_info);
1270 logging_vty_add_cmds(NULL);
Harald Welte3e443ca2018-02-14 01:04:04 +01001271 osmo_talloc_vty_add_cmds();
Harald Weltedda21ed2017-08-12 15:07:02 +02001272 osmo_stats_vty_add_cmds(&log_info);
1273 ggsn_vty_init();
1274 ctrl_vty_init(tall_ggsn_ctx);
1275
1276 handle_options(argc, argv);
1277
1278 rate_ctr_init(tall_ggsn_ctx);
1279
1280 rc = vty_read_config_file(config_file, NULL);
1281 if (rc < 0) {
1282 fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
1283 exit(2);
Harald Weltebed35df2011-11-02 13:06:18 +01001284 }
jjako52c24142002-12-16 13:33:51 +00001285
Harald Weltedda21ed2017-08-12 15:07:02 +02001286 rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN);
1287 if (rc < 0)
Harald Weltebed35df2011-11-02 13:06:18 +01001288 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +01001289
Pau Espin Pedrol3e0baa62018-06-19 11:50:02 +02001290 g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
1291 OSMO_CTRL_PORT_GGSN, NULL);
Harald Weltedda21ed2017-08-12 15:07:02 +02001292 if (!g_ctrlh) {
1293 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001294 exit(1);
1295 }
jjako88c22162003-07-06 19:33:18 +00001296
Harald Weltedda21ed2017-08-12 15:07:02 +02001297 if (daemonize) {
1298 rc = osmo_daemonize();
1299 if (rc < 0) {
1300 perror("Error during daemonize");
Harald Weltebed35df2011-11-02 13:06:18 +01001301 exit(1);
1302 }
1303 }
jjako1d3db972004-01-16 09:56:56 +00001304
Harald Weltedda21ed2017-08-12 15:07:02 +02001305#if 0
Harald Weltebed35df2011-11-02 13:06:18 +01001306 /* qos */
1307 qos.l = 3;
1308 qos.v[2] = (args_info.qos_arg) & 0xff;
1309 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
1310 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
Harald Weltedda21ed2017-08-12 15:07:02 +02001311#endif
jjakoa7cd2492003-04-11 09:40:12 +00001312
Harald Weltedda21ed2017-08-12 15:07:02 +02001313 /* Main select loop */
1314 while (!end) {
1315 osmo_select_main(0);
Harald Weltebed35df2011-11-02 13:06:18 +01001316 }
jjakoe0149782003-07-06 17:07:04 +00001317
Harald Weltedda21ed2017-08-12 15:07:02 +02001318 llist_for_each_entry(ggsn, &g_ggsn_list, list)
1319 ggsn_stop(ggsn);
Harald Weltebed35df2011-11-02 13:06:18 +01001320
Max3fc9cc92019-03-14 11:16:55 +01001321 return 0;
jjako52c24142002-12-16 13:33:51 +00001322}