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