blob: ffa508b07ad633dbc8abcfa1454c7eaf3b7bd8b8 [file] [log] [blame]
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02001/*
Harald Welte632e8432017-09-05 18:12:14 +02002 * OsmoGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welte7bdc80d2019-04-11 18:47:59 +02004 * Copyright (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02005 *
jjakoa7cd2492003-04-11 09:40:12 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +020010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/* ggsn.c
14 *
15 */
16
17#ifdef __linux__
18#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
19#endif
20
jjako0fe0df02004-09-17 11:30:40 +000021#include "../config.h"
22
23#ifdef HAVE_STDINT_H
24#include <stdint.h>
25#endif
jjako52c24142002-12-16 13:33:51 +000026
Harald Weltedda21ed2017-08-12 15:07:02 +020027#include <getopt.h>
jjako52c24142002-12-16 13:33:51 +000028#include <ctype.h>
jjako52c24142002-12-16 13:33:51 +000029#include <signal.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020033#include <unistd.h>
34#include <inttypes.h>
35#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000036#include <sys/types.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020037#include <sys/ioctl.h>
38
39#include <net/if.h>
40#include <arpa/inet.h>
jjako52c24142002-12-16 13:33:51 +000041#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020042#include <netinet/ip.h>
Harald Weltea0d281d2017-08-02 21:48:16 +020043#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000044
Harald Weltedda21ed2017-08-12 15:07:02 +020045#include <osmocom/core/timer.h>
Max727417d2016-08-02 17:10:38 +020046#include <osmocom/ctrl/control_if.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020047#include <osmocom/gsm/apn.h>
Max727417d2016-08-02 17:10:38 +020048
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020049#include "../lib/tun.h"
50#include "../lib/ippool.h"
51#include "../lib/syserr.h"
Harald Welted12eab92017-08-02 19:49:47 +020052#include "../lib/in46_addr.h"
Harald Weltef2286392018-04-25 19:02:31 +020053#include "../lib/gtp-kernel.h"
Pau Espin Pedrolf612ffe2019-08-20 13:24:55 +020054#include "../lib/util.h"
jjako52c24142002-12-16 13:33:51 +000055#include "../gtp/pdp.h"
56#include "../gtp/gtp.h"
Harald Welted46bcd22017-08-08 23:27:22 +020057#include "icmpv6.h"
Pau Espin Pedrolf7884e82019-08-20 12:06:13 +020058#include "pco.h"
Harald Weltedda21ed2017-08-12 15:07:02 +020059#include "ggsn.h"
jjako52c24142002-12-16 13:33:51 +000060
Harald Weltedda21ed2017-08-12 15:07:02 +020061static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what);
62static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len);
63
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 */
197 osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, BSC_FD_READ, ggsn_tun_fd_cb, apn, 0);
198 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 Welted9d88622017-08-04 00:22:35 +0200470 /* FIXME: we manually force all context requests to dynamic here! */
471 if (pdp->eua.l > 2)
472 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000473
Harald Weltebed35df2011-11-02 13:06:18 +0100474 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
jjako52c24142002-12-16 13:33:51 +0000475
Harald Weltebed35df2011-11-02 13:06:18 +0100476 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
477 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000478
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100479 memset(addr, 0, sizeof(addr));
480 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200481 LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
Harald Welted1bf1e12017-08-03 00:00:23 +0200482 osmo_hexdump(pdp->eua.v, pdp->eua.l));
483 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
484 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100485 }
jjakoa7cd2492003-04-11 09:40:12 +0000486
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700487 /* Store the actual APN for logging and the VTY */
488 rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
489 if (rc < 0) /* Unlikely this would happen, but anyway... */
490 LOGPPDP(LOGL_ERROR, pdp, "Failed to store APN '%s'\n", apn->cfg.name);
491 pdp->apn_use.l = rc;
492
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100493 /* Allocate dynamic addresses from the pool */
494 for (i = 0; i < num_addr; i++) {
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200495 if (in46a_is_v4(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100496 /* does this APN actually have an IPv4 pool? */
497 if (!apn_supports_ipv4(apn))
498 goto err_wrong_af;
Harald Welte9d9d91b2017-10-14 16:22:16 +0200499
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100500 rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
501 if (rc < 0)
502 goto err_pool_full;
503 /* copy back */
504 memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
jjakoa7cd2492003-04-11 09:40:12 +0000505
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100506 addrv4 = member;
507
Pau Espin Pedrol60ee0db2019-08-20 11:43:25 +0200508 } else if (in46a_is_v6(&addr[i])) {
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100509
510 /* does this APN actually have an IPv6 pool? */
511 if (!apn_supports_ipv6(apn))
512 goto err_wrong_af;
513
514 rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
515 if (rc < 0)
516 goto err_pool_full;
517
518 /* IPv6 doesn't really send the real/allocated address at this point, but just
519 * the link-identifier which the MS shall use for router solicitation */
520 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
521 memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
522 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
523 memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100524
525 addrv6 = member;
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100526 } else
527 OSMO_ASSERT(0);
528
529 pdp->peer[i] = member;
530 member->peer = pdp;
531 }
532
533 in46a_to_eua(addr, num_addr, &pdp->eua);
534
Harald Welte546884d2018-04-25 21:13:06 +0200535 if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200536 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Harald Welte698a2332017-11-08 15:09:58 +0900537 if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200538 LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
539 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
540 return 0;
541 }
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100542 }
Harald Welte9d9d91b2017-10-14 16:22:16 +0200543
Harald Weltedda21ed2017-08-12 15:07:02 +0200544 pdp->ipif = apn->tun.tun; /* TODO */
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200545
546 pdp_priv = talloc_zero(ggsn, struct pdp_priv_t);
547 pdp->priv = pdp_priv;
548 pdp_priv->lib = pdp;
549 /* Create sgsn and assign pdp to it */
550 sgsn = ggsn_find_or_create_sgsn(ggsn, pdp);
551 sgsn_peer_add_pdp_priv(sgsn, pdp_priv);
552 pdp_priv->apn = apn;
Max3142d8d2017-05-04 17:45:10 +0200553
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100554 /* TODO: change trap to send 2 IPs */
Max3142d8d2017-05-04 17:45:10 +0200555 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200556 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
557 return 0;
558 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100559
Harald Weltedda21ed2017-08-12 15:07:02 +0200560 process_pco(apn, pdp);
Harald Welte1ae98772017-08-09 20:28:52 +0200561
Harald Welte93fed3b2017-09-24 11:43:17 +0800562 /* Transmit G-PDU sequence numbers (only) if configured in APN */
563 pdp->tx_gpdu_seq = apn->cfg.tx_gpdu_seq;
564
Pau Espin Pedrol4e43ef52018-01-26 18:12:19 +0100565 LOGPPDP(LOGL_INFO, pdp, "Successful PDP Context Creation: APN=%s(%s), TEIC=%u, IPv4=%s, IPv6=%s\n",
566 name_buf, apn->cfg.name, pdp->teic_own,
567 addrv4 ? inet_ntop(AF_INET, &addrv4->addr.v4, straddrv4, sizeof(straddrv4)) : "none",
568 addrv6 ? inet_ntop(AF_INET6, &addrv6->addr.v6, straddrv6, sizeof(straddrv6)) : "none");
Harald Weltebed35df2011-11-02 13:06:18 +0100569 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
570 return 0; /* Success */
Harald Weltedda21ed2017-08-12 15:07:02 +0200571
572err_pool_full:
573 LOGPPDP(LOGL_ERROR, pdp, "Cannot allocate IP address from pool (full!)\n");
574 gtp_create_context_resp(gsn, pdp, -rc);
575 return 0; /* Already in use, or no more available */
Harald Welte9d9d91b2017-10-14 16:22:16 +0200576
577err_wrong_af:
578 LOGPPDP(LOGL_ERROR, pdp, "APN doesn't support requested EUA / AF type\n");
579 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
580 return 0;
jjako52c24142002-12-16 13:33:51 +0000581}
582
Harald Weltedda21ed2017-08-12 15:07:02 +0200583/* Internet-originated IP packet, needs to be sent via GTP towards MS */
584static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100585{
Harald Weltedda21ed2017-08-12 15:07:02 +0200586 struct apn_ctx *apn = tun->priv;
Harald Weltebed35df2011-11-02 13:06:18 +0100587 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200588 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200589 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200590 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltedda21ed2017-08-12 15:07:02 +0200591 struct ippool_t *pool;
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100592 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100593 uint8_t pref_offset;
jjakoc6762cf2004-04-28 14:52:58 +0000594
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100595 switch (iph->version) {
596 case 4:
Harald Welted12eab92017-08-02 19:49:47 +0200597 if (len < sizeof(*iph) || len < 4*iph->ihl)
598 return -1;
599 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200600 dst.v4.s_addr = iph->daddr;
Harald Weltedda21ed2017-08-12 15:07:02 +0200601 pool = apn->v4.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100602 break;
603 case 6:
Harald Welted4d6e092017-08-08 18:10:43 +0200604 /* Due to the fact that 3GPP requires an allocation of a
605 * /64 prefix to each MS, we must instruct
606 * ippool_getip() below to match only the leading /64
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100607 * prefix, i.e. the first 8 bytes of the address. If the ll addr
608 * is used, then the match should be done on the trailing 64
609 * bits. */
Harald Welted4d6e092017-08-08 18:10:43 +0200610 dst.len = 8;
Pau Espin Pedroldddbbaa2018-01-30 16:16:33 +0100611 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
612 memcpy(&dst.v6, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
Harald Weltedda21ed2017-08-12 15:07:02 +0200613 pool = apn->v6.pool;
Pau Espin Pedrola4942e62018-01-30 16:01:27 +0100614 break;
615 default:
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200616 LOGTUN(LOGL_NOTICE, tun, "non-IPv%u packet received\n", iph->version);
Harald Welted12eab92017-08-02 19:49:47 +0200617 return -1;
618 }
jjakoc6762cf2004-04-28 14:52:58 +0000619
Harald Weltedda21ed2017-08-12 15:07:02 +0200620 /* IPv6 packet but no IPv6 pool, or IPv4 packet with no IPv4 pool */
621 if (!pool)
622 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100623
Harald Weltedda21ed2017-08-12 15:07:02 +0200624 if (ippool_getip(pool, &ipm, &dst)) {
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200625 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s) with no PDP contex! (%s)\n",
626 apn->cfg.name,
627 iph->version == 4 ?
Pau Espin Pedrol134855c2018-01-30 16:04:53 +0100628 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
629 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
Harald Weltebed35df2011-11-02 13:06:18 +0100630 return 0;
631 }
Pau Espin Pedrol012d51e2019-08-20 13:43:38 +0200632 LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s)\n", apn->cfg.name);
Harald Weltebed35df2011-11-02 13:06:18 +0100633
634 if (ipm->peer) /* Check if a peer protocol is defined */
Harald Weltedda21ed2017-08-12 15:07:02 +0200635 gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +0100636 return 0;
jjako52c24142002-12-16 13:33:51 +0000637}
638
Harald Welted46bcd22017-08-08 23:27:22 +0200639/* RFC3307 link-local scope multicast address */
640static const struct in6_addr all_router_mcast_addr = {
641 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
642};
643
Harald Weltedda21ed2017-08-12 15:07:02 +0200644/* MS-originated GTP1-U packet, needs to be sent via TUN device */
645static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +0100646{
Harald Welted46bcd22017-08-08 23:27:22 +0200647 struct iphdr *iph = (struct iphdr *)pack;
648 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
Harald Weltef85fe972017-09-24 20:00:34 +0800649 struct tun_t *tun = (struct tun_t *)pdp->ipif;
650 struct apn_ctx *apn = tun->priv;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100651 char straddr[INET6_ADDRSTRLEN];
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100652 struct ippoolm_t *peer;
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100653 uint8_t pref_offset;
Harald Weltef85fe972017-09-24 20:00:34 +0800654
655 OSMO_ASSERT(tun);
656 OSMO_ASSERT(apn);
Harald Welted46bcd22017-08-08 23:27:22 +0200657
Max427699e2017-12-05 16:30:37 +0100658 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 +0200659
660 switch (iph->version) {
661 case 6:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100662 peer = pdp_get_peer_ipv(pdp, true);
663 if (!peer) {
664 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
665 osmo_hexdump(pack, len));
666 return -1;
667 }
668
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100669 /* Validate packet comes from IPaddr assigned to the pdp ctx.
670 If packet is a LL addr, then EUA is in the lower 64 bits,
671 otherwise it's used as the 64 prefix */
672 pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ? 8 : 0;
673 if (memcmp(((uint8_t*)&ip6h->ip6_src) + pref_offset, &peer->addr.v6, 8)) {
674 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv6: %s\n",
675 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
676 return -1;
677 }
678
Harald Welted46bcd22017-08-08 23:27:22 +0200679 /* daddr: all-routers multicast addr */
680 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100681 return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
682 &apn->v6_lladdr, pack, len);
Harald Welted46bcd22017-08-08 23:27:22 +0200683 break;
684 case 4:
Pau Espin Pedrol7d54ed42018-01-25 20:09:16 +0100685 peer = pdp_get_peer_ipv(pdp, false);
686 if (!peer) {
687 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
688 osmo_hexdump(pack, len));
689 return -1;
690 }
Pau Espin Pedrol5b1ef952018-01-25 20:50:59 +0100691
692 /* Validate packet comes from IPaddr assigned to the pdp ctx */
693 if (memcmp(&iph->saddr, &peer->addr.v4, sizeof(peer->addr.v4))) {
694 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS using unassigned src IPv4: %s\n",
695 inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)));
696 return -1;
697 }
Harald Welted46bcd22017-08-08 23:27:22 +0200698 break;
699 default:
Harald Weltedda21ed2017-08-12 15:07:02 +0200700 LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
701 osmo_hexdump(pack, len));
Harald Welted46bcd22017-08-08 23:27:22 +0200702 return -1;
703 }
Harald Weltebed35df2011-11-02 13:06:18 +0100704 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000705}
706
Harald Weltedda21ed2017-08-12 15:07:02 +0200707/* callback for tun device osmocom select loop integration */
708static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
709{
710 struct apn_ctx *apn = fd->data;
711
712 OSMO_ASSERT(what & BSC_FD_READ);
713
714 return tun_decaps(apn->tun.tun);
715}
716
717/* callback for libgtp osmocom select loop integration */
718static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
719{
720 struct ggsn_ctx *ggsn = fd->data;
721 int rc;
722
723 OSMO_ASSERT(what & BSC_FD_READ);
724
725 switch (fd->priv_nr) {
726 case 0:
727 rc = gtp_decaps0(ggsn->gsn);
728 break;
729 case 1:
730 rc = gtp_decaps1c(ggsn->gsn);
731 break;
732 case 2:
733 rc = gtp_decaps1u(ggsn->gsn);
734 break;
735 default:
736 OSMO_ASSERT(0);
737 break;
738 }
739 return rc;
740}
741
742static void ggsn_gtp_tmr_start(struct ggsn_ctx *ggsn)
743{
744 struct timeval next;
745
746 /* Retrieve next retransmission as timeval */
747 gtp_retranstimeout(ggsn->gsn, &next);
748
749 /* re-schedule the timer */
750 osmo_timer_schedule(&ggsn->gtp_timer, next.tv_sec, next.tv_usec/1000);
751}
752
753/* timer callback for libgtp retransmission and ping */
754static void ggsn_gtp_tmr_cb(void *data)
755{
756 struct ggsn_ctx *ggsn = data;
757
758 /* do all the retransmissions as needed */
759 gtp_retrans(ggsn->gsn);
760
761 ggsn_gtp_tmr_start(ggsn);
762}
763
Oliver Smith1cde2c12019-05-13 11:35:03 +0200764/* libgtp callback for confirmations */
765static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
766{
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200767 struct sgsn_peer *sgsn;
Oliver Smith1cde2c12019-05-13 11:35:03 +0200768 int rc = 0;
769
770 if (cause == EOF)
771 LOGP(DGGSN, LOGL_NOTICE, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
772 type, pdp, cbp);
773
774 switch (type) {
775 case GTP_DELETE_PDP_REQ:
776 /* Remark: We actually never reach this path nowadays because
777 only place where we call gtp_delete_context_req2() is during
Pau Espin Pedrol26e300f2019-08-29 14:02:28 +0200778 ggsn_close_one_pdp() path, and in that case we free all pdp
779 contexts immediatelly without waiting for confirmation
780 (through gtp_freepdp_teardown()) since we want to tear down
781 the whole APN anyways. As a result, DeleteCtxResponse will
782 never reach here since it will be dropped at some point in
783 lower layers in the Rx path. This code is nevertheless left
784 here in order to ease future developent and avoid possible
785 future memleaks once more scenarios where GGSN sends a
786 DeleteCtxRequest are introduced. */
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200787 if (pdp)
Pau Espin Pedrol26e300f2019-08-29 14:02:28 +0200788 rc = gtp_freepdp(pdp->gsn, pdp);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200789 break;
790 case GTP_ECHO_REQ:
791 sgsn = (struct sgsn_peer *)cbp;
792 sgsn_peer_echo_resp(sgsn, cause == EOF);
793 break;
Oliver Smith1cde2c12019-05-13 11:35:03 +0200794 }
795 return rc;
796}
Harald Weltedda21ed2017-08-12 15:07:02 +0200797
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200798static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
799{
800 struct ggsn_ctx *ggsn = (struct ggsn_ctx *)gsn->priv;
801 struct sgsn_peer *sgsn;
802
803 sgsn = ggsn_find_sgsn(ggsn, &peer->sin_addr);
804 if (!sgsn) {
805 LOGPGGSN(LOGL_NOTICE, ggsn, "Received Recovery IE for unknown SGSN (no PDP contexts active)\n");
806 return -EINVAL;
807 }
808
809 return sgsn_peer_handle_recovery(sgsn, pdp, recovery);
810}
811
Harald Weltedda21ed2017-08-12 15:07:02 +0200812/* Start a given GGSN */
813int ggsn_start(struct ggsn_ctx *ggsn)
814{
815 struct apn_ctx *apn;
816 int rc;
817
818 if (ggsn->started)
819 return 0;
820
821 LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n");
822
823 /* Start libgtp listener */
824 if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) {
825 LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno));
826 return -1;
827 }
828 ggsn->gsn->priv = ggsn;
829
Harald Welte98146772017-09-05 17:41:20 +0200830 /* patch in different addresses to use (in case we're behind NAT, the listen
831 * address is different from what we advertise externally) */
832 if (ggsn->cfg.gtpc_addr.v4.s_addr)
833 ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4;
834
835 if (ggsn->cfg.gtpu_addr.v4.s_addr)
836 ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
837
Harald Weltedda21ed2017-08-12 15:07:02 +0200838 /* Register File Descriptors */
839 osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
840 rc = osmo_fd_register(&ggsn->gtp_fd0);
841 OSMO_ASSERT(rc == 0);
842
843 osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
844 rc = osmo_fd_register(&ggsn->gtp_fd1c);
845 OSMO_ASSERT(rc == 0);
846
847 osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
848 rc = osmo_fd_register(&ggsn->gtp_fd1u);
849 OSMO_ASSERT(rc == 0);
850
851 /* Start GTP re-transmission timer */
852 osmo_timer_setup(&ggsn->gtp_timer, ggsn_gtp_tmr_cb, ggsn);
Pau Espin Pedrolcd87c5f2019-05-27 16:35:00 +0200853 ggsn_gtp_tmr_start(ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200854
855 gtp_set_cb_data_ind(ggsn->gsn, encaps_tun);
856 gtp_set_cb_delete_context(ggsn->gsn, delete_context);
857 gtp_set_cb_create_context_ind(ggsn->gsn, create_context_ind);
Oliver Smith1cde2c12019-05-13 11:35:03 +0200858 gtp_set_cb_conf(ggsn->gsn, cb_conf);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200859 gtp_set_cb_recovery3(ggsn->gsn, cb_recovery3);
Harald Weltedda21ed2017-08-12 15:07:02 +0200860
861 LOGPGGSN(LOGL_NOTICE, ggsn, "Successfully started\n");
862 ggsn->started = true;
863
864 llist_for_each_entry(apn, &ggsn->apn_list, list)
865 apn_start(apn);
866
867 return 0;
868}
869
870/* Stop a given GGSN */
871int ggsn_stop(struct ggsn_ctx *ggsn)
872{
873 struct apn_ctx *apn;
874
875 if (!ggsn->started)
876 return 0;
877
878 /* iterate over all APNs and stop them */
879 llist_for_each_entry(apn, &ggsn->apn_list, list)
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200880 apn_stop(apn);
Harald Weltedda21ed2017-08-12 15:07:02 +0200881
882 osmo_timer_del(&ggsn->gtp_timer);
883
884 osmo_fd_unregister(&ggsn->gtp_fd1u);
885 osmo_fd_unregister(&ggsn->gtp_fd1c);
886 osmo_fd_unregister(&ggsn->gtp_fd0);
887
888 if (ggsn->gsn) {
889 gtp_free(ggsn->gsn);
890 ggsn->gsn = NULL;
891 }
892
893 ggsn->started = false;
894 return 0;
895}