blob: 7893f4ff5f0cd6ef0ce961e2a63efffec6492da0 [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 */
Keith568ac5e2020-10-12 13:17:49 +0200495 if (strlen(args_info.imsi_arg) < 6 || strlen(args_info.imsi_arg) > 15) {
Harald Weltebed35df2011-11-02 13:06:18 +0100496 printf("Invalid IMSI\n");
497 return -1;
498 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200499
Keithfb2a7292020-10-12 15:32:07 +0200500 options.imsi = gtp_imsi_str2gtp(args_info.imsi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200501
Harald Weltebed35df2011-11-02 13:06:18 +0100502 printf("IMSI is: %s (%#08llx)\n",
503 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200504
Harald Weltebed35df2011-11-02 13:06:18 +0100505 /* nsapi */
506 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
507 printf("Invalid NSAPI\n");
508 return -1;
509 }
510 options.nsapi = args_info.nsapi_arg;
511 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200512
Harald Weltebed35df2011-11-02 13:06:18 +0100513 /* qos */
514 options.qos.l = 4;
515 options.qos.v[3] = (args_info.qos_arg) & 0xff;
516 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
517 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
518 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
519 /* Extensions according to 3GPP TS 24.008 */
520 if (args_info.qose1_given == 1) {
521 options.qos.l = 12;
522 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
523 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
524 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
525 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
526 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
527 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
528 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
529 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
530 if (args_info.qose2_given == 1) {
531 options.qos.l = 13;
532 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
533 if (args_info.qose3_given == 1) {
534 options.qos.l = 15;
535 options.qos.v[14] =
536 (args_info.qose3_arg) & 0xff;
537 options.qos.v[13] =
538 ((args_info.qose3_arg) >> 8) & 0xff;
539 if (args_info.qose4_given == 1) {
540 options.qos.l = 17;
541 options.qos.v[16] =
542 (args_info.qose4_arg) & 0xff;
543 options.qos.v[15] =
544 ((args_info.qose4_arg) >> 8) & 0xff;
545 }
546 }
547 }
548 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200549
Harald Weltebed35df2011-11-02 13:06:18 +0100550 /* charging */
551 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200552
Harald Weltebed35df2011-11-02 13:06:18 +0100553 /* contexts */
554 if (args_info.contexts_arg > MAXCONTEXTS) {
555 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
556 return -1;
557 }
558 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200559
Harald Weltebed35df2011-11-02 13:06:18 +0100560 /* Timelimit */
561 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200562
Harald Weltebed35df2011-11-02 13:06:18 +0100563 /* gtpversion */
564 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
565 printf("Invalid GTP version\n");
566 return -1;
567 }
568 options.gtpversion = args_info.gtpversion_arg;
569 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200570
Harald Weltebed35df2011-11-02 13:06:18 +0100571 /* apn */
572 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
573 printf("Invalid APN\n");
574 return -1;
575 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100576 options.apn.l = strlen(args_info.apn_arg) + 1;
577
578 apn = (char *)options.apn.v;
579 for (tok = strtok(args_info.apn_arg, ".");
580 tok != NULL;
581 tok = strtok(NULL, ".")) {
582 size_t len = strlen(tok);
583
584 *apn++ = (char)len;
585 strncpy(apn, tok, len);
586 apn += len;
587 }
588
Harald Weltebed35df2011-11-02 13:06:18 +0100589 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200590
Harald Weltebed35df2011-11-02 13:06:18 +0100591 /* selmode */
592 options.selmode = args_info.selmode_arg;
593 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200594
Harald Weltebed35df2011-11-02 13:06:18 +0100595 /* rattype */
596 if (args_info.rattype_given == 1) {
597 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800598 options.rattype.l = 1;
599 options.rattype.v[0] = args_info.rattype_arg;
600 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100601 }
Harald Welte41af5692011-10-07 18:42:34 +0200602
Harald Weltebed35df2011-11-02 13:06:18 +0100603 /* userloc */
604 if (args_info.userloc_given == 1) {
605 printf("Using User Location Information: %s\n",
606 args_info.userloc_arg);
607 tmp = args_info.userloc_arg;
608 n = 0;
609 pch = strtok(tmp, ".");
610 while (pch != NULL) {
611 userloc_el[n] = pch;
612 pch = strtok(NULL, ".");
613 n++;
614 }
Harald Welte41af5692011-10-07 18:42:34 +0200615
Harald Weltebed35df2011-11-02 13:06:18 +0100616 options.userloc_given = 1;
617 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200618
Harald Weltebed35df2011-11-02 13:06:18 +0100619 /* 3GPP Geographic Location Type t0 / t1 / t2 */
620 type = userloc_el[0];
621 printf("->type : %c\n", type[0]);
622 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
623 printf("Invalid type \n");
624 return -1;
625 }
626 /* options.userloc.v[0] = 0x00 */
627 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200628
Harald Weltebed35df2011-11-02 13:06:18 +0100629 /* MCC */
630 mcc = userloc_el[1];
631 printf("->mcc : %s\n", mcc);
632 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200633 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100634 return -1;
635 }
Harald Welte41af5692011-10-07 18:42:34 +0200636
Harald Weltebed35df2011-11-02 13:06:18 +0100637 /* MNC */
638 mnc = userloc_el[2];
639 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200640
Harald Weltebed35df2011-11-02 13:06:18 +0100641 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
642 /* options.userloc.v[1] = 0x52 */
643 a = (uint8_t) (mcc[0] - 48);
644 b = (uint8_t) (mcc[1] - 48);
645 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200646
Harald Weltebed35df2011-11-02 13:06:18 +0100647 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
648 /* options.userloc.v[2] = 0xf0 */
649 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200650
Harald Weltebed35df2011-11-02 13:06:18 +0100651 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200652 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100653 return -1;
654 }
655 if (strlen(mnc) == 2) {
656 b = 15;
657 }
658 if (strlen(mnc) == 3) {
659 b = (uint8_t) (mnc[2] - 48);
660 }
661 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200662
Harald Weltebed35df2011-11-02 13:06:18 +0100663 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
664 /* options.userloc.v[3] = 0x99 */
665 a = (uint8_t) (mnc[0] - 48);
666 b = (uint8_t) (mnc[1] - 48);
667 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200668
Harald Weltebed35df2011-11-02 13:06:18 +0100669 /* LAC */
670 lac = userloc_el[3];
671 /*options.userloc.v[4] = 0x12 ; */
672 /*options.userloc.v[5] = 0x10 ; */
673 printf("->LAC: %s\n", lac);
674 lac_d = atoi(lac);
675 if (lac_d > 65535 || lac_d < 1) {
676 printf("Invalid LAC\n");
677 return -1;
678 }
679 i = lac_d >> 8;
680 options.userloc.v[4] = i; /* octet 8 - LAC */
681 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200682
Harald Weltebed35df2011-11-02 13:06:18 +0100683 /* CI/SAC/RAC */
684 rest = userloc_el[4];
685 printf("->CI/SAC/RAC : %s\n", rest);
686 lac_d = atoi(rest);
687 if (lac_d > 65535 || lac_d < 1) {
688 printf("Invalid CI/SAC/RAC\n");
689 return -1;
690 }
691 /*options.userloc.v[6] = 0x04 ; */
692 /*options.userloc.v[7] = 0xb7 ; */
693 i = lac_d >> 8;
694 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
695 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
696 }
jjakoa7cd2492003-04-11 09:40:12 +0000697
Harald Weltebed35df2011-11-02 13:06:18 +0100698 /* RAI */
699 if (args_info.rai_given == 1) {
700 printf("Using RAI: %s\n", args_info.rai_arg);
701 tmp = args_info.rai_arg;
702 n = 0;
703 pch = strtok(tmp, ".");
704 while (pch != NULL) {
705 rai_el[n] = pch;
706 pch = strtok(NULL, ".");
707 n++;
708 }
jjakoa7cd2492003-04-11 09:40:12 +0000709
Harald Weltebed35df2011-11-02 13:06:18 +0100710 options.rai_given = 1;
711 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000712
Harald Weltebed35df2011-11-02 13:06:18 +0100713 /* MCC */
714 mcc = rai_el[0];
715 printf("->mcc : %s\n", mcc);
716 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200717 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100718 return -1;
719 }
720
721 /* MNC */
722 mnc = rai_el[1];
723 printf("->mnc : %s\n", mnc);
724
725 a = (uint8_t) (mcc[0] - 48);
726 b = (uint8_t) (mcc[1] - 48);
727 options.rai.v[0] = 16 * b + a;
728
729 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
730 a = (uint8_t) (mcc[2] - 48);
731
732 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200733 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100734 return -1;
735 }
736 if (strlen(mnc) == 2) {
737 b = 15;
738 }
739 if (strlen(mnc) == 3) {
740 b = (uint8_t) (mnc[2] - 48);
741 }
742 options.rai.v[1] = 16 * b + a;
743
744 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
745 a = (uint8_t) (mnc[0] - 48);
746 b = (uint8_t) (mnc[1] - 48);
747 options.rai.v[2] = 16 * b + a;
748
749 /* LAC */
750 lac = rai_el[2];
751 printf("->LAC: %s\n", lac);
752 lac_d = atoi(lac);
753 if (lac_d > 65535 || lac_d < 1) {
754 printf("Invalid LAC\n");
755 return -1;
756 }
757 i = lac_d >> 8;
758 options.rai.v[3] = i; /* octet 5 - LAC */
759 options.rai.v[4] = lac_d; /* octet 6 - LAC */
760
761 /* RAC */
762 rest = rai_el[3];
763 printf("->RAC : %s\n", rest);
764 lac_d = atoi(rest);
765 if (lac_d > 255 || lac_d < 1) {
766 printf("Invalid RAC\n");
767 return -1;
768 }
769 options.rai.v[5] = lac_d; /* octet 7 - RAC */
770 }
771
772 /* mstz */
773 if (args_info.mstz_given == 1) {
774 options.mstz_given = 1;
775 options.mstz.l = 2;
776
777 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
778 tmp = args_info.mstz_arg;
779 n = 0;
780 pch = strtok(tmp, ".");
781 while (pch != NULL) {
782 mstz_el[n] = pch;
783 pch = strtok(NULL, ".");
784 n++;
785 }
786
787 /* sign */
788 sign = atoi(mstz_el[0]);
789 printf("->Sign (0=+ / 1=-): %d\n", sign);
790 if (sign != 0 && sign != 1) {
791 printf("Invalid Sign \n");
792 return -1;
793 }
794 /* nbquarters */
795 nbquarters = atoi(mstz_el[1]);
796 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
797 if (nbquarters < 0 || nbquarters > 79) {
798 printf("Invalid Number of Quarters \n");
799 return -1;
800 }
801 /* DST */
802 DST = atoi(mstz_el[2]);
803 printf("->Daylight Saving Time Adjustment : %d\n", DST);
804 if (DST < 0 || DST > 3) {
805 printf("Invalid DST Adjustment \n");
806 return -1;
807 }
808 /* 12345678
809 bits 123 = unit of # of quarters of an hour
810 bits 678 = # of quarters of an hour / 10
811 bit 5 = sign
812 */
813 i = nbquarters % 10;
814 i = i << 4;
815 i = i + nbquarters / 10 + 8 * sign;
816 /* options.mstz.v[0] = 0x69 ; */
817 /* options.mstz.v[1] = 0x01 ; */
818 options.mstz.v[0] = i;
819 options.mstz.v[1] = DST;
820 n = (i & 0x08) ? '-' : '+';
821 printf
822 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
823 n, nbquarters / 4, nbquarters % 4 * 15);
824 }
825
826 /* imeisv */
827 if (args_info.imeisv_given == 1) {
828 options.imeisv_given = 1;
829 if (strlen(args_info.imeisv_arg) != 16) {
830 printf("Invalid IMEI(SV)\n");
831 return -1;
832 }
833 options.imeisv.l = 8;
834 for (n = 0; n < 8; n++) {
835 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
836 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
837 options.imeisv.v[n] = 16 * b + a;
838 }
839 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
840 }
841
842 /* msisdn */
843 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
844 printf("Invalid MSISDN\n");
845 return -1;
846 }
847 options.msisdn.l = 1;
848 options.msisdn.v[0] = 0x91; /* International format */
849 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
850 if ((n % 2) == 0) {
851 options.msisdn.v[((int)n / 2) + 1] =
852 args_info.msisdn_arg[n] - 48 + 0xf0;
853 options.msisdn.l += 1;
854 } else {
855 options.msisdn.v[((int)n / 2) + 1] =
856 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
857 (args_info.msisdn_arg[n] - 48) * 16;
858 }
859 }
860 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
861
862 /* UID and PWD */
863 /* Might need to also insert stuff like DNS etc. */
864 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
865 (sizeof(options.pco.v) - 1)) {
866 printf("invalid UID and PWD\n");
867 return -1;
868 }
869 options.pco.l =
870 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
871 options.pco.v[0] = 0x80; /* PPP */
872 options.pco.v[1] = 0xc0; /* PAP */
873 options.pco.v[2] = 0x23;
874 options.pco.v[3] =
875 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
876 options.pco.v[4] = 0x01; /* Authenticate request */
877 options.pco.v[5] = 0x01;
878 options.pco.v[6] = 0x00; /* MSB of length */
879 options.pco.v[7] =
880 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
881 options.pco.v[8] = strlen(args_info.uid_arg);
882 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
883 options.pco.v[9 + strlen(args_info.uid_arg)] =
884 strlen(args_info.pwd_arg);
885 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
886 args_info.pwd_arg, strlen(args_info.pwd_arg));
887
888 /* createif */
889 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800890 options.tun_dev_name = args_info.tun_device_arg;
Andreas Schultzb6292402018-10-05 13:58:45 +0100891 options.netns = args_info.netns_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100892
893 /* net */
894 /* Store net as in_addr net and mask */
895 if (args_info.net_arg) {
896 if (ippool_aton
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +0200897 (&options.netaddr, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100898 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100899 "Invalid network address: %s!",
900 args_info.net_arg);
901 exit(1);
902 }
Harald Weltebed35df2011-11-02 13:06:18 +0100903 } else {
Harald Welted12eab92017-08-02 19:49:47 +0200904 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100905 memset(&options.netaddr, 0, sizeof(options.netaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100906 }
jjako193e8b12003-11-10 12:31:41 +0000907
Harald Weltebed35df2011-11-02 13:06:18 +0100908 /* ipup */
909 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000910
Harald Weltebed35df2011-11-02 13:06:18 +0100911 /* ipdown */
912 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000913
Harald Weltebed35df2011-11-02 13:06:18 +0100914 /* statedir */
915 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000916
Harald Weltebed35df2011-11-02 13:06:18 +0100917 /* defaultroute */
918 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000919
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200920 /* PDP Type */
921 if (!strcmp(args_info.pdp_type_arg, "v6"))
922 options.pdp_type = PDP_EUA_TYPE_v6;
923 else if (!strcmp(args_info.pdp_type_arg, "v4"))
924 options.pdp_type = PDP_EUA_TYPE_v4;
925 else {
926 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
927 args_info.pdp_type_arg);
928 return -1;
929 }
930
Harald Weltebed35df2011-11-02 13:06:18 +0100931 /* pinghost */
932 /* Store ping host as in_addr */
933 if (args_info.pinghost_arg) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200934 struct addrinfo hints;
935 struct addrinfo *result;
936 memset(&hints, 0, sizeof(struct addrinfo));
937 switch (options.pdp_type) {
938 case PDP_EUA_TYPE_v4:
939 hints.ai_family = AF_INET;
940 break;
941 case PDP_EUA_TYPE_v6:
942 hints.ai_family = AF_INET6;
943 break;
944 default:
945 SYS_ERR(DSGSN, LOGL_ERROR, 0, "lookup(AF_UNSPEC) %d", options.pdp_type);
946 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
947 }
948 hints.ai_socktype = SOCK_DGRAM;
949 hints.ai_flags = 0;
950 hints.ai_protocol = 0;
951 hints.ai_canonname = NULL;
952 hints.ai_addr = NULL;
953 hints.ai_next = NULL;
954 if ((i = getaddrinfo(args_info.pinghost_arg, NULL, &hints, &result)) != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100955 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200956 "Invalid ping host '%s': %s",
957 args_info.pinghost_arg, gai_strerror(i));
Harald Weltebed35df2011-11-02 13:06:18 +0100958 return -1;
959 } else {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200960 switch (result->ai_family) {
961 case AF_INET:
962 options.pinghost.len = sizeof(struct in_addr);
963 options.pinghost.v4 = ((struct sockaddr_in*)result->ai_addr)->sin_addr;
964 SYS_ERR(DSGSN, LOGL_ERROR, 0, "AF_INET %d", options.pinghost.len);
965 break;
966 case AF_INET6:
967 options.pinghost.len = sizeof(struct in6_addr);
968 options.pinghost.v6 = ((struct sockaddr_in6*)result->ai_addr)->sin6_addr;
969 break;
970 }
Harald Weltebed35df2011-11-02 13:06:18 +0100971 printf("Using ping host: %s (%s)\n",
972 args_info.pinghost_arg,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200973 in46a_ntoa(&options.pinghost));
974 freeaddrinfo(result);
Harald Weltebed35df2011-11-02 13:06:18 +0100975 }
976 }
jjakoa7cd2492003-04-11 09:40:12 +0000977
Harald Weltebed35df2011-11-02 13:06:18 +0100978 /* Other ping parameters */
979 options.pingrate = args_info.pingrate_arg;
980 options.pingsize = args_info.pingsize_arg;
981 options.pingcount = args_info.pingcount_arg;
982 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000983
Harald Weltebed35df2011-11-02 13:06:18 +0100984 /* norecovery */
985 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000986
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800987 if (args_info.no_tx_gpdu_seq_flag)
988 options.tx_gpdu_seq = 0;
989 else
990 options.tx_gpdu_seq = 1;
991
Harald Weltebed35df2011-11-02 13:06:18 +0100992 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000993
994}
995
Pau Espin Pedrol98f81262020-04-14 18:38:52 +0200996/* write a single value to a /proc file */
997static int proc_write(const char *path, const char *value)
998{
999 int ret;
1000 FILE *f;
1001
1002 f = fopen(path, "w");
1003 if (!f) {
1004 SYS_ERR(DSGSN, LOGL_ERROR, 0, "fopen(%s) failed!\n", path);
1005 return -1;
1006 }
1007
1008 if ((ret = fputs(value, f)) < 0) {
1009 SYS_ERR(DSGSN, LOGL_ERROR, 0, "proc_write(%s, %s) failed!\n", path, value);
1010 } else {
1011 ret = 0;
1012 }
1013 fclose(f);
1014 return ret;
1015}
1016
1017/* Write value of to /proc/sys/net/ipv6/conf file for given device.
1018 * Memory is dynamically allocated, caller must free it later. */
1019static int proc_ipv6_conf_write(const char *dev, const char *file, const char *value)
1020{
1021 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
1022 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
1023 snprintf(path, sizeof(path), fmt, dev, file);
1024 return proc_write(path, value);
1025}
1026
Harald Weltefed33892017-10-10 09:02:45 +08001027static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001028{
Harald Weltee37f48e2017-10-10 09:05:50 +08001029 struct protoent *pe = getprotobynumber(t);
1030
1031 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +01001032 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +08001033 else
1034 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001035}
1036
Harald Weltefed33892017-10-10 09:02:45 +08001037static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001038{
1039 static char *ttab[] = {
1040 "Echo Reply",
1041 "ICMP 1",
1042 "ICMP 2",
1043 "Dest Unreachable",
1044 "Source Quench",
1045 "Redirect",
1046 "ICMP 6",
1047 "ICMP 7",
1048 "Echo",
1049 "ICMP 9",
1050 "ICMP 10",
1051 "Time Exceeded",
1052 "Parameter Problem",
1053 "Timestamp",
1054 "Timestamp Reply",
1055 "Info Request",
1056 "Info Reply"
1057 };
1058 if (t < 0 || t > 16)
1059 return ("OUT-OF-RANGE");
1060 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001061}
1062
Harald Weltefed33892017-10-10 09:02:45 +08001063static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001064{
1065 unsigned int n;
1066 uint64_t i64 = 0;
1067 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1068 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001069
Harald Weltebed35df2011-11-02 13:06:18 +01001070 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1071 /* ul16_t format always starts with 0x91 to indicate international format */
1072 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1073 for (n = 0; n < src->l; n++) {
1074 if ((src->v[n] & 0x0f) != 0x0f) {
1075 i64 *= 10;
1076 i64 += src->v[n] & 0x0f;
1077 }
1078 if ((src->v[n] & 0xf0) != 0xf0) {
1079 i64 *= 10;
1080 i64 += (src->v[n] & 0xf0) >> 4;
1081 }
1082 }
jjako193e8b12003-11-10 12:31:41 +00001083
Harald Weltebed35df2011-11-02 13:06:18 +01001084 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001085
Harald Weltebed35df2011-11-02 13:06:18 +01001086 /* Generate array with least significant digit in first octet */
1087 while (i64) {
1088 msa[msalen++] = i64 % 10;
1089 i64 = i64 / 10;
1090 }
jjako193e8b12003-11-10 12:31:41 +00001091
Harald Weltebed35df2011-11-02 13:06:18 +01001092 /* Convert back to ul16_t format */
1093 for (n = 0; n < msalen; n++) {
1094 if ((n % 2) == 0) {
1095 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1096 dst->l += 1;
1097 } else {
1098 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1099 msa[msalen - n - 1] * 16;
1100 }
1101 }
jjako193e8b12003-11-10 12:31:41 +00001102
Harald Weltebed35df2011-11-02 13:06:18 +01001103 return 0;
jjako193e8b12003-11-10 12:31:41 +00001104
1105}
1106
Harald Weltefed33892017-10-10 09:02:45 +08001107static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001108{
1109 /* TODO: big endian / small endian ??? */
1110 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001111
Harald Weltebed35df2011-11-02 13:06:18 +01001112 /* Convert from uint64_t bcd to uint64_t integer format */
1113 /* The resulting integer format is multiplied by 10 */
1114 while (src) {
1115 if ((src & 0x0f) != 0x0f) {
1116 i64 *= 10;
1117 i64 += (src & 0x0f);
1118 }
1119 if ((src & 0xf0) != 0xf0) {
1120 i64 *= 10;
1121 i64 += (src & 0xf0) >> 4;
1122 }
1123 src = src >> 8;
1124 }
jjako193e8b12003-11-10 12:31:41 +00001125
Harald Weltebed35df2011-11-02 13:06:18 +01001126 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 *dst = 0;
1129 while (i64) {
1130 *dst = *dst << 4;
1131 *dst += (i64 % 10);
1132 i64 = i64 / 10;
1133 }
jjako193e8b12003-11-10 12:31:41 +00001134
Harald Weltebed35df2011-11-02 13:06:18 +01001135 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001136
Harald Weltebed35df2011-11-02 13:06:18 +01001137 return 0;
jjako193e8b12003-11-10 12:31:41 +00001138
1139}
1140
jjakoafb2a972003-01-29 21:04:13 +00001141/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001142static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001143{
1144 struct timezone tz;
1145 struct timeval tv;
1146 int diff;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001147 if ((options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01001148 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1149 gettimeofday(&tv, &tz);
1150 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1151 tp->tv_sec = 0;
1152 if (diff > 0)
1153 tp->tv_usec = diff;
1154 else {
1155 /* For some reason we get packet loss if set to zero */
1156 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1157 tp->tv_usec = 0;
1158 }
1159 }
1160 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001161}
1162
jjako5da68452003-01-28 16:08:47 +00001163/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001164static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001165{
Harald Weltebed35df2011-11-02 13:06:18 +01001166 struct timezone tz;
1167 struct timeval tv;
1168 int elapsed;
1169 gettimeofday(&tv, &tz);
1170 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1171 printf("\n");
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001172 printf("\n----%s PING Statistics----\n", in46a_ntoa(&options.pinghost));
Harald Weltebed35df2011-11-02 13:06:18 +01001173 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1174 elapsed / 1000000.0);
1175 printf("%d packets received, ", nreceived);
1176 if (ntransmitted) {
1177 if (nreceived > ntransmitted)
1178 printf("-- somebody's printing up packets!");
1179 else
1180 printf("%d%% packet loss",
1181 (int)(((ntransmitted - nreceived) * 100) /
1182 ntransmitted));
1183 }
1184 printf("\n");
1185 if (options.debug)
1186 printf("%d packets received in total\n", ntreceived);
1187 if (nreceived && tsum)
1188 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1189 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
Pau Espin Pedrolcdcaeda2020-04-15 16:37:58 +02001190 printf("%d packets transmitted \n", ntransmitted);
jjakoafb2a972003-01-29 21:04:13 +00001191
Harald Weltebed35df2011-11-02 13:06:18 +01001192 ntransmitted = 0;
1193 return 0;
jjako5da68452003-01-28 16:08:47 +00001194}
1195
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001196static int encaps_ping4(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001197{
Harald Weltebed35df2011-11-02 13:06:18 +01001198 struct timeval tv;
1199 struct timeval *tp;
1200 struct ip_ping *pingpack = pack;
1201 struct in_addr src;
1202 int triptime;
jjako5da68452003-01-28 16:08:47 +00001203
Harald Weltebed35df2011-11-02 13:06:18 +01001204 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001205
Harald Weltebed35df2011-11-02 13:06:18 +01001206 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1207 printf("packet too short (%d bytes) from %s\n", len,
1208 inet_ntoa(src));
1209 return 0;
1210 }
jjako5da68452003-01-28 16:08:47 +00001211
Harald Weltebed35df2011-11-02 13:06:18 +01001212 if (pingpack->protocol != 1) {
1213 if (!options.pingquiet)
1214 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1215 len, inet_ntoa(src), pingpack->protocol,
1216 print_ipprot(pingpack->protocol));
1217 return 0;
1218 }
jjako5da68452003-01-28 16:08:47 +00001219
Harald Weltebed35df2011-11-02 13:06:18 +01001220 if (pingpack->type != 0) {
1221 if (!options.pingquiet)
1222 printf
1223 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1224 len, inet_ntoa(src), pingpack->type,
1225 print_icmptype(pingpack->type), pingpack->code);
1226 return 0;
1227 }
jjako5da68452003-01-28 16:08:47 +00001228
Harald Weltebed35df2011-11-02 13:06:18 +01001229 nreceived++;
1230 if (!options.pingquiet)
1231 printf("%d bytes from %s: icmp_seq=%d", len,
1232 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001233
Harald Weltebed35df2011-11-02 13:06:18 +01001234 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001235 gettimeofday(&tv, NULL);
Harald Weltebed35df2011-11-02 13:06:18 +01001236 tp = (struct timeval *)pingpack->data;
1237 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1238 tv.tv_sec--;
1239 tv.tv_usec += 1000000;
1240 }
1241 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001242
Harald Weltebed35df2011-11-02 13:06:18 +01001243 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1244 tsum += triptime;
1245 if (triptime < tmin)
1246 tmin = triptime;
1247 if (triptime > tmax)
1248 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001249
Harald Weltebed35df2011-11-02 13:06:18 +01001250 if (!options.pingquiet)
1251 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001252
Harald Weltebed35df2011-11-02 13:06:18 +01001253 } else if (!options.pingquiet)
1254 printf("\n");
1255 return 0;
jjako5da68452003-01-28 16:08:47 +00001256}
1257
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001258static int encaps_ping6(struct pdp_t *pdp, struct ip6_hdr *ip6h, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001259{
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001260 const struct icmpv6_echo_hdr *ic6h = (struct icmpv6_echo_hdr *) ((uint8_t*)ip6h + sizeof(*ip6h));
1261 struct timeval tv;
1262 struct timeval tp;
1263 int triptime;
1264 char straddr[128];
jjako5da68452003-01-28 16:08:47 +00001265
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001266 if (len < sizeof(struct ip6_hdr)) {
1267 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain IPv6 header (%d)", len);
1268 return 0;
1269 }
1270
1271 if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_ICMPV6) {
1272 if (!options.pingquiet)
1273 printf("%d bytes from %s: ip6_protocol=%d (%s)\n", len,
1274 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1275 ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt,
1276 print_ipprot(ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt));
1277 return 0;
1278 }
1279
1280 if (len < sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr)) {
1281 LOGP(DSGSN, LOGL_ERROR, "Packet len too small to contain ICMPv6 echo header (%d)\n", len);
1282 return 0;
1283 }
1284
1285 if (ic6h->hdr.type != 129 || ic6h->hdr.code != 0) {
1286 if (!options.pingquiet)
1287 printf
1288 ("%d bytes from %s: icmp_type=%d icmp_code=%d\n", len,
1289 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1290 ic6h->hdr.type, ic6h->hdr.code);
1291 return 0;
1292 }
1293
1294 nreceived++;
1295 if (!options.pingquiet)
1296 printf("%d bytes from %s: icmp_seq=%d", len,
1297 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1298 ntohs(ic6h->seq));
1299
1300 if (len >= sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr) + sizeof(struct timeval)) {
1301 gettimeofday(&tv, NULL);
1302 memcpy(&tp, ic6h->data, sizeof(struct timeval));
1303 if ((tv.tv_usec -= tp.tv_usec) < 0) {
1304 tv.tv_sec--;
1305 tv.tv_usec += 1000000;
1306 }
1307 tv.tv_sec -= tp.tv_sec;
1308
1309 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1310 tsum += triptime;
1311 if (triptime < tmin)
1312 tmin = triptime;
1313 if (triptime > tmax)
1314 tmax = triptime;
1315
1316 if (!options.pingquiet)
1317 printf(" time=%.3f ms\n", triptime / 1000.0);
1318
1319 } else if (!options.pingquiet)
1320 printf("\n");
1321 return 0;
1322}
1323
1324/* Handle a received ping packet. Print out line and update statistics. */
1325static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1326{
1327 struct iphdr *iph = (struct iphdr *)pack;
1328 struct timeval tv;
1329
1330
1331 gettimeofday(&tv, NULL);
1332 if (options.debug)
1333 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
1334
1335 ntreceived++;
1336
1337 if (len < sizeof(struct iphdr)) {
1338 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain ip header (%d)", len);
1339 return -1;
1340 }
1341 switch(iph->version) {
1342 case 4:
1343 return encaps_ping4(pdp, pack, len);
1344 case 6:
1345 return encaps_ping6(pdp, (struct ip6_hdr *)pack, len);
1346 default:
1347 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unknown ip header version %d", iph->version);
1348 return -1;
1349 }
1350}
1351
1352static int create_ping4(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1353 struct in46_addr *dst, int seq, unsigned int datasize)
1354{
Harald Weltebed35df2011-11-02 13:06:18 +01001355 struct ip_ping pack;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001356 uint16_t v16;
Harald Weltebed35df2011-11-02 13:06:18 +01001357 uint8_t *p8 = (uint8_t *) & pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001358 unsigned int n;
1359 long int sum = 0;
1360 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001361
Harald Weltebed35df2011-11-02 13:06:18 +01001362 struct timezone tz;
1363 struct timeval *tp =
1364 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001365
Harald Weltebed35df2011-11-02 13:06:18 +01001366 pack.ipver = 0x45;
1367 pack.tos = 0x00;
1368 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1369 pack.fragid = 0x0000;
1370 pack.offset = 0x0040;
1371 pack.ttl = 0x40;
1372 pack.protocol = 0x01;
1373 pack.ipcheck = 0x0000;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001374 pack.src = src->v4.s_addr;
1375 pack.dst = dst->v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +01001376 pack.type = 0x08;
1377 pack.code = 0x00;
1378 pack.checksum = 0x0000;
1379 pack.ident = 0x0000;
1380 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001381
Harald Weltebed35df2011-11-02 13:06:18 +01001382 /* Generate ICMP payload */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001383 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
Harald Weltebed35df2011-11-02 13:06:18 +01001384 for (n = 0; n < (datasize); n++)
1385 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001386
Harald Weltebed35df2011-11-02 13:06:18 +01001387 if (datasize >= sizeof(struct timeval))
1388 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001389
Harald Weltebed35df2011-11-02 13:06:18 +01001390 /* Calculate IP header checksum */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001391 p8 = (uint8_t *) &pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001392 count = CREATEPING_IP;
1393 sum = 0;
1394 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001395 memcpy(&v16, p8, 2);
1396 sum += v16;
1397 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001398 count -= 2;
1399 }
1400 while (sum >> 16)
1401 sum = (sum & 0xffff) + (sum >> 16);
1402 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001403
Harald Weltebed35df2011-11-02 13:06:18 +01001404 /* Calculate ICMP checksum */
1405 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1406 sum = 0;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001407 p8 = (uint8_t *) &pack;
1408 p8 += CREATEPING_IP;
Harald Weltebed35df2011-11-02 13:06:18 +01001409 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 if (count > 0)
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001416 sum += *(unsigned char *)p8;
Harald Weltebed35df2011-11-02 13:06:18 +01001417 while (sum >> 16)
1418 sum = (sum & 0xffff) + (sum >> 16);
1419 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001420
Harald Weltebed35df2011-11-02 13:06:18 +01001421 ntransmitted++;
1422 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001423}
1424
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001425static int create_ping6(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1426 struct in46_addr *dst, int seq, unsigned int datasize)
1427{
1428 struct ip6_ping *pack;
1429 uint8_t *p8;
1430 unsigned int n;
1431 struct timezone tz;
1432 struct timeval *tp;
1433
1434 struct msgb *msg = msgb_alloc_headroom(sizeof(struct ip6_ping) + 128,128, "ICMPv6 echo");
1435 OSMO_ASSERT(msg);
1436 pack = (struct ip6_ping *) msgb_put(msg, sizeof(struct icmpv6_echo_hdr) + datasize);
1437 pack->hdr.hdr.type = 128;
1438 pack->hdr.hdr.code = 0;
1439 pack->hdr.hdr.csum = 0; /* updated below */
1440 pack->hdr.ident = 0x0000;
1441 pack->hdr.seq = htons(seq);
1442
1443 p8 = pack->data;
1444 for (n = 0; n < (datasize); n++)
1445 p8[n] = n;
1446
1447 if (datasize >= sizeof(struct timeval)) {
1448 tp = (struct timeval *)pack->data;
1449 gettimeofday(tp, &tz);
1450 }
1451
1452 pack->hdr.hdr.csum = icmpv6_prepend_ip6hdr(msg, &src->v6, &dst->v6);
1453
1454 ntransmitted++;
1455 return gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
1456}
1457
1458/* Create a new ping packet and send it off to peer. */
1459static int create_ping(void *gsn, struct pdp_t *pdp,
1460 struct in46_addr *dst, int seq, unsigned int datasize)
1461{
1462 int num_addr;
1463 struct in46_addr addr[2];
1464 struct in46_addr *src;
1465
1466 if (datasize > CREATEPING_MAX) {
1467 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1468 "Ping size to large: %d!", datasize);
1469 return -1;
1470 }
1471
1472 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
1473 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1474 "in46a_from_eua() failed! %d", num_addr);
1475 return -1;
1476 }
1477 if (dst->len == addr[0].len) {
1478 src = &addr[0];
1479 } else if (num_addr > 1 && dst->len == addr[1].len) {
1480 src = &addr[1];
1481 } else {
1482 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1483 "Mismaching source and destination IP addr types (%d vs %d)", dst->len, addr[0].len);
1484 return -1;
1485 }
1486 if (in46a_is_v4(dst))
1487 return create_ping4(gsn, pdp, src, dst, seq, datasize);
1488 else
1489 return create_ping6(gsn, pdp, src, dst, seq, datasize);
1490}
1491
Harald Weltefed33892017-10-10 09:02:45 +08001492static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001493{
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001494 int rc;
1495
Andreas Schultzb6292402018-10-05 13:58:45 +01001496 if (tun && options.ipdown) {
1497#if defined(__linux__)
1498 sigset_t oldmask;
Harald Weltebed35df2011-11-02 13:06:18 +01001499
Andreas Schultzb6292402018-10-05 13:58:45 +01001500 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001501 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1502 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1503 "Failed to switch to netns %s: %s\n",
1504 options.netns, strerror(-rc));
1505 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001506 }
1507#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001508 tun_runscript(tun, options.ipdown);
1509
Andreas Schultzb6292402018-10-05 13:58:45 +01001510#if defined(__linux__)
1511 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001512 if ((rc = restore_ns(&oldmask)) < 0) {
1513 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1514 "Failed to switch to original netns: %s\n",
1515 strerror(-rc));
1516 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001517 }
1518#endif
1519 }
1520
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001521 ipdel((struct iphash_t *)pdp->peer[0]);
1522 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001523
1524 if (1 == options.contexts)
1525 state = 5; /* Disconnected */
1526
1527 return 0;
1528}
jjakoa7cd2492003-04-11 09:40:12 +00001529
Harald Welte6748dc92017-09-24 21:54:59 +08001530/* Link-Local address prefix fe80::/64 */
1531static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1532
jjakoa7cd2492003-04-11 09:40:12 +00001533/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001534static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001535{
1536 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001537 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001538 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001539 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001540
Harald Welte6748dc92017-09-24 21:54:59 +08001541 if (iph->version == 4) {
1542 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1543 printf("Dropping packet with too short IP header\n");
1544 return 0;
1545 }
1546 src.len = 4;
1547 src.v4.s_addr = iph->saddr;
1548 } else if (iph->version == 6) {
Harald Welte6748dc92017-09-24 21:54:59 +08001549 src.len = 16;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001550 src.v6 = ip6h->ip6_src;
Harald Welte6748dc92017-09-24 21:54:59 +08001551 } else {
1552 printf("Dropping packet with invalid IP version %u\n", iph->version);
1553 return 0;
1554 }
jjakoa7cd2492003-04-11 09:40:12 +00001555
Harald Weltebed35df2011-11-02 13:06:18 +01001556 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001557 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001558 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001559 return 0;
1560 }
1561
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001562 if (ipm->ctx->pdp) /* Check if a peer protocol is defined */
1563 gtp_data_req(gsn, ipm->ctx->pdp, pack, len);
Harald Weltebed35df2011-11-02 13:06:18 +01001564 return 0;
jjako52c24142002-12-16 13:33:51 +00001565}
1566
Harald Weltefed33892017-10-10 09:02:45 +08001567static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001568{
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001569 int rc, i, num_addr;
1570 struct in46_addr addr[2];
Andreas Schultzb6292402018-10-05 13:58:45 +01001571#if defined(__linux__)
1572 sigset_t oldmask;
1573#endif
jjako52c24142002-12-16 13:33:51 +00001574
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001575 struct pdp_peer_sgsnemu_ctx *ctx = (struct pdp_peer_sgsnemu_ctx *) cbp;
jjako2c381332003-10-21 19:09:53 +00001576
Harald Weltebed35df2011-11-02 13:06:18 +01001577 if (cause < 0) {
1578 printf("Create PDP Context Request timed out\n");
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001579 if (ctx->pdp->version == 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001580 printf("Retrying with version 0\n");
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001581 ctx->pdp->version = 0;
1582 gtp_create_context_req(gsn, ctx->pdp, ctx);
Harald Weltebed35df2011-11-02 13:06:18 +01001583 return 0;
1584 } else {
1585 state = 0;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001586 pdp_freepdp(ctx->pdp);
1587 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001588 return EOF;
1589 }
1590 }
jjako2c381332003-10-21 19:09:53 +00001591
Harald Weltebed35df2011-11-02 13:06:18 +01001592 if (cause != 128) {
1593 printf
1594 ("Received create PDP context response. Cause value: %d\n",
1595 cause);
1596 state = 0;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001597 pdp_freepdp(ctx->pdp);
1598 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001599 return EOF; /* Not what we expected */
1600 }
jjako52c24142002-12-16 13:33:51 +00001601
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001602 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001603 printf
1604 ("Received create PDP context response. Cause value: %d\n",
1605 cause);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001606 pdp_freepdp(ctx->pdp);
1607 ctx->pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001608 state = 0;
1609 return EOF; /* Not a valid IP address */
1610 }
jjakoa7cd2492003-04-11 09:40:12 +00001611
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001612 printf("Received create PDP context response.\n");
jjakoa7cd2492003-04-11 09:40:12 +00001613
Andreas Schultzb6292402018-10-05 13:58:45 +01001614#if defined(__linux__)
1615 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001616 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1617 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1618 "Failed to switch to netns %s: %s\n",
1619 options.netns, strerror(-rc));
1620 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001621 }
1622#endif
1623
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001624 for (i = 0; i < num_addr; i++) {
1625 printf("PDP ctx: received EUA with IP address: %s\n", in46a_ntoa(&addr[i]));
1626
1627 switch (addr[i].len) {
1628 case 16: /* IPv6 */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001629 /* Convert address to link local using the lower 64bits
1630 of the allocated EUA as Interface-Identifier to
1631 send router solicitation, as per 3GPP TS 29.061
1632 Section 11.2.1.3.2 */
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001633 memcpy(addr[i].v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1634 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr[i]));
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001635 ctx->hash_v6_ll.inuse = 1;
1636 ipset(&ctx->hash_v6_ll, &addr[i]);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001637 break;
1638 case 4: /* IPv4 */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001639 ctx->hash_v4.inuse = 1;
1640 ipset(&ctx->hash_v4, &addr[i]);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001641 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001642 }
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001643
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001644 if ((options.createif) && (!options.netaddr.len)) {
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001645 size_t prefixlen = 32;
1646 if (addr[i].len == 16)
1647 prefixlen = 64;
1648 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrole5d71632020-04-15 14:43:50 +02001649 tun_addaddr(tun, &addr[i], NULL, prefixlen);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001650 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001651 if (in46a_is_v4(&addr[i])) {
1652 struct in_addr rm;
1653 rm.s_addr = 0;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001654 if (netdev_addroute4(&rm, &addr[i].v4, &rm) < 0) {
1655 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", in46a_ntoa(&addr[i]));
1656 }
1657 } /* else: route will be set up once we have a global link address (Router Advertisement) */
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001658 }
1659 if (options.ipup)
1660 tun_runscript(tun, options.ipup);
1661 }
Harald Weltebed35df2011-11-02 13:06:18 +01001662 }
jjako52c24142002-12-16 13:33:51 +00001663
Harald Welte081f30c2017-10-10 09:36:35 +08001664 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001665 struct in6_addr *saddr6;
1666 struct msgb *msg;
1667 if (in46a_is_v6(&addr[0])) {
1668 saddr6 = &addr[0].v6;
1669 } else if (num_addr > 1 && in46a_is_v6(&addr[1])) {
1670 saddr6 = &addr[1].v6;
1671 } else {
1672 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to find IPv6 EUA on IPv6 APN");
1673 return EOF; /* Not a valid IP address */
Harald Welte081f30c2017-10-10 09:36:35 +08001674 }
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001675 SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN...");
1676 msg = icmpv6_construct_rs(saddr6);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001677 gtp_data_req(gsn, ctx->pdp, msgb_data(msg), msgb_length(msg));
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001678 msgb_free(msg);
Harald Welte081f30c2017-10-10 09:36:35 +08001679 }
1680
Andreas Schultzb6292402018-10-05 13:58:45 +01001681#if defined(__linux__)
1682 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001683 if ((rc = restore_ns(&oldmask)) < 0) {
1684 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1685 strerror(-rc));
1686 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001687 }
1688#endif
1689
Harald Weltebed35df2011-11-02 13:06:18 +01001690
1691 state = 2; /* Connected */
1692
1693 return 0;
jjako52c24142002-12-16 13:33:51 +00001694}
1695
Harald Weltefed33892017-10-10 09:02:45 +08001696static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001697{
1698 printf("Received delete PDP context response. Cause value: %d\n",
1699 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001700 if (pdp)
1701 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001702 return 0;
jjako52c24142002-12-16 13:33:51 +00001703}
1704
Harald Weltefed33892017-10-10 09:02:45 +08001705static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001706{
jjako91aaf222003-10-22 10:09:32 +00001707
Harald Weltebed35df2011-11-02 13:06:18 +01001708 if (recovery < 0) {
1709 printf("Echo Request timed out\n");
1710 if (echoversion == 1) {
1711 printf("Retrying with version 0\n");
1712 echoversion = 0;
1713 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1714 return 0;
1715 } else {
1716 state = 0;
1717 return EOF;
1718 }
1719 } else {
1720 printf("Received echo response\n");
1721 if (!options.contexts)
1722 state = 5;
1723 }
1724 return 0;
jjako52c24142002-12-16 13:33:51 +00001725}
1726
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001727static int _gtp_cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001728{
1729 /* if (cause < 0) return 0; Some error occurred. We don't care */
1730 switch (type) {
1731 case GTP_ECHO_REQ:
1732 return echo_conf(cause);
1733 case GTP_CREATE_PDP_REQ:
1734 return create_pdp_conf(pdp, cbp, cause);
1735 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001736 return delete_pdp_conf(pdp, cause);
1737 default:
1738 return 0;
1739 }
jjako52c24142002-12-16 13:33:51 +00001740}
1741
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001742static 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 +02001743{
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001744 struct pdp_peer_sgsnemu_ctx* ctx = (struct pdp_peer_sgsnemu_ctx*)pdp->peer[0];
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001745 struct icmpv6_opt_hdr *opt_hdr;
1746 struct icmpv6_opt_prefix *opt_prefix;
1747 int rc;
1748 sigset_t oldmask;
1749 struct in6_addr rm;
1750 char ip6strbuf[200];
1751 memset(&rm, 0, sizeof(rm));
1752
1753 SYS_ERR(DSGSN, LOGL_INFO, 0, "Received ICMPv6 Router Advertisement");
1754
1755 foreach_icmpv6_opt(ra, ra_len, opt_hdr) {
1756 if (opt_hdr->type == ICMPv6_OPT_TYPE_PREFIX_INFO) {
1757 opt_prefix = (struct icmpv6_opt_prefix *)opt_hdr;
1758 size_t prefix_len_bytes = (opt_prefix->prefix_len + 7)/8;
1759 SYS_ERR(DSGSN, LOGL_INFO, 0, "Parsing OPT Prefix info (prefix_len=%u): %s",
1760 opt_prefix->prefix_len,
1761 osmo_hexdump((const unsigned char *)opt_prefix->prefix, prefix_len_bytes));
1762 if ((options.createif) && (!options.netaddr.len)) {
1763 struct in46_addr addr;
1764 addr.len = 16;
1765 memcpy(addr.v6.s6_addr, opt_prefix->prefix, prefix_len_bytes);
1766 memset(&addr.v6.s6_addr[prefix_len_bytes], 0, 16 - prefix_len_bytes);
1767 addr.v6.s6_addr[15] = 0x02;
1768 SYS_ERR(DSGSN, LOGL_INFO, 0, "Adding addr %s to tun %s",
1769 in46a_ntoa(&addr), tun->devname);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001770 if (!ctx->hash_v6_global.inuse) {
1771 ctx->hash_v6_global.inuse = 1;
1772 ipset(&ctx->hash_v6_global, &addr);
1773 } else {
1774 SYS_ERR(DSGSN, LOGL_ERROR, 0, "First v6 global address in hash already in use!");
1775 }
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001776
1777#if defined(__linux__)
1778 if ((options.netns)) {
1779 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1780 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1781 "Failed to switch to netns %s: %s",
1782 options.netns, strerror(-rc));
1783 }
1784 }
1785#endif
1786 rc = tun_addaddr(tun, &addr, NULL, opt_prefix->prefix_len);
1787 if (rc < 0) {
1788 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to add addr %s to tun %s",
1789 in46a_ntoa(&addr), tun->devname);
1790 }
1791
1792 struct in6_addr rm;
1793 memset(&rm, 0, sizeof(rm));
1794 if (netdev_addroute6(&rm, &ip6h->ip6_src, 0, tun->devname) < 0) {
1795 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", inet_ntop(AF_INET6, &ip6h->ip6_src, ip6strbuf, sizeof(ip6strbuf)));
1796 }
1797
1798#if defined(__linux__)
1799 if ((options.netns)) {
1800 if ((rc = restore_ns(&oldmask)) < 0) {
1801 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1802 "Failed to switch to original netns: %s",
1803 strerror(-rc));
1804 }
1805 }
1806#endif
1807 }
1808 }
1809 }
1810}
1811
Harald Weltefed33892017-10-10 09:02:45 +08001812static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001813{
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001814 struct iphdr *iph = (struct iphdr *)pack;
1815 struct icmpv6_radv_hdr *ra;
1816 switch (iph->version) {
1817 case 6:
1818 if ((ra = icmpv6_validate_router_adv(pack, len))) {
1819 size_t ra_len = (uint8_t*)ra - (uint8_t*)pack;
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001820 handle_router_adv(pdp, (struct ip6_hdr *)pack, ra, ra_len);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001821 return 0;
1822 }
1823 break;
1824 }
1825
Harald Weltebed35df2011-11-02 13:06:18 +01001826 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1827 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001828}
1829
1830int main(int argc, char **argv)
1831{
Harald Weltebed35df2011-11-02 13:06:18 +01001832 fd_set fds; /* For select() */
1833 struct timeval idleTime; /* How long to select() */
1834 struct pdp_t *pdp;
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001835 int n, rc;
Harald Weltebed35df2011-11-02 13:06:18 +01001836 int starttime = time(NULL); /* Time program was started */
1837 int stoptime = 0; /* Time to exit */
1838 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001839 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001840
Harald Weltebed35df2011-11-02 13:06:18 +01001841 struct timezone tz; /* Used for calculating ping times */
1842 struct timeval tv;
1843 int diff;
Andreas Schultzb6292402018-10-05 13:58:45 +01001844#if defined(__linux__)
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001845 char buf[10];
Andreas Schultzb6292402018-10-05 13:58:45 +01001846 sigset_t oldmask;
1847#endif
jjako52c24142002-12-16 13:33:51 +00001848
bjovana8f71eb2017-02-24 17:39:20 +01001849 signal(SIGTERM, signal_handler);
1850 signal(SIGHUP, signal_handler);
1851 signal(SIGINT, signal_handler);
1852
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001853 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1854 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1855 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001856
Andreas Schultzb6292402018-10-05 13:58:45 +01001857#if defined(__linux__)
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001858 if ((rc = init_netns()) < 0) {
1859 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
1860 exit(1);
1861 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001862#endif
1863
Harald Weltebed35df2011-11-02 13:06:18 +01001864 /* Process options given in configuration file and command line */
1865 if (process_options(argc, argv))
1866 exit(1);
jjako52c24142002-12-16 13:33:51 +00001867
Harald Weltebed35df2011-11-02 13:06:18 +01001868 printf("\nInitialising GTP library\n");
1869 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001870 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001871 exit(1);
1872 }
1873 if (gsn->fd0 > maxfd)
1874 maxfd = gsn->fd0;
1875 if (gsn->fd1c > maxfd)
1876 maxfd = gsn->fd1c;
1877 if (gsn->fd1u > maxfd)
1878 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001879
Harald Weltebed35df2011-11-02 13:06:18 +01001880 gtp_set_cb_delete_context(gsn, delete_context);
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001881 gtp_set_cb_conf(gsn, _gtp_cb_conf);
Harald Weltebed35df2011-11-02 13:06:18 +01001882 if (options.createif)
1883 gtp_set_cb_data_ind(gsn, encaps_tun);
1884 else
1885 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001886
Andreas Schultzb6292402018-10-05 13:58:45 +01001887#if defined(__linux__)
1888 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001889 if ((netns = get_nsfd(options.netns)) < 0) {
1890 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
1891 options.netns, strerror(-netns));
1892 exit(1);
1893 }
1894 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1895 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
1896 options.netns, strerror(-rc));
1897 exit(1);
1898 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001899 }
1900#endif
1901
Harald Weltebed35df2011-11-02 13:06:18 +01001902 if (options.createif) {
1903 printf("Setting up interface\n");
1904 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001905 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001906 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001907 "Failed to create tun");
1908 exit(1);
1909 }
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001910
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001911#if defined(__linux__) && defined(HAVE_IN6_ADDR_GEN_MODE_NONE)
1912 /* Avoid tunnel setting its own link-local addr automatically,
1913 we don't need it. Don't exit on error since this sysctl is
1914 only available starting with linux 4.11. */
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001915 snprintf(buf, sizeof(buf), "%u", IN6_ADDR_GEN_MODE_NONE);
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001916 if (proc_ipv6_conf_write(tun->devname, "addr_gen_mode", buf) < 0) {
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001917 SYS_ERR(DSGSN, LOGL_ERROR, errno,
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001918 "Failed to disable addr_gen_mode on %s, an extra link-local "
1919 "ip address will appear on the tun device.\n",
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001920 tun->devname);
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001921 }
1922#endif
1923
Harald Weltebed35df2011-11-02 13:06:18 +01001924 tun_set_cb_ind(tun, cb_tun_ind);
1925 if (tun->fd > maxfd)
1926 maxfd = tun->fd;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001927
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001928 if (proc_ipv6_conf_write(tun->devname, "accept_ra", "0") < 0) {
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001929 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Dmitri Kalashnikdb98f302020-04-28 13:10:56 +04001930 "Failed to disable IPv6 SLAAC on %s\n", tun->devname);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001931 exit(1);
1932 }
Harald Weltebed35df2011-11-02 13:06:18 +01001933 }
jjakoa7cd2492003-04-11 09:40:12 +00001934
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001935 if ((options.createif) && (options.netaddr.len)) {
Pau Espin Pedrol964f08a2020-04-15 14:29:25 +02001936 tun_addaddr(tun, &options.netaddr, NULL, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001937 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001938 if (in46a_is_v4(&options.netaddr)) {
1939 struct in_addr rm;
1940 rm.s_addr = 0;
1941 netdev_addroute4(&rm, &options.netaddr.v4, &rm);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001942 } else {
1943 struct in6_addr rm;
1944 memset(&rm, 0, sizeof(rm));
1945 netdev_addroute6(&rm, &options.netaddr.v6, 0, tun->devname);
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001946 }
Harald Weltebed35df2011-11-02 13:06:18 +01001947 }
1948 if (options.ipup)
1949 tun_runscript(tun, options.ipup);
1950 }
jjakoa7cd2492003-04-11 09:40:12 +00001951
Andreas Schultzb6292402018-10-05 13:58:45 +01001952#if defined(__linux__)
1953 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001954 if ((rc = restore_ns(&oldmask)) < 0) {
1955 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1956 strerror(-rc));
1957 exit(1);
1958 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001959 }
1960#endif
1961
Harald Weltebed35df2011-11-02 13:06:18 +01001962 /* Initialise hash tables */
1963 memset(&iphash, 0, sizeof(iphash));
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001964 memset(&ctx_arr, 0, sizeof(ctx_arr));
jjako193e8b12003-11-10 12:31:41 +00001965
Harald Weltebed35df2011-11-02 13:06:18 +01001966 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001967
Harald Weltebed35df2011-11-02 13:06:18 +01001968 /* See if anybody is there */
1969 printf("Sending off echo request\n");
1970 echoversion = options.gtpversion;
1971 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001972
Harald Weltebed35df2011-11-02 13:06:18 +01001973 for (n = 0; n < options.contexts; n++) {
1974 uint64_t myimsi;
1975 printf("Setting up PDP context #%d\n", n);
jjako52c24142002-12-16 13:33:51 +00001976
Harald Weltebed35df2011-11-02 13:06:18 +01001977 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001978
Harald Weltebed35df2011-11-02 13:06:18 +01001979 /* Allocated here. */
1980 /* If create context failes we have to deallocate ourselves. */
1981 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001982 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001983
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001984 pdp->peer[0] = &ctx_arr[n];
Harald Weltebed35df2011-11-02 13:06:18 +01001985 pdp->ipif = tun; /* TODO */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02001986 ctx_arr[n].pdp = pdp;
1987 ctx_arr[n].hash_v4.ctx = &ctx_arr[n];
1988 ctx_arr[n].hash_v6_ll.ctx = &ctx_arr[n];
1989 ctx_arr[n].hash_v6_global.ctx = &ctx_arr[n];
jjako193e8b12003-11-10 12:31:41 +00001990
Harald Weltebed35df2011-11-02 13:06:18 +01001991 if (options.gtpversion == 0) {
1992 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001993 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001994 "QoS length too big");
1995 exit(1);
1996 } else {
1997 memcpy(pdp->qos_req0, options.qos.v,
1998 options.qos.l);
1999 }
2000 }
jjakoa7cd2492003-04-11 09:40:12 +00002001
Harald Weltebed35df2011-11-02 13:06:18 +01002002 pdp->qos_req.l = options.qos.l;
2003 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00002004
Harald Weltebed35df2011-11-02 13:06:18 +01002005 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00002006
Harald Weltebed35df2011-11-02 13:06:18 +01002007 pdp->rattype.l = options.rattype.l;
2008 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
2009 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002010
Harald Weltebed35df2011-11-02 13:06:18 +01002011 pdp->userloc.l = options.userloc.l;
2012 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
2013 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002014
Harald Weltebed35df2011-11-02 13:06:18 +01002015 pdp->rai.l = options.rai.l;
2016 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
2017 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02002018
Harald Weltebed35df2011-11-02 13:06:18 +01002019 pdp->mstz.l = options.mstz.l;
2020 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
2021 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002022
Harald Weltebed35df2011-11-02 13:06:18 +01002023 pdp->imeisv.l = options.imeisv.l;
2024 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
2025 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002026
Harald Weltebed35df2011-11-02 13:06:18 +01002027 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02002028
Harald Weltebed35df2011-11-02 13:06:18 +01002029 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002030 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002031 "APN length too big");
2032 exit(1);
2033 } else {
2034 pdp->apn_use.l = options.apn.l;
2035 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
2036 }
jjako193e8b12003-11-10 12:31:41 +00002037
Harald Weltebed35df2011-11-02 13:06:18 +01002038 pdp->gsnlc.l = sizeof(options.listen);
2039 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
2040 pdp->gsnlu.l = sizeof(options.listen);
2041 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00002042
Harald Weltebed35df2011-11-02 13:06:18 +01002043 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002044 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002045 "MSISDN length too big");
2046 exit(1);
2047 } else {
2048 msisdn_add(&options.msisdn, &pdp->msisdn, n);
2049 }
jjakob62c3dd2004-05-27 18:51:55 +00002050
Harald Welte840a8e92017-09-24 18:12:40 +08002051 /* Request dynamic IP address */
2052 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
2053 pdp->eua.v[1] = options.pdp_type;
2054 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00002055
Harald Weltebed35df2011-11-02 13:06:18 +01002056 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002057 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002058 "PCO length too big");
2059 exit(1);
2060 } else {
2061 pdp->pco_req.l = options.pco.l;
2062 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
2063 }
jjako52c24142002-12-16 13:33:51 +00002064
Harald Weltebed35df2011-11-02 13:06:18 +01002065 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00002066
Harald Weltebed35df2011-11-02 13:06:18 +01002067 pdp->hisaddr0 = options.remote;
2068 pdp->hisaddr1 = options.remote;
2069
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01002070 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01002071 512 = Flat rate, 256 = Hot billing */
2072
Harald Weltefbb9c7f2017-09-24 11:50:20 +08002073 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
2074
Harald Weltebed35df2011-11-02 13:06:18 +01002075 /* Create context */
2076 /* We send this of once. Retransmissions are handled by gtplib */
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002077 gtp_create_context_req(gsn, pdp, &ctx_arr[n]);
Harald Weltebed35df2011-11-02 13:06:18 +01002078 }
2079
2080 state = 1; /* Enter wait_connection state */
2081
2082 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00002083
jjako52c24142002-12-16 13:33:51 +00002084 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01002085 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00002086 /******************************************************************/
2087
Harald Weltebed35df2011-11-02 13:06:18 +01002088 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00002089
Harald Weltebed35df2011-11-02 13:06:18 +01002090 /* Take down client after timeout after disconnect */
2091 if ((4 == state) && ((stoptime) <= time(NULL))) {
2092 state = 5;
2093 }
jjako7b8fad42003-07-07 14:37:42 +00002094
Harald Weltebed35df2011-11-02 13:06:18 +01002095 /* Take down client after timelimit timeout */
2096 if ((2 == state) && (options.timelimit) &&
2097 ((starttime + options.timelimit) <= time(NULL))) {
2098 state = 3;
2099 }
jjako7b8fad42003-07-07 14:37:42 +00002100
Harald Weltebed35df2011-11-02 13:06:18 +01002101 /* Take down client after ping timeout */
2102 if ((2 == state) && (pingtimeout)
2103 && (pingtimeout <= time(NULL))) {
2104 state = 3;
2105 }
jjako7b8fad42003-07-07 14:37:42 +00002106
Harald Weltebed35df2011-11-02 13:06:18 +01002107 /* Set pingtimeout for later disconnection */
2108 if (options.pingcount && ntransmitted >= options.pingcount) {
2109 pingtimeout = time(NULL) + 5; /* Extra seconds */
2110 }
jjako7b8fad42003-07-07 14:37:42 +00002111
Harald Weltebed35df2011-11-02 13:06:18 +01002112 /* Print statistics if no more ping packets are missing */
2113 if (ntransmitted && options.pingcount
2114 && nreceived >= options.pingcount) {
2115 ping_finish();
2116 if (!options.createif)
2117 state = 3;
2118 }
jjako7b8fad42003-07-07 14:37:42 +00002119
Harald Weltebed35df2011-11-02 13:06:18 +01002120 /* Send off disconnect */
2121 if (3 == state) {
2122 state = 4;
2123 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
2124 for (n = 0; n < options.contexts; n++) {
2125 /* Delete context */
2126 printf("Disconnecting PDP context #%d\n", n);
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002127 gtp_delete_context_req2(gsn, ctx_arr[n].pdp, NULL, 1);
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002128 if ((options.pinghost.len)
Harald Weltebed35df2011-11-02 13:06:18 +01002129 && ntransmitted)
2130 ping_finish();
2131 }
2132 }
jjako7b8fad42003-07-07 14:37:42 +00002133
Harald Weltebed35df2011-11-02 13:06:18 +01002134 /* Send of ping packets */
2135 diff = 0;
2136 while ((diff <= 0) &&
2137 /* Send off an ICMP ping packet */
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002138 /*if ( */ (options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01002139 ((pingseq < options.pingcount)
2140 || (options.pingcount == 0))) {
2141 if (!pingseq)
2142 gettimeofday(&firstping, &tz); /* Set time of first ping */
2143 gettimeofday(&tv, &tz);
2144 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
2145 if (diff <= 0) {
2146 if (options.debug)
2147 printf("Create_ping %d\n", diff);
2148 create_ping(gsn,
Pau Espin Pedrol04715d22020-04-15 19:44:01 +02002149 ctx_arr[pingseq %
Harald Weltebed35df2011-11-02 13:06:18 +01002150 options.contexts].pdp,
2151 &options.pinghost, pingseq,
2152 options.pingsize);
2153 pingseq++;
2154 }
2155 }
jjako5da68452003-01-28 16:08:47 +00002156
Harald Weltebed35df2011-11-02 13:06:18 +01002157 FD_ZERO(&fds);
2158 if (tun)
2159 FD_SET(tun->fd, &fds);
2160 FD_SET(gsn->fd0, &fds);
2161 FD_SET(gsn->fd1c, &fds);
2162 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00002163
Pau Espin Pedrol1bf41e42019-08-28 19:44:54 +02002164 idleTime.tv_sec = 10;
2165 idleTime.tv_usec = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002166 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00002167
Harald Weltebed35df2011-11-02 13:06:18 +01002168 if (options.debug)
2169 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
2170 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00002171
bjovana8f71eb2017-02-24 17:39:20 +01002172 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002173 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
2174 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01002175 if (errno == EINTR)
2176 signal_received = 1;
2177 else
2178 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2179 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01002180 break;
Harald Weltebed35df2011-11-02 13:06:18 +01002181 default:
2182 break;
2183 }
2184
bjovana8f71eb2017-02-24 17:39:20 +01002185 if (!signal_received) {
2186
2187 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
2188 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2189 "TUN decaps failed");
2190 }
2191
2192 if (FD_ISSET(gsn->fd0, &fds))
2193 gtp_decaps0(gsn);
2194
2195 if (FD_ISSET(gsn->fd1c, &fds))
2196 gtp_decaps1c(gsn);
2197
2198 if (FD_ISSET(gsn->fd1u, &fds))
2199 gtp_decaps1u(gsn);
2200
Harald Weltebed35df2011-11-02 13:06:18 +01002201 }
Harald Weltebed35df2011-11-02 13:06:18 +01002202 }
2203
2204 gtp_free(gsn); /* Clean up the gsn instance */
2205
2206 if (options.createif)
2207 tun_free(tun);
2208
2209 if (0 == state)
2210 exit(1); /* Indicate error */
2211
2212 return 0;
jjako52c24142002-12-16 13:33:51 +00002213}