blob: f137f2c6f82d3c2dbcd785f52ba0e3be384d32a5 [file] [log] [blame]
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001/*
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 Welte6748dc92017-09-24 21:54:59 +08004 * Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01005 *
jjako52c24142002-12-16 13:33:51 +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 Pedrol7c4de072017-12-14 13:59:02 +010010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/*
14 * sgsnemu.c
15 *
16 */
17
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020018#include "config.h"
19
jjako52c24142002-12-16 13:33:51 +000020#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010021#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000022#endif
23
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010024#include <osmocom/core/application.h>
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020025#include <osmocom/core/msgb.h>
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010026
jjako52c24142002-12-16 13:33:51 +000027#include <ctype.h>
28#include <netdb.h>
29#include <signal.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020036#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080037#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000038#include <arpa/inet.h>
39#include <sys/wait.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include <sys/socket.h>
43#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000044#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000045#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000046#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000047#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000048#include <resolv.h>
49#include <time.h>
50
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020051#if defined(__linux__)
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020052#if defined(HAVE_IN6_ADDR_GEN_MODE_NONE)
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020053#include <linux/if_link.h>
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020054#endif // HAVE_IN6_ADDR_GEN_MODE_NONE
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020055#endif
56
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020057#include "../lib/tun.h"
58#include "../lib/ippool.h"
59#include "../lib/syserr.h"
Andreas Schultzb6292402018-10-05 13:58:45 +010060#include "../lib/netns.h"
Pau Espin Pedrole2b09612020-04-15 15:09:30 +020061#include "../lib/icmpv6.h"
jjako52c24142002-12-16 13:33:51 +000062#include "../gtp/pdp.h"
63#include "../gtp/gtp.h"
64#include "cmdline.h"
65
Harald Weltebed35df2011-11-02 13:06:18 +010066#define IPADDRLEN 256 /* Character length of addresses */
67#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000068
jjakoa7cd2492003-04-11 09:40:12 +000069/* HASH tables for IP address allocation */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +020070struct pdp_peer_sgsnemu_ctx;
jjakoa7cd2492003-04-11 09:40:12 +000071struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010072 uint8_t inuse; /* 0=free. 1=used by somebody */
73 struct iphash_t *ipnext;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +020074 struct pdp_peer_sgsnemu_ctx *ctx;
Harald Welted12eab92017-08-02 19:49:47 +020075 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000076};
jjakoa7cd2492003-04-11 09:40:12 +000077struct iphash_t *iphash[MAXCONTEXTS];
78
Pau Espin Pedrol04715d22020-04-15 19:44:01 +020079struct pdp_peer_sgsnemu_ctx {
80 struct iphash_t hash_v4;
81 struct iphash_t hash_v6_ll;
82 struct iphash_t hash_v6_global;
83 struct pdp_t *pdp;
84};
85struct pdp_peer_sgsnemu_ctx ctx_arr[MAXCONTEXTS];
86
jjakoa7cd2492003-04-11 09:40:12 +000087/* State variable used for ping */
88/* 0: Idle */
89/* 1: Wait_connect */
90/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000091/* 3: Done */
92/* 4: Wait_disconnect */
93/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010094volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000095
Harald Weltebed35df2011-11-02 13:06:18 +010096struct gsn_t *gsn = NULL; /* GSN instance */
97struct tun_t *tun = NULL; /* TUN instance */
98int maxfd = 0; /* For select() */
99int echoversion = 1; /* First try this version */
Pau Espin Pedrol042a4452018-04-17 14:31:42 +0200100void *tall_sgsnemu_ctx; /* root talloc ctx */
Andreas Schultzb6292402018-10-05 13:58:45 +0100101#if defined(__linux__)
102int netns = -1; /* network namespace */
103#endif
jjako52c24142002-12-16 13:33:51 +0000104
jjakoa7cd2492003-04-11 09:40:12 +0000105/* Struct with local versions of gengetopt options */
106struct {
Harald Weltebed35df2011-11-02 13:06:18 +0100107 int debug; /* Print debug messages */
108 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +0800109 char *tun_dev_name;
Andreas Schultzb6292402018-10-05 13:58:45 +0100110 char *netns;
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +0200111 struct in46_addr netaddr; /* Network interface */
Harald Welted12eab92017-08-02 19:49:47 +0200112 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +0100113 char *ipup, *ipdown; /* Filename of scripts */
114 int defaultroute; /* Set up default route */
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200115 struct in46_addr pinghost; /* Remote ping host */
Harald Weltebed35df2011-11-02 13:06:18 +0100116 int pingrate;
117 int pingsize;
118 int pingcount;
119 int pingquiet;
120 struct in_addr listen;
121 struct in_addr remote;
122 struct in_addr dns;
123 int contexts; /* Number of contexts to create */
124 int timelimit; /* Number of seconds to be connected */
125 char *statedir;
126 uint64_t imsi;
127 uint8_t nsapi;
128 int gtpversion;
129 struct ul255_t pco;
130 struct ul255_t qos;
131 uint16_t cch;
132 struct ul255_t apn;
133 uint8_t selmode;
134 struct ul255_t rattype;
135 int rattype_given;
136 struct ul255_t userloc;
137 int userloc_given;
138 struct ul255_t rai;
139 int rai_given;
140 struct ul255_t mstz;
141 int mstz_given;
142 struct ul255_t imeisv;
143 int imeisv_given;
144 struct ul16_t msisdn;
145 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800146 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800147 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000148} options;
jjako52c24142002-12-16 13:33:51 +0000149
jjako5da68452003-01-28 16:08:47 +0000150/* Definitions to use for PING. Most of the ping code was derived from */
151/* the original ping program by Mike Muuss */
152
153/* IP header and ICMP echo header */
154#define CREATEPING_MAX 2048
155#define CREATEPING_IP 20
156#define CREATEPING_ICMP 8
157
158struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100159 uint8_t ipver; /* Type and header length */
160 uint8_t tos; /* Type of Service */
161 uint16_t length; /* Total length */
162 uint16_t fragid; /* Identifier */
163 uint16_t offset; /* Flags and fragment offset */
164 uint8_t ttl; /* Time to live */
165 uint8_t protocol; /* Protocol */
166 uint16_t ipcheck; /* Header checksum */
167 uint32_t src; /* Source address */
168 uint32_t dst; /* Destination */
169 uint8_t type; /* Type and header length */
170 uint8_t code; /* Code */
171 uint16_t checksum; /* Header checksum */
172 uint16_t ident; /* Identifier */
173 uint16_t seq; /* Sequence number */
174 uint8_t data[CREATEPING_MAX]; /* Data */
175} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000176
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200177struct ip6_ping {
178 struct icmpv6_echo_hdr hdr;
179 uint8_t data[CREATEPING_MAX]; /* Data */
180} __attribute__ ((packed));
181
jjako5da68452003-01-28 16:08:47 +0000182/* Statistical values for ping */
183int nreceived = 0;
184int ntreceived = 0;
185int ntransmitted = 0;
186int tmin = 999999999;
187int tmax = 0;
188int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100189int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000190struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000191
Harald Weltefed33892017-10-10 09:02:45 +0800192static void signal_handler(int signo)
bjovana8f71eb2017-02-24 17:39:20 +0100193{
194 if (state == 2)
195 state = 3; /* Tell main loop to finish. */
196}
197
Harald Weltefed33892017-10-10 09:02:45 +0800198static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100199{
Harald Welted12eab92017-08-02 19:49:47 +0200200 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100201 struct iphash_t *h;
202 struct iphash_t *prev = NULL;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +0200203
204 printf("Adding IP to local pool: %s\n", in46a_ntoa(addr));
205
Harald Weltebed35df2011-11-02 13:06:18 +0100206 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200207 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100208 for (h = iphash[hash]; h; h = h->ipnext)
209 prev = h;
210 if (!prev)
211 iphash[hash] = ipaddr;
212 else
213 prev->ipnext = ipaddr;
214 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000215}
216
Harald Weltefed33892017-10-10 09:02:45 +0800217static int ipdel(struct iphash_t *ipaddr)
Harald Weltebed35df2011-11-02 13:06:18 +0100218{
Harald Welted12eab92017-08-02 19:49:47 +0200219 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100220 struct iphash_t *h;
221 struct iphash_t *prev = NULL;
222 for (h = iphash[hash]; h; h = h->ipnext) {
223 if (h == ipaddr) {
224 if (!prev)
225 iphash[hash] = h->ipnext;
226 else
227 prev->ipnext = h->ipnext;
228 return 0;
229 }
230 prev = h;
231 }
232 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000233}
234
Harald Weltefed33892017-10-10 09:02:45 +0800235static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100236{
Harald Welted12eab92017-08-02 19:49:47 +0200237 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100238 struct iphash_t *h;
239 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200240 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100241 *ipaddr = h;
242 return 0;
243 }
244 }
245 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000246}
247
jjakoa7cd2492003-04-11 09:40:12 +0000248/* Used to write process ID to file. Assume someone else will delete */
Harald Weltefed33892017-10-10 09:02:45 +0800249static void log_pid(char *pidfile)
Harald Weltebed35df2011-11-02 13:06:18 +0100250{
251 FILE *file;
252 mode_t oldmask;
253
254 oldmask = umask(022);
255 file = fopen(pidfile, "w");
256 umask(oldmask);
257 if (!file)
258 return;
259 fprintf(file, "%d\n", (int)getpid());
260 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000261}
262
Harald Weltefed33892017-10-10 09:02:45 +0800263static int process_options(int argc, char **argv)
Harald Weltebed35df2011-11-02 13:06:18 +0100264{
265 /* gengeopt declarations */
266 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000267
Harald Weltebed35df2011-11-02 13:06:18 +0100268 struct hostent *host;
269 unsigned int n;
270 uint16_t i;
271 uint8_t a;
272 uint8_t b;
273 char *tmp;
274 char *pch;
275 char *type;
276 char *mcc;
277 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100278 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100279 char *lac;
280 int lac_d;
281 char *rest;
282 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
283 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
284 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
285 int sign;
286 int nbquarters;
287 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000288
Harald Weltebed35df2011-11-02 13:06:18 +0100289 if (cmdline_parser(argc, argv, &args_info) != 0)
290 return -1;
291 if (args_info.debug_flag) {
292 if (args_info.remote_arg)
293 printf("remote: %s\n", args_info.remote_arg);
294 if (args_info.listen_arg)
295 printf("listen: %s\n", args_info.listen_arg);
296 if (args_info.conf_arg)
297 printf("conf: %s\n", args_info.conf_arg);
298 printf("debug: %d\n", args_info.debug_flag);
299 if (args_info.imsi_arg)
300 printf("imsi: %s\n", args_info.imsi_arg);
301 printf("qos: %#08x\n", args_info.qos_arg);
302 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
303 printf("qose2: %#04x\n", args_info.qose2_arg);
304 printf("qose3: %#06x\n", args_info.qose3_arg);
305 printf("qose4: %#06x\n", args_info.qose4_arg);
306 printf("charging: %#04x\n", args_info.charging_arg);
307 if (args_info.apn_arg)
308 printf("apn: %s\n", args_info.apn_arg);
309 if (args_info.msisdn_arg)
310 printf("msisdn: %s\n", args_info.msisdn_arg);
311 if (args_info.uid_arg)
312 printf("uid: %s\n", args_info.uid_arg);
313 if (args_info.pwd_arg)
314 printf("pwd: %s\n", args_info.pwd_arg);
315 if (args_info.pidfile_arg)
316 printf("pidfile: %s\n", args_info.pidfile_arg);
317 if (args_info.statedir_arg)
318 printf("statedir: %s\n", args_info.statedir_arg);
319 if (args_info.dns_arg)
320 printf("dns: %s\n", args_info.dns_arg);
321 printf("contexts: %d\n", args_info.contexts_arg);
322 printf("timelimit: %d\n", args_info.timelimit_arg);
323 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800324 if (args_info.tun_device_arg)
Harald Welte7b9230a2018-10-21 13:09:21 +0200325 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100326 if (args_info.netns_arg)
327 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100328 if (args_info.ipup_arg)
329 printf("ipup: %s\n", args_info.ipup_arg);
330 if (args_info.ipdown_arg)
331 printf("ipdown: %s\n", args_info.ipdown_arg);
332 printf("defaultroute: %d\n", args_info.defaultroute_flag);
333 if (args_info.pinghost_arg)
334 printf("pinghost: %s\n", args_info.pinghost_arg);
335 printf("pingrate: %d\n", args_info.pingrate_arg);
336 printf("pingsize: %d\n", args_info.pingsize_arg);
337 printf("pingcount: %d\n", args_info.pingcount_arg);
338 printf("pingquiet: %d\n", args_info.pingquiet_flag);
339 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800340 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100341 }
jjakoa7cd2492003-04-11 09:40:12 +0000342
Harald Weltebed35df2011-11-02 13:06:18 +0100343 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000344
Harald Weltebed35df2011-11-02 13:06:18 +0100345 if (args_info.conf_arg) {
346 if (cmdline_parser_configfile
347 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
348 return -1;
349 if (args_info.debug_flag) {
350 printf("cmdline_parser_configfile\n");
351 if (args_info.remote_arg)
352 printf("remote: %s\n", args_info.remote_arg);
353 if (args_info.listen_arg)
354 printf("listen: %s\n", args_info.listen_arg);
355 if (args_info.conf_arg)
356 printf("conf: %s\n", args_info.conf_arg);
357 printf("debug: %d\n", args_info.debug_flag);
358 if (args_info.imsi_arg)
359 printf("imsi: %s\n", args_info.imsi_arg);
360 printf("qos: %#08x\n", args_info.qos_arg);
361 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
362 printf("qose2: %#04x\n", args_info.qose2_arg);
363 printf("qose3: %#06x\n", args_info.qose3_arg);
364 printf("qose4: %#06x\n", args_info.qose4_arg);
365 printf("charging: %#04x\n", args_info.charging_arg);
366 if (args_info.apn_arg)
367 printf("apn: %s\n", args_info.apn_arg);
368 if (args_info.msisdn_arg)
369 printf("msisdn: %s\n", args_info.msisdn_arg);
370 if (args_info.uid_arg)
371 printf("uid: %s\n", args_info.uid_arg);
372 if (args_info.pwd_arg)
373 printf("pwd: %s\n", args_info.pwd_arg);
374 if (args_info.pidfile_arg)
375 printf("pidfile: %s\n", args_info.pidfile_arg);
376 if (args_info.statedir_arg)
377 printf("statedir: %s\n",
378 args_info.statedir_arg);
379 if (args_info.dns_arg)
380 printf("dns: %s\n", args_info.dns_arg);
381 printf("contexts: %d\n", args_info.contexts_arg);
382 printf("timelimit: %d\n", args_info.timelimit_arg);
383 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800384 if (args_info.tun_device_arg)
Harald Welte9c332102017-11-06 02:44:42 +0900385 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100386 if (args_info.netns_arg)
387 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100388 if (args_info.ipup_arg)
389 printf("ipup: %s\n", args_info.ipup_arg);
390 if (args_info.ipdown_arg)
391 printf("ipdown: %s\n", args_info.ipdown_arg);
392 printf("defaultroute: %d\n",
393 args_info.defaultroute_flag);
394 if (args_info.pinghost_arg)
395 printf("pinghost: %s\n",
396 args_info.pinghost_arg);
397 printf("pingrate: %d\n", args_info.pingrate_arg);
398 printf("pingsize: %d\n", args_info.pingsize_arg);
399 printf("pingcount: %d\n", args_info.pingcount_arg);
400 printf("pingquiet: %d\n", args_info.pingquiet_flag);
401 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800402 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100403 }
404 }
jjako193e8b12003-11-10 12:31:41 +0000405
Harald Weltebed35df2011-11-02 13:06:18 +0100406 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000407
Harald Weltebed35df2011-11-02 13:06:18 +0100408 /* foreground */
409 /* If fg flag not given run as a daemon */
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100410 /* Do not allow sgsnemu to run as deamon
Harald Weltebed35df2011-11-02 13:06:18 +0100411 if (!args_info.fg_flag)
412 {
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100413 closelog();
Harald Weltebed35df2011-11-02 13:06:18 +0100414 freopen("/dev/null", "w", stdout);
415 freopen("/dev/null", "w", stderr);
416 freopen("/dev/null", "r", stdin);
417 daemon(0, 0);
418 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
419 } */
jjako1a51df72004-07-20 08:30:21 +0000420
Harald Weltebed35df2011-11-02 13:06:18 +0100421 /* debug */
422 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000423
Harald Weltebed35df2011-11-02 13:06:18 +0100424 /* pidfile */
425 /* This has to be done after we have our final pid */
426 if (args_info.pidfile_arg) {
427 log_pid(args_info.pidfile_arg);
428 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200429
Harald Weltebed35df2011-11-02 13:06:18 +0100430 /* dns */
431 /* If no dns option is given use system default */
432 /* Do hostname lookup to translate hostname to IP address */
433 printf("\n");
434 if (args_info.dns_arg) {
435 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100436 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100437 "Invalid DNS address: %s!", args_info.dns_arg);
438 return -1;
439 } else {
440 memcpy(&options.dns.s_addr, host->h_addr,
441 host->h_length);
442 _res.nscount = 1;
443 _res.nsaddr_list[0].sin_addr = options.dns;
444 printf("Using DNS server: %s (%s)\n",
445 args_info.dns_arg, inet_ntoa(options.dns));
446 }
447 } else {
448 options.dns.s_addr = 0;
449 printf("Using default DNS server\n");
450 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200451
Harald Weltebed35df2011-11-02 13:06:18 +0100452 /* listen */
453 /* If no listen option is specified listen to any local port */
454 /* Do hostname lookup to translate hostname to IP address */
455 if (args_info.listen_arg) {
456 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100457 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100458 "Invalid listening address: %s!",
459 args_info.listen_arg);
460 return -1;
461 } else {
462 memcpy(&options.listen.s_addr, host->h_addr,
463 host->h_length);
464 printf("Local IP address is: %s (%s)\n",
465 args_info.listen_arg, inet_ntoa(options.listen));
466 }
467 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100468 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltefdf33582019-12-01 09:25:27 +0100469 "Listening address must be specified!");
Harald Weltebed35df2011-11-02 13:06:18 +0100470 return -1;
471 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200472
Harald Weltebed35df2011-11-02 13:06:18 +0100473 /* remote */
474 /* If no remote option is specified terminate */
475 /* Do hostname lookup to translate hostname to IP address */
476 if (args_info.remote_arg) {
477 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100478 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100479 "Invalid remote address: %s!",
480 args_info.remote_arg);
481 return -1;
482 } else {
483 memcpy(&options.remote.s_addr, host->h_addr,
484 host->h_length);
485 printf("Remote IP address is: %s (%s)\n",
486 args_info.remote_arg, inet_ntoa(options.remote));
487 }
488 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100489 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100490 "No remote address given!");
491 return -1;
492 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200493
Harald Weltebed35df2011-11-02 13:06:18 +0100494 /* imsi */
495 if (strlen(args_info.imsi_arg) != 15) {
496 printf("Invalid IMSI\n");
497 return -1;
498 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200499
Harald Weltebed35df2011-11-02 13:06:18 +0100500 options.imsi = 0xf000000000000000ull;
501 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
502 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
503 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
504 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
505 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
506 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
507 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
508 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
509 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
510 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
511 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
512 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
513 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
514 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
515 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200516
Harald Weltebed35df2011-11-02 13:06:18 +0100517 printf("IMSI is: %s (%#08llx)\n",
518 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200519
Harald Weltebed35df2011-11-02 13:06:18 +0100520 /* nsapi */
521 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
522 printf("Invalid NSAPI\n");
523 return -1;
524 }
525 options.nsapi = args_info.nsapi_arg;
526 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200527
Harald Weltebed35df2011-11-02 13:06:18 +0100528 /* qos */
529 options.qos.l = 4;
530 options.qos.v[3] = (args_info.qos_arg) & 0xff;
531 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
532 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
533 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
534 /* Extensions according to 3GPP TS 24.008 */
535 if (args_info.qose1_given == 1) {
536 options.qos.l = 12;
537 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
538 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
539 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
540 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
541 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
542 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
543 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
544 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
545 if (args_info.qose2_given == 1) {
546 options.qos.l = 13;
547 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
548 if (args_info.qose3_given == 1) {
549 options.qos.l = 15;
550 options.qos.v[14] =
551 (args_info.qose3_arg) & 0xff;
552 options.qos.v[13] =
553 ((args_info.qose3_arg) >> 8) & 0xff;
554 if (args_info.qose4_given == 1) {
555 options.qos.l = 17;
556 options.qos.v[16] =
557 (args_info.qose4_arg) & 0xff;
558 options.qos.v[15] =
559 ((args_info.qose4_arg) >> 8) & 0xff;
560 }
561 }
562 }
563 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 /* charging */
566 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 /* contexts */
569 if (args_info.contexts_arg > MAXCONTEXTS) {
570 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
571 return -1;
572 }
573 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200574
Harald Weltebed35df2011-11-02 13:06:18 +0100575 /* Timelimit */
576 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200577
Harald Weltebed35df2011-11-02 13:06:18 +0100578 /* gtpversion */
579 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
580 printf("Invalid GTP version\n");
581 return -1;
582 }
583 options.gtpversion = args_info.gtpversion_arg;
584 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200585
Harald Weltebed35df2011-11-02 13:06:18 +0100586 /* apn */
587 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
588 printf("Invalid APN\n");
589 return -1;
590 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100591 options.apn.l = strlen(args_info.apn_arg) + 1;
592
593 apn = (char *)options.apn.v;
594 for (tok = strtok(args_info.apn_arg, ".");
595 tok != NULL;
596 tok = strtok(NULL, ".")) {
597 size_t len = strlen(tok);
598
599 *apn++ = (char)len;
600 strncpy(apn, tok, len);
601 apn += len;
602 }
603
Harald Weltebed35df2011-11-02 13:06:18 +0100604 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200605
Harald Weltebed35df2011-11-02 13:06:18 +0100606 /* selmode */
607 options.selmode = args_info.selmode_arg;
608 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 /* rattype */
611 if (args_info.rattype_given == 1) {
612 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800613 options.rattype.l = 1;
614 options.rattype.v[0] = args_info.rattype_arg;
615 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100616 }
Harald Welte41af5692011-10-07 18:42:34 +0200617
Harald Weltebed35df2011-11-02 13:06:18 +0100618 /* userloc */
619 if (args_info.userloc_given == 1) {
620 printf("Using User Location Information: %s\n",
621 args_info.userloc_arg);
622 tmp = args_info.userloc_arg;
623 n = 0;
624 pch = strtok(tmp, ".");
625 while (pch != NULL) {
626 userloc_el[n] = pch;
627 pch = strtok(NULL, ".");
628 n++;
629 }
Harald Welte41af5692011-10-07 18:42:34 +0200630
Harald Weltebed35df2011-11-02 13:06:18 +0100631 options.userloc_given = 1;
632 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200633
Harald Weltebed35df2011-11-02 13:06:18 +0100634 /* 3GPP Geographic Location Type t0 / t1 / t2 */
635 type = userloc_el[0];
636 printf("->type : %c\n", type[0]);
637 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
638 printf("Invalid type \n");
639 return -1;
640 }
641 /* options.userloc.v[0] = 0x00 */
642 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200643
Harald Weltebed35df2011-11-02 13:06:18 +0100644 /* MCC */
645 mcc = userloc_el[1];
646 printf("->mcc : %s\n", mcc);
647 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200648 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100649 return -1;
650 }
Harald Welte41af5692011-10-07 18:42:34 +0200651
Harald Weltebed35df2011-11-02 13:06:18 +0100652 /* MNC */
653 mnc = userloc_el[2];
654 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200655
Harald Weltebed35df2011-11-02 13:06:18 +0100656 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
657 /* options.userloc.v[1] = 0x52 */
658 a = (uint8_t) (mcc[0] - 48);
659 b = (uint8_t) (mcc[1] - 48);
660 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200661
Harald Weltebed35df2011-11-02 13:06:18 +0100662 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
663 /* options.userloc.v[2] = 0xf0 */
664 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200665
Harald Weltebed35df2011-11-02 13:06:18 +0100666 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200667 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100668 return -1;
669 }
670 if (strlen(mnc) == 2) {
671 b = 15;
672 }
673 if (strlen(mnc) == 3) {
674 b = (uint8_t) (mnc[2] - 48);
675 }
676 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200677
Harald Weltebed35df2011-11-02 13:06:18 +0100678 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
679 /* options.userloc.v[3] = 0x99 */
680 a = (uint8_t) (mnc[0] - 48);
681 b = (uint8_t) (mnc[1] - 48);
682 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200683
Harald Weltebed35df2011-11-02 13:06:18 +0100684 /* LAC */
685 lac = userloc_el[3];
686 /*options.userloc.v[4] = 0x12 ; */
687 /*options.userloc.v[5] = 0x10 ; */
688 printf("->LAC: %s\n", lac);
689 lac_d = atoi(lac);
690 if (lac_d > 65535 || lac_d < 1) {
691 printf("Invalid LAC\n");
692 return -1;
693 }
694 i = lac_d >> 8;
695 options.userloc.v[4] = i; /* octet 8 - LAC */
696 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200697
Harald Weltebed35df2011-11-02 13:06:18 +0100698 /* CI/SAC/RAC */
699 rest = userloc_el[4];
700 printf("->CI/SAC/RAC : %s\n", rest);
701 lac_d = atoi(rest);
702 if (lac_d > 65535 || lac_d < 1) {
703 printf("Invalid CI/SAC/RAC\n");
704 return -1;
705 }
706 /*options.userloc.v[6] = 0x04 ; */
707 /*options.userloc.v[7] = 0xb7 ; */
708 i = lac_d >> 8;
709 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
710 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
711 }
jjakoa7cd2492003-04-11 09:40:12 +0000712
Harald Weltebed35df2011-11-02 13:06:18 +0100713 /* RAI */
714 if (args_info.rai_given == 1) {
715 printf("Using RAI: %s\n", args_info.rai_arg);
716 tmp = args_info.rai_arg;
717 n = 0;
718 pch = strtok(tmp, ".");
719 while (pch != NULL) {
720 rai_el[n] = pch;
721 pch = strtok(NULL, ".");
722 n++;
723 }
jjakoa7cd2492003-04-11 09:40:12 +0000724
Harald Weltebed35df2011-11-02 13:06:18 +0100725 options.rai_given = 1;
726 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000727
Harald Weltebed35df2011-11-02 13:06:18 +0100728 /* MCC */
729 mcc = rai_el[0];
730 printf("->mcc : %s\n", mcc);
731 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200732 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100733 return -1;
734 }
735
736 /* MNC */
737 mnc = rai_el[1];
738 printf("->mnc : %s\n", mnc);
739
740 a = (uint8_t) (mcc[0] - 48);
741 b = (uint8_t) (mcc[1] - 48);
742 options.rai.v[0] = 16 * b + a;
743
744 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
745 a = (uint8_t) (mcc[2] - 48);
746
747 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200748 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100749 return -1;
750 }
751 if (strlen(mnc) == 2) {
752 b = 15;
753 }
754 if (strlen(mnc) == 3) {
755 b = (uint8_t) (mnc[2] - 48);
756 }
757 options.rai.v[1] = 16 * b + a;
758
759 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
760 a = (uint8_t) (mnc[0] - 48);
761 b = (uint8_t) (mnc[1] - 48);
762 options.rai.v[2] = 16 * b + a;
763
764 /* LAC */
765 lac = rai_el[2];
766 printf("->LAC: %s\n", lac);
767 lac_d = atoi(lac);
768 if (lac_d > 65535 || lac_d < 1) {
769 printf("Invalid LAC\n");
770 return -1;
771 }
772 i = lac_d >> 8;
773 options.rai.v[3] = i; /* octet 5 - LAC */
774 options.rai.v[4] = lac_d; /* octet 6 - LAC */
775
776 /* RAC */
777 rest = rai_el[3];
778 printf("->RAC : %s\n", rest);
779 lac_d = atoi(rest);
780 if (lac_d > 255 || lac_d < 1) {
781 printf("Invalid RAC\n");
782 return -1;
783 }
784 options.rai.v[5] = lac_d; /* octet 7 - RAC */
785 }
786
787 /* mstz */
788 if (args_info.mstz_given == 1) {
789 options.mstz_given = 1;
790 options.mstz.l = 2;
791
792 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
793 tmp = args_info.mstz_arg;
794 n = 0;
795 pch = strtok(tmp, ".");
796 while (pch != NULL) {
797 mstz_el[n] = pch;
798 pch = strtok(NULL, ".");
799 n++;
800 }
801
802 /* sign */
803 sign = atoi(mstz_el[0]);
804 printf("->Sign (0=+ / 1=-): %d\n", sign);
805 if (sign != 0 && sign != 1) {
806 printf("Invalid Sign \n");
807 return -1;
808 }
809 /* nbquarters */
810 nbquarters = atoi(mstz_el[1]);
811 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
812 if (nbquarters < 0 || nbquarters > 79) {
813 printf("Invalid Number of Quarters \n");
814 return -1;
815 }
816 /* DST */
817 DST = atoi(mstz_el[2]);
818 printf("->Daylight Saving Time Adjustment : %d\n", DST);
819 if (DST < 0 || DST > 3) {
820 printf("Invalid DST Adjustment \n");
821 return -1;
822 }
823 /* 12345678
824 bits 123 = unit of # of quarters of an hour
825 bits 678 = # of quarters of an hour / 10
826 bit 5 = sign
827 */
828 i = nbquarters % 10;
829 i = i << 4;
830 i = i + nbquarters / 10 + 8 * sign;
831 /* options.mstz.v[0] = 0x69 ; */
832 /* options.mstz.v[1] = 0x01 ; */
833 options.mstz.v[0] = i;
834 options.mstz.v[1] = DST;
835 n = (i & 0x08) ? '-' : '+';
836 printf
837 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
838 n, nbquarters / 4, nbquarters % 4 * 15);
839 }
840
841 /* imeisv */
842 if (args_info.imeisv_given == 1) {
843 options.imeisv_given = 1;
844 if (strlen(args_info.imeisv_arg) != 16) {
845 printf("Invalid IMEI(SV)\n");
846 return -1;
847 }
848 options.imeisv.l = 8;
849 for (n = 0; n < 8; n++) {
850 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
851 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
852 options.imeisv.v[n] = 16 * b + a;
853 }
854 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
855 }
856
857 /* msisdn */
858 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
859 printf("Invalid MSISDN\n");
860 return -1;
861 }
862 options.msisdn.l = 1;
863 options.msisdn.v[0] = 0x91; /* International format */
864 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
865 if ((n % 2) == 0) {
866 options.msisdn.v[((int)n / 2) + 1] =
867 args_info.msisdn_arg[n] - 48 + 0xf0;
868 options.msisdn.l += 1;
869 } else {
870 options.msisdn.v[((int)n / 2) + 1] =
871 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
872 (args_info.msisdn_arg[n] - 48) * 16;
873 }
874 }
875 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
876
877 /* UID and PWD */
878 /* Might need to also insert stuff like DNS etc. */
879 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
880 (sizeof(options.pco.v) - 1)) {
881 printf("invalid UID and PWD\n");
882 return -1;
883 }
884 options.pco.l =
885 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
886 options.pco.v[0] = 0x80; /* PPP */
887 options.pco.v[1] = 0xc0; /* PAP */
888 options.pco.v[2] = 0x23;
889 options.pco.v[3] =
890 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
891 options.pco.v[4] = 0x01; /* Authenticate request */
892 options.pco.v[5] = 0x01;
893 options.pco.v[6] = 0x00; /* MSB of length */
894 options.pco.v[7] =
895 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
896 options.pco.v[8] = strlen(args_info.uid_arg);
897 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
898 options.pco.v[9 + strlen(args_info.uid_arg)] =
899 strlen(args_info.pwd_arg);
900 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
901 args_info.pwd_arg, strlen(args_info.pwd_arg));
902
903 /* createif */
904 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800905 options.tun_dev_name = args_info.tun_device_arg;
Andreas Schultzb6292402018-10-05 13:58:45 +0100906 options.netns = args_info.netns_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100907
908 /* net */
909 /* Store net as in_addr net and mask */
910 if (args_info.net_arg) {
911 if (ippool_aton
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +0200912 (&options.netaddr, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100913 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100914 "Invalid network address: %s!",
915 args_info.net_arg);
916 exit(1);
917 }
Harald Weltebed35df2011-11-02 13:06:18 +0100918 } else {
Harald Welted12eab92017-08-02 19:49:47 +0200919 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100920 memset(&options.netaddr, 0, sizeof(options.netaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100921 }
jjako193e8b12003-11-10 12:31:41 +0000922
Harald Weltebed35df2011-11-02 13:06:18 +0100923 /* ipup */
924 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000925
Harald Weltebed35df2011-11-02 13:06:18 +0100926 /* ipdown */
927 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000928
Harald Weltebed35df2011-11-02 13:06:18 +0100929 /* statedir */
930 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000931
Harald Weltebed35df2011-11-02 13:06:18 +0100932 /* defaultroute */
933 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000934
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200935 /* PDP Type */
936 if (!strcmp(args_info.pdp_type_arg, "v6"))
937 options.pdp_type = PDP_EUA_TYPE_v6;
938 else if (!strcmp(args_info.pdp_type_arg, "v4"))
939 options.pdp_type = PDP_EUA_TYPE_v4;
940 else {
941 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
942 args_info.pdp_type_arg);
943 return -1;
944 }
945
Harald Weltebed35df2011-11-02 13:06:18 +0100946 /* pinghost */
947 /* Store ping host as in_addr */
948 if (args_info.pinghost_arg) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200949 struct addrinfo hints;
950 struct addrinfo *result;
951 memset(&hints, 0, sizeof(struct addrinfo));
952 switch (options.pdp_type) {
953 case PDP_EUA_TYPE_v4:
954 hints.ai_family = AF_INET;
955 break;
956 case PDP_EUA_TYPE_v6:
957 hints.ai_family = AF_INET6;
958 break;
959 default:
960 SYS_ERR(DSGSN, LOGL_ERROR, 0, "lookup(AF_UNSPEC) %d", options.pdp_type);
961 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
962 }
963 hints.ai_socktype = SOCK_DGRAM;
964 hints.ai_flags = 0;
965 hints.ai_protocol = 0;
966 hints.ai_canonname = NULL;
967 hints.ai_addr = NULL;
968 hints.ai_next = NULL;
969 if ((i = getaddrinfo(args_info.pinghost_arg, NULL, &hints, &result)) != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100970 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200971 "Invalid ping host '%s': %s",
972 args_info.pinghost_arg, gai_strerror(i));
Harald Weltebed35df2011-11-02 13:06:18 +0100973 return -1;
974 } else {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200975 switch (result->ai_family) {
976 case AF_INET:
977 options.pinghost.len = sizeof(struct in_addr);
978 options.pinghost.v4 = ((struct sockaddr_in*)result->ai_addr)->sin_addr;
979 SYS_ERR(DSGSN, LOGL_ERROR, 0, "AF_INET %d", options.pinghost.len);
980 break;
981 case AF_INET6:
982 options.pinghost.len = sizeof(struct in6_addr);
983 options.pinghost.v6 = ((struct sockaddr_in6*)result->ai_addr)->sin6_addr;
984 break;
985 }
Harald Weltebed35df2011-11-02 13:06:18 +0100986 printf("Using ping host: %s (%s)\n",
987 args_info.pinghost_arg,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200988 in46a_ntoa(&options.pinghost));
989 freeaddrinfo(result);
Harald Weltebed35df2011-11-02 13:06:18 +0100990 }
991 }
jjakoa7cd2492003-04-11 09:40:12 +0000992
Harald Weltebed35df2011-11-02 13:06:18 +0100993 /* Other ping parameters */
994 options.pingrate = args_info.pingrate_arg;
995 options.pingsize = args_info.pingsize_arg;
996 options.pingcount = args_info.pingcount_arg;
997 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000998
Harald Weltebed35df2011-11-02 13:06:18 +0100999 /* norecovery */
1000 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +00001001
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001002 if (args_info.no_tx_gpdu_seq_flag)
1003 options.tx_gpdu_seq = 0;
1004 else
1005 options.tx_gpdu_seq = 1;
1006
Harald Weltebed35df2011-11-02 13:06:18 +01001007 return 0;
jjakoa7cd2492003-04-11 09:40:12 +00001008
1009}
1010
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001011/* write a single value to a /proc file */
1012static int proc_write(const char *path, const char *value)
1013{
1014 int ret;
1015 FILE *f;
1016
1017 f = fopen(path, "w");
1018 if (!f) {
1019 SYS_ERR(DSGSN, LOGL_ERROR, 0, "fopen(%s) failed!\n", path);
1020 return -1;
1021 }
1022
1023 if ((ret = fputs(value, f)) < 0) {
1024 SYS_ERR(DSGSN, LOGL_ERROR, 0, "proc_write(%s, %s) failed!\n", path, value);
1025 } else {
1026 ret = 0;
1027 }
1028 fclose(f);
1029 return ret;
1030}
1031
1032/* Write value of to /proc/sys/net/ipv6/conf file for given device.
1033 * Memory is dynamically allocated, caller must free it later. */
1034static int proc_ipv6_conf_write(const char *dev, const char *file, const char *value)
1035{
1036 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
1037 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
1038 snprintf(path, sizeof(path), fmt, dev, file);
1039 return proc_write(path, value);
1040}
1041
Harald Weltefed33892017-10-10 09:02:45 +08001042static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001043{
Harald Weltee37f48e2017-10-10 09:05:50 +08001044 struct protoent *pe = getprotobynumber(t);
1045
1046 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +01001047 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +08001048 else
1049 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001050}
1051
Harald Weltefed33892017-10-10 09:02:45 +08001052static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001053{
1054 static char *ttab[] = {
1055 "Echo Reply",
1056 "ICMP 1",
1057 "ICMP 2",
1058 "Dest Unreachable",
1059 "Source Quench",
1060 "Redirect",
1061 "ICMP 6",
1062 "ICMP 7",
1063 "Echo",
1064 "ICMP 9",
1065 "ICMP 10",
1066 "Time Exceeded",
1067 "Parameter Problem",
1068 "Timestamp",
1069 "Timestamp Reply",
1070 "Info Request",
1071 "Info Reply"
1072 };
1073 if (t < 0 || t > 16)
1074 return ("OUT-OF-RANGE");
1075 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001076}
1077
Harald Weltefed33892017-10-10 09:02:45 +08001078static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001079{
1080 unsigned int n;
1081 uint64_t i64 = 0;
1082 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1083 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001084
Harald Weltebed35df2011-11-02 13:06:18 +01001085 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1086 /* ul16_t format always starts with 0x91 to indicate international format */
1087 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1088 for (n = 0; n < src->l; n++) {
1089 if ((src->v[n] & 0x0f) != 0x0f) {
1090 i64 *= 10;
1091 i64 += src->v[n] & 0x0f;
1092 }
1093 if ((src->v[n] & 0xf0) != 0xf0) {
1094 i64 *= 10;
1095 i64 += (src->v[n] & 0xf0) >> 4;
1096 }
1097 }
jjako193e8b12003-11-10 12:31:41 +00001098
Harald Weltebed35df2011-11-02 13:06:18 +01001099 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 /* Generate array with least significant digit in first octet */
1102 while (i64) {
1103 msa[msalen++] = i64 % 10;
1104 i64 = i64 / 10;
1105 }
jjako193e8b12003-11-10 12:31:41 +00001106
Harald Weltebed35df2011-11-02 13:06:18 +01001107 /* Convert back to ul16_t format */
1108 for (n = 0; n < msalen; n++) {
1109 if ((n % 2) == 0) {
1110 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1111 dst->l += 1;
1112 } else {
1113 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1114 msa[msalen - n - 1] * 16;
1115 }
1116 }
jjako193e8b12003-11-10 12:31:41 +00001117
Harald Weltebed35df2011-11-02 13:06:18 +01001118 return 0;
jjako193e8b12003-11-10 12:31:41 +00001119
1120}
1121
Harald Weltefed33892017-10-10 09:02:45 +08001122static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001123{
1124 /* TODO: big endian / small endian ??? */
1125 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001126
Harald Weltebed35df2011-11-02 13:06:18 +01001127 /* Convert from uint64_t bcd to uint64_t integer format */
1128 /* The resulting integer format is multiplied by 10 */
1129 while (src) {
1130 if ((src & 0x0f) != 0x0f) {
1131 i64 *= 10;
1132 i64 += (src & 0x0f);
1133 }
1134 if ((src & 0xf0) != 0xf0) {
1135 i64 *= 10;
1136 i64 += (src & 0xf0) >> 4;
1137 }
1138 src = src >> 8;
1139 }
jjako193e8b12003-11-10 12:31:41 +00001140
Harald Weltebed35df2011-11-02 13:06:18 +01001141 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001142
Harald Weltebed35df2011-11-02 13:06:18 +01001143 *dst = 0;
1144 while (i64) {
1145 *dst = *dst << 4;
1146 *dst += (i64 % 10);
1147 i64 = i64 / 10;
1148 }
jjako193e8b12003-11-10 12:31:41 +00001149
Harald Weltebed35df2011-11-02 13:06:18 +01001150 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001151
Harald Weltebed35df2011-11-02 13:06:18 +01001152 return 0;
jjako193e8b12003-11-10 12:31:41 +00001153
1154}
1155
jjakoafb2a972003-01-29 21:04:13 +00001156/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001157static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001158{
1159 struct timezone tz;
1160 struct timeval tv;
1161 int diff;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001162 if ((options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01001163 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1164 gettimeofday(&tv, &tz);
1165 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1166 tp->tv_sec = 0;
1167 if (diff > 0)
1168 tp->tv_usec = diff;
1169 else {
1170 /* For some reason we get packet loss if set to zero */
1171 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1172 tp->tv_usec = 0;
1173 }
1174 }
1175 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001176}
1177
jjako5da68452003-01-28 16:08:47 +00001178/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001179static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001180{
Harald Weltebed35df2011-11-02 13:06:18 +01001181 struct timezone tz;
1182 struct timeval tv;
1183 int elapsed;
1184 gettimeofday(&tv, &tz);
1185 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1186 printf("\n");
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001187 printf("\n----%s PING Statistics----\n", in46a_ntoa(&options.pinghost));
Harald Weltebed35df2011-11-02 13:06:18 +01001188 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1189 elapsed / 1000000.0);
1190 printf("%d packets received, ", nreceived);
1191 if (ntransmitted) {
1192 if (nreceived > ntransmitted)
1193 printf("-- somebody's printing up packets!");
1194 else
1195 printf("%d%% packet loss",
1196 (int)(((ntransmitted - nreceived) * 100) /
1197 ntransmitted));
1198 }
1199 printf("\n");
1200 if (options.debug)
1201 printf("%d packets received in total\n", ntreceived);
1202 if (nreceived && tsum)
1203 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1204 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
Pau Espin Pedrolcdcaeda2020-04-15 16:37:58 +02001205 printf("%d packets transmitted \n", ntransmitted);
jjakoafb2a972003-01-29 21:04:13 +00001206
Harald Weltebed35df2011-11-02 13:06:18 +01001207 ntransmitted = 0;
1208 return 0;
jjako5da68452003-01-28 16:08:47 +00001209}
1210
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001211static int encaps_ping4(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001212{
Harald Weltebed35df2011-11-02 13:06:18 +01001213 struct timeval tv;
1214 struct timeval *tp;
1215 struct ip_ping *pingpack = pack;
1216 struct in_addr src;
1217 int triptime;
jjako5da68452003-01-28 16:08:47 +00001218
Harald Weltebed35df2011-11-02 13:06:18 +01001219 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1222 printf("packet too short (%d bytes) from %s\n", len,
1223 inet_ntoa(src));
1224 return 0;
1225 }
jjako5da68452003-01-28 16:08:47 +00001226
Harald Weltebed35df2011-11-02 13:06:18 +01001227 if (pingpack->protocol != 1) {
1228 if (!options.pingquiet)
1229 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1230 len, inet_ntoa(src), pingpack->protocol,
1231 print_ipprot(pingpack->protocol));
1232 return 0;
1233 }
jjako5da68452003-01-28 16:08:47 +00001234
Harald Weltebed35df2011-11-02 13:06:18 +01001235 if (pingpack->type != 0) {
1236 if (!options.pingquiet)
1237 printf
1238 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1239 len, inet_ntoa(src), pingpack->type,
1240 print_icmptype(pingpack->type), pingpack->code);
1241 return 0;
1242 }
jjako5da68452003-01-28 16:08:47 +00001243
Harald Weltebed35df2011-11-02 13:06:18 +01001244 nreceived++;
1245 if (!options.pingquiet)
1246 printf("%d bytes from %s: icmp_seq=%d", len,
1247 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001248
Harald Weltebed35df2011-11-02 13:06:18 +01001249 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001250 gettimeofday(&tv, NULL);
Harald Weltebed35df2011-11-02 13:06:18 +01001251 tp = (struct timeval *)pingpack->data;
1252 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1253 tv.tv_sec--;
1254 tv.tv_usec += 1000000;
1255 }
1256 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001257
Harald Weltebed35df2011-11-02 13:06:18 +01001258 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1259 tsum += triptime;
1260 if (triptime < tmin)
1261 tmin = triptime;
1262 if (triptime > tmax)
1263 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001264
Harald Weltebed35df2011-11-02 13:06:18 +01001265 if (!options.pingquiet)
1266 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001267
Harald Weltebed35df2011-11-02 13:06:18 +01001268 } else if (!options.pingquiet)
1269 printf("\n");
1270 return 0;
jjako5da68452003-01-28 16:08:47 +00001271}
1272
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001273static int encaps_ping6(struct pdp_t *pdp, struct ip6_hdr *ip6h, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001274{
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001275 const struct icmpv6_echo_hdr *ic6h = (struct icmpv6_echo_hdr *) ((uint8_t*)ip6h + sizeof(*ip6h));
1276 struct timeval tv;
1277 struct timeval tp;
1278 int triptime;
1279 char straddr[128];
jjako5da68452003-01-28 16:08:47 +00001280
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001281 if (len < sizeof(struct ip6_hdr)) {
1282 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain IPv6 header (%d)", len);
1283 return 0;
1284 }
1285
1286 if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_ICMPV6) {
1287 if (!options.pingquiet)
1288 printf("%d bytes from %s: ip6_protocol=%d (%s)\n", len,
1289 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1290 ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt,
1291 print_ipprot(ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt));
1292 return 0;
1293 }
1294
1295 if (len < sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr)) {
1296 LOGP(DSGSN, LOGL_ERROR, "Packet len too small to contain ICMPv6 echo header (%d)\n", len);
1297 return 0;
1298 }
1299
1300 if (ic6h->hdr.type != 129 || ic6h->hdr.code != 0) {
1301 if (!options.pingquiet)
1302 printf
1303 ("%d bytes from %s: icmp_type=%d icmp_code=%d\n", len,
1304 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1305 ic6h->hdr.type, ic6h->hdr.code);
1306 return 0;
1307 }
1308
1309 nreceived++;
1310 if (!options.pingquiet)
1311 printf("%d bytes from %s: icmp_seq=%d", len,
1312 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1313 ntohs(ic6h->seq));
1314
1315 if (len >= sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr) + sizeof(struct timeval)) {
1316 gettimeofday(&tv, NULL);
1317 memcpy(&tp, ic6h->data, sizeof(struct timeval));
1318 if ((tv.tv_usec -= tp.tv_usec) < 0) {
1319 tv.tv_sec--;
1320 tv.tv_usec += 1000000;
1321 }
1322 tv.tv_sec -= tp.tv_sec;
1323
1324 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1325 tsum += triptime;
1326 if (triptime < tmin)
1327 tmin = triptime;
1328 if (triptime > tmax)
1329 tmax = triptime;
1330
1331 if (!options.pingquiet)
1332 printf(" time=%.3f ms\n", triptime / 1000.0);
1333
1334 } else if (!options.pingquiet)
1335 printf("\n");
1336 return 0;
1337}
1338
1339/* Handle a received ping packet. Print out line and update statistics. */
1340static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1341{
1342 struct iphdr *iph = (struct iphdr *)pack;
1343 struct timeval tv;
1344
1345
1346 gettimeofday(&tv, NULL);
1347 if (options.debug)
1348 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
1349
1350 ntreceived++;
1351
1352 if (len < sizeof(struct iphdr)) {
1353 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain ip header (%d)", len);
1354 return -1;
1355 }
1356 switch(iph->version) {
1357 case 4:
1358 return encaps_ping4(pdp, pack, len);
1359 case 6:
1360 return encaps_ping6(pdp, (struct ip6_hdr *)pack, len);
1361 default:
1362 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unknown ip header version %d", iph->version);
1363 return -1;
1364 }
1365}
1366
1367static int create_ping4(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1368 struct in46_addr *dst, int seq, unsigned int datasize)
1369{
Harald Weltebed35df2011-11-02 13:06:18 +01001370 struct ip_ping pack;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001371 uint16_t v16;
Harald Weltebed35df2011-11-02 13:06:18 +01001372 uint8_t *p8 = (uint8_t *) & pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001373 unsigned int n;
1374 long int sum = 0;
1375 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001376
Harald Weltebed35df2011-11-02 13:06:18 +01001377 struct timezone tz;
1378 struct timeval *tp =
1379 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001380
Harald Weltebed35df2011-11-02 13:06:18 +01001381 pack.ipver = 0x45;
1382 pack.tos = 0x00;
1383 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1384 pack.fragid = 0x0000;
1385 pack.offset = 0x0040;
1386 pack.ttl = 0x40;
1387 pack.protocol = 0x01;
1388 pack.ipcheck = 0x0000;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001389 pack.src = src->v4.s_addr;
1390 pack.dst = dst->v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +01001391 pack.type = 0x08;
1392 pack.code = 0x00;
1393 pack.checksum = 0x0000;
1394 pack.ident = 0x0000;
1395 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001396
Harald Weltebed35df2011-11-02 13:06:18 +01001397 /* Generate ICMP payload */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001398 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
Harald Weltebed35df2011-11-02 13:06:18 +01001399 for (n = 0; n < (datasize); n++)
1400 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001401
Harald Weltebed35df2011-11-02 13:06:18 +01001402 if (datasize >= sizeof(struct timeval))
1403 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001404
Harald Weltebed35df2011-11-02 13:06:18 +01001405 /* Calculate IP header checksum */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001406 p8 = (uint8_t *) &pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001407 count = CREATEPING_IP;
1408 sum = 0;
1409 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001410 memcpy(&v16, p8, 2);
1411 sum += v16;
1412 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001413 count -= 2;
1414 }
1415 while (sum >> 16)
1416 sum = (sum & 0xffff) + (sum >> 16);
1417 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001418
Harald Weltebed35df2011-11-02 13:06:18 +01001419 /* Calculate ICMP checksum */
1420 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1421 sum = 0;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001422 p8 = (uint8_t *) &pack;
1423 p8 += CREATEPING_IP;
Harald Weltebed35df2011-11-02 13:06:18 +01001424 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001425 memcpy(&v16, p8, 2);
1426 sum += v16;
1427 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001428 count -= 2;
1429 }
1430 if (count > 0)
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001431 sum += *(unsigned char *)p8;
Harald Weltebed35df2011-11-02 13:06:18 +01001432 while (sum >> 16)
1433 sum = (sum & 0xffff) + (sum >> 16);
1434 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001435
Harald Weltebed35df2011-11-02 13:06:18 +01001436 ntransmitted++;
1437 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001438}
1439
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001440static int create_ping6(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1441 struct in46_addr *dst, int seq, unsigned int datasize)
1442{
1443 struct ip6_ping *pack;
1444 uint8_t *p8;
1445 unsigned int n;
1446 struct timezone tz;
1447 struct timeval *tp;
1448
1449 struct msgb *msg = msgb_alloc_headroom(sizeof(struct ip6_ping) + 128,128, "ICMPv6 echo");
1450 OSMO_ASSERT(msg);
1451 pack = (struct ip6_ping *) msgb_put(msg, sizeof(struct icmpv6_echo_hdr) + datasize);
1452 pack->hdr.hdr.type = 128;
1453 pack->hdr.hdr.code = 0;
1454 pack->hdr.hdr.csum = 0; /* updated below */
1455 pack->hdr.ident = 0x0000;
1456 pack->hdr.seq = htons(seq);
1457
1458 p8 = pack->data;
1459 for (n = 0; n < (datasize); n++)
1460 p8[n] = n;
1461
1462 if (datasize >= sizeof(struct timeval)) {
1463 tp = (struct timeval *)pack->data;
1464 gettimeofday(tp, &tz);
1465 }
1466
1467 pack->hdr.hdr.csum = icmpv6_prepend_ip6hdr(msg, &src->v6, &dst->v6);
1468
1469 ntransmitted++;
1470 return gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
1471}
1472
1473/* Create a new ping packet and send it off to peer. */
1474static int create_ping(void *gsn, struct pdp_t *pdp,
1475 struct in46_addr *dst, int seq, unsigned int datasize)
1476{
1477 int num_addr;
1478 struct in46_addr addr[2];
1479 struct in46_addr *src;
1480
1481 if (datasize > CREATEPING_MAX) {
1482 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1483 "Ping size to large: %d!", datasize);
1484 return -1;
1485 }
1486
1487 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
1488 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1489 "in46a_from_eua() failed! %d", num_addr);
1490 return -1;
1491 }
1492 if (dst->len == addr[0].len) {
1493 src = &addr[0];
1494 } else if (num_addr > 1 && dst->len == addr[1].len) {
1495 src = &addr[1];
1496 } else {
1497 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1498 "Mismaching source and destination IP addr types (%d vs %d)", dst->len, addr[0].len);
1499 return -1;
1500 }
1501 if (in46a_is_v4(dst))
1502 return create_ping4(gsn, pdp, src, dst, seq, datasize);
1503 else
1504 return create_ping6(gsn, pdp, src, dst, seq, datasize);
1505}
1506
Harald Weltefed33892017-10-10 09:02:45 +08001507static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001508{
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001509 int rc;
1510
Andreas Schultzb6292402018-10-05 13:58:45 +01001511 if (tun && options.ipdown) {
1512#if defined(__linux__)
1513 sigset_t oldmask;
Harald Weltebed35df2011-11-02 13:06:18 +01001514
Andreas Schultzb6292402018-10-05 13:58:45 +01001515 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001516 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1517 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1518 "Failed to switch to netns %s: %s\n",
1519 options.netns, strerror(-rc));
1520 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001521 }
1522#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001523 tun_runscript(tun, options.ipdown);
1524
Andreas Schultzb6292402018-10-05 13:58:45 +01001525#if defined(__linux__)
1526 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001527 if ((rc = restore_ns(&oldmask)) < 0) {
1528 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1529 "Failed to switch to original netns: %s\n",
1530 strerror(-rc));
1531 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001532 }
1533#endif
1534 }
1535
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001536 ipdel((struct iphash_t *)pdp->peer[0]);
1537 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001538
1539 if (1 == options.contexts)
1540 state = 5; /* Disconnected */
1541
1542 return 0;
1543}
jjakoa7cd2492003-04-11 09:40:12 +00001544
Harald Welte6748dc92017-09-24 21:54:59 +08001545/* Link-Local address prefix fe80::/64 */
1546static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1547
jjakoa7cd2492003-04-11 09:40:12 +00001548/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001549static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001550{
1551 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001552 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001553 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001554 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001555
Harald Welte6748dc92017-09-24 21:54:59 +08001556 if (iph->version == 4) {
1557 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1558 printf("Dropping packet with too short IP header\n");
1559 return 0;
1560 }
1561 src.len = 4;
1562 src.v4.s_addr = iph->saddr;
1563 } else if (iph->version == 6) {
Harald Welte6748dc92017-09-24 21:54:59 +08001564 src.len = 16;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001565 src.v6 = ip6h->ip6_src;
Harald Welte6748dc92017-09-24 21:54:59 +08001566 } else {
1567 printf("Dropping packet with invalid IP version %u\n", iph->version);
1568 return 0;
1569 }
jjakoa7cd2492003-04-11 09:40:12 +00001570
Harald Weltebed35df2011-11-02 13:06:18 +01001571 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001572 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001573 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001574 return 0;
1575 }
1576
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001577 if (ipm->ctx->pdp) /* Check if a peer protocol is defined */
1578 gtp_data_req(gsn, ipm->ctx->pdp, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +01001579 return 0;
jjako52c24142002-12-16 13:33:51 +00001580}
1581
Harald Weltefed33892017-10-10 09:02:45 +08001582static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001583{
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001584 int rc, i, num_addr;
1585 struct in46_addr addr[2];
Andreas Schultzb6292402018-10-05 13:58:45 +01001586#if defined(__linux__)
1587 sigset_t oldmask;
1588#endif
jjako52c24142002-12-16 13:33:51 +00001589
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001590 struct pdp_peer_sgsnemu_ctx *ctx = (struct pdp_peer_sgsnemu_ctx *) cbp;
jjako2c381332003-10-21 19:09:53 +00001591
Harald Weltebed35df2011-11-02 13:06:18 +01001592 if (cause < 0) {
1593 printf("Create PDP Context Request timed out\n");
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001594 if (ctx->pdp->version == 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001595 printf("Retrying with version 0\n");
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001596 ctx->pdp->version = 0;
1597 gtp_create_context_req(gsn, ctx->pdp, ctx);
Harald Weltebed35df2011-11-02 13:06:18 +01001598 return 0;
1599 } else {
1600 state = 0;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001601 pdp_freepdp(ctx->pdp);
1602 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001603 return EOF;
1604 }
1605 }
jjako2c381332003-10-21 19:09:53 +00001606
Harald Weltebed35df2011-11-02 13:06:18 +01001607 if (cause != 128) {
1608 printf
1609 ("Received create PDP context response. Cause value: %d\n",
1610 cause);
1611 state = 0;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001612 pdp_freepdp(ctx->pdp);
1613 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001614 return EOF; /* Not what we expected */
1615 }
jjako52c24142002-12-16 13:33:51 +00001616
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001617 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001618 printf
1619 ("Received create PDP context response. Cause value: %d\n",
1620 cause);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001621 pdp_freepdp(ctx->pdp);
1622 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001623 state = 0;
1624 return EOF; /* Not a valid IP address */
1625 }
jjakoa7cd2492003-04-11 09:40:12 +00001626
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001627 printf("Received create PDP context response.\n");
jjakoa7cd2492003-04-11 09:40:12 +00001628
Andreas Schultzb6292402018-10-05 13:58:45 +01001629#if defined(__linux__)
1630 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001631 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1632 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1633 "Failed to switch to netns %s: %s\n",
1634 options.netns, strerror(-rc));
1635 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001636 }
1637#endif
1638
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001639 for (i = 0; i < num_addr; i++) {
1640 printf("PDP ctx: received EUA with IP address: %s\n", in46a_ntoa(&addr[i]));
1641
1642 switch (addr[i].len) {
1643 case 16: /* IPv6 */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001644 /* Convert address to link local using the lower 64bits
1645 of the allocated EUA as Interface-Identifier to
1646 send router solicitation, as per 3GPP TS 29.061
1647 Section 11.2.1.3.2 */
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001648 memcpy(addr[i].v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1649 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr[i]));
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001650 ctx->hash_v6_ll.inuse = 1;
1651 ipset(&ctx->hash_v6_ll, &addr[i]);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001652 break;
1653 case 4: /* IPv4 */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001654 ctx->hash_v4.inuse = 1;
1655 ipset(&ctx->hash_v4, &addr[i]);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001656 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001657 }
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001658
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001659 if ((options.createif) && (!options.netaddr.len)) {
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001660 size_t prefixlen = 32;
1661 if (addr[i].len == 16)
1662 prefixlen = 64;
1663 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrole5d71632020-04-15 14:43:50 +02001664 tun_addaddr(tun, &addr[i], NULL, prefixlen);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001665 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001666 if (in46a_is_v4(&addr[i])) {
1667 struct in_addr rm;
1668 rm.s_addr = 0;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001669 if (netdev_addroute4(&rm, &addr[i].v4, &rm) < 0) {
1670 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", in46a_ntoa(&addr[i]));
1671 }
1672 } /* else: route will be set up once we have a global link address (Router Advertisement) */
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001673 }
1674 if (options.ipup)
1675 tun_runscript(tun, options.ipup);
1676 }
Harald Weltebed35df2011-11-02 13:06:18 +01001677 }
jjako52c24142002-12-16 13:33:51 +00001678
Harald Welte081f30c2017-10-10 09:36:35 +08001679 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001680 struct in6_addr *saddr6;
1681 struct msgb *msg;
1682 if (in46a_is_v6(&addr[0])) {
1683 saddr6 = &addr[0].v6;
1684 } else if (num_addr > 1 && in46a_is_v6(&addr[1])) {
1685 saddr6 = &addr[1].v6;
1686 } else {
1687 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to find IPv6 EUA on IPv6 APN");
1688 return EOF; /* Not a valid IP address */
Harald Welte081f30c2017-10-10 09:36:35 +08001689 }
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001690 SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN...");
1691 msg = icmpv6_construct_rs(saddr6);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001692 gtp_data_req(gsn, ctx->pdp, msgb_data(msg), msgb_length(msg));
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001693 msgb_free(msg);
Harald Welte081f30c2017-10-10 09:36:35 +08001694 }
1695
Andreas Schultzb6292402018-10-05 13:58:45 +01001696#if defined(__linux__)
1697 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001698 if ((rc = restore_ns(&oldmask)) < 0) {
1699 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1700 strerror(-rc));
1701 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001702 }
1703#endif
1704
Harald Weltebed35df2011-11-02 13:06:18 +01001705
1706 state = 2; /* Connected */
1707
1708 return 0;
jjako52c24142002-12-16 13:33:51 +00001709}
1710
Harald Weltefed33892017-10-10 09:02:45 +08001711static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001712{
1713 printf("Received delete PDP context response. Cause value: %d\n",
1714 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001715 if (pdp)
1716 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001717 return 0;
jjako52c24142002-12-16 13:33:51 +00001718}
1719
Harald Weltefed33892017-10-10 09:02:45 +08001720static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001721{
jjako91aaf222003-10-22 10:09:32 +00001722
Harald Weltebed35df2011-11-02 13:06:18 +01001723 if (recovery < 0) {
1724 printf("Echo Request timed out\n");
1725 if (echoversion == 1) {
1726 printf("Retrying with version 0\n");
1727 echoversion = 0;
1728 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1729 return 0;
1730 } else {
1731 state = 0;
1732 return EOF;
1733 }
1734 } else {
1735 printf("Received echo response\n");
1736 if (!options.contexts)
1737 state = 5;
1738 }
1739 return 0;
jjako52c24142002-12-16 13:33:51 +00001740}
1741
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001742static int _gtp_cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001743{
1744 /* if (cause < 0) return 0; Some error occurred. We don't care */
1745 switch (type) {
1746 case GTP_ECHO_REQ:
1747 return echo_conf(cause);
1748 case GTP_CREATE_PDP_REQ:
1749 return create_pdp_conf(pdp, cbp, cause);
1750 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001751 return delete_pdp_conf(pdp, cause);
1752 default:
1753 return 0;
1754 }
jjako52c24142002-12-16 13:33:51 +00001755}
1756
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001757static void handle_router_adv(struct pdp_t *pdp, struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len)
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001758{
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001759 struct pdp_peer_sgsnemu_ctx* ctx = (struct pdp_peer_sgsnemu_ctx*)pdp->peer[0];
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001760 struct icmpv6_opt_hdr *opt_hdr;
1761 struct icmpv6_opt_prefix *opt_prefix;
1762 int rc;
1763 sigset_t oldmask;
1764 struct in6_addr rm;
1765 char ip6strbuf[200];
1766 memset(&rm, 0, sizeof(rm));
1767
1768 SYS_ERR(DSGSN, LOGL_INFO, 0, "Received ICMPv6 Router Advertisement");
1769
1770 foreach_icmpv6_opt(ra, ra_len, opt_hdr) {
1771 if (opt_hdr->type == ICMPv6_OPT_TYPE_PREFIX_INFO) {
1772 opt_prefix = (struct icmpv6_opt_prefix *)opt_hdr;
1773 size_t prefix_len_bytes = (opt_prefix->prefix_len + 7)/8;
1774 SYS_ERR(DSGSN, LOGL_INFO, 0, "Parsing OPT Prefix info (prefix_len=%u): %s",
1775 opt_prefix->prefix_len,
1776 osmo_hexdump((const unsigned char *)opt_prefix->prefix, prefix_len_bytes));
1777 if ((options.createif) && (!options.netaddr.len)) {
1778 struct in46_addr addr;
1779 addr.len = 16;
1780 memcpy(addr.v6.s6_addr, opt_prefix->prefix, prefix_len_bytes);
1781 memset(&addr.v6.s6_addr[prefix_len_bytes], 0, 16 - prefix_len_bytes);
1782 addr.v6.s6_addr[15] = 0x02;
1783 SYS_ERR(DSGSN, LOGL_INFO, 0, "Adding addr %s to tun %s",
1784 in46a_ntoa(&addr), tun->devname);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001785 if (!ctx->hash_v6_global.inuse) {
1786 ctx->hash_v6_global.inuse = 1;
1787 ipset(&ctx->hash_v6_global, &addr);
1788 } else {
1789 SYS_ERR(DSGSN, LOGL_ERROR, 0, "First v6 global address in hash already in use!");
1790 }
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001791
1792#if defined(__linux__)
1793 if ((options.netns)) {
1794 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1795 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1796 "Failed to switch to netns %s: %s",
1797 options.netns, strerror(-rc));
1798 }
1799 }
1800#endif
1801 rc = tun_addaddr(tun, &addr, NULL, opt_prefix->prefix_len);
1802 if (rc < 0) {
1803 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to add addr %s to tun %s",
1804 in46a_ntoa(&addr), tun->devname);
1805 }
1806
1807 struct in6_addr rm;
1808 memset(&rm, 0, sizeof(rm));
1809 if (netdev_addroute6(&rm, &ip6h->ip6_src, 0, tun->devname) < 0) {
1810 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", inet_ntop(AF_INET6, &ip6h->ip6_src, ip6strbuf, sizeof(ip6strbuf)));
1811 }
1812
1813#if defined(__linux__)
1814 if ((options.netns)) {
1815 if ((rc = restore_ns(&oldmask)) < 0) {
1816 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1817 "Failed to switch to original netns: %s",
1818 strerror(-rc));
1819 }
1820 }
1821#endif
1822 }
1823 }
1824 }
1825}
1826
Harald Weltefed33892017-10-10 09:02:45 +08001827static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001828{
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001829 struct iphdr *iph = (struct iphdr *)pack;
1830 struct icmpv6_radv_hdr *ra;
1831 switch (iph->version) {
1832 case 6:
1833 if ((ra = icmpv6_validate_router_adv(pack, len))) {
1834 size_t ra_len = (uint8_t*)ra - (uint8_t*)pack;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001835 handle_router_adv(pdp, (struct ip6_hdr *)pack, ra, ra_len);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001836 return 0;
1837 }
1838 break;
1839 }
1840
Harald Weltebed35df2011-11-02 13:06:18 +01001841 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1842 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001843}
1844
1845int main(int argc, char **argv)
1846{
Harald Weltebed35df2011-11-02 13:06:18 +01001847 fd_set fds; /* For select() */
1848 struct timeval idleTime; /* How long to select() */
1849 struct pdp_t *pdp;
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001850 int n, rc;
Harald Weltebed35df2011-11-02 13:06:18 +01001851 int starttime = time(NULL); /* Time program was started */
1852 int stoptime = 0; /* Time to exit */
1853 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001854 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001855
Harald Weltebed35df2011-11-02 13:06:18 +01001856 struct timezone tz; /* Used for calculating ping times */
1857 struct timeval tv;
1858 int diff;
Andreas Schultzb6292402018-10-05 13:58:45 +01001859#if defined(__linux__)
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001860 char buf[10];
Andreas Schultzb6292402018-10-05 13:58:45 +01001861 sigset_t oldmask;
1862#endif
jjako52c24142002-12-16 13:33:51 +00001863
bjovana8f71eb2017-02-24 17:39:20 +01001864 signal(SIGTERM, signal_handler);
1865 signal(SIGHUP, signal_handler);
1866 signal(SIGINT, signal_handler);
1867
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001868 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1869 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1870 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001871
Andreas Schultzb6292402018-10-05 13:58:45 +01001872#if defined(__linux__)
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001873 if ((rc = init_netns()) < 0) {
1874 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
1875 exit(1);
1876 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001877#endif
1878
Harald Weltebed35df2011-11-02 13:06:18 +01001879 /* Process options given in configuration file and command line */
1880 if (process_options(argc, argv))
1881 exit(1);
jjako52c24142002-12-16 13:33:51 +00001882
Harald Weltebed35df2011-11-02 13:06:18 +01001883 printf("\nInitialising GTP library\n");
1884 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001885 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001886 exit(1);
1887 }
1888 if (gsn->fd0 > maxfd)
1889 maxfd = gsn->fd0;
1890 if (gsn->fd1c > maxfd)
1891 maxfd = gsn->fd1c;
1892 if (gsn->fd1u > maxfd)
1893 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001894
Harald Weltebed35df2011-11-02 13:06:18 +01001895 gtp_set_cb_delete_context(gsn, delete_context);
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001896 gtp_set_cb_conf(gsn, _gtp_cb_conf);
Harald Weltebed35df2011-11-02 13:06:18 +01001897 if (options.createif)
1898 gtp_set_cb_data_ind(gsn, encaps_tun);
1899 else
1900 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001901
Andreas Schultzb6292402018-10-05 13:58:45 +01001902#if defined(__linux__)
1903 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001904 if ((netns = get_nsfd(options.netns)) < 0) {
1905 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
1906 options.netns, strerror(-netns));
1907 exit(1);
1908 }
1909 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1910 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
1911 options.netns, strerror(-rc));
1912 exit(1);
1913 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001914 }
1915#endif
1916
Harald Weltebed35df2011-11-02 13:06:18 +01001917 if (options.createif) {
1918 printf("Setting up interface\n");
1919 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001920 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001921 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001922 "Failed to create tun");
1923 exit(1);
1924 }
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001925
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001926#if defined(__linux__) && defined(HAVE_IN6_ADDR_GEN_MODE_NONE)
1927 /* Avoid tunnel setting its own link-local addr automatically,
1928 we don't need it. Don't exit on error since this sysctl is
1929 only available starting with linux 4.11. */
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001930 snprintf(buf, sizeof(buf), "%u", IN6_ADDR_GEN_MODE_NONE);
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001931 if (proc_ipv6_conf_write(tun->devname, "addr_gen_mode", buf) < 0) {
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001932 SYS_ERR(DSGSN, LOGL_ERROR, errno,
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001933 "Failed to disable addr_gen_mode on %s, an extra link-local "
1934 "ip address will appear on the tun device.\n",
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001935 tun->devname);
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001936 }
1937#endif
1938
Harald Weltebed35df2011-11-02 13:06:18 +01001939 tun_set_cb_ind(tun, cb_tun_ind);
1940 if (tun->fd > maxfd)
1941 maxfd = tun->fd;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001942
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001943 if (proc_ipv6_conf_write(tun->devname, "accept_ra", "0") < 0) {
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001944 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001945 "Failed to disable IPv6 SLAAC on %s\n", tun->devname);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001946 exit(1);
1947 }
Harald Weltebed35df2011-11-02 13:06:18 +01001948 }
jjakoa7cd2492003-04-11 09:40:12 +00001949
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001950 if ((options.createif) && (options.netaddr.len)) {
Pau Espin Pedrol964f08a2020-04-15 14:29:25 +02001951 tun_addaddr(tun, &options.netaddr, NULL, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001952 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001953 if (in46a_is_v4(&options.netaddr)) {
1954 struct in_addr rm;
1955 rm.s_addr = 0;
1956 netdev_addroute4(&rm, &options.netaddr.v4, &rm);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001957 } else {
1958 struct in6_addr rm;
1959 memset(&rm, 0, sizeof(rm));
1960 netdev_addroute6(&rm, &options.netaddr.v6, 0, tun->devname);
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001961 }
Harald Weltebed35df2011-11-02 13:06:18 +01001962 }
1963 if (options.ipup)
1964 tun_runscript(tun, options.ipup);
1965 }
jjakoa7cd2492003-04-11 09:40:12 +00001966
Andreas Schultzb6292402018-10-05 13:58:45 +01001967#if defined(__linux__)
1968 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001969 if ((rc = restore_ns(&oldmask)) < 0) {
1970 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1971 strerror(-rc));
1972 exit(1);
1973 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001974 }
1975#endif
1976
Harald Weltebed35df2011-11-02 13:06:18 +01001977 /* Initialise hash tables */
1978 memset(&iphash, 0, sizeof(iphash));
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001979 memset(&ctx_arr, 0, sizeof(ctx_arr));
jjako193e8b12003-11-10 12:31:41 +00001980
Harald Weltebed35df2011-11-02 13:06:18 +01001981 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001982
Harald Weltebed35df2011-11-02 13:06:18 +01001983 /* See if anybody is there */
1984 printf("Sending off echo request\n");
1985 echoversion = options.gtpversion;
1986 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001987
Harald Weltebed35df2011-11-02 13:06:18 +01001988 for (n = 0; n < options.contexts; n++) {
1989 uint64_t myimsi;
1990 printf("Setting up PDP context #%d\n", n);
jjako52c24142002-12-16 13:33:51 +00001991
Harald Weltebed35df2011-11-02 13:06:18 +01001992 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001993
Harald Weltebed35df2011-11-02 13:06:18 +01001994 /* Allocated here. */
1995 /* If create context failes we have to deallocate ourselves. */
1996 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001997 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001998
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001999 pdp->peer[0] = &ctx_arr[n];
Harald Weltebed35df2011-11-02 13:06:18 +01002000 pdp->ipif = tun; /* TODO */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002001 ctx_arr[n].pdp = pdp;
2002 ctx_arr[n].hash_v4.ctx = &ctx_arr[n];
2003 ctx_arr[n].hash_v6_ll.ctx = &ctx_arr[n];
2004 ctx_arr[n].hash_v6_global.ctx = &ctx_arr[n];
jjako193e8b12003-11-10 12:31:41 +00002005
Harald Weltebed35df2011-11-02 13:06:18 +01002006 if (options.gtpversion == 0) {
2007 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002008 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002009 "QoS length too big");
2010 exit(1);
2011 } else {
2012 memcpy(pdp->qos_req0, options.qos.v,
2013 options.qos.l);
2014 }
2015 }
jjakoa7cd2492003-04-11 09:40:12 +00002016
Harald Weltebed35df2011-11-02 13:06:18 +01002017 pdp->qos_req.l = options.qos.l;
2018 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00002019
Harald Weltebed35df2011-11-02 13:06:18 +01002020 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00002021
Harald Weltebed35df2011-11-02 13:06:18 +01002022 pdp->rattype.l = options.rattype.l;
2023 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
2024 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002025
Harald Weltebed35df2011-11-02 13:06:18 +01002026 pdp->userloc.l = options.userloc.l;
2027 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
2028 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002029
Harald Weltebed35df2011-11-02 13:06:18 +01002030 pdp->rai.l = options.rai.l;
2031 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
2032 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02002033
Harald Weltebed35df2011-11-02 13:06:18 +01002034 pdp->mstz.l = options.mstz.l;
2035 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
2036 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002037
Harald Weltebed35df2011-11-02 13:06:18 +01002038 pdp->imeisv.l = options.imeisv.l;
2039 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
2040 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002041
Harald Weltebed35df2011-11-02 13:06:18 +01002042 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02002043
Harald Weltebed35df2011-11-02 13:06:18 +01002044 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002045 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002046 "APN length too big");
2047 exit(1);
2048 } else {
2049 pdp->apn_use.l = options.apn.l;
2050 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
2051 }
jjako193e8b12003-11-10 12:31:41 +00002052
Harald Weltebed35df2011-11-02 13:06:18 +01002053 pdp->gsnlc.l = sizeof(options.listen);
2054 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
2055 pdp->gsnlu.l = sizeof(options.listen);
2056 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00002057
Harald Weltebed35df2011-11-02 13:06:18 +01002058 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002059 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002060 "MSISDN length too big");
2061 exit(1);
2062 } else {
2063 msisdn_add(&options.msisdn, &pdp->msisdn, n);
2064 }
jjakob62c3dd2004-05-27 18:51:55 +00002065
Harald Welte840a8e92017-09-24 18:12:40 +08002066 /* Request dynamic IP address */
2067 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
2068 pdp->eua.v[1] = options.pdp_type;
2069 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00002070
Harald Weltebed35df2011-11-02 13:06:18 +01002071 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002072 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002073 "PCO length too big");
2074 exit(1);
2075 } else {
2076 pdp->pco_req.l = options.pco.l;
2077 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
2078 }
jjako52c24142002-12-16 13:33:51 +00002079
Harald Weltebed35df2011-11-02 13:06:18 +01002080 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00002081
Harald Weltebed35df2011-11-02 13:06:18 +01002082 pdp->hisaddr0 = options.remote;
2083 pdp->hisaddr1 = options.remote;
2084
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01002085 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01002086 512 = Flat rate, 256 = Hot billing */
2087
Harald Weltefbb9c7f2017-09-24 11:50:20 +08002088 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
2089
Harald Weltebed35df2011-11-02 13:06:18 +01002090 /* Create context */
2091 /* We send this of once. Retransmissions are handled by gtplib */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002092 gtp_create_context_req(gsn, pdp, &ctx_arr[n]);
Harald Weltebed35df2011-11-02 13:06:18 +01002093 }
2094
2095 state = 1; /* Enter wait_connection state */
2096
2097 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00002098
jjako52c24142002-12-16 13:33:51 +00002099 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01002100 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00002101 /******************************************************************/
2102
Harald Weltebed35df2011-11-02 13:06:18 +01002103 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00002104
Harald Weltebed35df2011-11-02 13:06:18 +01002105 /* Take down client after timeout after disconnect */
2106 if ((4 == state) && ((stoptime) <= time(NULL))) {
2107 state = 5;
2108 }
jjako7b8fad42003-07-07 14:37:42 +00002109
Harald Weltebed35df2011-11-02 13:06:18 +01002110 /* Take down client after timelimit timeout */
2111 if ((2 == state) && (options.timelimit) &&
2112 ((starttime + options.timelimit) <= time(NULL))) {
2113 state = 3;
2114 }
jjako7b8fad42003-07-07 14:37:42 +00002115
Harald Weltebed35df2011-11-02 13:06:18 +01002116 /* Take down client after ping timeout */
2117 if ((2 == state) && (pingtimeout)
2118 && (pingtimeout <= time(NULL))) {
2119 state = 3;
2120 }
jjako7b8fad42003-07-07 14:37:42 +00002121
Harald Weltebed35df2011-11-02 13:06:18 +01002122 /* Set pingtimeout for later disconnection */
2123 if (options.pingcount && ntransmitted >= options.pingcount) {
2124 pingtimeout = time(NULL) + 5; /* Extra seconds */
2125 }
jjako7b8fad42003-07-07 14:37:42 +00002126
Harald Weltebed35df2011-11-02 13:06:18 +01002127 /* Print statistics if no more ping packets are missing */
2128 if (ntransmitted && options.pingcount
2129 && nreceived >= options.pingcount) {
2130 ping_finish();
2131 if (!options.createif)
2132 state = 3;
2133 }
jjako7b8fad42003-07-07 14:37:42 +00002134
Harald Weltebed35df2011-11-02 13:06:18 +01002135 /* Send off disconnect */
2136 if (3 == state) {
2137 state = 4;
2138 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
2139 for (n = 0; n < options.contexts; n++) {
2140 /* Delete context */
2141 printf("Disconnecting PDP context #%d\n", n);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002142 gtp_delete_context_req2(gsn, ctx_arr[n].pdp, NULL, 1);
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002143 if ((options.pinghost.len)
Harald Weltebed35df2011-11-02 13:06:18 +01002144 && ntransmitted)
2145 ping_finish();
2146 }
2147 }
jjako7b8fad42003-07-07 14:37:42 +00002148
Harald Weltebed35df2011-11-02 13:06:18 +01002149 /* Send of ping packets */
2150 diff = 0;
2151 while ((diff <= 0) &&
2152 /* Send off an ICMP ping packet */
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002153 /*if ( */ (options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01002154 ((pingseq < options.pingcount)
2155 || (options.pingcount == 0))) {
2156 if (!pingseq)
2157 gettimeofday(&firstping, &tz); /* Set time of first ping */
2158 gettimeofday(&tv, &tz);
2159 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
2160 if (diff <= 0) {
2161 if (options.debug)
2162 printf("Create_ping %d\n", diff);
2163 create_ping(gsn,
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002164 ctx_arr[pingseq %
Harald Weltebed35df2011-11-02 13:06:18 +01002165 options.contexts].pdp,
2166 &options.pinghost, pingseq,
2167 options.pingsize);
2168 pingseq++;
2169 }
2170 }
jjako5da68452003-01-28 16:08:47 +00002171
Harald Weltebed35df2011-11-02 13:06:18 +01002172 FD_ZERO(&fds);
2173 if (tun)
2174 FD_SET(tun->fd, &fds);
2175 FD_SET(gsn->fd0, &fds);
2176 FD_SET(gsn->fd1c, &fds);
2177 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00002178
Pau Espin Pedrol1bf41e42019-08-28 19:44:54 +02002179 idleTime.tv_sec = 10;
2180 idleTime.tv_usec = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002181 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00002182
Harald Weltebed35df2011-11-02 13:06:18 +01002183 if (options.debug)
2184 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
2185 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00002186
bjovana8f71eb2017-02-24 17:39:20 +01002187 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002188 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
2189 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01002190 if (errno == EINTR)
2191 signal_received = 1;
2192 else
2193 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2194 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01002195 break;
Harald Weltebed35df2011-11-02 13:06:18 +01002196 default:
2197 break;
2198 }
2199
bjovana8f71eb2017-02-24 17:39:20 +01002200 if (!signal_received) {
2201
2202 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
2203 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2204 "TUN decaps failed");
2205 }
2206
2207 if (FD_ISSET(gsn->fd0, &fds))
2208 gtp_decaps0(gsn);
2209
2210 if (FD_ISSET(gsn->fd1c, &fds))
2211 gtp_decaps1c(gsn);
2212
2213 if (FD_ISSET(gsn->fd1u, &fds))
2214 gtp_decaps1u(gsn);
2215
Harald Weltebed35df2011-11-02 13:06:18 +01002216 }
Harald Weltebed35df2011-11-02 13:06:18 +01002217 }
2218
2219 gtp_free(gsn); /* Clean up the gsn instance */
2220
2221 if (options.createif)
2222 tun_free(tun);
2223
2224 if (0 == state)
2225 exit(1); /* Indicate error */
2226
2227 return 0;
jjako52c24142002-12-16 13:33:51 +00002228}