blob: 22be2fe1357515918f01a6408af81e3f562a75a3 [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
jjako52c24142002-12-16 13:33:51 +000018#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010019#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000020#endif
21
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010022#include <osmocom/core/application.h>
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020023#include <osmocom/core/msgb.h>
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010024
jjako52c24142002-12-16 13:33:51 +000025#include <ctype.h>
26#include <netdb.h>
27#include <signal.h>
28#include <stdio.h>
29#include <string.h>
30#include <stdlib.h>
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020034#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080035#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000036#include <arpa/inet.h>
37#include <sys/wait.h>
38#include <sys/stat.h>
39#include <unistd.h>
40#include <sys/socket.h>
41#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000042#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000043#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000044#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000045#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000046#include <resolv.h>
47#include <time.h>
48
jjakoff9985c2004-01-16 11:05:22 +000049#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020050#include "../lib/tun.h"
51#include "../lib/ippool.h"
52#include "../lib/syserr.h"
Andreas Schultzb6292402018-10-05 13:58:45 +010053#include "../lib/netns.h"
jjako52c24142002-12-16 13:33:51 +000054#include "../gtp/pdp.h"
55#include "../gtp/gtp.h"
56#include "cmdline.h"
57
Harald Weltebed35df2011-11-02 13:06:18 +010058#define IPADDRLEN 256 /* Character length of addresses */
59#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000060
jjakoa7cd2492003-04-11 09:40:12 +000061/* HASH tables for IP address allocation */
62struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010063 uint8_t inuse; /* 0=free. 1=used by somebody */
64 struct iphash_t *ipnext;
65 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020066 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000067};
68struct iphash_t iparr[MAXCONTEXTS];
69struct iphash_t *iphash[MAXCONTEXTS];
70
71/* State variable used for ping */
72/* 0: Idle */
73/* 1: Wait_connect */
74/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000075/* 3: Done */
76/* 4: Wait_disconnect */
77/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010078volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000079
Harald Weltebed35df2011-11-02 13:06:18 +010080struct gsn_t *gsn = NULL; /* GSN instance */
81struct tun_t *tun = NULL; /* TUN instance */
82int maxfd = 0; /* For select() */
83int echoversion = 1; /* First try this version */
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020084void *tall_sgsnemu_ctx; /* root talloc ctx */
Andreas Schultzb6292402018-10-05 13:58:45 +010085#if defined(__linux__)
86int netns = -1; /* network namespace */
87#endif
jjako52c24142002-12-16 13:33:51 +000088
jjakoa7cd2492003-04-11 09:40:12 +000089/* Struct with local versions of gengetopt options */
90struct {
Harald Weltebed35df2011-11-02 13:06:18 +010091 int debug; /* Print debug messages */
92 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +080093 char *tun_dev_name;
Andreas Schultzb6292402018-10-05 13:58:45 +010094 char *netns;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +010095 struct in46_addr netaddr, destaddr, net; /* Network interface */
Harald Welted12eab92017-08-02 19:49:47 +020096 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010097 char *ipup, *ipdown; /* Filename of scripts */
98 int defaultroute; /* Set up default route */
99 struct in_addr pinghost; /* Remote ping host */
100 int pingrate;
101 int pingsize;
102 int pingcount;
103 int pingquiet;
104 struct in_addr listen;
105 struct in_addr remote;
106 struct in_addr dns;
107 int contexts; /* Number of contexts to create */
108 int timelimit; /* Number of seconds to be connected */
109 char *statedir;
110 uint64_t imsi;
111 uint8_t nsapi;
112 int gtpversion;
113 struct ul255_t pco;
114 struct ul255_t qos;
115 uint16_t cch;
116 struct ul255_t apn;
117 uint8_t selmode;
118 struct ul255_t rattype;
119 int rattype_given;
120 struct ul255_t userloc;
121 int userloc_given;
122 struct ul255_t rai;
123 int rai_given;
124 struct ul255_t mstz;
125 int mstz_given;
126 struct ul255_t imeisv;
127 int imeisv_given;
128 struct ul16_t msisdn;
129 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800130 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800131 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000132} options;
jjako52c24142002-12-16 13:33:51 +0000133
jjako5da68452003-01-28 16:08:47 +0000134/* Definitions to use for PING. Most of the ping code was derived from */
135/* the original ping program by Mike Muuss */
136
137/* IP header and ICMP echo header */
138#define CREATEPING_MAX 2048
139#define CREATEPING_IP 20
140#define CREATEPING_ICMP 8
141
142struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100143 uint8_t ipver; /* Type and header length */
144 uint8_t tos; /* Type of Service */
145 uint16_t length; /* Total length */
146 uint16_t fragid; /* Identifier */
147 uint16_t offset; /* Flags and fragment offset */
148 uint8_t ttl; /* Time to live */
149 uint8_t protocol; /* Protocol */
150 uint16_t ipcheck; /* Header checksum */
151 uint32_t src; /* Source address */
152 uint32_t dst; /* Destination */
153 uint8_t type; /* Type and header length */
154 uint8_t code; /* Code */
155 uint16_t checksum; /* Header checksum */
156 uint16_t ident; /* Identifier */
157 uint16_t seq; /* Sequence number */
158 uint8_t data[CREATEPING_MAX]; /* Data */
159} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000160
161/* Statistical values for ping */
162int nreceived = 0;
163int ntreceived = 0;
164int ntransmitted = 0;
165int tmin = 999999999;
166int tmax = 0;
167int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100168int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000169struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000170
Harald Weltefed33892017-10-10 09:02:45 +0800171static void signal_handler(int signo)
bjovana8f71eb2017-02-24 17:39:20 +0100172{
173 if (state == 2)
174 state = 3; /* Tell main loop to finish. */
175}
176
Harald Weltefed33892017-10-10 09:02:45 +0800177static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100178{
Harald Welted12eab92017-08-02 19:49:47 +0200179 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100180 struct iphash_t *h;
181 struct iphash_t *prev = NULL;
182 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200183 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100184 for (h = iphash[hash]; h; h = h->ipnext)
185 prev = h;
186 if (!prev)
187 iphash[hash] = ipaddr;
188 else
189 prev->ipnext = ipaddr;
190 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000191}
192
Harald Weltefed33892017-10-10 09:02:45 +0800193static int ipdel(struct iphash_t *ipaddr)
Harald Weltebed35df2011-11-02 13:06:18 +0100194{
Harald Welted12eab92017-08-02 19:49:47 +0200195 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100196 struct iphash_t *h;
197 struct iphash_t *prev = NULL;
198 for (h = iphash[hash]; h; h = h->ipnext) {
199 if (h == ipaddr) {
200 if (!prev)
201 iphash[hash] = h->ipnext;
202 else
203 prev->ipnext = h->ipnext;
204 return 0;
205 }
206 prev = h;
207 }
208 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000209}
210
Harald Weltefed33892017-10-10 09:02:45 +0800211static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100212{
Harald Welted12eab92017-08-02 19:49:47 +0200213 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100214 struct iphash_t *h;
215 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200216 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100217 *ipaddr = h;
218 return 0;
219 }
220 }
221 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000222}
223
jjakoa7cd2492003-04-11 09:40:12 +0000224/* Used to write process ID to file. Assume someone else will delete */
Harald Weltefed33892017-10-10 09:02:45 +0800225static void log_pid(char *pidfile)
Harald Weltebed35df2011-11-02 13:06:18 +0100226{
227 FILE *file;
228 mode_t oldmask;
229
230 oldmask = umask(022);
231 file = fopen(pidfile, "w");
232 umask(oldmask);
233 if (!file)
234 return;
235 fprintf(file, "%d\n", (int)getpid());
236 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000237}
238
Harald Weltefed33892017-10-10 09:02:45 +0800239static int process_options(int argc, char **argv)
Harald Weltebed35df2011-11-02 13:06:18 +0100240{
241 /* gengeopt declarations */
242 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000243
Harald Weltebed35df2011-11-02 13:06:18 +0100244 struct hostent *host;
245 unsigned int n;
246 uint16_t i;
247 uint8_t a;
248 uint8_t b;
249 char *tmp;
250 char *pch;
251 char *type;
252 char *mcc;
253 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100254 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100255 char *lac;
256 int lac_d;
257 char *rest;
258 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
259 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
260 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
261 int sign;
262 int nbquarters;
263 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000264
Harald Weltebed35df2011-11-02 13:06:18 +0100265 if (cmdline_parser(argc, argv, &args_info) != 0)
266 return -1;
267 if (args_info.debug_flag) {
268 if (args_info.remote_arg)
269 printf("remote: %s\n", args_info.remote_arg);
270 if (args_info.listen_arg)
271 printf("listen: %s\n", args_info.listen_arg);
272 if (args_info.conf_arg)
273 printf("conf: %s\n", args_info.conf_arg);
274 printf("debug: %d\n", args_info.debug_flag);
275 if (args_info.imsi_arg)
276 printf("imsi: %s\n", args_info.imsi_arg);
277 printf("qos: %#08x\n", args_info.qos_arg);
278 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
279 printf("qose2: %#04x\n", args_info.qose2_arg);
280 printf("qose3: %#06x\n", args_info.qose3_arg);
281 printf("qose4: %#06x\n", args_info.qose4_arg);
282 printf("charging: %#04x\n", args_info.charging_arg);
283 if (args_info.apn_arg)
284 printf("apn: %s\n", args_info.apn_arg);
285 if (args_info.msisdn_arg)
286 printf("msisdn: %s\n", args_info.msisdn_arg);
287 if (args_info.uid_arg)
288 printf("uid: %s\n", args_info.uid_arg);
289 if (args_info.pwd_arg)
290 printf("pwd: %s\n", args_info.pwd_arg);
291 if (args_info.pidfile_arg)
292 printf("pidfile: %s\n", args_info.pidfile_arg);
293 if (args_info.statedir_arg)
294 printf("statedir: %s\n", args_info.statedir_arg);
295 if (args_info.dns_arg)
296 printf("dns: %s\n", args_info.dns_arg);
297 printf("contexts: %d\n", args_info.contexts_arg);
298 printf("timelimit: %d\n", args_info.timelimit_arg);
299 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800300 if (args_info.tun_device_arg)
Harald Welte7b9230a2018-10-21 13:09:21 +0200301 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100302 if (args_info.netns_arg)
303 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100304 if (args_info.ipup_arg)
305 printf("ipup: %s\n", args_info.ipup_arg);
306 if (args_info.ipdown_arg)
307 printf("ipdown: %s\n", args_info.ipdown_arg);
308 printf("defaultroute: %d\n", args_info.defaultroute_flag);
309 if (args_info.pinghost_arg)
310 printf("pinghost: %s\n", args_info.pinghost_arg);
311 printf("pingrate: %d\n", args_info.pingrate_arg);
312 printf("pingsize: %d\n", args_info.pingsize_arg);
313 printf("pingcount: %d\n", args_info.pingcount_arg);
314 printf("pingquiet: %d\n", args_info.pingquiet_flag);
315 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800316 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100317 }
jjakoa7cd2492003-04-11 09:40:12 +0000318
Harald Weltebed35df2011-11-02 13:06:18 +0100319 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000320
Harald Weltebed35df2011-11-02 13:06:18 +0100321 if (args_info.conf_arg) {
322 if (cmdline_parser_configfile
323 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
324 return -1;
325 if (args_info.debug_flag) {
326 printf("cmdline_parser_configfile\n");
327 if (args_info.remote_arg)
328 printf("remote: %s\n", args_info.remote_arg);
329 if (args_info.listen_arg)
330 printf("listen: %s\n", args_info.listen_arg);
331 if (args_info.conf_arg)
332 printf("conf: %s\n", args_info.conf_arg);
333 printf("debug: %d\n", args_info.debug_flag);
334 if (args_info.imsi_arg)
335 printf("imsi: %s\n", args_info.imsi_arg);
336 printf("qos: %#08x\n", args_info.qos_arg);
337 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
338 printf("qose2: %#04x\n", args_info.qose2_arg);
339 printf("qose3: %#06x\n", args_info.qose3_arg);
340 printf("qose4: %#06x\n", args_info.qose4_arg);
341 printf("charging: %#04x\n", args_info.charging_arg);
342 if (args_info.apn_arg)
343 printf("apn: %s\n", args_info.apn_arg);
344 if (args_info.msisdn_arg)
345 printf("msisdn: %s\n", args_info.msisdn_arg);
346 if (args_info.uid_arg)
347 printf("uid: %s\n", args_info.uid_arg);
348 if (args_info.pwd_arg)
349 printf("pwd: %s\n", args_info.pwd_arg);
350 if (args_info.pidfile_arg)
351 printf("pidfile: %s\n", args_info.pidfile_arg);
352 if (args_info.statedir_arg)
353 printf("statedir: %s\n",
354 args_info.statedir_arg);
355 if (args_info.dns_arg)
356 printf("dns: %s\n", args_info.dns_arg);
357 printf("contexts: %d\n", args_info.contexts_arg);
358 printf("timelimit: %d\n", args_info.timelimit_arg);
359 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800360 if (args_info.tun_device_arg)
Harald Welte9c332102017-11-06 02:44:42 +0900361 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100362 if (args_info.netns_arg)
363 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100364 if (args_info.ipup_arg)
365 printf("ipup: %s\n", args_info.ipup_arg);
366 if (args_info.ipdown_arg)
367 printf("ipdown: %s\n", args_info.ipdown_arg);
368 printf("defaultroute: %d\n",
369 args_info.defaultroute_flag);
370 if (args_info.pinghost_arg)
371 printf("pinghost: %s\n",
372 args_info.pinghost_arg);
373 printf("pingrate: %d\n", args_info.pingrate_arg);
374 printf("pingsize: %d\n", args_info.pingsize_arg);
375 printf("pingcount: %d\n", args_info.pingcount_arg);
376 printf("pingquiet: %d\n", args_info.pingquiet_flag);
377 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800378 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100379 }
380 }
jjako193e8b12003-11-10 12:31:41 +0000381
Harald Weltebed35df2011-11-02 13:06:18 +0100382 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000383
Harald Weltebed35df2011-11-02 13:06:18 +0100384 /* foreground */
385 /* If fg flag not given run as a daemon */
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100386 /* Do not allow sgsnemu to run as deamon
Harald Weltebed35df2011-11-02 13:06:18 +0100387 if (!args_info.fg_flag)
388 {
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100389 closelog();
Harald Weltebed35df2011-11-02 13:06:18 +0100390 freopen("/dev/null", "w", stdout);
391 freopen("/dev/null", "w", stderr);
392 freopen("/dev/null", "r", stdin);
393 daemon(0, 0);
394 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
395 } */
jjako1a51df72004-07-20 08:30:21 +0000396
Harald Weltebed35df2011-11-02 13:06:18 +0100397 /* debug */
398 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000399
Harald Weltebed35df2011-11-02 13:06:18 +0100400 /* pidfile */
401 /* This has to be done after we have our final pid */
402 if (args_info.pidfile_arg) {
403 log_pid(args_info.pidfile_arg);
404 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200405
Harald Weltebed35df2011-11-02 13:06:18 +0100406 /* dns */
407 /* If no dns option is given use system default */
408 /* Do hostname lookup to translate hostname to IP address */
409 printf("\n");
410 if (args_info.dns_arg) {
411 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100412 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100413 "Invalid DNS address: %s!", args_info.dns_arg);
414 return -1;
415 } else {
416 memcpy(&options.dns.s_addr, host->h_addr,
417 host->h_length);
418 _res.nscount = 1;
419 _res.nsaddr_list[0].sin_addr = options.dns;
420 printf("Using DNS server: %s (%s)\n",
421 args_info.dns_arg, inet_ntoa(options.dns));
422 }
423 } else {
424 options.dns.s_addr = 0;
425 printf("Using default DNS server\n");
426 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200427
Harald Weltebed35df2011-11-02 13:06:18 +0100428 /* listen */
429 /* If no listen option is specified listen to any local port */
430 /* Do hostname lookup to translate hostname to IP address */
431 if (args_info.listen_arg) {
432 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100433 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100434 "Invalid listening address: %s!",
435 args_info.listen_arg);
436 return -1;
437 } else {
438 memcpy(&options.listen.s_addr, host->h_addr,
439 host->h_length);
440 printf("Local IP address is: %s (%s)\n",
441 args_info.listen_arg, inet_ntoa(options.listen));
442 }
443 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100444 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltefdf33582019-12-01 09:25:27 +0100445 "Listening address must be specified!");
Harald Weltebed35df2011-11-02 13:06:18 +0100446 return -1;
447 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200448
Harald Weltebed35df2011-11-02 13:06:18 +0100449 /* remote */
450 /* If no remote option is specified terminate */
451 /* Do hostname lookup to translate hostname to IP address */
452 if (args_info.remote_arg) {
453 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100454 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100455 "Invalid remote address: %s!",
456 args_info.remote_arg);
457 return -1;
458 } else {
459 memcpy(&options.remote.s_addr, host->h_addr,
460 host->h_length);
461 printf("Remote IP address is: %s (%s)\n",
462 args_info.remote_arg, inet_ntoa(options.remote));
463 }
464 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100465 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100466 "No remote address given!");
467 return -1;
468 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200469
Harald Weltebed35df2011-11-02 13:06:18 +0100470 /* imsi */
471 if (strlen(args_info.imsi_arg) != 15) {
472 printf("Invalid IMSI\n");
473 return -1;
474 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200475
Harald Weltebed35df2011-11-02 13:06:18 +0100476 options.imsi = 0xf000000000000000ull;
477 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
478 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
479 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
480 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
481 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
482 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
483 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
484 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
485 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
486 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
487 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
488 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
489 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
490 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
491 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200492
Harald Weltebed35df2011-11-02 13:06:18 +0100493 printf("IMSI is: %s (%#08llx)\n",
494 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200495
Harald Weltebed35df2011-11-02 13:06:18 +0100496 /* nsapi */
497 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
498 printf("Invalid NSAPI\n");
499 return -1;
500 }
501 options.nsapi = args_info.nsapi_arg;
502 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200503
Harald Weltebed35df2011-11-02 13:06:18 +0100504 /* qos */
505 options.qos.l = 4;
506 options.qos.v[3] = (args_info.qos_arg) & 0xff;
507 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
508 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
509 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
510 /* Extensions according to 3GPP TS 24.008 */
511 if (args_info.qose1_given == 1) {
512 options.qos.l = 12;
513 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
514 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
515 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
516 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
517 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
518 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
519 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
520 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
521 if (args_info.qose2_given == 1) {
522 options.qos.l = 13;
523 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
524 if (args_info.qose3_given == 1) {
525 options.qos.l = 15;
526 options.qos.v[14] =
527 (args_info.qose3_arg) & 0xff;
528 options.qos.v[13] =
529 ((args_info.qose3_arg) >> 8) & 0xff;
530 if (args_info.qose4_given == 1) {
531 options.qos.l = 17;
532 options.qos.v[16] =
533 (args_info.qose4_arg) & 0xff;
534 options.qos.v[15] =
535 ((args_info.qose4_arg) >> 8) & 0xff;
536 }
537 }
538 }
539 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200540
Harald Weltebed35df2011-11-02 13:06:18 +0100541 /* charging */
542 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 /* contexts */
545 if (args_info.contexts_arg > MAXCONTEXTS) {
546 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
547 return -1;
548 }
549 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200550
Harald Weltebed35df2011-11-02 13:06:18 +0100551 /* Timelimit */
552 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200553
Harald Weltebed35df2011-11-02 13:06:18 +0100554 /* gtpversion */
555 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
556 printf("Invalid GTP version\n");
557 return -1;
558 }
559 options.gtpversion = args_info.gtpversion_arg;
560 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200561
Harald Weltebed35df2011-11-02 13:06:18 +0100562 /* apn */
563 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
564 printf("Invalid APN\n");
565 return -1;
566 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100567 options.apn.l = strlen(args_info.apn_arg) + 1;
568
569 apn = (char *)options.apn.v;
570 for (tok = strtok(args_info.apn_arg, ".");
571 tok != NULL;
572 tok = strtok(NULL, ".")) {
573 size_t len = strlen(tok);
574
575 *apn++ = (char)len;
576 strncpy(apn, tok, len);
577 apn += len;
578 }
579
Harald Weltebed35df2011-11-02 13:06:18 +0100580 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200581
Harald Weltebed35df2011-11-02 13:06:18 +0100582 /* selmode */
583 options.selmode = args_info.selmode_arg;
584 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200585
Harald Weltebed35df2011-11-02 13:06:18 +0100586 /* rattype */
587 if (args_info.rattype_given == 1) {
588 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800589 options.rattype.l = 1;
590 options.rattype.v[0] = args_info.rattype_arg;
591 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100592 }
Harald Welte41af5692011-10-07 18:42:34 +0200593
Harald Weltebed35df2011-11-02 13:06:18 +0100594 /* userloc */
595 if (args_info.userloc_given == 1) {
596 printf("Using User Location Information: %s\n",
597 args_info.userloc_arg);
598 tmp = args_info.userloc_arg;
599 n = 0;
600 pch = strtok(tmp, ".");
601 while (pch != NULL) {
602 userloc_el[n] = pch;
603 pch = strtok(NULL, ".");
604 n++;
605 }
Harald Welte41af5692011-10-07 18:42:34 +0200606
Harald Weltebed35df2011-11-02 13:06:18 +0100607 options.userloc_given = 1;
608 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 /* 3GPP Geographic Location Type t0 / t1 / t2 */
611 type = userloc_el[0];
612 printf("->type : %c\n", type[0]);
613 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
614 printf("Invalid type \n");
615 return -1;
616 }
617 /* options.userloc.v[0] = 0x00 */
618 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200619
Harald Weltebed35df2011-11-02 13:06:18 +0100620 /* MCC */
621 mcc = userloc_el[1];
622 printf("->mcc : %s\n", mcc);
623 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200624 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100625 return -1;
626 }
Harald Welte41af5692011-10-07 18:42:34 +0200627
Harald Weltebed35df2011-11-02 13:06:18 +0100628 /* MNC */
629 mnc = userloc_el[2];
630 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200631
Harald Weltebed35df2011-11-02 13:06:18 +0100632 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
633 /* options.userloc.v[1] = 0x52 */
634 a = (uint8_t) (mcc[0] - 48);
635 b = (uint8_t) (mcc[1] - 48);
636 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200637
Harald Weltebed35df2011-11-02 13:06:18 +0100638 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
639 /* options.userloc.v[2] = 0xf0 */
640 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200641
Harald Weltebed35df2011-11-02 13:06:18 +0100642 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200643 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100644 return -1;
645 }
646 if (strlen(mnc) == 2) {
647 b = 15;
648 }
649 if (strlen(mnc) == 3) {
650 b = (uint8_t) (mnc[2] - 48);
651 }
652 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200653
Harald Weltebed35df2011-11-02 13:06:18 +0100654 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
655 /* options.userloc.v[3] = 0x99 */
656 a = (uint8_t) (mnc[0] - 48);
657 b = (uint8_t) (mnc[1] - 48);
658 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200659
Harald Weltebed35df2011-11-02 13:06:18 +0100660 /* LAC */
661 lac = userloc_el[3];
662 /*options.userloc.v[4] = 0x12 ; */
663 /*options.userloc.v[5] = 0x10 ; */
664 printf("->LAC: %s\n", lac);
665 lac_d = atoi(lac);
666 if (lac_d > 65535 || lac_d < 1) {
667 printf("Invalid LAC\n");
668 return -1;
669 }
670 i = lac_d >> 8;
671 options.userloc.v[4] = i; /* octet 8 - LAC */
672 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200673
Harald Weltebed35df2011-11-02 13:06:18 +0100674 /* CI/SAC/RAC */
675 rest = userloc_el[4];
676 printf("->CI/SAC/RAC : %s\n", rest);
677 lac_d = atoi(rest);
678 if (lac_d > 65535 || lac_d < 1) {
679 printf("Invalid CI/SAC/RAC\n");
680 return -1;
681 }
682 /*options.userloc.v[6] = 0x04 ; */
683 /*options.userloc.v[7] = 0xb7 ; */
684 i = lac_d >> 8;
685 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
686 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
687 }
jjakoa7cd2492003-04-11 09:40:12 +0000688
Harald Weltebed35df2011-11-02 13:06:18 +0100689 /* RAI */
690 if (args_info.rai_given == 1) {
691 printf("Using RAI: %s\n", args_info.rai_arg);
692 tmp = args_info.rai_arg;
693 n = 0;
694 pch = strtok(tmp, ".");
695 while (pch != NULL) {
696 rai_el[n] = pch;
697 pch = strtok(NULL, ".");
698 n++;
699 }
jjakoa7cd2492003-04-11 09:40:12 +0000700
Harald Weltebed35df2011-11-02 13:06:18 +0100701 options.rai_given = 1;
702 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000703
Harald Weltebed35df2011-11-02 13:06:18 +0100704 /* MCC */
705 mcc = rai_el[0];
706 printf("->mcc : %s\n", mcc);
707 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200708 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100709 return -1;
710 }
711
712 /* MNC */
713 mnc = rai_el[1];
714 printf("->mnc : %s\n", mnc);
715
716 a = (uint8_t) (mcc[0] - 48);
717 b = (uint8_t) (mcc[1] - 48);
718 options.rai.v[0] = 16 * b + a;
719
720 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
721 a = (uint8_t) (mcc[2] - 48);
722
723 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200724 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100725 return -1;
726 }
727 if (strlen(mnc) == 2) {
728 b = 15;
729 }
730 if (strlen(mnc) == 3) {
731 b = (uint8_t) (mnc[2] - 48);
732 }
733 options.rai.v[1] = 16 * b + a;
734
735 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
736 a = (uint8_t) (mnc[0] - 48);
737 b = (uint8_t) (mnc[1] - 48);
738 options.rai.v[2] = 16 * b + a;
739
740 /* LAC */
741 lac = rai_el[2];
742 printf("->LAC: %s\n", lac);
743 lac_d = atoi(lac);
744 if (lac_d > 65535 || lac_d < 1) {
745 printf("Invalid LAC\n");
746 return -1;
747 }
748 i = lac_d >> 8;
749 options.rai.v[3] = i; /* octet 5 - LAC */
750 options.rai.v[4] = lac_d; /* octet 6 - LAC */
751
752 /* RAC */
753 rest = rai_el[3];
754 printf("->RAC : %s\n", rest);
755 lac_d = atoi(rest);
756 if (lac_d > 255 || lac_d < 1) {
757 printf("Invalid RAC\n");
758 return -1;
759 }
760 options.rai.v[5] = lac_d; /* octet 7 - RAC */
761 }
762
763 /* mstz */
764 if (args_info.mstz_given == 1) {
765 options.mstz_given = 1;
766 options.mstz.l = 2;
767
768 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
769 tmp = args_info.mstz_arg;
770 n = 0;
771 pch = strtok(tmp, ".");
772 while (pch != NULL) {
773 mstz_el[n] = pch;
774 pch = strtok(NULL, ".");
775 n++;
776 }
777
778 /* sign */
779 sign = atoi(mstz_el[0]);
780 printf("->Sign (0=+ / 1=-): %d\n", sign);
781 if (sign != 0 && sign != 1) {
782 printf("Invalid Sign \n");
783 return -1;
784 }
785 /* nbquarters */
786 nbquarters = atoi(mstz_el[1]);
787 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
788 if (nbquarters < 0 || nbquarters > 79) {
789 printf("Invalid Number of Quarters \n");
790 return -1;
791 }
792 /* DST */
793 DST = atoi(mstz_el[2]);
794 printf("->Daylight Saving Time Adjustment : %d\n", DST);
795 if (DST < 0 || DST > 3) {
796 printf("Invalid DST Adjustment \n");
797 return -1;
798 }
799 /* 12345678
800 bits 123 = unit of # of quarters of an hour
801 bits 678 = # of quarters of an hour / 10
802 bit 5 = sign
803 */
804 i = nbquarters % 10;
805 i = i << 4;
806 i = i + nbquarters / 10 + 8 * sign;
807 /* options.mstz.v[0] = 0x69 ; */
808 /* options.mstz.v[1] = 0x01 ; */
809 options.mstz.v[0] = i;
810 options.mstz.v[1] = DST;
811 n = (i & 0x08) ? '-' : '+';
812 printf
813 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
814 n, nbquarters / 4, nbquarters % 4 * 15);
815 }
816
817 /* imeisv */
818 if (args_info.imeisv_given == 1) {
819 options.imeisv_given = 1;
820 if (strlen(args_info.imeisv_arg) != 16) {
821 printf("Invalid IMEI(SV)\n");
822 return -1;
823 }
824 options.imeisv.l = 8;
825 for (n = 0; n < 8; n++) {
826 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
827 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
828 options.imeisv.v[n] = 16 * b + a;
829 }
830 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
831 }
832
833 /* msisdn */
834 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
835 printf("Invalid MSISDN\n");
836 return -1;
837 }
838 options.msisdn.l = 1;
839 options.msisdn.v[0] = 0x91; /* International format */
840 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
841 if ((n % 2) == 0) {
842 options.msisdn.v[((int)n / 2) + 1] =
843 args_info.msisdn_arg[n] - 48 + 0xf0;
844 options.msisdn.l += 1;
845 } else {
846 options.msisdn.v[((int)n / 2) + 1] =
847 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
848 (args_info.msisdn_arg[n] - 48) * 16;
849 }
850 }
851 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
852
853 /* UID and PWD */
854 /* Might need to also insert stuff like DNS etc. */
855 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
856 (sizeof(options.pco.v) - 1)) {
857 printf("invalid UID and PWD\n");
858 return -1;
859 }
860 options.pco.l =
861 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
862 options.pco.v[0] = 0x80; /* PPP */
863 options.pco.v[1] = 0xc0; /* PAP */
864 options.pco.v[2] = 0x23;
865 options.pco.v[3] =
866 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
867 options.pco.v[4] = 0x01; /* Authenticate request */
868 options.pco.v[5] = 0x01;
869 options.pco.v[6] = 0x00; /* MSB of length */
870 options.pco.v[7] =
871 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
872 options.pco.v[8] = strlen(args_info.uid_arg);
873 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
874 options.pco.v[9 + strlen(args_info.uid_arg)] =
875 strlen(args_info.pwd_arg);
876 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
877 args_info.pwd_arg, strlen(args_info.pwd_arg));
878
879 /* createif */
880 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800881 options.tun_dev_name = args_info.tun_device_arg;
Andreas Schultzb6292402018-10-05 13:58:45 +0100882 options.netns = args_info.netns_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100883
884 /* net */
885 /* Store net as in_addr net and mask */
886 if (args_info.net_arg) {
887 if (ippool_aton
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100888 (&options.net, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100889 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100890 "Invalid network address: %s!",
891 args_info.net_arg);
892 exit(1);
893 }
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100894 options.netaddr = options.net;
895 options.destaddr = options.net;
jjakoc6762cf2004-04-28 14:52:58 +0000896
Harald Weltebed35df2011-11-02 13:06:18 +0100897 } else {
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100898 memset(&options.net, 0, sizeof(options.net));
Harald Welted12eab92017-08-02 19:49:47 +0200899 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100900 memset(&options.netaddr, 0, sizeof(options.netaddr));
901 memset(&options.destaddr, 0, sizeof(options.destaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100902 }
jjako193e8b12003-11-10 12:31:41 +0000903
Harald Weltebed35df2011-11-02 13:06:18 +0100904 /* ipup */
905 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000906
Harald Weltebed35df2011-11-02 13:06:18 +0100907 /* ipdown */
908 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000909
Harald Weltebed35df2011-11-02 13:06:18 +0100910 /* statedir */
911 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000912
Harald Weltebed35df2011-11-02 13:06:18 +0100913 /* defaultroute */
914 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000915
Harald Weltebed35df2011-11-02 13:06:18 +0100916 /* pinghost */
917 /* Store ping host as in_addr */
918 if (args_info.pinghost_arg) {
919 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100920 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100921 "Invalid ping host: %s!",
922 args_info.pinghost_arg);
923 return -1;
924 } else {
925 memcpy(&options.pinghost.s_addr, host->h_addr,
926 host->h_length);
927 printf("Using ping host: %s (%s)\n",
928 args_info.pinghost_arg,
929 inet_ntoa(options.pinghost));
930 }
931 }
jjakoa7cd2492003-04-11 09:40:12 +0000932
Harald Weltebed35df2011-11-02 13:06:18 +0100933 /* Other ping parameters */
934 options.pingrate = args_info.pingrate_arg;
935 options.pingsize = args_info.pingsize_arg;
936 options.pingcount = args_info.pingcount_arg;
937 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000938
Harald Weltebed35df2011-11-02 13:06:18 +0100939 /* norecovery */
940 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000941
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800942 if (args_info.no_tx_gpdu_seq_flag)
943 options.tx_gpdu_seq = 0;
944 else
945 options.tx_gpdu_seq = 1;
946
Harald Welte840a8e92017-09-24 18:12:40 +0800947 /* PDP Type */
948 if (!strcmp(args_info.pdp_type_arg, "v6"))
949 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800950 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800951 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800952 else {
953 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
954 args_info.pdp_type_arg);
955 return -1;
956 }
957
958 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
959 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
960 return -1;
961 }
Harald Welte840a8e92017-09-24 18:12:40 +0800962
Harald Weltebed35df2011-11-02 13:06:18 +0100963 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000964
965}
966
Harald Welte081f30c2017-10-10 09:36:35 +0800967/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
968static char *proc_read(const char *path)
969{
970 char *ret = NULL;
971 FILE *f;
972
973 f = fopen(path, "r");
974 if (!f)
975 return NULL;
976
977 ret = malloc(256);
978 if (!ret)
979 goto out;
980
981 if (!fgets(ret, 256, f)) {
982 free(ret);
983 ret = NULL;
984 goto out;
985 }
Harald Welte081f30c2017-10-10 09:36:35 +0800986
987out:
988 fclose(f);
989 return ret;
990}
991
992/* Read value of a /proc/sys/net/ipv6/conf file for given device.
993 * Memory is dynamically allocated, caller must free it later. */
994static char *proc_ipv6_conf_read(const char *dev, const char *file)
995{
996 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
Harald Welteb11ed0f2017-11-06 03:07:26 +0900997 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
Harald Welte081f30c2017-10-10 09:36:35 +0800998 snprintf(path, sizeof(path), fmt, dev, file);
999 return proc_read(path);
1000}
1001
Harald Weltefed33892017-10-10 09:02:45 +08001002static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001003{
Harald Weltee37f48e2017-10-10 09:05:50 +08001004 struct protoent *pe = getprotobynumber(t);
1005
1006 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +01001007 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +08001008 else
1009 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001010}
1011
Harald Weltefed33892017-10-10 09:02:45 +08001012static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001013{
1014 static char *ttab[] = {
1015 "Echo Reply",
1016 "ICMP 1",
1017 "ICMP 2",
1018 "Dest Unreachable",
1019 "Source Quench",
1020 "Redirect",
1021 "ICMP 6",
1022 "ICMP 7",
1023 "Echo",
1024 "ICMP 9",
1025 "ICMP 10",
1026 "Time Exceeded",
1027 "Parameter Problem",
1028 "Timestamp",
1029 "Timestamp Reply",
1030 "Info Request",
1031 "Info Reply"
1032 };
1033 if (t < 0 || t > 16)
1034 return ("OUT-OF-RANGE");
1035 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001036}
1037
Harald Weltefed33892017-10-10 09:02:45 +08001038static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001039{
1040 unsigned int n;
1041 uint64_t i64 = 0;
1042 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1043 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001044
Harald Weltebed35df2011-11-02 13:06:18 +01001045 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1046 /* ul16_t format always starts with 0x91 to indicate international format */
1047 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1048 for (n = 0; n < src->l; n++) {
1049 if ((src->v[n] & 0x0f) != 0x0f) {
1050 i64 *= 10;
1051 i64 += src->v[n] & 0x0f;
1052 }
1053 if ((src->v[n] & 0xf0) != 0xf0) {
1054 i64 *= 10;
1055 i64 += (src->v[n] & 0xf0) >> 4;
1056 }
1057 }
jjako193e8b12003-11-10 12:31:41 +00001058
Harald Weltebed35df2011-11-02 13:06:18 +01001059 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001060
Harald Weltebed35df2011-11-02 13:06:18 +01001061 /* Generate array with least significant digit in first octet */
1062 while (i64) {
1063 msa[msalen++] = i64 % 10;
1064 i64 = i64 / 10;
1065 }
jjako193e8b12003-11-10 12:31:41 +00001066
Harald Weltebed35df2011-11-02 13:06:18 +01001067 /* Convert back to ul16_t format */
1068 for (n = 0; n < msalen; n++) {
1069 if ((n % 2) == 0) {
1070 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1071 dst->l += 1;
1072 } else {
1073 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1074 msa[msalen - n - 1] * 16;
1075 }
1076 }
jjako193e8b12003-11-10 12:31:41 +00001077
Harald Weltebed35df2011-11-02 13:06:18 +01001078 return 0;
jjako193e8b12003-11-10 12:31:41 +00001079
1080}
1081
Harald Weltefed33892017-10-10 09:02:45 +08001082static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001083{
1084 /* TODO: big endian / small endian ??? */
1085 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001086
Harald Weltebed35df2011-11-02 13:06:18 +01001087 /* Convert from uint64_t bcd to uint64_t integer format */
1088 /* The resulting integer format is multiplied by 10 */
1089 while (src) {
1090 if ((src & 0x0f) != 0x0f) {
1091 i64 *= 10;
1092 i64 += (src & 0x0f);
1093 }
1094 if ((src & 0xf0) != 0xf0) {
1095 i64 *= 10;
1096 i64 += (src & 0xf0) >> 4;
1097 }
1098 src = src >> 8;
1099 }
jjako193e8b12003-11-10 12:31:41 +00001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001102
Harald Weltebed35df2011-11-02 13:06:18 +01001103 *dst = 0;
1104 while (i64) {
1105 *dst = *dst << 4;
1106 *dst += (i64 % 10);
1107 i64 = i64 / 10;
1108 }
jjako193e8b12003-11-10 12:31:41 +00001109
Harald Weltebed35df2011-11-02 13:06:18 +01001110 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001111
Harald Weltebed35df2011-11-02 13:06:18 +01001112 return 0;
jjako193e8b12003-11-10 12:31:41 +00001113
1114}
1115
jjakoafb2a972003-01-29 21:04:13 +00001116/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001117static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001118{
1119 struct timezone tz;
1120 struct timeval tv;
1121 int diff;
1122 if ((options.pinghost.s_addr) && (2 == state) &&
1123 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1124 gettimeofday(&tv, &tz);
1125 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1126 tp->tv_sec = 0;
1127 if (diff > 0)
1128 tp->tv_usec = diff;
1129 else {
1130 /* For some reason we get packet loss if set to zero */
1131 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1132 tp->tv_usec = 0;
1133 }
1134 }
1135 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001136}
1137
jjako5da68452003-01-28 16:08:47 +00001138/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001139static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001140{
Harald Weltebed35df2011-11-02 13:06:18 +01001141 struct timezone tz;
1142 struct timeval tv;
1143 int elapsed;
1144 gettimeofday(&tv, &tz);
1145 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1146 printf("\n");
1147 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1148 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1149 elapsed / 1000000.0);
1150 printf("%d packets received, ", nreceived);
1151 if (ntransmitted) {
1152 if (nreceived > ntransmitted)
1153 printf("-- somebody's printing up packets!");
1154 else
1155 printf("%d%% packet loss",
1156 (int)(((ntransmitted - nreceived) * 100) /
1157 ntransmitted));
1158 }
1159 printf("\n");
1160 if (options.debug)
1161 printf("%d packets received in total\n", ntreceived);
1162 if (nreceived && tsum)
1163 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1164 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1165 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001166
Harald Weltebed35df2011-11-02 13:06:18 +01001167 ntransmitted = 0;
1168 return 0;
jjako5da68452003-01-28 16:08:47 +00001169}
1170
1171/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001172static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001173{
1174 struct timezone tz;
1175 struct timeval tv;
1176 struct timeval *tp;
1177 struct ip_ping *pingpack = pack;
1178 struct in_addr src;
1179 int triptime;
jjako5da68452003-01-28 16:08:47 +00001180
Harald Weltebed35df2011-11-02 13:06:18 +01001181 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001182
Harald Weltebed35df2011-11-02 13:06:18 +01001183 gettimeofday(&tv, &tz);
1184 if (options.debug)
1185 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001186
Harald Weltebed35df2011-11-02 13:06:18 +01001187 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1188 printf("packet too short (%d bytes) from %s\n", len,
1189 inet_ntoa(src));
1190 return 0;
1191 }
jjako5da68452003-01-28 16:08:47 +00001192
Harald Weltebed35df2011-11-02 13:06:18 +01001193 ntreceived++;
1194 if (pingpack->protocol != 1) {
1195 if (!options.pingquiet)
1196 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1197 len, inet_ntoa(src), pingpack->protocol,
1198 print_ipprot(pingpack->protocol));
1199 return 0;
1200 }
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 if (pingpack->type != 0) {
1203 if (!options.pingquiet)
1204 printf
1205 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1206 len, inet_ntoa(src), pingpack->type,
1207 print_icmptype(pingpack->type), pingpack->code);
1208 return 0;
1209 }
jjako5da68452003-01-28 16:08:47 +00001210
Harald Weltebed35df2011-11-02 13:06:18 +01001211 nreceived++;
1212 if (!options.pingquiet)
1213 printf("%d bytes from %s: icmp_seq=%d", len,
1214 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001215
Harald Weltebed35df2011-11-02 13:06:18 +01001216 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1217 gettimeofday(&tv, &tz);
1218 tp = (struct timeval *)pingpack->data;
1219 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1220 tv.tv_sec--;
1221 tv.tv_usec += 1000000;
1222 }
1223 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001224
Harald Weltebed35df2011-11-02 13:06:18 +01001225 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1226 tsum += triptime;
1227 if (triptime < tmin)
1228 tmin = triptime;
1229 if (triptime > tmax)
1230 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001231
Harald Weltebed35df2011-11-02 13:06:18 +01001232 if (!options.pingquiet)
1233 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001234
Harald Weltebed35df2011-11-02 13:06:18 +01001235 } else if (!options.pingquiet)
1236 printf("\n");
1237 return 0;
jjako5da68452003-01-28 16:08:47 +00001238}
1239
1240/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001241static int create_ping(void *gsn, struct pdp_t *pdp,
1242 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001243{
jjako5da68452003-01-28 16:08:47 +00001244
Harald Weltebed35df2011-11-02 13:06:18 +01001245 struct ip_ping pack;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001246 uint16_t v16;
Harald Weltebed35df2011-11-02 13:06:18 +01001247 uint8_t *p8 = (uint8_t *) & pack;
1248 struct in_addr src;
1249 unsigned int n;
1250 long int sum = 0;
1251 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001252
Harald Weltebed35df2011-11-02 13:06:18 +01001253 struct timezone tz;
1254 struct timeval *tp =
1255 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001256
Harald Weltebed35df2011-11-02 13:06:18 +01001257 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001258 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001259 "Ping size to large: %d!", datasize);
1260 return -1;
1261 }
jjako5da68452003-01-28 16:08:47 +00001262
Harald Weltebed35df2011-11-02 13:06:18 +01001263 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001264
Harald Weltebed35df2011-11-02 13:06:18 +01001265 pack.ipver = 0x45;
1266 pack.tos = 0x00;
1267 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1268 pack.fragid = 0x0000;
1269 pack.offset = 0x0040;
1270 pack.ttl = 0x40;
1271 pack.protocol = 0x01;
1272 pack.ipcheck = 0x0000;
1273 pack.src = src.s_addr;
1274 pack.dst = dst->s_addr;
1275 pack.type = 0x08;
1276 pack.code = 0x00;
1277 pack.checksum = 0x0000;
1278 pack.ident = 0x0000;
1279 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001280
Harald Weltebed35df2011-11-02 13:06:18 +01001281 /* Generate ICMP payload */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001282 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
Harald Weltebed35df2011-11-02 13:06:18 +01001283 for (n = 0; n < (datasize); n++)
1284 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001285
Harald Weltebed35df2011-11-02 13:06:18 +01001286 if (datasize >= sizeof(struct timeval))
1287 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001288
Harald Weltebed35df2011-11-02 13:06:18 +01001289 /* Calculate IP header checksum */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001290 p8 = (uint8_t *) &pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001291 count = CREATEPING_IP;
1292 sum = 0;
1293 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001294 memcpy(&v16, p8, 2);
1295 sum += v16;
1296 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001297 count -= 2;
1298 }
1299 while (sum >> 16)
1300 sum = (sum & 0xffff) + (sum >> 16);
1301 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001302
Harald Weltebed35df2011-11-02 13:06:18 +01001303 /* Calculate ICMP checksum */
1304 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1305 sum = 0;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001306 p8 = (uint8_t *) &pack;
1307 p8 += CREATEPING_IP;
Harald Weltebed35df2011-11-02 13:06:18 +01001308 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001309 memcpy(&v16, p8, 2);
1310 sum += v16;
1311 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001312 count -= 2;
1313 }
1314 if (count > 0)
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001315 sum += *(unsigned char *)p8;
Harald Weltebed35df2011-11-02 13:06:18 +01001316 while (sum >> 16)
1317 sum = (sum & 0xffff) + (sum >> 16);
1318 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001319
Harald Weltebed35df2011-11-02 13:06:18 +01001320 ntransmitted++;
1321 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001322}
1323
Harald Weltefed33892017-10-10 09:02:45 +08001324static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001325{
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001326 int rc;
1327
Andreas Schultzb6292402018-10-05 13:58:45 +01001328 if (tun && options.ipdown) {
1329#if defined(__linux__)
1330 sigset_t oldmask;
Harald Weltebed35df2011-11-02 13:06:18 +01001331
Andreas Schultzb6292402018-10-05 13:58:45 +01001332 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001333 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1334 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1335 "Failed to switch to netns %s: %s\n",
1336 options.netns, strerror(-rc));
1337 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001338 }
1339#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001340 tun_runscript(tun, options.ipdown);
1341
Andreas Schultzb6292402018-10-05 13:58:45 +01001342#if defined(__linux__)
1343 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001344 if ((rc = restore_ns(&oldmask)) < 0) {
1345 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1346 "Failed to switch to original netns: %s\n",
1347 strerror(-rc));
1348 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001349 }
1350#endif
1351 }
1352
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001353 ipdel((struct iphash_t *)pdp->peer[0]);
1354 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001355
1356 if (1 == options.contexts)
1357 state = 5; /* Disconnected */
1358
1359 return 0;
1360}
jjakoa7cd2492003-04-11 09:40:12 +00001361
Harald Welte6748dc92017-09-24 21:54:59 +08001362/* Link-Local address prefix fe80::/64 */
1363static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1364
jjakoa7cd2492003-04-11 09:40:12 +00001365/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001366static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001367{
1368 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001369 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001370 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001371 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001372
Harald Welte6748dc92017-09-24 21:54:59 +08001373 if (iph->version == 4) {
1374 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1375 printf("Dropping packet with too short IP header\n");
1376 return 0;
1377 }
1378 src.len = 4;
1379 src.v4.s_addr = iph->saddr;
1380 } else if (iph->version == 6) {
1381 /* We only have a single entry in the hash table, and it consists of the link-local
1382 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1383 * addresses to that format before looking up the hash table via ippool_getip() */
1384 src.len = 16;
1385 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1386 /* is a link-local address, we can do the hash lookup 1:1 */
1387 src.v6 = ip6h->ip6_src;
1388 } else {
1389 /* it is not a link-local address, so we must convert from the /64 prefix
1390 * to the link-local format that's used in the hash table */
1391 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1392 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1393 }
1394 } else {
1395 printf("Dropping packet with invalid IP version %u\n", iph->version);
1396 return 0;
1397 }
jjakoa7cd2492003-04-11 09:40:12 +00001398
Harald Weltebed35df2011-11-02 13:06:18 +01001399 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001400 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001401 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001402 return 0;
1403 }
1404
1405 if (ipm->pdp) /* Check if a peer protocol is defined */
1406 gtp_data_req(gsn, ipm->pdp, pack, len);
1407 return 0;
jjako52c24142002-12-16 13:33:51 +00001408}
1409
Harald Weltefed33892017-10-10 09:02:45 +08001410static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001411{
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001412 int rc, i, num_addr;
1413 struct in46_addr addr[2];
Andreas Schultzb6292402018-10-05 13:58:45 +01001414#if defined(__linux__)
1415 sigset_t oldmask;
1416#endif
jjako52c24142002-12-16 13:33:51 +00001417
Harald Weltebed35df2011-11-02 13:06:18 +01001418 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001419
Harald Weltebed35df2011-11-02 13:06:18 +01001420 if (cause < 0) {
1421 printf("Create PDP Context Request timed out\n");
1422 if (iph->pdp->version == 1) {
1423 printf("Retrying with version 0\n");
1424 iph->pdp->version = 0;
1425 gtp_create_context_req(gsn, iph->pdp, iph);
1426 return 0;
1427 } else {
1428 state = 0;
1429 pdp_freepdp(iph->pdp);
1430 iph->pdp = NULL;
1431 return EOF;
1432 }
1433 }
jjako2c381332003-10-21 19:09:53 +00001434
Harald Weltebed35df2011-11-02 13:06:18 +01001435 if (cause != 128) {
1436 printf
1437 ("Received create PDP context response. Cause value: %d\n",
1438 cause);
1439 state = 0;
1440 pdp_freepdp(iph->pdp);
1441 iph->pdp = NULL;
1442 return EOF; /* Not what we expected */
1443 }
jjako52c24142002-12-16 13:33:51 +00001444
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001445 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001446 printf
1447 ("Received create PDP context response. Cause value: %d\n",
1448 cause);
1449 pdp_freepdp(iph->pdp);
1450 iph->pdp = NULL;
1451 state = 0;
1452 return EOF; /* Not a valid IP address */
1453 }
jjakoa7cd2492003-04-11 09:40:12 +00001454
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001455 printf("Received create PDP context response.\n");
jjakoa7cd2492003-04-11 09:40:12 +00001456
Andreas Schultzb6292402018-10-05 13:58:45 +01001457#if defined(__linux__)
1458 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001459 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1460 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1461 "Failed to switch to netns %s: %s\n",
1462 options.netns, strerror(-rc));
1463 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001464 }
1465#endif
1466
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001467 for (i = 0; i < num_addr; i++) {
1468 printf("PDP ctx: received EUA with IP address: %s\n", in46a_ntoa(&addr[i]));
1469
1470 switch (addr[i].len) {
1471 case 16: /* IPv6 */
1472 /* we have to enable the kernel to perform stateless autoconfiguration,
1473 * i.e. send a router solicitation using the lover 64bits of the allocated
1474 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1475 memcpy(addr[i].v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1476 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr[i]));
1477 break;
1478 case 4: /* IPv4 */
1479 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001480 }
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001481
1482 if ((options.createif) && (!options.net.len)) {
1483 size_t prefixlen = 32;
1484 if (addr[i].len == 16)
1485 prefixlen = 64;
1486 /* printf("Setting up interface and routing\n"); */
1487 tun_addaddr(tun, &addr[i], &addr[i], prefixlen);
1488 if (options.defaultroute) {
1489 struct in_addr rm;
1490 rm.s_addr = 0;
1491 netdev_addroute(&rm, &addr[i].v4, &rm);
1492 }
1493 if (options.ipup)
1494 tun_runscript(tun, options.ipup);
1495 }
1496
1497 ipset(iph, &addr[i]);
Harald Weltebed35df2011-11-02 13:06:18 +01001498 }
jjako52c24142002-12-16 13:33:51 +00001499
Harald Welte081f30c2017-10-10 09:36:35 +08001500 /* now that ip-up has been executed, check if we are configured to
1501 * accept router advertisements */
1502 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1503 char *accept_ra, *forwarding;
1504
1505 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1506 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1507 if (!accept_ra || !forwarding)
1508 printf("Could not open proc file for %s ?!?\n", tun->devname);
1509 else {
Harald Weltef1e01512019-07-21 12:36:27 +02001510 if (!strcmp(accept_ra, "0")) {
1511 printf("accept_ra=0, i.e. your tun device is not configured to accept "
1512 "router advertisements; SLAAC will not succeed, please "
Harald Welte081f30c2017-10-10 09:36:35 +08001513 "fix your setup!\n");
1514 }
Harald Weltef1e01512019-07-21 12:36:27 +02001515 if (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1")) {
1516 printf("forwarding=1 and accept_ra=1, i.e. your tun device is not "
1517 "configured to accept router advertisements; SLAAC will not "
1518 "succeed, please fix your setup!\n");
1519 }
Harald Welte081f30c2017-10-10 09:36:35 +08001520 }
Harald Welteb589e782017-11-06 03:09:35 +09001521 free(accept_ra);
1522 free(forwarding);
Harald Welte081f30c2017-10-10 09:36:35 +08001523 }
1524
Andreas Schultzb6292402018-10-05 13:58:45 +01001525#if defined(__linux__)
1526 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001527 if ((rc = restore_ns(&oldmask)) < 0) {
1528 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1529 strerror(-rc));
1530 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001531 }
1532#endif
1533
Harald Weltebed35df2011-11-02 13:06:18 +01001534
1535 state = 2; /* Connected */
1536
1537 return 0;
jjako52c24142002-12-16 13:33:51 +00001538}
1539
Harald Weltefed33892017-10-10 09:02:45 +08001540static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001541{
1542 printf("Received delete PDP context response. Cause value: %d\n",
1543 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001544 if (pdp)
1545 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001546 return 0;
jjako52c24142002-12-16 13:33:51 +00001547}
1548
Harald Weltefed33892017-10-10 09:02:45 +08001549static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001550{
jjako91aaf222003-10-22 10:09:32 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 if (recovery < 0) {
1553 printf("Echo Request timed out\n");
1554 if (echoversion == 1) {
1555 printf("Retrying with version 0\n");
1556 echoversion = 0;
1557 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1558 return 0;
1559 } else {
1560 state = 0;
1561 return EOF;
1562 }
1563 } else {
1564 printf("Received echo response\n");
1565 if (!options.contexts)
1566 state = 5;
1567 }
1568 return 0;
jjako52c24142002-12-16 13:33:51 +00001569}
1570
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001571static int _gtp_cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001572{
1573 /* if (cause < 0) return 0; Some error occurred. We don't care */
1574 switch (type) {
1575 case GTP_ECHO_REQ:
1576 return echo_conf(cause);
1577 case GTP_CREATE_PDP_REQ:
1578 return create_pdp_conf(pdp, cbp, cause);
1579 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001580 return delete_pdp_conf(pdp, cause);
1581 default:
1582 return 0;
1583 }
jjako52c24142002-12-16 13:33:51 +00001584}
1585
Harald Weltefed33892017-10-10 09:02:45 +08001586static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001587{
1588 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1589 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001590}
1591
1592int main(int argc, char **argv)
1593{
Harald Weltebed35df2011-11-02 13:06:18 +01001594 fd_set fds; /* For select() */
1595 struct timeval idleTime; /* How long to select() */
1596 struct pdp_t *pdp;
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001597 int n, rc;
Harald Weltebed35df2011-11-02 13:06:18 +01001598 int starttime = time(NULL); /* Time program was started */
1599 int stoptime = 0; /* Time to exit */
1600 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001601 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001602
Harald Weltebed35df2011-11-02 13:06:18 +01001603 struct timezone tz; /* Used for calculating ping times */
1604 struct timeval tv;
1605 int diff;
Andreas Schultzb6292402018-10-05 13:58:45 +01001606#if defined(__linux__)
1607 sigset_t oldmask;
1608#endif
jjako52c24142002-12-16 13:33:51 +00001609
bjovana8f71eb2017-02-24 17:39:20 +01001610 signal(SIGTERM, signal_handler);
1611 signal(SIGHUP, signal_handler);
1612 signal(SIGINT, signal_handler);
1613
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001614 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1615 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1616 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001617
Andreas Schultzb6292402018-10-05 13:58:45 +01001618#if defined(__linux__)
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001619 if ((rc = init_netns()) < 0) {
1620 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
1621 exit(1);
1622 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001623#endif
1624
Harald Weltebed35df2011-11-02 13:06:18 +01001625 /* Process options given in configuration file and command line */
1626 if (process_options(argc, argv))
1627 exit(1);
jjako52c24142002-12-16 13:33:51 +00001628
Harald Weltebed35df2011-11-02 13:06:18 +01001629 printf("\nInitialising GTP library\n");
1630 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001631 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001632 exit(1);
1633 }
1634 if (gsn->fd0 > maxfd)
1635 maxfd = gsn->fd0;
1636 if (gsn->fd1c > maxfd)
1637 maxfd = gsn->fd1c;
1638 if (gsn->fd1u > maxfd)
1639 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001640
Harald Weltebed35df2011-11-02 13:06:18 +01001641 gtp_set_cb_delete_context(gsn, delete_context);
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001642 gtp_set_cb_conf(gsn, _gtp_cb_conf);
Harald Weltebed35df2011-11-02 13:06:18 +01001643 if (options.createif)
1644 gtp_set_cb_data_ind(gsn, encaps_tun);
1645 else
1646 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001647
Andreas Schultzb6292402018-10-05 13:58:45 +01001648#if defined(__linux__)
1649 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001650 if ((netns = get_nsfd(options.netns)) < 0) {
1651 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
1652 options.netns, strerror(-netns));
1653 exit(1);
1654 }
1655 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1656 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
1657 options.netns, strerror(-rc));
1658 exit(1);
1659 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001660 }
1661#endif
1662
Harald Weltebed35df2011-11-02 13:06:18 +01001663 if (options.createif) {
1664 printf("Setting up interface\n");
1665 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001666 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001667 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001668 "Failed to create tun");
1669 exit(1);
1670 }
1671 tun_set_cb_ind(tun, cb_tun_ind);
1672 if (tun->fd > maxfd)
1673 maxfd = tun->fd;
1674 }
jjakoa7cd2492003-04-11 09:40:12 +00001675
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001676 if ((options.createif) && (options.net.len)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001677 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001678 tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001679 if (options.defaultroute) {
1680 struct in_addr rm;
1681 rm.s_addr = 0;
Harald Welteb4c08282018-04-25 16:55:39 +02001682 netdev_addroute(&rm, &options.destaddr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001683 }
1684 if (options.ipup)
1685 tun_runscript(tun, options.ipup);
1686 }
jjakoa7cd2492003-04-11 09:40:12 +00001687
Andreas Schultzb6292402018-10-05 13:58:45 +01001688#if defined(__linux__)
1689 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001690 if ((rc = restore_ns(&oldmask)) < 0) {
1691 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1692 strerror(-rc));
1693 exit(1);
1694 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001695 }
1696#endif
1697
Harald Weltebed35df2011-11-02 13:06:18 +01001698 /* Initialise hash tables */
1699 memset(&iphash, 0, sizeof(iphash));
1700 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001701
Harald Weltebed35df2011-11-02 13:06:18 +01001702 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001703
Harald Weltebed35df2011-11-02 13:06:18 +01001704 /* See if anybody is there */
1705 printf("Sending off echo request\n");
1706 echoversion = options.gtpversion;
1707 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001708
Harald Weltebed35df2011-11-02 13:06:18 +01001709 for (n = 0; n < options.contexts; n++) {
1710 uint64_t myimsi;
1711 printf("Setting up PDP context #%d\n", n);
1712 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001713
Harald Weltebed35df2011-11-02 13:06:18 +01001714 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001715
Harald Weltebed35df2011-11-02 13:06:18 +01001716 /* Allocated here. */
1717 /* If create context failes we have to deallocate ourselves. */
1718 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001719 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001720
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001721 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001722 pdp->ipif = tun; /* TODO */
1723 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001724
Harald Weltebed35df2011-11-02 13:06:18 +01001725 if (options.gtpversion == 0) {
1726 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001727 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001728 "QoS length too big");
1729 exit(1);
1730 } else {
1731 memcpy(pdp->qos_req0, options.qos.v,
1732 options.qos.l);
1733 }
1734 }
jjakoa7cd2492003-04-11 09:40:12 +00001735
Harald Weltebed35df2011-11-02 13:06:18 +01001736 pdp->qos_req.l = options.qos.l;
1737 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001738
Harald Weltebed35df2011-11-02 13:06:18 +01001739 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001740
Harald Weltebed35df2011-11-02 13:06:18 +01001741 pdp->rattype.l = options.rattype.l;
1742 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1743 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001744
Harald Weltebed35df2011-11-02 13:06:18 +01001745 pdp->userloc.l = options.userloc.l;
1746 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1747 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001748
Harald Weltebed35df2011-11-02 13:06:18 +01001749 pdp->rai.l = options.rai.l;
1750 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1751 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001752
Harald Weltebed35df2011-11-02 13:06:18 +01001753 pdp->mstz.l = options.mstz.l;
1754 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1755 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001756
Harald Weltebed35df2011-11-02 13:06:18 +01001757 pdp->imeisv.l = options.imeisv.l;
1758 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1759 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001760
Harald Weltebed35df2011-11-02 13:06:18 +01001761 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001762
Harald Weltebed35df2011-11-02 13:06:18 +01001763 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001764 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001765 "APN length too big");
1766 exit(1);
1767 } else {
1768 pdp->apn_use.l = options.apn.l;
1769 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1770 }
jjako193e8b12003-11-10 12:31:41 +00001771
Harald Weltebed35df2011-11-02 13:06:18 +01001772 pdp->gsnlc.l = sizeof(options.listen);
1773 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1774 pdp->gsnlu.l = sizeof(options.listen);
1775 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001776
Harald Weltebed35df2011-11-02 13:06:18 +01001777 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001778 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001779 "MSISDN length too big");
1780 exit(1);
1781 } else {
1782 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1783 }
jjakob62c3dd2004-05-27 18:51:55 +00001784
Harald Welte840a8e92017-09-24 18:12:40 +08001785 /* Request dynamic IP address */
1786 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1787 pdp->eua.v[1] = options.pdp_type;
1788 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001789
Harald Weltebed35df2011-11-02 13:06:18 +01001790 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001791 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001792 "PCO length too big");
1793 exit(1);
1794 } else {
1795 pdp->pco_req.l = options.pco.l;
1796 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1797 }
jjako52c24142002-12-16 13:33:51 +00001798
Harald Weltebed35df2011-11-02 13:06:18 +01001799 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001800
Harald Weltebed35df2011-11-02 13:06:18 +01001801 pdp->hisaddr0 = options.remote;
1802 pdp->hisaddr1 = options.remote;
1803
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001804 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01001805 512 = Flat rate, 256 = Hot billing */
1806
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001807 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1808
Harald Weltebed35df2011-11-02 13:06:18 +01001809 /* Create context */
1810 /* We send this of once. Retransmissions are handled by gtplib */
1811 gtp_create_context_req(gsn, pdp, &iparr[n]);
1812 }
1813
1814 state = 1; /* Enter wait_connection state */
1815
1816 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001817
jjako52c24142002-12-16 13:33:51 +00001818 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001819 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001820 /******************************************************************/
1821
Harald Weltebed35df2011-11-02 13:06:18 +01001822 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001823
Harald Weltebed35df2011-11-02 13:06:18 +01001824 /* Take down client after timeout after disconnect */
1825 if ((4 == state) && ((stoptime) <= time(NULL))) {
1826 state = 5;
1827 }
jjako7b8fad42003-07-07 14:37:42 +00001828
Harald Weltebed35df2011-11-02 13:06:18 +01001829 /* Take down client after timelimit timeout */
1830 if ((2 == state) && (options.timelimit) &&
1831 ((starttime + options.timelimit) <= time(NULL))) {
1832 state = 3;
1833 }
jjako7b8fad42003-07-07 14:37:42 +00001834
Harald Weltebed35df2011-11-02 13:06:18 +01001835 /* Take down client after ping timeout */
1836 if ((2 == state) && (pingtimeout)
1837 && (pingtimeout <= time(NULL))) {
1838 state = 3;
1839 }
jjako7b8fad42003-07-07 14:37:42 +00001840
Harald Weltebed35df2011-11-02 13:06:18 +01001841 /* Set pingtimeout for later disconnection */
1842 if (options.pingcount && ntransmitted >= options.pingcount) {
1843 pingtimeout = time(NULL) + 5; /* Extra seconds */
1844 }
jjako7b8fad42003-07-07 14:37:42 +00001845
Harald Weltebed35df2011-11-02 13:06:18 +01001846 /* Print statistics if no more ping packets are missing */
1847 if (ntransmitted && options.pingcount
1848 && nreceived >= options.pingcount) {
1849 ping_finish();
1850 if (!options.createif)
1851 state = 3;
1852 }
jjako7b8fad42003-07-07 14:37:42 +00001853
Harald Weltebed35df2011-11-02 13:06:18 +01001854 /* Send off disconnect */
1855 if (3 == state) {
1856 state = 4;
1857 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1858 for (n = 0; n < options.contexts; n++) {
1859 /* Delete context */
1860 printf("Disconnecting PDP context #%d\n", n);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001861 gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
Harald Weltebed35df2011-11-02 13:06:18 +01001862 if ((options.pinghost.s_addr != 0)
1863 && ntransmitted)
1864 ping_finish();
1865 }
1866 }
jjako7b8fad42003-07-07 14:37:42 +00001867
Harald Weltebed35df2011-11-02 13:06:18 +01001868 /* Send of ping packets */
1869 diff = 0;
1870 while ((diff <= 0) &&
1871 /* Send off an ICMP ping packet */
1872 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1873 ((pingseq < options.pingcount)
1874 || (options.pingcount == 0))) {
1875 if (!pingseq)
1876 gettimeofday(&firstping, &tz); /* Set time of first ping */
1877 gettimeofday(&tv, &tz);
1878 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1879 if (diff <= 0) {
1880 if (options.debug)
1881 printf("Create_ping %d\n", diff);
1882 create_ping(gsn,
1883 iparr[pingseq %
1884 options.contexts].pdp,
1885 &options.pinghost, pingseq,
1886 options.pingsize);
1887 pingseq++;
1888 }
1889 }
jjako5da68452003-01-28 16:08:47 +00001890
Harald Weltebed35df2011-11-02 13:06:18 +01001891 FD_ZERO(&fds);
1892 if (tun)
1893 FD_SET(tun->fd, &fds);
1894 FD_SET(gsn->fd0, &fds);
1895 FD_SET(gsn->fd1c, &fds);
1896 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001897
Pau Espin Pedrol1bf41e42019-08-28 19:44:54 +02001898 idleTime.tv_sec = 10;
1899 idleTime.tv_usec = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001900 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001901
Harald Weltebed35df2011-11-02 13:06:18 +01001902 if (options.debug)
1903 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1904 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001905
bjovana8f71eb2017-02-24 17:39:20 +01001906 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001907 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1908 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001909 if (errno == EINTR)
1910 signal_received = 1;
1911 else
1912 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1913 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001914 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001915 default:
1916 break;
1917 }
1918
bjovana8f71eb2017-02-24 17:39:20 +01001919 if (!signal_received) {
1920
1921 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1922 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1923 "TUN decaps failed");
1924 }
1925
1926 if (FD_ISSET(gsn->fd0, &fds))
1927 gtp_decaps0(gsn);
1928
1929 if (FD_ISSET(gsn->fd1c, &fds))
1930 gtp_decaps1c(gsn);
1931
1932 if (FD_ISSET(gsn->fd1u, &fds))
1933 gtp_decaps1u(gsn);
1934
Harald Weltebed35df2011-11-02 13:06:18 +01001935 }
Harald Weltebed35df2011-11-02 13:06:18 +01001936 }
1937
1938 gtp_free(gsn); /* Clean up the gsn instance */
1939
1940 if (options.createif)
1941 tun_free(tun);
1942
1943 if (0 == state)
1944 exit(1); /* Indicate error */
1945
1946 return 0;
jjako52c24142002-12-16 13:33:51 +00001947}