blob: e95471a2d57c0389bbce712b4eb8114a8f1035d2 [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 Welte9272d212019-04-11 15:39:16 +0200598 if (!peer_v4)
599 return;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200600
Harald Welte9272d212019-04-11 15:39:16 +0200601 ipcp = pco_elem->data;
602 consumed = (ipcp - &pdp->pco_req.v[0]);
603 remain = sizeof(pdp->pco_req.v) - consumed;
604 ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
605 if (remain < 0 || remain < ipcp_len)
606 return;
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100607
Harald Welte9272d212019-04-11 15:39:16 +0200608 /* Three byte T16L header */
609 msgb_put_u16(resp, 0x8021); /* IPCP */
610 len1 = msgb_put(resp, 1); /* Length of contents: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200611
Harald Welte9272d212019-04-11 15:39:16 +0200612 msgb_put_u8(resp, 0x02); /* ACK */
613 msgb_put_u8(resp, ipcp[1]); /* ID: Needs to match request */
614 msgb_put_u8(resp, 0x00); /* Length MSB */
615 len2 = msgb_put(resp, 1); /* Length LSB: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200616
Harald Welte9272d212019-04-11 15:39:16 +0200617 if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
618 msgb_put_u8(resp, 0x81); /* DNS1 Tag */
619 msgb_put_u8(resp, 2 + dns1->len); /* DNS1 Length, incl. TL */
620 msgb_put_u32(resp, ntohl(dns1->v4.s_addr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200621 }
622
Harald Welte9272d212019-04-11 15:39:16 +0200623 if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
624 msgb_put_u8(resp, 0x83); /* DNS2 Tag */
625 msgb_put_u8(resp, 2 + dns2->len); /* DNS2 Length, incl. TL */
626 msgb_put_u32(resp, ntohl(dns2->v4.s_addr));
627 }
628
629 /* patch in length values */
630 len_appended = resp->tail - start;
631 *len1 = len_appended - 3;
632 *len2 = len_appended - 3;
633}
634
635static void process_pco_element_dns_ipv6(const struct pco_element *pco_elem, struct msgb *resp,
636 const struct apn_ctx *apn, struct pdp_t *pdp)
637{
638 unsigned int i;
639
640 for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
641 const struct in46_addr *i46a = &apn->v6.cfg.dns[i];
642 if (i46a->len != 16)
643 continue;
644 msgb_t16lv_put(resp, PCO_P_DNS_IPv6_ADDR, i46a->len, i46a->v6.s6_addr);
645 }
646}
647
648static void process_pco_element_dns_ipv4(const struct pco_element *pco_elem, struct msgb *resp,
649 const struct apn_ctx *apn, struct pdp_t *pdp)
650{
651 unsigned int i;
652
653 for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
654 const struct in46_addr *i46a = &apn->v4.cfg.dns[i];
655 if (i46a->len != 4)
656 continue;
657 msgb_t16lv_put(resp, PCO_P_DNS_IPv4_ADDR, i46a->len, (uint8_t *)&i46a->v4);
658 }
659}
660
661static void process_pco_element(const struct pco_element *pco_elem, struct msgb *resp,
662 const struct apn_ctx *apn, struct pdp_t *pdp)
663{
664 switch (ntohs(pco_elem->protocol_id)) {
Harald Welte7bdc80d2019-04-11 18:47:59 +0200665 case PCO_P_PAP:
666 process_pco_element_pap(pco_elem, resp, apn, pdp);
667 break;
Harald Welte9272d212019-04-11 15:39:16 +0200668 case PCO_P_IPCP:
669 process_pco_element_ipcp(pco_elem, resp, apn, pdp);
670 break;
671 case PCO_P_DNS_IPv6_ADDR:
672 process_pco_element_dns_ipv6(pco_elem, resp, apn, pdp);
673 break;
674 case PCO_P_DNS_IPv4_ADDR:
675 process_pco_element_dns_ipv4(pco_elem, resp, apn, pdp);
676 break;
677 default:
678 break;
679 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200680}
681
Harald Welte1ae98772017-08-09 20:28:52 +0200682/* process one PCO request from a MS/UE, putting together the proper responses */
Harald Welteffa22732019-04-10 14:30:21 +0200683static void process_pco(const struct apn_ctx *apn, struct pdp_t *pdp)
Harald Welte1ae98772017-08-09 20:28:52 +0200684{
Harald Welte9272d212019-04-11 15:39:16 +0200685 struct msgb *resp = msgb_alloc(256, "PCO.resp");
686 const struct ul255_t *pco = &pdp->pco_req;
687 const struct pco_element *pco_elem;
688 const uint8_t *cur;
Harald Weltedda21ed2017-08-12 15:07:02 +0200689
Harald Welte9272d212019-04-11 15:39:16 +0200690 /* build the header of the PCO response */
691 OSMO_ASSERT(resp);
692 msgb_put_u8(resp, 0x80); /* ext-bit + configuration protocol byte */
Harald Welte1ae98772017-08-09 20:28:52 +0200693
Harald Welte9272d212019-04-11 15:39:16 +0200694 /* iterate over the PCO elements in the request; call process_pco_element() for each */
695 for (cur = pco->v + 1, pco_elem = (const struct pco_element *) cur;
696 cur + sizeof(struct pco_element) <= pco->v + pco->l;
697 cur += pco_elem->length + sizeof(*pco_elem), pco_elem = (const struct pco_element *) cur) {
698 process_pco_element(pco_elem, resp, apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200699 }
700
Harald Welte9272d212019-04-11 15:39:16 +0200701 /* copy the PCO response msgb and copy its contents over to the PDP context */
702 if (msgb_length(resp) > 1) {
703 memcpy(pdp->pco_neg.v, msgb_data(resp), msgb_length(resp));
704 pdp->pco_neg.l = msgb_length(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200705 } else
706 pdp->pco_neg.l = 0;
Harald Welte9272d212019-04-11 15:39:16 +0200707 msgb_free(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200708}
709
Harald Welte9d9d91b2017-10-14 16:22:16 +0200710static bool apn_supports_ipv4(const struct apn_ctx *apn)
711{
712 if (apn->v4.cfg.static_prefix.addr.len || apn->v4.cfg.dynamic_prefix.addr.len)
713 return true;
714 return false;
715}
716
717static bool apn_supports_ipv6(const struct apn_ctx *apn)
718{
719 if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len)
720 return true;
721 return false;
722}
723
Harald Weltebed35df2011-11-02 13:06:18 +0100724int create_context_ind(struct pdp_t *pdp)
725{
Harald Weltedda21ed2017-08-12 15:07:02 +0200726 static char name_buf[256];
727 struct gsn_t *gsn = pdp->gsn;
728 struct ggsn_ctx *ggsn = gsn->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100729 struct in46_addr addr[2];
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100730 struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
731 char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700732 struct apn_ctx *apn = NULL;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100733 int rc, num_addr, i;
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700734 char *apn_name;
jjako52c24142002-12-16 13:33:51 +0000735
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700736 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
737 LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
738 apn_name ? name_buf : "(NONE)");
Harald Weltedda21ed2017-08-12 15:07:02 +0200739
740 /* First find an exact APN name match */
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700741 if (apn_name != NULL)
742 apn = ggsn_find_apn(ggsn, name_buf);
Harald Welte2e84d2c2017-10-01 13:36:52 +0800743 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200744 if (apn && !apn->started)
Harald Welte2e84d2c2017-10-01 13:36:52 +0800745 apn = NULL;
Harald Welteb16c46b2017-10-01 18:28:18 +0800746
Harald Weltedda21ed2017-08-12 15:07:02 +0200747 /* then try default (if any) */
748 if (!apn)
749 apn = ggsn->cfg.default_apn;
Harald Welteb16c46b2017-10-01 18:28:18 +0800750 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200751 if (apn && !apn->started)
Harald Welteb16c46b2017-10-01 18:28:18 +0800752 apn = NULL;
753
Harald Weltedda21ed2017-08-12 15:07:02 +0200754 if (!apn) {
755 /* no APN found for what user requested */
756 LOGPPDP(LOGL_NOTICE, pdp, "Unknown APN '%s', rejecting\n", name_buf);
757 gtp_create_context_resp(gsn, pdp, GTPCAUSE_MISSING_APN);
758 return 0;
759 }
jjako52c24142002-12-16 13:33:51 +0000760
Harald Welted9d88622017-08-04 00:22:35 +0200761 /* FIXME: we manually force all context requests to dynamic here! */
762 if (pdp->eua.l > 2)
763 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000764
Harald Weltebed35df2011-11-02 13:06:18 +0100765 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000766
Harald Weltebed35df2011-11-02 13:06:18 +0100767 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
768 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000769
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100770 memset(addr, 0, sizeof(addr));
771 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200772 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200773 osmo_hexdump(pdp->eua.v, pdp->eua.l));
774 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
775 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100776 }
jjakoa7cd2492003-04-11 09:40:12 +0000777
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700778 /* Store the actual APN for logging and the VTY */
779 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
780 if (rc < 0) /* Unlikely this would happen, but anyway... */
781 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
782 pdp->apn_use.l = rc;
783
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100784 /* Allocate dynamic addresses from the pool */
785 for (i = 0; i < num_addr; i++) {
786 if (addr[i].len == sizeof(struct in_addr)) {
787 /* does this APN actually have an IPv4 pool? */
788 if (!apn_supports_ipv4(apn))
789 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200790
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100791 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
792 if (rc < 0)
793 goto err_pool_full;
794 /* copy back */
795 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000796
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100797 addrv4 = member;
798
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100799 } else if (addr[i].len == sizeof(struct in6_addr)) {
800
801 /* does this APN actually have an IPv6 pool? */
802 if (!apn_supports_ipv6(apn))
803 goto err_wrong_af;
804
805 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
806 if (rc < 0)
807 goto err_pool_full;
808
809 /* IPv6 doesn't really send the real/allocated address at this point, but just
810 * the link-identifier which the MS shall use for router solicitation */
811 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
812 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
813 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
814 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100815
816 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100817 } else
818 OSMO_ASSERT(0);
819
820 pdp->peer[i] = member;
821 member->peer = pdp;
822 }
823
824 in46a_to_eua(addr, num_addr, &pdp->eua);
825
Harald Welte546884d2018-04-25 21:13:06 +0200826 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200827 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900828 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200829 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
830 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
831 return 0;
832 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100833 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200834
Harald Weltedda21ed2017-08-12 15:07:02 +0200835 pdp->ipif = apn->tun.tun; /* TODO */
Harald Welte698a2332017-11-08 15:09:58 +0900836 pdp->priv = apn;
Max3142d8d2017-05-04 17:45:10 +0200837
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100838 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200839 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200840 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
841 return 0;
842 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100843
Harald Weltedda21ed2017-08-12 15:07:02 +0200844 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200845
Harald Welte93fed3b2017-09-24 11:43:17 +0800846 /* Transmit G-PDU sequence numbers (only) if configured in APN */
847 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
848
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100849 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
850 name_buf, apn->cfg.name, pdp->teic_own,
851 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
852 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100853 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
854 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200855
856err_pool_full:
857 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
858 gtp_create_context_resp(gsn, pdp, -rc);
859 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200860
861err_wrong_af:
862 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
863 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
864 return 0;
jjako52c24142002-12-16 13:33:51 +0000865}
866
Harald Weltedda21ed2017-08-12 15:07:02 +0200867/* Internet-originated IP packet, needs to be sent via GTP towards MS */
868static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100869{
Harald Weltedda21ed2017-08-12 15:07:02 +0200870 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100871 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200872 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200873 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200874 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200875 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100876 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100877 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000878
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100879 switch (iph->version) {
880 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200881 if (len < sizeof(*iph) || len < 4*iph->ihl)
882 return -1;
883 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200884 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200885 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100886 break;
887 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200888 /* Due to the fact that 3GPP requires an allocation of a
889 * /64 prefix to each MS, we must instruct
890 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100891 * prefix, i.e. the first 8 bytes of the address. If the ll addr
892 * is used, then the match should be done on the trailing 64
893 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200894 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100895 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
896 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200897 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100898 break;
899 default:
Pau Espin Pedrol55d639f2017-12-04 13:17:07 +0100900 LOGP(DTUN, LOGL_NOTICE, "non-IPv%u packet received from tun\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200901 return -1;
902 }
jjakoc6762cf2004-04-28 14:52:58 +0000903
Harald Weltedda21ed2017-08-12 15:07:02 +0200904 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
905 if (!pool)
906 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100907
Max427699e2017-12-05 16:30:37 +0100908 DEBUGP(DTUN, "Received packet for APN(%s) from tun %s", apn->cfg.name, tun->devname);
Harald Weltedda21ed2017-08-12 15:07:02 +0200909
910 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100911 DEBUGPC(DTUN, " with no PDP contex! (%s)\n", iph->version == 4 ?
912 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
913 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100914 return 0;
915 }
Max427699e2017-12-05 16:30:37 +0100916 DEBUGPC(DTUN, "\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100917
918 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200919 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100920 return 0;
jjako52c24142002-12-16 13:33:51 +0000921}
922
Harald Welted46bcd22017-08-08 23:27:22 +0200923/* RFC3307 link-local scope multicast address */
924static const struct in6_addr all_router_mcast_addr = {
925 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
926};
927
Harald Weltedda21ed2017-08-12 15:07:02 +0200928/* MS-originated GTP1-U packet, needs to be sent via TUN device */
929static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100930{
Harald Welted46bcd22017-08-08 23:27:22 +0200931 struct iphdr *iph = (struct iphdr *)pack;
932 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800933 struct tun_t *tun = (struct tun_t *)pdp->ipif;
934 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100935 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100936 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100937 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800938
939 OSMO_ASSERT(tun);
940 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200941
Max427699e2017-12-05 16:30:37 +0100942 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 +0200943
944 switch (iph->version) {
945 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100946 peer = pdp_get_peer_ipv(pdp, true);
947 if (!peer) {
948 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
949 osmo_hexdump(pack, len));
950 return -1;
951 }
952
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100953 /* Validate packet comes from IPaddr assigned to the pdp ctx.
954 If packet is a LL addr, then EUA is in the lower 64 bits,
955 otherwise it's used as the 64 prefix */
956 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
957 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
958 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
959 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
960 return -1;
961 }
962
Harald Welted46bcd22017-08-08 23:27:22 +0200963 /* daddr: all-routers multicast addr */
964 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100965 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
966 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200967 break;
968 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100969 peer = pdp_get_peer_ipv(pdp, false);
970 if (!peer) {
971 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
972 osmo_hexdump(pack, len));
973 return -1;
974 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100975
976 /* Validate packet comes from IPaddr assigned to the pdp ctx */
977 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
978 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
979 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
980 return -1;
981 }
Harald Welted46bcd22017-08-08 23:27:22 +0200982 break;
983 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200984 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
985 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +0200986 return -1;
987 }
Harald Weltebed35df2011-11-02 13:06:18 +0100988 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000989}
990
Harald Welte632e8432017-09-05 18:12:14 +0200991static char *config_file = "osmo-ggsn.cfg";
Harald Weltedda21ed2017-08-12 15:07:02 +0200992
993/* callback for tun device osmocom select loop integration */
994static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
995{
996 struct apn_ctx *apn = fd->data;
997
998 OSMO_ASSERT(what & BSC_FD_READ);
999
1000 return tun_decaps(apn->tun.tun);
1001}
1002
1003/* callback for libgtp osmocom select loop integration */
1004static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
1005{
1006 struct ggsn_ctx *ggsn = fd->data;
1007 int rc;
1008
1009 OSMO_ASSERT(what & BSC_FD_READ);
1010
1011 switch (fd->priv_nr) {
1012 case 0:
1013 rc = gtp_decaps0(ggsn->gsn);
1014 break;
1015 case 1:
1016 rc = gtp_decaps1c(ggsn->gsn);
1017 break;
1018 case 2:
1019 rc = gtp_decaps1u(ggsn->gsn);
1020 break;
1021 default:
1022 OSMO_ASSERT(0);
1023 break;
1024 }
1025 return rc;
1026}
1027
1028static void ggsn_gtp_tmr_start(struct ggsn_ctx *ggsn)
1029{
1030 struct timeval next;
1031
1032 /* Retrieve next retransmission as timeval */
1033 gtp_retranstimeout(ggsn->gsn, &next);
1034
1035 /* re-schedule the timer */
1036 osmo_timer_schedule(&ggsn->gtp_timer, next.tv_sec, next.tv_usec/1000);
1037}
1038
1039/* timer callback for libgtp retransmission and ping */
1040static void ggsn_gtp_tmr_cb(void *data)
1041{
1042 struct ggsn_ctx *ggsn = data;
1043
1044 /* do all the retransmissions as needed */
1045 gtp_retrans(ggsn->gsn);
1046
1047 ggsn_gtp_tmr_start(ggsn);
1048}
1049
1050/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
1051static void signal_handler(int s)
1052{
1053 LOGP(DGGSN, LOGL_NOTICE, "signal %d received\n", s);
1054 switch (s) {
1055 case SIGINT:
Harald Weltee8049472017-08-20 12:44:21 +02001056 case SIGTERM:
Harald Weltedda21ed2017-08-12 15:07:02 +02001057 LOGP(DGGSN, LOGL_NOTICE, "SIGINT received, shutting down\n");
1058 end = 1;
1059 break;
1060 case SIGABRT:
1061 case SIGUSR1:
1062 talloc_report(tall_vty_ctx, stderr);
1063 talloc_report_full(tall_ggsn_ctx, stderr);
1064 break;
1065 case SIGUSR2:
1066 talloc_report_full(tall_vty_ctx, stderr);
1067 break;
1068 default:
1069 break;
1070 }
1071}
1072
Oliver Smith1cde2c12019-05-13 11:35:03 +02001073/* libgtp callback for confirmations */
1074static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1075{
1076 int rc = 0;
1077
1078 if (cause == EOF)
1079 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
1080 type, pdp, cbp);
1081
1082 switch (type) {
1083 case GTP_DELETE_PDP_REQ:
1084 /* Remark: We actually never reach this path nowadays because
1085 only place where we call gtp_delete_context_req2() is during
1086 apn_stop()->pool_close_all_pdp() path, and in that case we
1087 free all pdp contexts immediatelly without waiting for
1088 confirmation since we want to tear down the whole APN
1089 anyways. As a result, DeleteCtxResponse will never reach here
1090 since it will be dropped at some point in lower layers in the
1091 Rx path. This code is nevertheless left here in order to ease
1092 future developent and avoid possible future memleaks once more
1093 scenarios where GGSN sends a DeleteCtxRequest are introduced. */
1094 if (pdp)
1095 rc = pdp_freepdp(pdp);
1096 }
1097 return rc;
1098}
Harald Weltedda21ed2017-08-12 15:07:02 +02001099
1100/* Start a given GGSN */
1101int ggsn_start(struct ggsn_ctx *ggsn)
1102{
1103 struct apn_ctx *apn;
1104 int rc;
1105
1106 if (ggsn->started)
1107 return 0;
1108
1109 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
1110
1111 /* Start libgtp listener */
1112 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
1113 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
1114 return -1;
1115 }
1116 ggsn->gsn->priv = ggsn;
1117
Harald Welte98146772017-09-05 17:41:20 +02001118 /* patch in different addresses to use (in case we're behind NAT, the listen
1119 * address is different from what we advertise externally) */
1120 if (ggsn->cfg.gtpc_addr.v4.s_addr)
1121 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
1122
1123 if (ggsn->cfg.gtpu_addr.v4.s_addr)
1124 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
1125
Harald Weltedda21ed2017-08-12 15:07:02 +02001126 /* Register File Descriptors */
1127 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
1128 rc = osmo_fd_register(&ggsn->gtp_fd0);
1129 OSMO_ASSERT(rc == 0);
1130
1131 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
1132 rc = osmo_fd_register(&ggsn->gtp_fd1c);
1133 OSMO_ASSERT(rc == 0);
1134
1135 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
1136 rc = osmo_fd_register(&ggsn->gtp_fd1u);
1137 OSMO_ASSERT(rc == 0);
1138
1139 /* Start GTP re-transmission timer */
1140 osmo_timer_setup(&ggsn->gtp_timer, ggsn_gtp_tmr_cb, ggsn);
Pau Espin Pedrolcd87c5f2019-05-27 16:35:00 +02001141 ggsn_gtp_tmr_start(ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001142
1143 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
1144 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
1145 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001146 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Harald Weltedda21ed2017-08-12 15:07:02 +02001147
1148 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
1149 ggsn->started = true;
1150
1151 llist_for_each_entry(apn, &ggsn->apn_list, list)
1152 apn_start(apn);
1153
1154 return 0;
1155}
1156
1157/* Stop a given GGSN */
1158int ggsn_stop(struct ggsn_ctx *ggsn)
1159{
1160 struct apn_ctx *apn;
1161
1162 if (!ggsn->started)
1163 return 0;
1164
1165 /* iterate over all APNs and stop them */
1166 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +02001167 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001168
1169 osmo_timer_del(&ggsn->gtp_timer);
1170
1171 osmo_fd_unregister(&ggsn->gtp_fd1u);
1172 osmo_fd_unregister(&ggsn->gtp_fd1c);
1173 osmo_fd_unregister(&ggsn->gtp_fd0);
1174
1175 if (ggsn->gsn) {
1176 gtp_free(ggsn->gsn);
1177 ggsn->gsn = NULL;
1178 }
1179
1180 ggsn->started = false;
1181 return 0;
1182}
1183
1184static void print_usage()
1185{
1186 printf("Usage: osmo-ggsn [-h] [-D] [-c configfile] [-V]\n");
1187}
1188
1189static void print_help()
1190{
1191 printf( " Some useful help...\n"
1192 " -h --help This help text\n"
1193 " -D --daemonize Fork the process into a background daemon\n"
1194 " -c --config-file filename The config file to use\n"
1195 " -V --version Print the version of OsmoGGSN\n"
1196 );
1197}
1198
1199static void handle_options(int argc, char **argv)
1200{
1201 while (1) {
1202 int option_index = 0, c;
1203 static struct option long_options[] = {
1204 { "help", 0, 0, 'h' },
1205 { "daemonize", 0, 0, 'D' },
1206 { "config-file", 1, 0, 'c' },
1207 { "version", 0, 0, 'V' },
1208 { 0, 0, 0, 0 }
1209 };
1210
1211 c = getopt_long(argc, argv, "hdc:V", long_options, &option_index);
1212 if (c == -1)
1213 break;
1214
1215 switch (c) {
1216 case 'h':
1217 print_usage();
1218 print_help();
1219 exit(0);
1220 case 'D':
1221 daemonize = 1;
1222 break;
1223 case 'c':
1224 config_file = optarg;
1225 break;
1226 case 'V':
1227 print_version(1);
1228 exit(0);
1229 break;
1230 }
1231 }
1232}
1233
jjako52c24142002-12-16 13:33:51 +00001234int main(int argc, char **argv)
1235{
Harald Weltedda21ed2017-08-12 15:07:02 +02001236 struct ggsn_ctx *ggsn;
1237 int rc;
jjako52c24142002-12-16 13:33:51 +00001238
Harald Welte632e8432017-09-05 18:12:14 +02001239 tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
Harald Weltedda21ed2017-08-12 15:07:02 +02001240 msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
Harald Welte3e443ca2018-02-14 01:04:04 +01001241 g_vty_info.tall_ctx = tall_ggsn_ctx;
jjako52c24142002-12-16 13:33:51 +00001242
Harald Weltee8049472017-08-20 12:44:21 +02001243 /* Handle keyboard interrupt SIGINT */
Harald Weltedda21ed2017-08-12 15:07:02 +02001244 signal(SIGINT, &signal_handler);
Harald Weltee8049472017-08-20 12:44:21 +02001245 signal(SIGTERM, &signal_handler);
Harald Weltedda21ed2017-08-12 15:07:02 +02001246 signal(SIGABRT, &signal_handler);
1247 signal(SIGUSR1, &signal_handler);
1248 signal(SIGUSR2, &signal_handler);
jjako52c24142002-12-16 13:33:51 +00001249
Harald Weltedda21ed2017-08-12 15:07:02 +02001250 osmo_init_ignore_signals();
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001251 osmo_init_logging2(tall_ggsn_ctx, &log_info);
Harald Weltedda21ed2017-08-12 15:07:02 +02001252 osmo_stats_init(tall_ggsn_ctx);
jjako0141d202004-01-09 15:19:20 +00001253
Harald Weltedda21ed2017-08-12 15:07:02 +02001254 vty_init(&g_vty_info);
1255 logging_vty_add_cmds(NULL);
Harald Welte3e443ca2018-02-14 01:04:04 +01001256 osmo_talloc_vty_add_cmds();
Harald Weltedda21ed2017-08-12 15:07:02 +02001257 osmo_stats_vty_add_cmds(&log_info);
1258 ggsn_vty_init();
1259 ctrl_vty_init(tall_ggsn_ctx);
1260
1261 handle_options(argc, argv);
1262
1263 rate_ctr_init(tall_ggsn_ctx);
1264
1265 rc = vty_read_config_file(config_file, NULL);
1266 if (rc < 0) {
1267 fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
1268 exit(2);
Harald Weltebed35df2011-11-02 13:06:18 +01001269 }
jjako52c24142002-12-16 13:33:51 +00001270
Harald Weltedda21ed2017-08-12 15:07:02 +02001271 rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN);
1272 if (rc < 0)
Harald Weltebed35df2011-11-02 13:06:18 +01001273 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +01001274
Pau Espin Pedrol3e0baa62018-06-19 11:50:02 +02001275 g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
1276 OSMO_CTRL_PORT_GGSN, NULL);
Harald Weltedda21ed2017-08-12 15:07:02 +02001277 if (!g_ctrlh) {
1278 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001279 exit(1);
1280 }
jjako88c22162003-07-06 19:33:18 +00001281
Harald Weltedda21ed2017-08-12 15:07:02 +02001282 if (daemonize) {
1283 rc = osmo_daemonize();
1284 if (rc < 0) {
1285 perror("Error during daemonize");
Harald Weltebed35df2011-11-02 13:06:18 +01001286 exit(1);
1287 }
1288 }
jjako1d3db972004-01-16 09:56:56 +00001289
Harald Weltedda21ed2017-08-12 15:07:02 +02001290#if 0
Harald Weltebed35df2011-11-02 13:06:18 +01001291 /* qos */
1292 qos.l = 3;
1293 qos.v[2] = (args_info.qos_arg) & 0xff;
1294 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
1295 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
Harald Weltedda21ed2017-08-12 15:07:02 +02001296#endif
jjakoa7cd2492003-04-11 09:40:12 +00001297
Harald Weltedda21ed2017-08-12 15:07:02 +02001298 /* Main select loop */
1299 while (!end) {
1300 osmo_select_main(0);
Harald Weltebed35df2011-11-02 13:06:18 +01001301 }
jjakoe0149782003-07-06 17:07:04 +00001302
Harald Weltedda21ed2017-08-12 15:07:02 +02001303 llist_for_each_entry(ggsn, &g_ggsn_list, list)
1304 ggsn_stop(ggsn);
Harald Weltebed35df2011-11-02 13:06:18 +01001305
Max3fc9cc92019-03-14 11:16:55 +01001306 return 0;
jjako52c24142002-12-16 13:33:51 +00001307}