blob: c55992385ac618935544e3d534734987cdf48eea [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 Weltedda21ed2017-08-12 15:07:02 +02004 * Copyright (C) 2017 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>
Max727417d2016-08-02 17:10:38 +020050#include <osmocom/ctrl/control_if.h>
51#include <osmocom/ctrl/control_cmd.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020052#include <osmocom/ctrl/control_vty.h>
Max727417d2016-08-02 17:10:38 +020053#include <osmocom/ctrl/ports.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020054#include <osmocom/vty/telnet_interface.h>
55#include <osmocom/vty/logging.h>
56#include <osmocom/vty/stats.h>
57#include <osmocom/vty/ports.h>
58#include <osmocom/vty/command.h>
Harald Welte3e443ca2018-02-14 01:04:04 +010059#include <osmocom/vty/misc.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020060#include <osmocom/gsm/apn.h>
Max727417d2016-08-02 17:10:38 +020061
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020062#include "../lib/tun.h"
63#include "../lib/ippool.h"
64#include "../lib/syserr.h"
Harald Welted12eab92017-08-02 19:49:47 +020065#include "../lib/in46_addr.h"
Harald Weltef2286392018-04-25 19:02:31 +020066#include "../lib/gtp-kernel.h"
jjako52c24142002-12-16 13:33:51 +000067#include "../gtp/pdp.h"
68#include "../gtp/gtp.h"
Harald Welted46bcd22017-08-08 23:27:22 +020069#include "icmpv6.h"
Harald Weltedda21ed2017-08-12 15:07:02 +020070#include "ggsn.h"
jjako52c24142002-12-16 13:33:51 +000071
Harald Weltedda21ed2017-08-12 15:07:02 +020072void *tall_ggsn_ctx;
jjakoa7cd2492003-04-11 09:40:12 +000073
Harald Weltedda21ed2017-08-12 15:07:02 +020074static int end = 0;
75static int daemonize = 0;
76static struct ctrl_handle *g_ctrlh;
77
jjakoa7cd2492003-04-11 09:40:12 +000078struct ul255_t qos;
79struct ul255_t apn;
80
Harald Weltedda21ed2017-08-12 15:07:02 +020081#define LOGPAPN(level, apn, fmt, args...) \
82 LOGP(DGGSN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args)
jjako52c24142002-12-16 13:33:51 +000083
Harald Weltedda21ed2017-08-12 15:07:02 +020084#define LOGPGGSN(level, ggsn, fmt, args...) \
85 LOGP(DGGSN, level, "GGSN(%s): " fmt, (ggsn)->cfg.name, ## args)
86
Max6a215272017-09-25 10:35:34 +020087#define LOGPPDP(level, pdp, fmt, args...) LOGPDPX(DGGSN, level, pdp, fmt, ## args)
Harald Weltedda21ed2017-08-12 15:07:02 +020088
89static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what);
90static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len);
91
92
93static void pool_close_all_pdp(struct ippool_t *pool)
Harald Weltebed35df2011-11-02 13:06:18 +010094{
Harald Weltedda21ed2017-08-12 15:07:02 +020095 unsigned int i;
jjako52c24142002-12-16 13:33:51 +000096
Harald Weltedda21ed2017-08-12 15:07:02 +020097 if (!pool)
Harald Weltebed35df2011-11-02 13:06:18 +010098 return;
Harald Weltedda21ed2017-08-12 15:07:02 +020099
100 for (i = 0; i < pool->listsize; i++) {
101 struct ippoolm_t *member = &pool->member[i];
102 struct pdp_t *pdp;
103
104 if (!member->inuse)
105 continue;
106 pdp = member->peer;
107 if (!pdp)
108 continue;
109 LOGPPDP(LOGL_DEBUG, pdp, "Sending DELETE PDP CTX due to shutdown\n");
Oliver Smith1cde2c12019-05-13 11:35:03 +0200110 gtp_delete_context_req2(pdp->gsn, pdp, NULL, 1);
111 /* We have nothing more to do with pdp ctx, free it. Upon cb_delete_context
112 called during this call we'll clean up ggsn related stuff attached to this
113 pdp context. After this call, ippool member is cleared so
114 data is no longer valid and should not be accessed anymore. */
115 gtp_freepdp_teardown(pdp->gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +0100116 }
jjako52c24142002-12-16 13:33:51 +0000117}
118
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200119int apn_stop(struct apn_ctx *apn)
Harald Weltebed35df2011-11-02 13:06:18 +0100120{
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200121 LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200122 /* check if pools have any active PDP contexts and bail out */
123 pool_close_all_pdp(apn->v4.pool);
124 pool_close_all_pdp(apn->v6.pool);
125
126 /* shutdown whatever old state might be left */
127 if (apn->tun.tun) {
128 /* run ip-down script */
129 if (apn->tun.cfg.ipdown_script) {
130 LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script);
131 tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script);
132 }
Harald Weltef2286392018-04-25 19:02:31 +0200133 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
134 /* release tun device */
135 LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
136 osmo_fd_unregister(&apn->tun.fd);
137 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200138 tun_free(apn->tun.tun);
139 apn->tun.tun = NULL;
140 }
141
142 if (apn->v4.pool) {
143 LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n");
144 ippool_free(apn->v4.pool);
145 apn->v4.pool = NULL;
146 }
147 if (apn->v6.pool) {
148 LOGPAPN(LOGL_INFO, apn, "Releasing IPv6 pool\n");
149 ippool_free(apn->v6.pool);
150 apn->v6.pool = NULL;
151 }
152
153 apn->started = false;
154 return 0;
155}
156
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200157
Harald Weltef55a0392017-11-08 14:33:55 +0900158static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blacklist, bool ipv6)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200159{
160
161 int flags, len, len2, i;
162
Harald Weltee2a1de52017-11-08 15:24:07 +0900163 *blacklist = NULL;
164
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200165 if (ipv6)
166 flags = IP_TYPE_IPv6_NONLINK;
167 else
168 flags = IP_TYPE_IPv4;
169
170 while (1) {
Harald Weltee2a1de52017-11-08 15:24:07 +0900171 len = netdev_ip_local_get(apn->tun.cfg.dev_name, NULL, 0, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200172 if (len < 1)
173 return len;
174
175 *blacklist = talloc_zero_size(apn, len * sizeof(struct in46_prefix));
Harald Weltee2a1de52017-11-08 15:24:07 +0900176 len2 = netdev_ip_local_get(apn->tun.cfg.dev_name, *blacklist, len, flags);
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200177 if (len2 < 1) {
178 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900179 *blacklist = NULL;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200180 return len2;
181 }
182
Harald Weltee2a1de52017-11-08 15:24:07 +0900183 if (len2 > len) { /* iface was added between 2 calls, repeat operation */
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200184 talloc_free(*blacklist);
Harald Weltee2a1de52017-11-08 15:24:07 +0900185 *blacklist = NULL;
186 } else
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200187 break;
188 }
189
190 for (i = 0; i < len2; i++)
191 LOGPAPN(LOGL_INFO, apn, "Blacklist tun IP %s\n",
192 in46p_ntoa(&(*blacklist)[i]));
193
194 return len2;
195}
196
Harald Weltedda21ed2017-08-12 15:07:02 +0200197/* actually start the APN with its current config */
198int apn_start(struct apn_ctx *apn)
199{
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200200 int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST;
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200201 struct in46_prefix ipv6_tun_linklocal_ip;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200202 struct in46_prefix *blacklist;
203 int blacklist_size;
Harald Weltef2286392018-04-25 19:02:31 +0200204 struct gsn_t *gsn = apn->ggsn->gsn;
Pau Espin Pedrolbffc3f92017-12-14 11:19:10 +0100205 int rc;
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200206
Harald Weltedda21ed2017-08-12 15:07:02 +0200207 if (apn->started)
208 return 0;
209
210 LOGPAPN(LOGL_INFO, apn, "Starting\n");
211 switch (apn->cfg.gtpu_mode) {
212 case APN_GTPU_MODE_TUN:
213 LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name);
Harald Weltef2286392018-04-25 19:02:31 +0200214 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200215 LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
216 return -1;
217 }
218 LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
219
220 /* Register with libosmcoore */
221 osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, BSC_FD_READ, ggsn_tun_fd_cb, apn, 0);
222 osmo_fd_register(&apn->tun.fd);
223
224 /* Set TUN library callback */
225 tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
Harald Weltedda21ed2017-08-12 15:07:02 +0200226 break;
227 case APN_GTPU_MODE_KERNEL_GTP:
Harald Welte2fc2bc62017-11-08 15:50:53 +0900228 LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
Harald Welte490782d2017-11-08 14:09:51 +0900229 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
230 LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200231 apn_stop(apn);
Harald Welte490782d2017-11-08 14:09:51 +0900232 return -1;
233 }
Harald Weltef2286392018-04-25 19:02:31 +0200234 if (gsn == NULL) {
Harald Welte07575042018-02-14 01:04:04 +0100235 /* skip bringing up the APN now if the GSN is not initialized yet.
236 * This happens during initial load of the config file, as the
237 * "no shutdown" in the ggsn node only happens after the "apn" nodes
238 * are brought up */
239 LOGPAPN(LOGL_NOTICE, apn, "Skipping APN start\n");
240 return 0;
241 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200242 /* use GTP kernel module for data packet encapsulation */
Harald Weltef2286392018-04-25 19:02:31 +0200243 if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) {
244 LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n");
Harald Welte490782d2017-11-08 14:09:51 +0900245 return -1;
246 }
Harald Weltebed35df2011-11-02 13:06:18 +0100247 break;
248 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200249 LOGPAPN(LOGL_ERROR, apn, "Unknown GTPU Mode %d\n", apn->cfg.gtpu_mode);
250 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100251 }
jjako0141d202004-01-09 15:19:20 +0000252
Harald Weltef2286392018-04-25 19:02:31 +0200253 /* common initialization below */
254
255 /* set back-pointer from TUN device to APN */
256 apn->tun.tun->priv = apn;
257
258 if (apn->v4.cfg.ifconfig_prefix.addr.len) {
259 LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
260 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
261 if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
262 apn->v4.cfg.ifconfig_prefix.prefixlen)) {
263 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
264 in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200265 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200266 return -1;
267 }
268 }
269
270 if (apn->v6.cfg.ifconfig_prefix.addr.len) {
271 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
272 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
273 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
274 apn->v6.cfg.ifconfig_prefix.prefixlen)) {
275 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
276 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
277 in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200278 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200279 return -1;
280 }
281 }
282
283 if (apn->v6.cfg.ll_prefix.addr.len) {
284 LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
285 in46p_ntoa(&apn->v6.cfg.ll_prefix));
286 if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
287 apn->v6.cfg.ll_prefix.prefixlen)) {
288 LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
289 "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
290 in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200291 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200292 return -1;
293 }
294 apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
295 }
296
297 if (apn->tun.cfg.ipup_script) {
298 LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
299 apn->tun.cfg.ipup_script);
300 tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
301 }
302
303 if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
304 apn->v6.cfg.ll_prefix.addr.len == 0) {
305 rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
306 if (rc < 1) {
307 LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
308 rc ? strerror(errno) : "tun interface has no link-local IP assigned");
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200309 apn_stop(apn);
Harald Weltef2286392018-04-25 19:02:31 +0200310 return -1;
311 }
312 apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
313 }
314
Harald Weltedda21ed2017-08-12 15:07:02 +0200315 /* Create IPv4 pool */
316 if (apn->v4.cfg.dynamic_prefix.addr.len) {
317 LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
318 in46p_ntoa(&apn->v4.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900319 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, false)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200320 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv4 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200321 if (ippool_new(&apn->v4.pool, &apn->v4.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200322 &apn->v4.cfg.static_prefix, ippool_flags,
323 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200324 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv4 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200325 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200326 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200327 return -1;
328 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200329 talloc_free(blacklist);
Harald Weltebed35df2011-11-02 13:06:18 +0100330 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200331
332 /* Create IPv6 pool */
333 if (apn->v6.cfg.dynamic_prefix.addr.len) {
334 LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n",
335 in46p_ntoa(&apn->v6.cfg.dynamic_prefix));
Harald Weltef55a0392017-11-08 14:33:55 +0900336 if ((blacklist_size = alloc_ippool_blacklist(apn, &blacklist, true)) < 0)
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200337 LOGPAPN(LOGL_ERROR, apn, "Failed obtaining IPv6 tun IPs\n");
Harald Weltedda21ed2017-08-12 15:07:02 +0200338 if (ippool_new(&apn->v6.pool, &apn->v6.cfg.dynamic_prefix,
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200339 &apn->v6.cfg.static_prefix, ippool_flags,
340 blacklist, blacklist_size)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200341 LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv6 pool\n");
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200342 talloc_free(blacklist);
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200343 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200344 return -1;
345 }
Pau Espin Pedrol859f9b02017-10-16 14:52:25 +0200346 talloc_free(blacklist);
Harald Weltedda21ed2017-08-12 15:07:02 +0200347 }
348
349 LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
350 apn->started = true;
351 return 0;
jjako0141d202004-01-09 15:19:20 +0000352}
jjako0141d202004-01-09 15:19:20 +0000353
Max3142d8d2017-05-04 17:45:10 +0200354static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
355{
Harald Welted12eab92017-08-02 19:49:47 +0200356 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200357 char val[NAMESIZE];
358
Harald Welted12eab92017-08-02 19:49:47 +0200359 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
360
Harald Welteb10ee082017-08-12 19:29:16 +0200361 snprintf(val, sizeof(val), "%s,%s", imsi_gtp2str(&pdp->imsi), addrstr);
Max3142d8d2017-05-04 17:45:10 +0200362
Harald Weltedda21ed2017-08-12 15:07:02 +0200363 if (ctrl_cmd_send_trap(g_ctrlh, var, val) < 0) {
364 LOGPPDP(LOGL_ERROR, pdp, "Failed to create and send TRAP %s\n", var);
Max3142d8d2017-05-04 17:45:10 +0200365 return false;
366 }
367 return true;
368}
369
Harald Weltedda21ed2017-08-12 15:07:02 +0200370static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +0100371{
Harald Weltedda21ed2017-08-12 15:07:02 +0200372 struct gsn_t *gsn = pdp->gsn;
Harald Welte698a2332017-11-08 15:09:58 +0900373 struct apn_ctx *apn = pdp->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100374 struct ippoolm_t *member;
375 int i;
Harald Weltedda21ed2017-08-12 15:07:02 +0200376
377 LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
Maxdbd70242016-10-14 13:38:05 +0200378
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100379 for (i = 0; i < 2; i++) {
380 if (pdp->peer[i]) {
381 member = pdp->peer[i];
382 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
383 ippool_freeip(member->pool, member);
384 } else if(i == 0)
385 LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
386 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100387
Harald Welte546884d2018-04-25 21:13:06 +0200388 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
389 if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
390 LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
391 strerror(errno));
392 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100393 }
394
Harald Weltebed35df2011-11-02 13:06:18 +0100395 return 0;
jjako52c24142002-12-16 13:33:51 +0000396}
397
Harald Welte1ae98772017-08-09 20:28:52 +0200398#include <osmocom/gsm/tlv.h>
399
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100400/* RFC 1332 */
401enum ipcp_options {
402 IPCP_OPT_IPADDR = 3,
403 IPCP_OPT_PRIMARY_DNS = 129,
404 IPCP_OPT_SECONDARY_DNS = 131,
405};
406
407struct ipcp_option_hdr {
408 uint8_t type;
409 uint8_t len;
410 uint8_t data[0];
Philipp Maier6a2856b2018-05-28 17:50:09 +0200411} __attribute__ ((packed));
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100412
413struct ipcp_hdr {
414 uint8_t code;
415 uint8_t id;
416 uint16_t len;
417 uint8_t options[0];
Philipp Maier6a2856b2018-05-28 17:50:09 +0200418} __attribute__ ((packed));
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100419
420/* determine if IPCP contains given option */
Harald Welte42c9fa42019-04-10 15:19:04 +0200421static const uint8_t *ipcp_contains_option(const uint8_t *ipcp, size_t ipcp_len,
422 enum ipcp_options opt, size_t opt_minlen)
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100423{
Harald Welte42c9fa42019-04-10 15:19:04 +0200424 const uint8_t *cur_opt = ipcp + sizeof(struct ipcp_hdr);
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100425
426 /* iterate over Options and check if protocol contained */
Harald Welte549417e2019-04-10 15:26:08 +0200427 while (cur_opt + sizeof(struct ipcp_option_hdr) <= ipcp + ipcp_len) {
428 const struct ipcp_option_hdr *cur_opt_hdr = (const struct ipcp_option_hdr *)cur_opt;
429 /* length value includes 2 bytes type/length */
430 if (cur_opt_hdr->len < sizeof(struct ipcp_option_hdr))
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200431 return NULL;
Harald Welte549417e2019-04-10 15:26:08 +0200432 if (cur_opt_hdr->type == opt &&
433 cur_opt_hdr->len >= sizeof(struct ipcp_option_hdr) + opt_minlen)
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100434 return cur_opt;
Harald Welte549417e2019-04-10 15:26:08 +0200435 cur_opt += cur_opt_hdr->len;
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100436 }
437 return NULL;
438}
439
Harald Welte1ae98772017-08-09 20:28:52 +0200440/* 3GPP TS 24.008 10.6.5.3 */
441enum pco_protocols {
442 PCO_P_LCP = 0xC021,
443 PCO_P_PAP = 0xC023,
444 PCO_P_CHAP = 0xC223,
445 PCO_P_IPCP = 0x8021,
446 PCO_P_PCSCF_ADDR = 0x0001,
447 PCO_P_IM_CN_SS_F = 0x0002,
448 PCO_P_DNS_IPv6_ADDR = 0x0003,
449 PCO_P_POLICY_CTRL_REJ = 0x0004, /* only in Network->MS */
450 PCO_P_MS_SUP_NETREQ_BCI = 0x0005,
451 /* reserved */
452 PCO_P_DSMIPv6_HA_ADDR = 0x0007,
453 PCO_P_DSMIPv6_HN_PREF = 0x0008,
454 PCO_P_DSMIPv6_v4_HA_ADDR= 0x0009,
455 PCO_P_IP_ADDR_VIA_NAS = 0x000a, /* only MS->Network */
456 PCO_P_IPv4_ADDR_VIA_DHCP= 0x000b, /* only MS->Netowrk */
457 PCO_P_PCSCF_IPv4_ADDR = 0x000c,
458 PCO_P_DNS_IPv4_ADDR = 0x000d,
459 PCO_P_MSISDN = 0x000e,
460 PCO_P_IFOM_SUPPORT = 0x000f,
461 PCO_P_IPv4_LINK_MTU = 0x0010,
462 PCO_P_MS_SUPP_LOC_A_TFT = 0x0011,
463 PCO_P_PCSCF_RESEL_SUP = 0x0012, /* only MS->Network */
464 PCO_P_NBIFOM_REQ = 0x0013,
465 PCO_P_NBIFOM_MODE = 0x0014,
466 PCO_P_NONIP_LINK_MTU = 0x0015,
467 PCO_P_APN_RATE_CTRL_SUP = 0x0016,
468 PCO_P_PS_DATA_OFF_UE = 0x0017,
469 PCO_P_REL_DATA_SVC = 0x0018,
470};
471
Harald Weltedf404c42019-04-10 15:15:26 +0200472struct pco_element {
473 uint16_t protocol_id; /* network byte order */
474 uint8_t length; /* length of data below */
475 uint8_t data[0];
476} __attribute__((packed));
477
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100478/*! Get the peer of pdp based on IP version used.
479 * \param[in] pdp PDP context to select the peer from.
480 * \param[in] v4v6 IP version to select. Valid values are 4 and 6.
481 * \returns The selected peer matching the given IP version. NULL if not present.
482 */
483static struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
484 uint8_t len1, len2, i;
485
486 if (is_ipv6) {
487 len1 = 8;
488 len2 = 16;
489 } else {
490 len1 = sizeof(struct in_addr);
491 len2 = len1;
492 }
493
494 for (i = 0; i < 2; i++) {
495 struct ippoolm_t * ippool = pdp->peer[i];
496 if (ippool && (ippool->addr.len == len1 || ippool->addr.len == len2))
497 return ippool;
498 }
499 return NULL;
500}
501
Harald Welte9272d212019-04-11 15:39:16 +0200502static void process_pco_element_ipcp(const struct pco_element *pco_elem, struct msgb *resp,
503 const struct apn_ctx *apn, struct pdp_t *pdp)
Harald Weltedda21ed2017-08-12 15:07:02 +0200504{
Harald Welte9272d212019-04-11 15:39:16 +0200505 struct ippoolm_t *peer_v4 = pdp_get_peer_ipv(pdp, false);
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100506 const struct in46_addr *dns1 = &apn->v4.cfg.dns[0];
507 const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
Harald Welte9272d212019-04-11 15:39:16 +0200508 uint8_t *start = resp->tail;
Harald Weltef653c5b2019-04-10 15:48:26 +0200509 const uint8_t *ipcp;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200510 uint16_t ipcp_len;
Harald Welte42c9fa42019-04-10 15:19:04 +0200511 uint8_t *len1, *len2;
Harald Weltedda21ed2017-08-12 15:07:02 +0200512 unsigned int len_appended;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200513 ptrdiff_t consumed;
Harald Welte9272d212019-04-11 15:39:16 +0200514 size_t remain;
Harald Weltedda21ed2017-08-12 15:07:02 +0200515
Harald Welte9272d212019-04-11 15:39:16 +0200516 if (!peer_v4)
517 return;
Stefan Sperlingd70ab972018-07-19 15:25:47 +0200518
Harald Welte9272d212019-04-11 15:39:16 +0200519 ipcp = pco_elem->data;
520 consumed = (ipcp - &pdp->pco_req.v[0]);
521 remain = sizeof(pdp->pco_req.v) - consumed;
522 ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
523 if (remain < 0 || remain < ipcp_len)
524 return;
Pau Espin Pedrol0bdd8bf2018-01-26 17:46:37 +0100525
Harald Welte9272d212019-04-11 15:39:16 +0200526 /* Three byte T16L header */
527 msgb_put_u16(resp, 0x8021); /* IPCP */
528 len1 = msgb_put(resp, 1); /* Length of contents: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200529
Harald Welte9272d212019-04-11 15:39:16 +0200530 msgb_put_u8(resp, 0x02); /* ACK */
531 msgb_put_u8(resp, ipcp[1]); /* ID: Needs to match request */
532 msgb_put_u8(resp, 0x00); /* Length MSB */
533 len2 = msgb_put(resp, 1); /* Length LSB: delay */
Harald Weltedda21ed2017-08-12 15:07:02 +0200534
Harald Welte9272d212019-04-11 15:39:16 +0200535 if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
536 msgb_put_u8(resp, 0x81); /* DNS1 Tag */
537 msgb_put_u8(resp, 2 + dns1->len); /* DNS1 Length, incl. TL */
538 msgb_put_u32(resp, ntohl(dns1->v4.s_addr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200539 }
540
Harald Welte9272d212019-04-11 15:39:16 +0200541 if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
542 msgb_put_u8(resp, 0x83); /* DNS2 Tag */
543 msgb_put_u8(resp, 2 + dns2->len); /* DNS2 Length, incl. TL */
544 msgb_put_u32(resp, ntohl(dns2->v4.s_addr));
545 }
546
547 /* patch in length values */
548 len_appended = resp->tail - start;
549 *len1 = len_appended - 3;
550 *len2 = len_appended - 3;
551}
552
553static void process_pco_element_dns_ipv6(const struct pco_element *pco_elem, struct msgb *resp,
554 const struct apn_ctx *apn, struct pdp_t *pdp)
555{
556 unsigned int i;
557
558 for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
559 const struct in46_addr *i46a = &apn->v6.cfg.dns[i];
560 if (i46a->len != 16)
561 continue;
562 msgb_t16lv_put(resp, PCO_P_DNS_IPv6_ADDR, i46a->len, i46a->v6.s6_addr);
563 }
564}
565
566static void process_pco_element_dns_ipv4(const struct pco_element *pco_elem, struct msgb *resp,
567 const struct apn_ctx *apn, struct pdp_t *pdp)
568{
569 unsigned int i;
570
571 for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
572 const struct in46_addr *i46a = &apn->v4.cfg.dns[i];
573 if (i46a->len != 4)
574 continue;
575 msgb_t16lv_put(resp, PCO_P_DNS_IPv4_ADDR, i46a->len, (uint8_t *)&i46a->v4);
576 }
577}
578
579static void process_pco_element(const struct pco_element *pco_elem, struct msgb *resp,
580 const struct apn_ctx *apn, struct pdp_t *pdp)
581{
582 switch (ntohs(pco_elem->protocol_id)) {
583 case PCO_P_IPCP:
584 process_pco_element_ipcp(pco_elem, resp, apn, pdp);
585 break;
586 case PCO_P_DNS_IPv6_ADDR:
587 process_pco_element_dns_ipv6(pco_elem, resp, apn, pdp);
588 break;
589 case PCO_P_DNS_IPv4_ADDR:
590 process_pco_element_dns_ipv4(pco_elem, resp, apn, pdp);
591 break;
592 default:
593 break;
594 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200595}
596
Harald Welte1ae98772017-08-09 20:28:52 +0200597/* process one PCO request from a MS/UE, putting together the proper responses */
Harald Welteffa22732019-04-10 14:30:21 +0200598static void process_pco(const struct apn_ctx *apn, struct pdp_t *pdp)
Harald Welte1ae98772017-08-09 20:28:52 +0200599{
Harald Welte9272d212019-04-11 15:39:16 +0200600 struct msgb *resp = msgb_alloc(256, "PCO.resp");
601 const struct ul255_t *pco = &pdp->pco_req;
602 const struct pco_element *pco_elem;
603 const uint8_t *cur;
Harald Weltedda21ed2017-08-12 15:07:02 +0200604
Harald Welte9272d212019-04-11 15:39:16 +0200605 /* build the header of the PCO response */
606 OSMO_ASSERT(resp);
607 msgb_put_u8(resp, 0x80); /* ext-bit + configuration protocol byte */
Harald Welte1ae98772017-08-09 20:28:52 +0200608
Harald Welte9272d212019-04-11 15:39:16 +0200609 /* iterate over the PCO elements in the request; call process_pco_element() for each */
610 for (cur = pco->v + 1, pco_elem = (const struct pco_element *) cur;
611 cur + sizeof(struct pco_element) <= pco->v + pco->l;
612 cur += pco_elem->length + sizeof(*pco_elem), pco_elem = (const struct pco_element *) cur) {
613 process_pco_element(pco_elem, resp, apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200614 }
615
Harald Welte9272d212019-04-11 15:39:16 +0200616 /* copy the PCO response msgb and copy its contents over to the PDP context */
617 if (msgb_length(resp) > 1) {
618 memcpy(pdp->pco_neg.v, msgb_data(resp), msgb_length(resp));
619 pdp->pco_neg.l = msgb_length(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200620 } else
621 pdp->pco_neg.l = 0;
Harald Welte9272d212019-04-11 15:39:16 +0200622 msgb_free(resp);
Harald Welte1ae98772017-08-09 20:28:52 +0200623}
624
Harald Welte9d9d91b2017-10-14 16:22:16 +0200625static bool apn_supports_ipv4(const struct apn_ctx *apn)
626{
627 if (apn->v4.cfg.static_prefix.addr.len || apn->v4.cfg.dynamic_prefix.addr.len)
628 return true;
629 return false;
630}
631
632static bool apn_supports_ipv6(const struct apn_ctx *apn)
633{
634 if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len)
635 return true;
636 return false;
637}
638
Harald Weltebed35df2011-11-02 13:06:18 +0100639int create_context_ind(struct pdp_t *pdp)
640{
Harald Weltedda21ed2017-08-12 15:07:02 +0200641 static char name_buf[256];
642 struct gsn_t *gsn = pdp->gsn;
643 struct ggsn_ctx *ggsn = gsn->priv;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100644 struct in46_addr addr[2];
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100645 struct ippoolm_t *member = NULL, *addrv4 = NULL, *addrv6 = NULL;
646 char straddrv4[INET_ADDRSTRLEN], straddrv6[INET6_ADDRSTRLEN];
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700647 struct apn_ctx *apn = NULL;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100648 int rc, num_addr, i;
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700649 char *apn_name;
jjako52c24142002-12-16 13:33:51 +0000650
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700651 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
652 LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
653 apn_name ? name_buf : "(NONE)");
Harald Weltedda21ed2017-08-12 15:07:02 +0200654
655 /* First find an exact APN name match */
Vadim Yanitskiy2e8e57a2019-05-13 22:09:15 +0700656 if (apn_name != NULL)
657 apn = ggsn_find_apn(ggsn, name_buf);
Harald Welte2e84d2c2017-10-01 13:36:52 +0800658 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200659 if (apn && !apn->started)
Harald Welte2e84d2c2017-10-01 13:36:52 +0800660 apn = NULL;
Harald Welteb16c46b2017-10-01 18:28:18 +0800661
Harald Weltedda21ed2017-08-12 15:07:02 +0200662 /* then try default (if any) */
663 if (!apn)
664 apn = ggsn->cfg.default_apn;
Harald Welteb16c46b2017-10-01 18:28:18 +0800665 /* ignore if the APN has not been started */
Pau Espin Pedrol958256f2017-10-11 20:32:55 +0200666 if (apn && !apn->started)
Harald Welteb16c46b2017-10-01 18:28:18 +0800667 apn = NULL;
668
Harald Weltedda21ed2017-08-12 15:07:02 +0200669 if (!apn) {
670 /* no APN found for what user requested */
671 LOGPPDP(LOGL_NOTICE, pdp, "Unknown APN '%s', rejecting\n", name_buf);
672 gtp_create_context_resp(gsn, pdp, GTPCAUSE_MISSING_APN);
673 return 0;
674 }
jjako52c24142002-12-16 13:33:51 +0000675
Harald Welted9d88622017-08-04 00:22:35 +0200676 /* FIXME: we manually force all context requests to dynamic here! */
677 if (pdp->eua.l > 2)
678 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000679
Harald Weltebed35df2011-11-02 13:06:18 +0100680 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000681
Harald Weltebed35df2011-11-02 13:06:18 +0100682 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
683 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000684
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100685 memset(addr, 0, sizeof(addr));
686 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200687 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200688 osmo_hexdump(pdp->eua.v, pdp->eua.l));
689 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
690 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100691 }
jjakoa7cd2492003-04-11 09:40:12 +0000692
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700693 /* Store the actual APN for logging and the VTY */
694 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
695 if (rc < 0) /* Unlikely this would happen, but anyway... */
696 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
697 pdp->apn_use.l = rc;
698
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100699 /* Allocate dynamic addresses from the pool */
700 for (i = 0; i < num_addr; i++) {
701 if (addr[i].len == sizeof(struct in_addr)) {
702 /* does this APN actually have an IPv4 pool? */
703 if (!apn_supports_ipv4(apn))
704 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200705
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100706 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
707 if (rc < 0)
708 goto err_pool_full;
709 /* copy back */
710 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000711
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100712 addrv4 = member;
713
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100714 } else if (addr[i].len == sizeof(struct in6_addr)) {
715
716 /* does this APN actually have an IPv6 pool? */
717 if (!apn_supports_ipv6(apn))
718 goto err_wrong_af;
719
720 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
721 if (rc < 0)
722 goto err_pool_full;
723
724 /* IPv6 doesn't really send the real/allocated address at this point, but just
725 * the link-identifier which the MS shall use for router solicitation */
726 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
727 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
728 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
729 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100730
731 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100732 } else
733 OSMO_ASSERT(0);
734
735 pdp->peer[i] = member;
736 member->peer = pdp;
737 }
738
739 in46a_to_eua(addr, num_addr, &pdp->eua);
740
Harald Welte546884d2018-04-25 21:13:06 +0200741 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200742 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900743 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200744 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
745 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
746 return 0;
747 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100748 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200749
Harald Weltedda21ed2017-08-12 15:07:02 +0200750 pdp->ipif = apn->tun.tun; /* TODO */
Harald Welte698a2332017-11-08 15:09:58 +0900751 pdp->priv = apn;
Max3142d8d2017-05-04 17:45:10 +0200752
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100753 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200754 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200755 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
756 return 0;
757 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100758
Harald Weltedda21ed2017-08-12 15:07:02 +0200759 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200760
Harald Welte93fed3b2017-09-24 11:43:17 +0800761 /* Transmit G-PDU sequence numbers (only) if configured in APN */
762 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
763
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100764 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
765 name_buf, apn->cfg.name, pdp->teic_own,
766 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
767 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100768 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
769 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200770
771err_pool_full:
772 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
773 gtp_create_context_resp(gsn, pdp, -rc);
774 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200775
776err_wrong_af:
777 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
778 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
779 return 0;
jjako52c24142002-12-16 13:33:51 +0000780}
781
Harald Weltedda21ed2017-08-12 15:07:02 +0200782/* Internet-originated IP packet, needs to be sent via GTP towards MS */
783static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100784{
Harald Weltedda21ed2017-08-12 15:07:02 +0200785 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100786 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200787 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200788 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200789 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200790 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100791 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100792 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000793
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100794 switch (iph->version) {
795 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200796 if (len < sizeof(*iph) || len < 4*iph->ihl)
797 return -1;
798 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200799 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200800 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100801 break;
802 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200803 /* Due to the fact that 3GPP requires an allocation of a
804 * /64 prefix to each MS, we must instruct
805 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100806 * prefix, i.e. the first 8 bytes of the address. If the ll addr
807 * is used, then the match should be done on the trailing 64
808 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200809 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100810 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
811 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200812 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100813 break;
814 default:
Pau Espin Pedrol55d639f2017-12-04 13:17:07 +0100815 LOGP(DTUN, LOGL_NOTICE, "non-IPv%u packet received from tun\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200816 return -1;
817 }
jjakoc6762cf2004-04-28 14:52:58 +0000818
Harald Weltedda21ed2017-08-12 15:07:02 +0200819 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
820 if (!pool)
821 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100822
Max427699e2017-12-05 16:30:37 +0100823 DEBUGP(DTUN, "Received packet for APN(%s) from tun %s", apn->cfg.name, tun->devname);
Harald Weltedda21ed2017-08-12 15:07:02 +0200824
825 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100826 DEBUGPC(DTUN, " with no PDP contex! (%s)\n", iph->version == 4 ?
827 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
828 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100829 return 0;
830 }
Max427699e2017-12-05 16:30:37 +0100831 DEBUGPC(DTUN, "\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100832
833 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200834 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100835 return 0;
jjako52c24142002-12-16 13:33:51 +0000836}
837
Harald Welted46bcd22017-08-08 23:27:22 +0200838/* RFC3307 link-local scope multicast address */
839static const struct in6_addr all_router_mcast_addr = {
840 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
841};
842
Harald Weltedda21ed2017-08-12 15:07:02 +0200843/* MS-originated GTP1-U packet, needs to be sent via TUN device */
844static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100845{
Harald Welted46bcd22017-08-08 23:27:22 +0200846 struct iphdr *iph = (struct iphdr *)pack;
847 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800848 struct tun_t *tun = (struct tun_t *)pdp->ipif;
849 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100850 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100851 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100852 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800853
854 OSMO_ASSERT(tun);
855 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200856
Max427699e2017-12-05 16:30:37 +0100857 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 +0200858
859 switch (iph->version) {
860 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100861 peer = pdp_get_peer_ipv(pdp, true);
862 if (!peer) {
863 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
864 osmo_hexdump(pack, len));
865 return -1;
866 }
867
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100868 /* Validate packet comes from IPaddr assigned to the pdp ctx.
869 If packet is a LL addr, then EUA is in the lower 64 bits,
870 otherwise it's used as the 64 prefix */
871 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
872 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
873 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
874 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
875 return -1;
876 }
877
Harald Welted46bcd22017-08-08 23:27:22 +0200878 /* daddr: all-routers multicast addr */
879 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100880 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
881 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200882 break;
883 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100884 peer = pdp_get_peer_ipv(pdp, false);
885 if (!peer) {
886 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
887 osmo_hexdump(pack, len));
888 return -1;
889 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100890
891 /* Validate packet comes from IPaddr assigned to the pdp ctx */
892 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
893 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
894 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
895 return -1;
896 }
Harald Welted46bcd22017-08-08 23:27:22 +0200897 break;
898 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200899 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
900 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +0200901 return -1;
902 }
Harald Weltebed35df2011-11-02 13:06:18 +0100903 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000904}
905
Harald Welte632e8432017-09-05 18:12:14 +0200906static char *config_file = "osmo-ggsn.cfg";
Harald Weltedda21ed2017-08-12 15:07:02 +0200907
908/* callback for tun device osmocom select loop integration */
909static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
910{
911 struct apn_ctx *apn = fd->data;
912
913 OSMO_ASSERT(what & BSC_FD_READ);
914
915 return tun_decaps(apn->tun.tun);
916}
917
918/* callback for libgtp osmocom select loop integration */
919static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
920{
921 struct ggsn_ctx *ggsn = fd->data;
922 int rc;
923
924 OSMO_ASSERT(what & BSC_FD_READ);
925
926 switch (fd->priv_nr) {
927 case 0:
928 rc = gtp_decaps0(ggsn->gsn);
929 break;
930 case 1:
931 rc = gtp_decaps1c(ggsn->gsn);
932 break;
933 case 2:
934 rc = gtp_decaps1u(ggsn->gsn);
935 break;
936 default:
937 OSMO_ASSERT(0);
938 break;
939 }
940 return rc;
941}
942
943static void ggsn_gtp_tmr_start(struct ggsn_ctx *ggsn)
944{
945 struct timeval next;
946
947 /* Retrieve next retransmission as timeval */
948 gtp_retranstimeout(ggsn->gsn, &next);
949
950 /* re-schedule the timer */
951 osmo_timer_schedule(&ggsn->gtp_timer, next.tv_sec, next.tv_usec/1000);
952}
953
954/* timer callback for libgtp retransmission and ping */
955static void ggsn_gtp_tmr_cb(void *data)
956{
957 struct ggsn_ctx *ggsn = data;
958
959 /* do all the retransmissions as needed */
960 gtp_retrans(ggsn->gsn);
961
962 ggsn_gtp_tmr_start(ggsn);
963}
964
965/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
966static void signal_handler(int s)
967{
968 LOGP(DGGSN, LOGL_NOTICE, "signal %d received\n", s);
969 switch (s) {
970 case SIGINT:
Harald Weltee8049472017-08-20 12:44:21 +0200971 case SIGTERM:
Harald Weltedda21ed2017-08-12 15:07:02 +0200972 LOGP(DGGSN, LOGL_NOTICE, "SIGINT received, shutting down\n");
973 end = 1;
974 break;
975 case SIGABRT:
976 case SIGUSR1:
977 talloc_report(tall_vty_ctx, stderr);
978 talloc_report_full(tall_ggsn_ctx, stderr);
979 break;
980 case SIGUSR2:
981 talloc_report_full(tall_vty_ctx, stderr);
982 break;
983 default:
984 break;
985 }
986}
987
Oliver Smith1cde2c12019-05-13 11:35:03 +0200988/* libgtp callback for confirmations */
989static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
990{
991 int rc = 0;
992
993 if (cause == EOF)
994 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
995 type, pdp, cbp);
996
997 switch (type) {
998 case GTP_DELETE_PDP_REQ:
999 /* Remark: We actually never reach this path nowadays because
1000 only place where we call gtp_delete_context_req2() is during
1001 apn_stop()->pool_close_all_pdp() path, and in that case we
1002 free all pdp contexts immediatelly without waiting for
1003 confirmation since we want to tear down the whole APN
1004 anyways. As a result, DeleteCtxResponse will never reach here
1005 since it will be dropped at some point in lower layers in the
1006 Rx path. This code is nevertheless left here in order to ease
1007 future developent and avoid possible future memleaks once more
1008 scenarios where GGSN sends a DeleteCtxRequest are introduced. */
1009 if (pdp)
1010 rc = pdp_freepdp(pdp);
1011 }
1012 return rc;
1013}
Harald Weltedda21ed2017-08-12 15:07:02 +02001014
1015/* Start a given GGSN */
1016int ggsn_start(struct ggsn_ctx *ggsn)
1017{
1018 struct apn_ctx *apn;
1019 int rc;
1020
1021 if (ggsn->started)
1022 return 0;
1023
1024 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
1025
1026 /* Start libgtp listener */
1027 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
1028 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
1029 return -1;
1030 }
1031 ggsn->gsn->priv = ggsn;
1032
Harald Welte98146772017-09-05 17:41:20 +02001033 /* patch in different addresses to use (in case we're behind NAT, the listen
1034 * address is different from what we advertise externally) */
1035 if (ggsn->cfg.gtpc_addr.v4.s_addr)
1036 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
1037
1038 if (ggsn->cfg.gtpu_addr.v4.s_addr)
1039 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
1040
Harald Weltedda21ed2017-08-12 15:07:02 +02001041 /* Register File Descriptors */
1042 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
1043 rc = osmo_fd_register(&ggsn->gtp_fd0);
1044 OSMO_ASSERT(rc == 0);
1045
1046 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
1047 rc = osmo_fd_register(&ggsn->gtp_fd1c);
1048 OSMO_ASSERT(rc == 0);
1049
1050 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
1051 rc = osmo_fd_register(&ggsn->gtp_fd1u);
1052 OSMO_ASSERT(rc == 0);
1053
1054 /* Start GTP re-transmission timer */
1055 osmo_timer_setup(&ggsn->gtp_timer, ggsn_gtp_tmr_cb, ggsn);
Pau Espin Pedrolcd87c5f2019-05-27 16:35:00 +02001056 ggsn_gtp_tmr_start(ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001057
1058 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
1059 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
1060 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001061 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Harald Weltedda21ed2017-08-12 15:07:02 +02001062
1063 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
1064 ggsn->started = true;
1065
1066 llist_for_each_entry(apn, &ggsn->apn_list, list)
1067 apn_start(apn);
1068
1069 return 0;
1070}
1071
1072/* Stop a given GGSN */
1073int ggsn_stop(struct ggsn_ctx *ggsn)
1074{
1075 struct apn_ctx *apn;
1076
1077 if (!ggsn->started)
1078 return 0;
1079
1080 /* iterate over all APNs and stop them */
1081 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +02001082 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001083
1084 osmo_timer_del(&ggsn->gtp_timer);
1085
1086 osmo_fd_unregister(&ggsn->gtp_fd1u);
1087 osmo_fd_unregister(&ggsn->gtp_fd1c);
1088 osmo_fd_unregister(&ggsn->gtp_fd0);
1089
1090 if (ggsn->gsn) {
1091 gtp_free(ggsn->gsn);
1092 ggsn->gsn = NULL;
1093 }
1094
1095 ggsn->started = false;
1096 return 0;
1097}
1098
1099static void print_usage()
1100{
1101 printf("Usage: osmo-ggsn [-h] [-D] [-c configfile] [-V]\n");
1102}
1103
1104static void print_help()
1105{
1106 printf( " Some useful help...\n"
1107 " -h --help This help text\n"
1108 " -D --daemonize Fork the process into a background daemon\n"
1109 " -c --config-file filename The config file to use\n"
1110 " -V --version Print the version of OsmoGGSN\n"
1111 );
1112}
1113
1114static void handle_options(int argc, char **argv)
1115{
1116 while (1) {
1117 int option_index = 0, c;
1118 static struct option long_options[] = {
1119 { "help", 0, 0, 'h' },
1120 { "daemonize", 0, 0, 'D' },
1121 { "config-file", 1, 0, 'c' },
1122 { "version", 0, 0, 'V' },
1123 { 0, 0, 0, 0 }
1124 };
1125
1126 c = getopt_long(argc, argv, "hdc:V", long_options, &option_index);
1127 if (c == -1)
1128 break;
1129
1130 switch (c) {
1131 case 'h':
1132 print_usage();
1133 print_help();
1134 exit(0);
1135 case 'D':
1136 daemonize = 1;
1137 break;
1138 case 'c':
1139 config_file = optarg;
1140 break;
1141 case 'V':
1142 print_version(1);
1143 exit(0);
1144 break;
1145 }
1146 }
1147}
1148
jjako52c24142002-12-16 13:33:51 +00001149int main(int argc, char **argv)
1150{
Harald Weltedda21ed2017-08-12 15:07:02 +02001151 struct ggsn_ctx *ggsn;
1152 int rc;
jjako52c24142002-12-16 13:33:51 +00001153
Harald Welte632e8432017-09-05 18:12:14 +02001154 tall_ggsn_ctx = talloc_named_const(NULL, 0, "OsmoGGSN");
Harald Weltedda21ed2017-08-12 15:07:02 +02001155 msgb_talloc_ctx_init(tall_ggsn_ctx, 0);
Harald Welte3e443ca2018-02-14 01:04:04 +01001156 g_vty_info.tall_ctx = tall_ggsn_ctx;
jjako52c24142002-12-16 13:33:51 +00001157
Harald Weltee8049472017-08-20 12:44:21 +02001158 /* Handle keyboard interrupt SIGINT */
Harald Weltedda21ed2017-08-12 15:07:02 +02001159 signal(SIGINT, &signal_handler);
Harald Weltee8049472017-08-20 12:44:21 +02001160 signal(SIGTERM, &signal_handler);
Harald Weltedda21ed2017-08-12 15:07:02 +02001161 signal(SIGABRT, &signal_handler);
1162 signal(SIGUSR1, &signal_handler);
1163 signal(SIGUSR2, &signal_handler);
jjako52c24142002-12-16 13:33:51 +00001164
Harald Weltedda21ed2017-08-12 15:07:02 +02001165 osmo_init_ignore_signals();
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001166 osmo_init_logging2(tall_ggsn_ctx, &log_info);
Harald Weltedda21ed2017-08-12 15:07:02 +02001167 osmo_stats_init(tall_ggsn_ctx);
jjako0141d202004-01-09 15:19:20 +00001168
Harald Weltedda21ed2017-08-12 15:07:02 +02001169 vty_init(&g_vty_info);
1170 logging_vty_add_cmds(NULL);
Harald Welte3e443ca2018-02-14 01:04:04 +01001171 osmo_talloc_vty_add_cmds();
Harald Weltedda21ed2017-08-12 15:07:02 +02001172 osmo_stats_vty_add_cmds(&log_info);
1173 ggsn_vty_init();
1174 ctrl_vty_init(tall_ggsn_ctx);
1175
1176 handle_options(argc, argv);
1177
1178 rate_ctr_init(tall_ggsn_ctx);
1179
1180 rc = vty_read_config_file(config_file, NULL);
1181 if (rc < 0) {
1182 fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
1183 exit(2);
Harald Weltebed35df2011-11-02 13:06:18 +01001184 }
jjako52c24142002-12-16 13:33:51 +00001185
Harald Weltedda21ed2017-08-12 15:07:02 +02001186 rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN);
1187 if (rc < 0)
Harald Weltebed35df2011-11-02 13:06:18 +01001188 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +01001189
Pau Espin Pedrol3e0baa62018-06-19 11:50:02 +02001190 g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
1191 OSMO_CTRL_PORT_GGSN, NULL);
Harald Weltedda21ed2017-08-12 15:07:02 +02001192 if (!g_ctrlh) {
1193 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001194 exit(1);
1195 }
jjako88c22162003-07-06 19:33:18 +00001196
Harald Weltedda21ed2017-08-12 15:07:02 +02001197 if (daemonize) {
1198 rc = osmo_daemonize();
1199 if (rc < 0) {
1200 perror("Error during daemonize");
Harald Weltebed35df2011-11-02 13:06:18 +01001201 exit(1);
1202 }
1203 }
jjako1d3db972004-01-16 09:56:56 +00001204
Harald Weltedda21ed2017-08-12 15:07:02 +02001205#if 0
Harald Weltebed35df2011-11-02 13:06:18 +01001206 /* qos */
1207 qos.l = 3;
1208 qos.v[2] = (args_info.qos_arg) & 0xff;
1209 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
1210 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
Harald Weltedda21ed2017-08-12 15:07:02 +02001211#endif
jjakoa7cd2492003-04-11 09:40:12 +00001212
Harald Weltedda21ed2017-08-12 15:07:02 +02001213 /* Main select loop */
1214 while (!end) {
1215 osmo_select_main(0);
Harald Weltebed35df2011-11-02 13:06:18 +01001216 }
jjakoe0149782003-07-06 17:07:04 +00001217
Harald Weltedda21ed2017-08-12 15:07:02 +02001218 llist_for_each_entry(ggsn, &g_ggsn_list, list)
1219 ggsn_stop(ggsn);
Harald Weltebed35df2011-11-02 13:06:18 +01001220
Max3fc9cc92019-03-14 11:16:55 +01001221 return 0;
jjako52c24142002-12-16 13:33:51 +00001222}