blob: a85c9cf241f10fb307372b98200f8c7bc5fd811d [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
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>
jjako52c24142002-12-16 13:33:51 +00005 *
6 * 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.
10 *
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>
23
jjako52c24142002-12-16 13:33:51 +000024#include <ctype.h>
25#include <netdb.h>
26#include <signal.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020033#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080034#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000035#include <arpa/inet.h>
36#include <sys/wait.h>
37#include <sys/stat.h>
38#include <unistd.h>
39#include <sys/socket.h>
40#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000041#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000042#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000043#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000044#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000045#include <resolv.h>
46#include <time.h>
47
jjakoff9985c2004-01-16 11:05:22 +000048#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020049#include "../lib/tun.h"
50#include "../lib/ippool.h"
51#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000052#include "../gtp/pdp.h"
53#include "../gtp/gtp.h"
54#include "cmdline.h"
55
Harald Weltebed35df2011-11-02 13:06:18 +010056#define IPADDRLEN 256 /* Character length of addresses */
57#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000058
jjakoa7cd2492003-04-11 09:40:12 +000059/* HASH tables for IP address allocation */
60struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010061 uint8_t inuse; /* 0=free. 1=used by somebody */
62 struct iphash_t *ipnext;
63 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020064 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000065};
66struct iphash_t iparr[MAXCONTEXTS];
67struct iphash_t *iphash[MAXCONTEXTS];
68
69/* State variable used for ping */
70/* 0: Idle */
71/* 1: Wait_connect */
72/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000073/* 3: Done */
74/* 4: Wait_disconnect */
75/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010076volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000077
Harald Weltebed35df2011-11-02 13:06:18 +010078struct gsn_t *gsn = NULL; /* GSN instance */
79struct tun_t *tun = NULL; /* TUN instance */
80int maxfd = 0; /* For select() */
81int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000082
jjakoa7cd2492003-04-11 09:40:12 +000083/* Struct with local versions of gengetopt options */
84struct {
Harald Weltebed35df2011-11-02 13:06:18 +010085 int debug; /* Print debug messages */
86 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +080087 char *tun_dev_name;
Harald Welted12eab92017-08-02 19:49:47 +020088 struct in_addr netaddr, destaddr, net; /* Network interface */
89 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010090 char *ipup, *ipdown; /* Filename of scripts */
91 int defaultroute; /* Set up default route */
92 struct in_addr pinghost; /* Remote ping host */
93 int pingrate;
94 int pingsize;
95 int pingcount;
96 int pingquiet;
97 struct in_addr listen;
98 struct in_addr remote;
99 struct in_addr dns;
100 int contexts; /* Number of contexts to create */
101 int timelimit; /* Number of seconds to be connected */
102 char *statedir;
103 uint64_t imsi;
104 uint8_t nsapi;
105 int gtpversion;
106 struct ul255_t pco;
107 struct ul255_t qos;
108 uint16_t cch;
109 struct ul255_t apn;
110 uint8_t selmode;
111 struct ul255_t rattype;
112 int rattype_given;
113 struct ul255_t userloc;
114 int userloc_given;
115 struct ul255_t rai;
116 int rai_given;
117 struct ul255_t mstz;
118 int mstz_given;
119 struct ul255_t imeisv;
120 int imeisv_given;
121 struct ul16_t msisdn;
122 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800123 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800124 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000125} options;
jjako52c24142002-12-16 13:33:51 +0000126
jjako5da68452003-01-28 16:08:47 +0000127/* Definitions to use for PING. Most of the ping code was derived from */
128/* the original ping program by Mike Muuss */
129
130/* IP header and ICMP echo header */
131#define CREATEPING_MAX 2048
132#define CREATEPING_IP 20
133#define CREATEPING_ICMP 8
134
135struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100136 uint8_t ipver; /* Type and header length */
137 uint8_t tos; /* Type of Service */
138 uint16_t length; /* Total length */
139 uint16_t fragid; /* Identifier */
140 uint16_t offset; /* Flags and fragment offset */
141 uint8_t ttl; /* Time to live */
142 uint8_t protocol; /* Protocol */
143 uint16_t ipcheck; /* Header checksum */
144 uint32_t src; /* Source address */
145 uint32_t dst; /* Destination */
146 uint8_t type; /* Type and header length */
147 uint8_t code; /* Code */
148 uint16_t checksum; /* Header checksum */
149 uint16_t ident; /* Identifier */
150 uint16_t seq; /* Sequence number */
151 uint8_t data[CREATEPING_MAX]; /* Data */
152} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000153
154/* Statistical values for ping */
155int nreceived = 0;
156int ntreceived = 0;
157int ntransmitted = 0;
158int tmin = 999999999;
159int tmax = 0;
160int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100161int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000162struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000163
bjovana8f71eb2017-02-24 17:39:20 +0100164void signal_handler(int signo)
165{
166 if (state == 2)
167 state = 3; /* Tell main loop to finish. */
168}
169
Harald Welted12eab92017-08-02 19:49:47 +0200170int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100171{
Harald Welted12eab92017-08-02 19:49:47 +0200172 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100173 struct iphash_t *h;
174 struct iphash_t *prev = NULL;
175 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200176 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100177 for (h = iphash[hash]; h; h = h->ipnext)
178 prev = h;
179 if (!prev)
180 iphash[hash] = ipaddr;
181 else
182 prev->ipnext = ipaddr;
183 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000184}
185
Harald Weltebed35df2011-11-02 13:06:18 +0100186int ipdel(struct iphash_t *ipaddr)
187{
Harald Welted12eab92017-08-02 19:49:47 +0200188 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100189 struct iphash_t *h;
190 struct iphash_t *prev = NULL;
191 for (h = iphash[hash]; h; h = h->ipnext) {
192 if (h == ipaddr) {
193 if (!prev)
194 iphash[hash] = h->ipnext;
195 else
196 prev->ipnext = h->ipnext;
197 return 0;
198 }
199 prev = h;
200 }
201 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000202}
203
Harald Welted12eab92017-08-02 19:49:47 +0200204int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100205{
Harald Welted12eab92017-08-02 19:49:47 +0200206 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100207 struct iphash_t *h;
208 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200209 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100210 *ipaddr = h;
211 return 0;
212 }
213 }
214 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000215}
216
jjakoa7cd2492003-04-11 09:40:12 +0000217/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100218void log_pid(char *pidfile)
219{
220 FILE *file;
221 mode_t oldmask;
222
223 oldmask = umask(022);
224 file = fopen(pidfile, "w");
225 umask(oldmask);
226 if (!file)
227 return;
228 fprintf(file, "%d\n", (int)getpid());
229 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000230}
231
Harald Weltebed35df2011-11-02 13:06:18 +0100232int process_options(int argc, char **argv)
233{
234 /* gengeopt declarations */
235 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000236
Harald Weltebed35df2011-11-02 13:06:18 +0100237 struct hostent *host;
238 unsigned int n;
239 uint16_t i;
240 uint8_t a;
241 uint8_t b;
242 char *tmp;
243 char *pch;
244 char *type;
245 char *mcc;
246 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100247 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100248 char *lac;
249 int lac_d;
250 char *rest;
251 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
252 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
253 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
254 int sign;
255 int nbquarters;
256 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000257
Harald Weltebed35df2011-11-02 13:06:18 +0100258 if (cmdline_parser(argc, argv, &args_info) != 0)
259 return -1;
260 if (args_info.debug_flag) {
261 if (args_info.remote_arg)
262 printf("remote: %s\n", args_info.remote_arg);
263 if (args_info.listen_arg)
264 printf("listen: %s\n", args_info.listen_arg);
265 if (args_info.conf_arg)
266 printf("conf: %s\n", args_info.conf_arg);
267 printf("debug: %d\n", args_info.debug_flag);
268 if (args_info.imsi_arg)
269 printf("imsi: %s\n", args_info.imsi_arg);
270 printf("qos: %#08x\n", args_info.qos_arg);
271 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
272 printf("qose2: %#04x\n", args_info.qose2_arg);
273 printf("qose3: %#06x\n", args_info.qose3_arg);
274 printf("qose4: %#06x\n", args_info.qose4_arg);
275 printf("charging: %#04x\n", args_info.charging_arg);
276 if (args_info.apn_arg)
277 printf("apn: %s\n", args_info.apn_arg);
278 if (args_info.msisdn_arg)
279 printf("msisdn: %s\n", args_info.msisdn_arg);
280 if (args_info.uid_arg)
281 printf("uid: %s\n", args_info.uid_arg);
282 if (args_info.pwd_arg)
283 printf("pwd: %s\n", args_info.pwd_arg);
284 if (args_info.pidfile_arg)
285 printf("pidfile: %s\n", args_info.pidfile_arg);
286 if (args_info.statedir_arg)
287 printf("statedir: %s\n", args_info.statedir_arg);
288 if (args_info.dns_arg)
289 printf("dns: %s\n", args_info.dns_arg);
290 printf("contexts: %d\n", args_info.contexts_arg);
291 printf("timelimit: %d\n", args_info.timelimit_arg);
292 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800293 if (args_info.tun_device_arg)
294 printf("tun-device: %d\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100295 if (args_info.ipup_arg)
296 printf("ipup: %s\n", args_info.ipup_arg);
297 if (args_info.ipdown_arg)
298 printf("ipdown: %s\n", args_info.ipdown_arg);
299 printf("defaultroute: %d\n", args_info.defaultroute_flag);
300 if (args_info.pinghost_arg)
301 printf("pinghost: %s\n", args_info.pinghost_arg);
302 printf("pingrate: %d\n", args_info.pingrate_arg);
303 printf("pingsize: %d\n", args_info.pingsize_arg);
304 printf("pingcount: %d\n", args_info.pingcount_arg);
305 printf("pingquiet: %d\n", args_info.pingquiet_flag);
306 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800307 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100308 }
jjakoa7cd2492003-04-11 09:40:12 +0000309
Harald Weltebed35df2011-11-02 13:06:18 +0100310 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000311
Harald Weltebed35df2011-11-02 13:06:18 +0100312 if (args_info.conf_arg) {
313 if (cmdline_parser_configfile
314 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
315 return -1;
316 if (args_info.debug_flag) {
317 printf("cmdline_parser_configfile\n");
318 if (args_info.remote_arg)
319 printf("remote: %s\n", args_info.remote_arg);
320 if (args_info.listen_arg)
321 printf("listen: %s\n", args_info.listen_arg);
322 if (args_info.conf_arg)
323 printf("conf: %s\n", args_info.conf_arg);
324 printf("debug: %d\n", args_info.debug_flag);
325 if (args_info.imsi_arg)
326 printf("imsi: %s\n", args_info.imsi_arg);
327 printf("qos: %#08x\n", args_info.qos_arg);
328 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
329 printf("qose2: %#04x\n", args_info.qose2_arg);
330 printf("qose3: %#06x\n", args_info.qose3_arg);
331 printf("qose4: %#06x\n", args_info.qose4_arg);
332 printf("charging: %#04x\n", args_info.charging_arg);
333 if (args_info.apn_arg)
334 printf("apn: %s\n", args_info.apn_arg);
335 if (args_info.msisdn_arg)
336 printf("msisdn: %s\n", args_info.msisdn_arg);
337 if (args_info.uid_arg)
338 printf("uid: %s\n", args_info.uid_arg);
339 if (args_info.pwd_arg)
340 printf("pwd: %s\n", args_info.pwd_arg);
341 if (args_info.pidfile_arg)
342 printf("pidfile: %s\n", args_info.pidfile_arg);
343 if (args_info.statedir_arg)
344 printf("statedir: %s\n",
345 args_info.statedir_arg);
346 if (args_info.dns_arg)
347 printf("dns: %s\n", args_info.dns_arg);
348 printf("contexts: %d\n", args_info.contexts_arg);
349 printf("timelimit: %d\n", args_info.timelimit_arg);
350 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800351 if (args_info.tun_device_arg)
352 printf("tun-device: %d\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100353 if (args_info.ipup_arg)
354 printf("ipup: %s\n", args_info.ipup_arg);
355 if (args_info.ipdown_arg)
356 printf("ipdown: %s\n", args_info.ipdown_arg);
357 printf("defaultroute: %d\n",
358 args_info.defaultroute_flag);
359 if (args_info.pinghost_arg)
360 printf("pinghost: %s\n",
361 args_info.pinghost_arg);
362 printf("pingrate: %d\n", args_info.pingrate_arg);
363 printf("pingsize: %d\n", args_info.pingsize_arg);
364 printf("pingcount: %d\n", args_info.pingcount_arg);
365 printf("pingquiet: %d\n", args_info.pingquiet_flag);
366 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800367 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100368 }
369 }
jjako193e8b12003-11-10 12:31:41 +0000370
Harald Weltebed35df2011-11-02 13:06:18 +0100371 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000372
Harald Weltebed35df2011-11-02 13:06:18 +0100373 /* foreground */
374 /* If fg flag not given run as a daemon */
375 /* Do not allow sgsnemu to run as deamon
376 if (!args_info.fg_flag)
377 {
378 closelog();
379 freopen("/dev/null", "w", stdout);
380 freopen("/dev/null", "w", stderr);
381 freopen("/dev/null", "r", stdin);
382 daemon(0, 0);
383 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
384 } */
jjako1a51df72004-07-20 08:30:21 +0000385
Harald Weltebed35df2011-11-02 13:06:18 +0100386 /* debug */
387 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000388
Harald Weltebed35df2011-11-02 13:06:18 +0100389 /* pidfile */
390 /* This has to be done after we have our final pid */
391 if (args_info.pidfile_arg) {
392 log_pid(args_info.pidfile_arg);
393 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200394
Harald Weltebed35df2011-11-02 13:06:18 +0100395 /* dns */
396 /* If no dns option is given use system default */
397 /* Do hostname lookup to translate hostname to IP address */
398 printf("\n");
399 if (args_info.dns_arg) {
400 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100401 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100402 "Invalid DNS address: %s!", args_info.dns_arg);
403 return -1;
404 } else {
405 memcpy(&options.dns.s_addr, host->h_addr,
406 host->h_length);
407 _res.nscount = 1;
408 _res.nsaddr_list[0].sin_addr = options.dns;
409 printf("Using DNS server: %s (%s)\n",
410 args_info.dns_arg, inet_ntoa(options.dns));
411 }
412 } else {
413 options.dns.s_addr = 0;
414 printf("Using default DNS server\n");
415 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200416
Harald Weltebed35df2011-11-02 13:06:18 +0100417 /* listen */
418 /* If no listen option is specified listen to any local port */
419 /* Do hostname lookup to translate hostname to IP address */
420 if (args_info.listen_arg) {
421 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100422 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100423 "Invalid listening address: %s!",
424 args_info.listen_arg);
425 return -1;
426 } else {
427 memcpy(&options.listen.s_addr, host->h_addr,
428 host->h_length);
429 printf("Local IP address is: %s (%s)\n",
430 args_info.listen_arg, inet_ntoa(options.listen));
431 }
432 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100433 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100434 "Listening address must be specified: %s!",
435 args_info.listen_arg);
436 return -1;
437 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200438
Harald Weltebed35df2011-11-02 13:06:18 +0100439 /* remote */
440 /* If no remote option is specified terminate */
441 /* Do hostname lookup to translate hostname to IP address */
442 if (args_info.remote_arg) {
443 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100444 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100445 "Invalid remote address: %s!",
446 args_info.remote_arg);
447 return -1;
448 } else {
449 memcpy(&options.remote.s_addr, host->h_addr,
450 host->h_length);
451 printf("Remote IP address is: %s (%s)\n",
452 args_info.remote_arg, inet_ntoa(options.remote));
453 }
454 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100455 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100456 "No remote address given!");
457 return -1;
458 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200459
Harald Weltebed35df2011-11-02 13:06:18 +0100460 /* imsi */
461 if (strlen(args_info.imsi_arg) != 15) {
462 printf("Invalid IMSI\n");
463 return -1;
464 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200465
Harald Weltebed35df2011-11-02 13:06:18 +0100466 options.imsi = 0xf000000000000000ull;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
474 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
475 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
476 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
477 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
478 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
479 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
480 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
481 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200482
Harald Weltebed35df2011-11-02 13:06:18 +0100483 printf("IMSI is: %s (%#08llx)\n",
484 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200485
Harald Weltebed35df2011-11-02 13:06:18 +0100486 /* nsapi */
487 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
488 printf("Invalid NSAPI\n");
489 return -1;
490 }
491 options.nsapi = args_info.nsapi_arg;
492 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200493
Harald Weltebed35df2011-11-02 13:06:18 +0100494 /* qos */
495 options.qos.l = 4;
496 options.qos.v[3] = (args_info.qos_arg) & 0xff;
497 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
498 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
499 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
500 /* Extensions according to 3GPP TS 24.008 */
501 if (args_info.qose1_given == 1) {
502 options.qos.l = 12;
503 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
504 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
505 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
506 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
507 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
508 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
509 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
510 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
511 if (args_info.qose2_given == 1) {
512 options.qos.l = 13;
513 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
514 if (args_info.qose3_given == 1) {
515 options.qos.l = 15;
516 options.qos.v[14] =
517 (args_info.qose3_arg) & 0xff;
518 options.qos.v[13] =
519 ((args_info.qose3_arg) >> 8) & 0xff;
520 if (args_info.qose4_given == 1) {
521 options.qos.l = 17;
522 options.qos.v[16] =
523 (args_info.qose4_arg) & 0xff;
524 options.qos.v[15] =
525 ((args_info.qose4_arg) >> 8) & 0xff;
526 }
527 }
528 }
529 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200530
Harald Weltebed35df2011-11-02 13:06:18 +0100531 /* charging */
532 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200533
Harald Weltebed35df2011-11-02 13:06:18 +0100534 /* contexts */
535 if (args_info.contexts_arg > MAXCONTEXTS) {
536 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
537 return -1;
538 }
539 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200540
Harald Weltebed35df2011-11-02 13:06:18 +0100541 /* Timelimit */
542 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 /* gtpversion */
545 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
546 printf("Invalid GTP version\n");
547 return -1;
548 }
549 options.gtpversion = args_info.gtpversion_arg;
550 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200551
Harald Weltebed35df2011-11-02 13:06:18 +0100552 /* apn */
553 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
554 printf("Invalid APN\n");
555 return -1;
556 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100557 options.apn.l = strlen(args_info.apn_arg) + 1;
558
559 apn = (char *)options.apn.v;
560 for (tok = strtok(args_info.apn_arg, ".");
561 tok != NULL;
562 tok = strtok(NULL, ".")) {
563 size_t len = strlen(tok);
564
565 *apn++ = (char)len;
566 strncpy(apn, tok, len);
567 apn += len;
568 }
569
Harald Weltebed35df2011-11-02 13:06:18 +0100570 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200571
Harald Weltebed35df2011-11-02 13:06:18 +0100572 /* selmode */
573 options.selmode = args_info.selmode_arg;
574 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200575
Harald Weltebed35df2011-11-02 13:06:18 +0100576 /* rattype */
577 if (args_info.rattype_given == 1) {
578 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800579 options.rattype.l = 1;
580 options.rattype.v[0] = args_info.rattype_arg;
581 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100582 }
Harald Welte41af5692011-10-07 18:42:34 +0200583
Harald Weltebed35df2011-11-02 13:06:18 +0100584 /* userloc */
585 if (args_info.userloc_given == 1) {
586 printf("Using User Location Information: %s\n",
587 args_info.userloc_arg);
588 tmp = args_info.userloc_arg;
589 n = 0;
590 pch = strtok(tmp, ".");
591 while (pch != NULL) {
592 userloc_el[n] = pch;
593 pch = strtok(NULL, ".");
594 n++;
595 }
Harald Welte41af5692011-10-07 18:42:34 +0200596
Harald Weltebed35df2011-11-02 13:06:18 +0100597 options.userloc_given = 1;
598 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200599
Harald Weltebed35df2011-11-02 13:06:18 +0100600 /* 3GPP Geographic Location Type t0 / t1 / t2 */
601 type = userloc_el[0];
602 printf("->type : %c\n", type[0]);
603 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
604 printf("Invalid type \n");
605 return -1;
606 }
607 /* options.userloc.v[0] = 0x00 */
608 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 /* MCC */
611 mcc = userloc_el[1];
612 printf("->mcc : %s\n", mcc);
613 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200614 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100615 return -1;
616 }
Harald Welte41af5692011-10-07 18:42:34 +0200617
Harald Weltebed35df2011-11-02 13:06:18 +0100618 /* MNC */
619 mnc = userloc_el[2];
620 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200621
Harald Weltebed35df2011-11-02 13:06:18 +0100622 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
623 /* options.userloc.v[1] = 0x52 */
624 a = (uint8_t) (mcc[0] - 48);
625 b = (uint8_t) (mcc[1] - 48);
626 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200627
Harald Weltebed35df2011-11-02 13:06:18 +0100628 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
629 /* options.userloc.v[2] = 0xf0 */
630 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200631
Harald Weltebed35df2011-11-02 13:06:18 +0100632 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200633 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100634 return -1;
635 }
636 if (strlen(mnc) == 2) {
637 b = 15;
638 }
639 if (strlen(mnc) == 3) {
640 b = (uint8_t) (mnc[2] - 48);
641 }
642 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200643
Harald Weltebed35df2011-11-02 13:06:18 +0100644 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
645 /* options.userloc.v[3] = 0x99 */
646 a = (uint8_t) (mnc[0] - 48);
647 b = (uint8_t) (mnc[1] - 48);
648 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200649
Harald Weltebed35df2011-11-02 13:06:18 +0100650 /* LAC */
651 lac = userloc_el[3];
652 /*options.userloc.v[4] = 0x12 ; */
653 /*options.userloc.v[5] = 0x10 ; */
654 printf("->LAC: %s\n", lac);
655 lac_d = atoi(lac);
656 if (lac_d > 65535 || lac_d < 1) {
657 printf("Invalid LAC\n");
658 return -1;
659 }
660 i = lac_d >> 8;
661 options.userloc.v[4] = i; /* octet 8 - LAC */
662 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200663
Harald Weltebed35df2011-11-02 13:06:18 +0100664 /* CI/SAC/RAC */
665 rest = userloc_el[4];
666 printf("->CI/SAC/RAC : %s\n", rest);
667 lac_d = atoi(rest);
668 if (lac_d > 65535 || lac_d < 1) {
669 printf("Invalid CI/SAC/RAC\n");
670 return -1;
671 }
672 /*options.userloc.v[6] = 0x04 ; */
673 /*options.userloc.v[7] = 0xb7 ; */
674 i = lac_d >> 8;
675 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
676 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
677 }
jjakoa7cd2492003-04-11 09:40:12 +0000678
Harald Weltebed35df2011-11-02 13:06:18 +0100679 /* RAI */
680 if (args_info.rai_given == 1) {
681 printf("Using RAI: %s\n", args_info.rai_arg);
682 tmp = args_info.rai_arg;
683 n = 0;
684 pch = strtok(tmp, ".");
685 while (pch != NULL) {
686 rai_el[n] = pch;
687 pch = strtok(NULL, ".");
688 n++;
689 }
jjakoa7cd2492003-04-11 09:40:12 +0000690
Harald Weltebed35df2011-11-02 13:06:18 +0100691 options.rai_given = 1;
692 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000693
Harald Weltebed35df2011-11-02 13:06:18 +0100694 /* MCC */
695 mcc = rai_el[0];
696 printf("->mcc : %s\n", mcc);
697 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200698 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100699 return -1;
700 }
701
702 /* MNC */
703 mnc = rai_el[1];
704 printf("->mnc : %s\n", mnc);
705
706 a = (uint8_t) (mcc[0] - 48);
707 b = (uint8_t) (mcc[1] - 48);
708 options.rai.v[0] = 16 * b + a;
709
710 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
711 a = (uint8_t) (mcc[2] - 48);
712
713 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200714 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100715 return -1;
716 }
717 if (strlen(mnc) == 2) {
718 b = 15;
719 }
720 if (strlen(mnc) == 3) {
721 b = (uint8_t) (mnc[2] - 48);
722 }
723 options.rai.v[1] = 16 * b + a;
724
725 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
726 a = (uint8_t) (mnc[0] - 48);
727 b = (uint8_t) (mnc[1] - 48);
728 options.rai.v[2] = 16 * b + a;
729
730 /* LAC */
731 lac = rai_el[2];
732 printf("->LAC: %s\n", lac);
733 lac_d = atoi(lac);
734 if (lac_d > 65535 || lac_d < 1) {
735 printf("Invalid LAC\n");
736 return -1;
737 }
738 i = lac_d >> 8;
739 options.rai.v[3] = i; /* octet 5 - LAC */
740 options.rai.v[4] = lac_d; /* octet 6 - LAC */
741
742 /* RAC */
743 rest = rai_el[3];
744 printf("->RAC : %s\n", rest);
745 lac_d = atoi(rest);
746 if (lac_d > 255 || lac_d < 1) {
747 printf("Invalid RAC\n");
748 return -1;
749 }
750 options.rai.v[5] = lac_d; /* octet 7 - RAC */
751 }
752
753 /* mstz */
754 if (args_info.mstz_given == 1) {
755 options.mstz_given = 1;
756 options.mstz.l = 2;
757
758 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
759 tmp = args_info.mstz_arg;
760 n = 0;
761 pch = strtok(tmp, ".");
762 while (pch != NULL) {
763 mstz_el[n] = pch;
764 pch = strtok(NULL, ".");
765 n++;
766 }
767
768 /* sign */
769 sign = atoi(mstz_el[0]);
770 printf("->Sign (0=+ / 1=-): %d\n", sign);
771 if (sign != 0 && sign != 1) {
772 printf("Invalid Sign \n");
773 return -1;
774 }
775 /* nbquarters */
776 nbquarters = atoi(mstz_el[1]);
777 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
778 if (nbquarters < 0 || nbquarters > 79) {
779 printf("Invalid Number of Quarters \n");
780 return -1;
781 }
782 /* DST */
783 DST = atoi(mstz_el[2]);
784 printf("->Daylight Saving Time Adjustment : %d\n", DST);
785 if (DST < 0 || DST > 3) {
786 printf("Invalid DST Adjustment \n");
787 return -1;
788 }
789 /* 12345678
790 bits 123 = unit of # of quarters of an hour
791 bits 678 = # of quarters of an hour / 10
792 bit 5 = sign
793 */
794 i = nbquarters % 10;
795 i = i << 4;
796 i = i + nbquarters / 10 + 8 * sign;
797 /* options.mstz.v[0] = 0x69 ; */
798 /* options.mstz.v[1] = 0x01 ; */
799 options.mstz.v[0] = i;
800 options.mstz.v[1] = DST;
801 n = (i & 0x08) ? '-' : '+';
802 printf
803 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
804 n, nbquarters / 4, nbquarters % 4 * 15);
805 }
806
807 /* imeisv */
808 if (args_info.imeisv_given == 1) {
809 options.imeisv_given = 1;
810 if (strlen(args_info.imeisv_arg) != 16) {
811 printf("Invalid IMEI(SV)\n");
812 return -1;
813 }
814 options.imeisv.l = 8;
815 for (n = 0; n < 8; n++) {
816 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
817 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
818 options.imeisv.v[n] = 16 * b + a;
819 }
820 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
821 }
822
823 /* msisdn */
824 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
825 printf("Invalid MSISDN\n");
826 return -1;
827 }
828 options.msisdn.l = 1;
829 options.msisdn.v[0] = 0x91; /* International format */
830 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
831 if ((n % 2) == 0) {
832 options.msisdn.v[((int)n / 2) + 1] =
833 args_info.msisdn_arg[n] - 48 + 0xf0;
834 options.msisdn.l += 1;
835 } else {
836 options.msisdn.v[((int)n / 2) + 1] =
837 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
838 (args_info.msisdn_arg[n] - 48) * 16;
839 }
840 }
841 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
842
843 /* UID and PWD */
844 /* Might need to also insert stuff like DNS etc. */
845 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
846 (sizeof(options.pco.v) - 1)) {
847 printf("invalid UID and PWD\n");
848 return -1;
849 }
850 options.pco.l =
851 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
852 options.pco.v[0] = 0x80; /* PPP */
853 options.pco.v[1] = 0xc0; /* PAP */
854 options.pco.v[2] = 0x23;
855 options.pco.v[3] =
856 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
857 options.pco.v[4] = 0x01; /* Authenticate request */
858 options.pco.v[5] = 0x01;
859 options.pco.v[6] = 0x00; /* MSB of length */
860 options.pco.v[7] =
861 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
862 options.pco.v[8] = strlen(args_info.uid_arg);
863 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
864 options.pco.v[9 + strlen(args_info.uid_arg)] =
865 strlen(args_info.pwd_arg);
866 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
867 args_info.pwd_arg, strlen(args_info.pwd_arg));
868
869 /* createif */
870 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800871 options.tun_dev_name = args_info.tun_device_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100872
873 /* net */
874 /* Store net as in_addr net and mask */
875 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200876 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100877 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200878 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100879 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100880 "Invalid network address: %s!",
881 args_info.net_arg);
882 exit(1);
883 }
Harald Welted12eab92017-08-02 19:49:47 +0200884 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100885 options.netaddr.s_addr = options.net.s_addr;
886 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000887
Harald Weltebed35df2011-11-02 13:06:18 +0100888 } else {
889 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200890 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100891 options.netaddr.s_addr = 0;
892 options.destaddr.s_addr = 0;
893 }
jjako193e8b12003-11-10 12:31:41 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* ipup */
896 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000897
Harald Weltebed35df2011-11-02 13:06:18 +0100898 /* ipdown */
899 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000900
Harald Weltebed35df2011-11-02 13:06:18 +0100901 /* statedir */
902 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000903
Harald Weltebed35df2011-11-02 13:06:18 +0100904 /* defaultroute */
905 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000906
Harald Weltebed35df2011-11-02 13:06:18 +0100907 /* pinghost */
908 /* Store ping host as in_addr */
909 if (args_info.pinghost_arg) {
910 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100911 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100912 "Invalid ping host: %s!",
913 args_info.pinghost_arg);
914 return -1;
915 } else {
916 memcpy(&options.pinghost.s_addr, host->h_addr,
917 host->h_length);
918 printf("Using ping host: %s (%s)\n",
919 args_info.pinghost_arg,
920 inet_ntoa(options.pinghost));
921 }
922 }
jjakoa7cd2492003-04-11 09:40:12 +0000923
Harald Weltebed35df2011-11-02 13:06:18 +0100924 /* Other ping parameters */
925 options.pingrate = args_info.pingrate_arg;
926 options.pingsize = args_info.pingsize_arg;
927 options.pingcount = args_info.pingcount_arg;
928 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000929
Harald Weltebed35df2011-11-02 13:06:18 +0100930 /* norecovery */
931 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000932
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800933 if (args_info.no_tx_gpdu_seq_flag)
934 options.tx_gpdu_seq = 0;
935 else
936 options.tx_gpdu_seq = 1;
937
Harald Welte840a8e92017-09-24 18:12:40 +0800938 /* PDP Type */
939 if (!strcmp(args_info.pdp_type_arg, "v6"))
940 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800941 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800942 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800943 else {
944 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
945 args_info.pdp_type_arg);
946 return -1;
947 }
948
949 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
950 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
951 return -1;
952 }
Harald Welte840a8e92017-09-24 18:12:40 +0800953
Harald Weltebed35df2011-11-02 13:06:18 +0100954 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000955
956}
957
Harald Weltebed35df2011-11-02 13:06:18 +0100958int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
959{
960 unsigned int i;
961 printf("The packet looks like this:\n");
962 for (i = 0; i < len; i++) {
963 printf("%02x ", (unsigned char)*(char *)(pack + i));
964 if (!((i + 1) % 16))
965 printf("\n");
966 };
967 printf("\n");
968 return 0;
jjako52c24142002-12-16 13:33:51 +0000969}
970
Harald Welte081f30c2017-10-10 09:36:35 +0800971/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
972static char *proc_read(const char *path)
973{
974 char *ret = NULL;
975 FILE *f;
976
977 f = fopen(path, "r");
978 if (!f)
979 return NULL;
980
981 ret = malloc(256);
982 if (!ret)
983 goto out;
984
985 if (!fgets(ret, 256, f)) {
986 free(ret);
987 ret = NULL;
988 goto out;
989 }
990 return ret;
991
992out:
993 fclose(f);
994 return ret;
995}
996
997/* Read value of a /proc/sys/net/ipv6/conf file for given device.
998 * Memory is dynamically allocated, caller must free it later. */
999static char *proc_ipv6_conf_read(const char *dev, const char *file)
1000{
1001 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
1002 char path[strlen(fmt) + strlen(dev) + strlen(file)];
1003 snprintf(path, sizeof(path), fmt, dev, file);
1004 return proc_read(path);
1005}
1006
Harald Weltebed35df2011-11-02 13:06:18 +01001007char *print_ipprot(int t)
1008{
1009 switch (t) {
1010 case 1:
1011 return "ICMP";
1012 case 6:
1013 return "TCP";
1014 case 17:
1015 return "UDP";
1016 default:
1017 return "Unknown";
1018 };
jjako5da68452003-01-28 16:08:47 +00001019}
1020
Harald Weltebed35df2011-11-02 13:06:18 +01001021char *print_icmptype(int t)
1022{
1023 static char *ttab[] = {
1024 "Echo Reply",
1025 "ICMP 1",
1026 "ICMP 2",
1027 "Dest Unreachable",
1028 "Source Quench",
1029 "Redirect",
1030 "ICMP 6",
1031 "ICMP 7",
1032 "Echo",
1033 "ICMP 9",
1034 "ICMP 10",
1035 "Time Exceeded",
1036 "Parameter Problem",
1037 "Timestamp",
1038 "Timestamp Reply",
1039 "Info Request",
1040 "Info Reply"
1041 };
1042 if (t < 0 || t > 16)
1043 return ("OUT-OF-RANGE");
1044 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001045}
1046
Harald Weltebed35df2011-11-02 13:06:18 +01001047int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
1048{
1049 unsigned int n;
1050 uint64_t i64 = 0;
1051 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1052 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001053
Harald Weltebed35df2011-11-02 13:06:18 +01001054 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1055 /* ul16_t format always starts with 0x91 to indicate international format */
1056 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1057 for (n = 0; n < src->l; n++) {
1058 if ((src->v[n] & 0x0f) != 0x0f) {
1059 i64 *= 10;
1060 i64 += src->v[n] & 0x0f;
1061 }
1062 if ((src->v[n] & 0xf0) != 0xf0) {
1063 i64 *= 10;
1064 i64 += (src->v[n] & 0xf0) >> 4;
1065 }
1066 }
jjako193e8b12003-11-10 12:31:41 +00001067
Harald Weltebed35df2011-11-02 13:06:18 +01001068 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001069
Harald Weltebed35df2011-11-02 13:06:18 +01001070 /* Generate array with least significant digit in first octet */
1071 while (i64) {
1072 msa[msalen++] = i64 % 10;
1073 i64 = i64 / 10;
1074 }
jjako193e8b12003-11-10 12:31:41 +00001075
Harald Weltebed35df2011-11-02 13:06:18 +01001076 /* Convert back to ul16_t format */
1077 for (n = 0; n < msalen; n++) {
1078 if ((n % 2) == 0) {
1079 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1080 dst->l += 1;
1081 } else {
1082 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1083 msa[msalen - n - 1] * 16;
1084 }
1085 }
jjako193e8b12003-11-10 12:31:41 +00001086
Harald Weltebed35df2011-11-02 13:06:18 +01001087 return 0;
jjako193e8b12003-11-10 12:31:41 +00001088
1089}
1090
Harald Weltebed35df2011-11-02 13:06:18 +01001091int imsi_add(uint64_t src, uint64_t * dst, int add)
1092{
1093 /* TODO: big endian / small endian ??? */
1094 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001095
Harald Weltebed35df2011-11-02 13:06:18 +01001096 /* Convert from uint64_t bcd to uint64_t integer format */
1097 /* The resulting integer format is multiplied by 10 */
1098 while (src) {
1099 if ((src & 0x0f) != 0x0f) {
1100 i64 *= 10;
1101 i64 += (src & 0x0f);
1102 }
1103 if ((src & 0xf0) != 0xf0) {
1104 i64 *= 10;
1105 i64 += (src & 0xf0) >> 4;
1106 }
1107 src = src >> 8;
1108 }
jjako193e8b12003-11-10 12:31:41 +00001109
Harald Weltebed35df2011-11-02 13:06:18 +01001110 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001111
Harald Weltebed35df2011-11-02 13:06:18 +01001112 *dst = 0;
1113 while (i64) {
1114 *dst = *dst << 4;
1115 *dst += (i64 % 10);
1116 i64 = i64 / 10;
1117 }
jjako193e8b12003-11-10 12:31:41 +00001118
Harald Weltebed35df2011-11-02 13:06:18 +01001119 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001120
Harald Weltebed35df2011-11-02 13:06:18 +01001121 return 0;
jjako193e8b12003-11-10 12:31:41 +00001122
1123}
1124
jjakoafb2a972003-01-29 21:04:13 +00001125/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001126int ping_timeout(struct timeval *tp)
1127{
1128 struct timezone tz;
1129 struct timeval tv;
1130 int diff;
1131 if ((options.pinghost.s_addr) && (2 == state) &&
1132 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1133 gettimeofday(&tv, &tz);
1134 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1135 tp->tv_sec = 0;
1136 if (diff > 0)
1137 tp->tv_usec = diff;
1138 else {
1139 /* For some reason we get packet loss if set to zero */
1140 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1141 tp->tv_usec = 0;
1142 }
1143 }
1144 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001145}
1146
jjako5da68452003-01-28 16:08:47 +00001147/* Print out statistics when at the end of ping sequence */
1148int ping_finish()
1149{
Harald Weltebed35df2011-11-02 13:06:18 +01001150 struct timezone tz;
1151 struct timeval tv;
1152 int elapsed;
1153 gettimeofday(&tv, &tz);
1154 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1155 printf("\n");
1156 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1157 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1158 elapsed / 1000000.0);
1159 printf("%d packets received, ", nreceived);
1160 if (ntransmitted) {
1161 if (nreceived > ntransmitted)
1162 printf("-- somebody's printing up packets!");
1163 else
1164 printf("%d%% packet loss",
1165 (int)(((ntransmitted - nreceived) * 100) /
1166 ntransmitted));
1167 }
1168 printf("\n");
1169 if (options.debug)
1170 printf("%d packets received in total\n", ntreceived);
1171 if (nreceived && tsum)
1172 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1173 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1174 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001175
Harald Weltebed35df2011-11-02 13:06:18 +01001176 ntransmitted = 0;
1177 return 0;
jjako5da68452003-01-28 16:08:47 +00001178}
1179
1180/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001181int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1182{
1183 struct timezone tz;
1184 struct timeval tv;
1185 struct timeval *tp;
1186 struct ip_ping *pingpack = pack;
1187 struct in_addr src;
1188 int triptime;
jjako5da68452003-01-28 16:08:47 +00001189
Harald Weltebed35df2011-11-02 13:06:18 +01001190 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001191
Harald Weltebed35df2011-11-02 13:06:18 +01001192 gettimeofday(&tv, &tz);
1193 if (options.debug)
1194 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001195
Harald Weltebed35df2011-11-02 13:06:18 +01001196 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1197 printf("packet too short (%d bytes) from %s\n", len,
1198 inet_ntoa(src));
1199 return 0;
1200 }
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 ntreceived++;
1203 if (pingpack->protocol != 1) {
1204 if (!options.pingquiet)
1205 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1206 len, inet_ntoa(src), pingpack->protocol,
1207 print_ipprot(pingpack->protocol));
1208 return 0;
1209 }
jjako5da68452003-01-28 16:08:47 +00001210
Harald Weltebed35df2011-11-02 13:06:18 +01001211 if (pingpack->type != 0) {
1212 if (!options.pingquiet)
1213 printf
1214 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1215 len, inet_ntoa(src), pingpack->type,
1216 print_icmptype(pingpack->type), pingpack->code);
1217 return 0;
1218 }
jjako5da68452003-01-28 16:08:47 +00001219
Harald Weltebed35df2011-11-02 13:06:18 +01001220 nreceived++;
1221 if (!options.pingquiet)
1222 printf("%d bytes from %s: icmp_seq=%d", len,
1223 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001224
Harald Weltebed35df2011-11-02 13:06:18 +01001225 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1226 gettimeofday(&tv, &tz);
1227 tp = (struct timeval *)pingpack->data;
1228 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1229 tv.tv_sec--;
1230 tv.tv_usec += 1000000;
1231 }
1232 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001233
Harald Weltebed35df2011-11-02 13:06:18 +01001234 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1235 tsum += triptime;
1236 if (triptime < tmin)
1237 tmin = triptime;
1238 if (triptime > tmax)
1239 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 if (!options.pingquiet)
1242 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001243
Harald Weltebed35df2011-11-02 13:06:18 +01001244 } else if (!options.pingquiet)
1245 printf("\n");
1246 return 0;
jjako5da68452003-01-28 16:08:47 +00001247}
1248
1249/* Create a new ping packet and send it off to peer. */
1250int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001251 struct in_addr *dst, int seq, unsigned int datasize)
1252{
jjako5da68452003-01-28 16:08:47 +00001253
Harald Weltebed35df2011-11-02 13:06:18 +01001254 struct ip_ping pack;
1255 uint16_t *p = (uint16_t *) & pack;
1256 uint8_t *p8 = (uint8_t *) & pack;
1257 struct in_addr src;
1258 unsigned int n;
1259 long int sum = 0;
1260 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001261
Harald Weltebed35df2011-11-02 13:06:18 +01001262 struct timezone tz;
1263 struct timeval *tp =
1264 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001265
Harald Weltebed35df2011-11-02 13:06:18 +01001266 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001267 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001268 "Ping size to large: %d!", datasize);
1269 return -1;
1270 }
jjako5da68452003-01-28 16:08:47 +00001271
Harald Weltebed35df2011-11-02 13:06:18 +01001272 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001273
Harald Weltebed35df2011-11-02 13:06:18 +01001274 pack.ipver = 0x45;
1275 pack.tos = 0x00;
1276 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1277 pack.fragid = 0x0000;
1278 pack.offset = 0x0040;
1279 pack.ttl = 0x40;
1280 pack.protocol = 0x01;
1281 pack.ipcheck = 0x0000;
1282 pack.src = src.s_addr;
1283 pack.dst = dst->s_addr;
1284 pack.type = 0x08;
1285 pack.code = 0x00;
1286 pack.checksum = 0x0000;
1287 pack.ident = 0x0000;
1288 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001289
Harald Weltebed35df2011-11-02 13:06:18 +01001290 /* Generate ICMP payload */
1291 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1292 for (n = 0; n < (datasize); n++)
1293 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001294
Harald Weltebed35df2011-11-02 13:06:18 +01001295 if (datasize >= sizeof(struct timeval))
1296 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001297
Harald Weltebed35df2011-11-02 13:06:18 +01001298 /* Calculate IP header checksum */
1299 p = (uint16_t *) & pack;
1300 count = CREATEPING_IP;
1301 sum = 0;
1302 while (count > 1) {
1303 sum += *p++;
1304 count -= 2;
1305 }
1306 while (sum >> 16)
1307 sum = (sum & 0xffff) + (sum >> 16);
1308 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001309
Harald Weltebed35df2011-11-02 13:06:18 +01001310 /* Calculate ICMP checksum */
1311 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1312 sum = 0;
1313 p = (uint16_t *) & pack;
1314 p += CREATEPING_IP / 2;
1315 while (count > 1) {
1316 sum += *p++;
1317 count -= 2;
1318 }
1319 if (count > 0)
1320 sum += *(unsigned char *)p;
1321 while (sum >> 16)
1322 sum = (sum & 0xffff) + (sum >> 16);
1323 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001324
Harald Weltebed35df2011-11-02 13:06:18 +01001325 ntransmitted++;
1326 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001327}
1328
Harald Weltebed35df2011-11-02 13:06:18 +01001329int delete_context(struct pdp_t *pdp)
1330{
1331
1332 if (tun && options.ipdown)
1333 tun_runscript(tun, options.ipdown);
1334
1335 ipdel((struct iphash_t *)pdp->peer);
1336 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1337
1338 if (1 == options.contexts)
1339 state = 5; /* Disconnected */
1340
1341 return 0;
1342}
jjakoa7cd2492003-04-11 09:40:12 +00001343
Harald Welte6748dc92017-09-24 21:54:59 +08001344/* Link-Local address prefix fe80::/64 */
1345static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1346
jjakoa7cd2492003-04-11 09:40:12 +00001347/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001348int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1349{
1350 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001351 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001352 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001353 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001354
Harald Welte6748dc92017-09-24 21:54:59 +08001355 if (iph->version == 4) {
1356 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1357 printf("Dropping packet with too short IP header\n");
1358 return 0;
1359 }
1360 src.len = 4;
1361 src.v4.s_addr = iph->saddr;
1362 } else if (iph->version == 6) {
1363 /* We only have a single entry in the hash table, and it consists of the link-local
1364 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1365 * addresses to that format before looking up the hash table via ippool_getip() */
1366 src.len = 16;
1367 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1368 /* is a link-local address, we can do the hash lookup 1:1 */
1369 src.v6 = ip6h->ip6_src;
1370 } else {
1371 /* it is not a link-local address, so we must convert from the /64 prefix
1372 * to the link-local format that's used in the hash table */
1373 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1374 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1375 }
1376 } else {
1377 printf("Dropping packet with invalid IP version %u\n", iph->version);
1378 return 0;
1379 }
jjakoa7cd2492003-04-11 09:40:12 +00001380
Harald Weltebed35df2011-11-02 13:06:18 +01001381 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001382 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001383 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001384 return 0;
1385 }
1386
1387 if (ipm->pdp) /* Check if a peer protocol is defined */
1388 gtp_data_req(gsn, ipm->pdp, pack, len);
1389 return 0;
jjako52c24142002-12-16 13:33:51 +00001390}
1391
Harald Weltebed35df2011-11-02 13:06:18 +01001392int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1393{
Harald Welted12eab92017-08-02 19:49:47 +02001394 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001395
Harald Weltebed35df2011-11-02 13:06:18 +01001396 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001397
Harald Weltebed35df2011-11-02 13:06:18 +01001398 if (cause < 0) {
1399 printf("Create PDP Context Request timed out\n");
1400 if (iph->pdp->version == 1) {
1401 printf("Retrying with version 0\n");
1402 iph->pdp->version = 0;
1403 gtp_create_context_req(gsn, iph->pdp, iph);
1404 return 0;
1405 } else {
1406 state = 0;
1407 pdp_freepdp(iph->pdp);
1408 iph->pdp = NULL;
1409 return EOF;
1410 }
1411 }
jjako2c381332003-10-21 19:09:53 +00001412
Harald Weltebed35df2011-11-02 13:06:18 +01001413 if (cause != 128) {
1414 printf
1415 ("Received create PDP context response. Cause value: %d\n",
1416 cause);
1417 state = 0;
1418 pdp_freepdp(iph->pdp);
1419 iph->pdp = NULL;
1420 return EOF; /* Not what we expected */
1421 }
jjako52c24142002-12-16 13:33:51 +00001422
Harald Weltea0d281d2017-08-02 21:48:16 +02001423 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001424 printf
1425 ("Received create PDP context response. Cause value: %d\n",
1426 cause);
1427 pdp_freepdp(iph->pdp);
1428 iph->pdp = NULL;
1429 state = 0;
1430 return EOF; /* Not a valid IP address */
1431 }
jjakoa7cd2492003-04-11 09:40:12 +00001432
Harald Weltebed35df2011-11-02 13:06:18 +01001433 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001434 in46a_ntoa(&addr));
1435
1436 switch (addr.len) {
1437 case 16: /* IPv6 */
1438 /* we have to enable the kernel to perform stateless autoconfiguration,
1439 * i.e. send a router solicitation using the lover 64bits of the allocated
1440 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1441 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1442 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1443 break;
1444 case 4: /* IPv4 */
1445 break;
1446 }
jjakoa7cd2492003-04-11 09:40:12 +00001447
Harald Weltebed35df2011-11-02 13:06:18 +01001448 if ((options.createif) && (!options.net.s_addr)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001449 size_t prefixlen = 32;
1450 if (addr.len == 16)
1451 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001452 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001453 /* FIXME: use tun_addattr() not tun_setaddr() */
1454 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001455 if (options.defaultroute) {
1456 struct in_addr rm;
1457 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001458 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001459 }
1460 if (options.ipup)
1461 tun_runscript(tun, options.ipup);
1462 }
jjako52c24142002-12-16 13:33:51 +00001463
Harald Welte081f30c2017-10-10 09:36:35 +08001464 /* now that ip-up has been executed, check if we are configured to
1465 * accept router advertisements */
1466 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1467 char *accept_ra, *forwarding;
1468
1469 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1470 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1471 if (!accept_ra || !forwarding)
1472 printf("Could not open proc file for %s ?!?\n", tun->devname);
1473 else {
1474 if (!strcmp(accept_ra, "0") ||
1475 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1476 printf("%s is %s, i.e. your tun device is not configured to accept "
1477 "router advertisements; SLAAC will not suceed, please "
1478 "fix your setup!\n");
1479 }
1480 free(accept_ra);
1481 free(forwarding);
1482 }
1483 }
1484
Harald Weltebed35df2011-11-02 13:06:18 +01001485 ipset((struct iphash_t *)pdp->peer, &addr);
1486
1487 state = 2; /* Connected */
1488
1489 return 0;
jjako52c24142002-12-16 13:33:51 +00001490}
1491
Harald Weltebed35df2011-11-02 13:06:18 +01001492int delete_pdp_conf(struct pdp_t *pdp, int cause)
1493{
1494 printf("Received delete PDP context response. Cause value: %d\n",
1495 cause);
1496 return 0;
jjako52c24142002-12-16 13:33:51 +00001497}
1498
Harald Weltebed35df2011-11-02 13:06:18 +01001499int echo_conf(int recovery)
1500{
jjako91aaf222003-10-22 10:09:32 +00001501
Harald Weltebed35df2011-11-02 13:06:18 +01001502 if (recovery < 0) {
1503 printf("Echo Request timed out\n");
1504 if (echoversion == 1) {
1505 printf("Retrying with version 0\n");
1506 echoversion = 0;
1507 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1508 return 0;
1509 } else {
1510 state = 0;
1511 return EOF;
1512 }
1513 } else {
1514 printf("Received echo response\n");
1515 if (!options.contexts)
1516 state = 5;
1517 }
1518 return 0;
jjako52c24142002-12-16 13:33:51 +00001519}
1520
Harald Weltebed35df2011-11-02 13:06:18 +01001521int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1522{
1523 /* if (cause < 0) return 0; Some error occurred. We don't care */
1524 switch (type) {
1525 case GTP_ECHO_REQ:
1526 return echo_conf(cause);
1527 case GTP_CREATE_PDP_REQ:
1528 return create_pdp_conf(pdp, cbp, cause);
1529 case GTP_DELETE_PDP_REQ:
1530 if (cause != 128)
1531 return 0; /* Request not accepted. We don't care */
1532 return delete_pdp_conf(pdp, cause);
1533 default:
1534 return 0;
1535 }
jjako52c24142002-12-16 13:33:51 +00001536}
1537
Harald Weltebed35df2011-11-02 13:06:18 +01001538int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1539{
1540 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1541 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001542}
1543
1544int main(int argc, char **argv)
1545{
Harald Weltebed35df2011-11-02 13:06:18 +01001546 fd_set fds; /* For select() */
1547 struct timeval idleTime; /* How long to select() */
1548 struct pdp_t *pdp;
1549 int n;
1550 int starttime = time(NULL); /* Time program was started */
1551 int stoptime = 0; /* Time to exit */
1552 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001553 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001554
Harald Weltebed35df2011-11-02 13:06:18 +01001555 struct timezone tz; /* Used for calculating ping times */
1556 struct timeval tv;
1557 int diff;
jjako52c24142002-12-16 13:33:51 +00001558
bjovana8f71eb2017-02-24 17:39:20 +01001559 signal(SIGTERM, signal_handler);
1560 signal(SIGHUP, signal_handler);
1561 signal(SIGINT, signal_handler);
1562
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001563 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001564
Harald Weltebed35df2011-11-02 13:06:18 +01001565 /* Process options given in configuration file and command line */
1566 if (process_options(argc, argv))
1567 exit(1);
jjako52c24142002-12-16 13:33:51 +00001568
Harald Weltebed35df2011-11-02 13:06:18 +01001569 printf("\nInitialising GTP library\n");
1570 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001571 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001572 exit(1);
1573 }
1574 if (gsn->fd0 > maxfd)
1575 maxfd = gsn->fd0;
1576 if (gsn->fd1c > maxfd)
1577 maxfd = gsn->fd1c;
1578 if (gsn->fd1u > maxfd)
1579 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001580
Harald Weltebed35df2011-11-02 13:06:18 +01001581 gtp_set_cb_delete_context(gsn, delete_context);
1582 gtp_set_cb_conf(gsn, conf);
1583 if (options.createif)
1584 gtp_set_cb_data_ind(gsn, encaps_tun);
1585 else
1586 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001587
Harald Weltebed35df2011-11-02 13:06:18 +01001588 if (options.createif) {
1589 printf("Setting up interface\n");
1590 /* Create a tunnel interface */
Harald Welte73abc382017-10-10 08:50:11 +08001591 if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001592 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001593 "Failed to create tun");
1594 exit(1);
1595 }
1596 tun_set_cb_ind(tun, cb_tun_ind);
1597 if (tun->fd > maxfd)
1598 maxfd = tun->fd;
1599 }
jjakoa7cd2492003-04-11 09:40:12 +00001600
Harald Weltebed35df2011-11-02 13:06:18 +01001601 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001602 struct in_addr mask;
1603 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001604 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001605 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001606 if (options.defaultroute) {
1607 struct in_addr rm;
1608 rm.s_addr = 0;
1609 tun_addroute(tun, &rm, &options.destaddr, &rm);
1610 }
1611 if (options.ipup)
1612 tun_runscript(tun, options.ipup);
1613 }
jjakoa7cd2492003-04-11 09:40:12 +00001614
Harald Weltebed35df2011-11-02 13:06:18 +01001615 /* Initialise hash tables */
1616 memset(&iphash, 0, sizeof(iphash));
1617 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001618
Harald Weltebed35df2011-11-02 13:06:18 +01001619 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001620
Harald Weltebed35df2011-11-02 13:06:18 +01001621 /* See if anybody is there */
1622 printf("Sending off echo request\n");
1623 echoversion = options.gtpversion;
1624 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001625
Harald Weltebed35df2011-11-02 13:06:18 +01001626 for (n = 0; n < options.contexts; n++) {
1627 uint64_t myimsi;
1628 printf("Setting up PDP context #%d\n", n);
1629 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001632
Harald Weltebed35df2011-11-02 13:06:18 +01001633 /* Allocated here. */
1634 /* If create context failes we have to deallocate ourselves. */
1635 /* Otherwise it is deallocated by gtplib */
1636 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001637
Harald Weltebed35df2011-11-02 13:06:18 +01001638 pdp->peer = &iparr[n];
1639 pdp->ipif = tun; /* TODO */
1640 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001641
Harald Weltebed35df2011-11-02 13:06:18 +01001642 if (options.gtpversion == 0) {
1643 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001644 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001645 "QoS length too big");
1646 exit(1);
1647 } else {
1648 memcpy(pdp->qos_req0, options.qos.v,
1649 options.qos.l);
1650 }
1651 }
jjakoa7cd2492003-04-11 09:40:12 +00001652
Harald Weltebed35df2011-11-02 13:06:18 +01001653 pdp->qos_req.l = options.qos.l;
1654 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001655
Harald Weltebed35df2011-11-02 13:06:18 +01001656 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001657
Harald Weltebed35df2011-11-02 13:06:18 +01001658 pdp->rattype.l = options.rattype.l;
1659 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1660 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001661
Harald Weltebed35df2011-11-02 13:06:18 +01001662 pdp->userloc.l = options.userloc.l;
1663 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1664 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001665
Harald Weltebed35df2011-11-02 13:06:18 +01001666 pdp->rai.l = options.rai.l;
1667 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1668 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001669
Harald Weltebed35df2011-11-02 13:06:18 +01001670 pdp->mstz.l = options.mstz.l;
1671 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1672 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001673
Harald Weltebed35df2011-11-02 13:06:18 +01001674 pdp->imeisv.l = options.imeisv.l;
1675 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1676 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001677
Harald Weltebed35df2011-11-02 13:06:18 +01001678 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001679
Harald Weltebed35df2011-11-02 13:06:18 +01001680 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001681 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001682 "APN length too big");
1683 exit(1);
1684 } else {
1685 pdp->apn_use.l = options.apn.l;
1686 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1687 }
jjako193e8b12003-11-10 12:31:41 +00001688
Harald Weltebed35df2011-11-02 13:06:18 +01001689 pdp->gsnlc.l = sizeof(options.listen);
1690 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1691 pdp->gsnlu.l = sizeof(options.listen);
1692 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001693
Harald Weltebed35df2011-11-02 13:06:18 +01001694 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001695 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001696 "MSISDN length too big");
1697 exit(1);
1698 } else {
1699 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1700 }
jjakob62c3dd2004-05-27 18:51:55 +00001701
Harald Welte840a8e92017-09-24 18:12:40 +08001702 /* Request dynamic IP address */
1703 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1704 pdp->eua.v[1] = options.pdp_type;
1705 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001706
Harald Weltebed35df2011-11-02 13:06:18 +01001707 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001708 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001709 "PCO length too big");
1710 exit(1);
1711 } else {
1712 pdp->pco_req.l = options.pco.l;
1713 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1714 }
jjako52c24142002-12-16 13:33:51 +00001715
Harald Weltebed35df2011-11-02 13:06:18 +01001716 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001717
Harald Weltebed35df2011-11-02 13:06:18 +01001718 pdp->hisaddr0 = options.remote;
1719 pdp->hisaddr1 = options.remote;
1720
1721 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1722 512 = Flat rate, 256 = Hot billing */
1723
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001724 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1725
Harald Weltebed35df2011-11-02 13:06:18 +01001726 /* Create context */
1727 /* We send this of once. Retransmissions are handled by gtplib */
1728 gtp_create_context_req(gsn, pdp, &iparr[n]);
1729 }
1730
1731 state = 1; /* Enter wait_connection state */
1732
1733 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001734
jjako52c24142002-12-16 13:33:51 +00001735 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001736 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001737 /******************************************************************/
1738
Harald Weltebed35df2011-11-02 13:06:18 +01001739 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001740
Harald Weltebed35df2011-11-02 13:06:18 +01001741 /* Take down client after timeout after disconnect */
1742 if ((4 == state) && ((stoptime) <= time(NULL))) {
1743 state = 5;
1744 }
jjako7b8fad42003-07-07 14:37:42 +00001745
Harald Weltebed35df2011-11-02 13:06:18 +01001746 /* Take down client after timelimit timeout */
1747 if ((2 == state) && (options.timelimit) &&
1748 ((starttime + options.timelimit) <= time(NULL))) {
1749 state = 3;
1750 }
jjako7b8fad42003-07-07 14:37:42 +00001751
Harald Weltebed35df2011-11-02 13:06:18 +01001752 /* Take down client after ping timeout */
1753 if ((2 == state) && (pingtimeout)
1754 && (pingtimeout <= time(NULL))) {
1755 state = 3;
1756 }
jjako7b8fad42003-07-07 14:37:42 +00001757
Harald Weltebed35df2011-11-02 13:06:18 +01001758 /* Set pingtimeout for later disconnection */
1759 if (options.pingcount && ntransmitted >= options.pingcount) {
1760 pingtimeout = time(NULL) + 5; /* Extra seconds */
1761 }
jjako7b8fad42003-07-07 14:37:42 +00001762
Harald Weltebed35df2011-11-02 13:06:18 +01001763 /* Print statistics if no more ping packets are missing */
1764 if (ntransmitted && options.pingcount
1765 && nreceived >= options.pingcount) {
1766 ping_finish();
1767 if (!options.createif)
1768 state = 3;
1769 }
jjako7b8fad42003-07-07 14:37:42 +00001770
Harald Weltebed35df2011-11-02 13:06:18 +01001771 /* Send off disconnect */
1772 if (3 == state) {
1773 state = 4;
1774 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1775 for (n = 0; n < options.contexts; n++) {
1776 /* Delete context */
1777 printf("Disconnecting PDP context #%d\n", n);
1778 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1779 1);
1780 if ((options.pinghost.s_addr != 0)
1781 && ntransmitted)
1782 ping_finish();
1783 }
1784 }
jjako7b8fad42003-07-07 14:37:42 +00001785
Harald Weltebed35df2011-11-02 13:06:18 +01001786 /* Send of ping packets */
1787 diff = 0;
1788 while ((diff <= 0) &&
1789 /* Send off an ICMP ping packet */
1790 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1791 ((pingseq < options.pingcount)
1792 || (options.pingcount == 0))) {
1793 if (!pingseq)
1794 gettimeofday(&firstping, &tz); /* Set time of first ping */
1795 gettimeofday(&tv, &tz);
1796 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1797 if (diff <= 0) {
1798 if (options.debug)
1799 printf("Create_ping %d\n", diff);
1800 create_ping(gsn,
1801 iparr[pingseq %
1802 options.contexts].pdp,
1803 &options.pinghost, pingseq,
1804 options.pingsize);
1805 pingseq++;
1806 }
1807 }
jjako5da68452003-01-28 16:08:47 +00001808
Harald Weltebed35df2011-11-02 13:06:18 +01001809 FD_ZERO(&fds);
1810 if (tun)
1811 FD_SET(tun->fd, &fds);
1812 FD_SET(gsn->fd0, &fds);
1813 FD_SET(gsn->fd1c, &fds);
1814 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001815
Harald Weltebed35df2011-11-02 13:06:18 +01001816 gtp_retranstimeout(gsn, &idleTime);
1817 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001818
Harald Weltebed35df2011-11-02 13:06:18 +01001819 if (options.debug)
1820 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1821 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001822
bjovana8f71eb2017-02-24 17:39:20 +01001823 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001824 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1825 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001826 if (errno == EINTR)
1827 signal_received = 1;
1828 else
1829 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1830 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001831 break;
1832 case 0:
1833 gtp_retrans(gsn); /* Only retransmit if nothing else */
1834 break;
1835 default:
1836 break;
1837 }
1838
bjovana8f71eb2017-02-24 17:39:20 +01001839 if (!signal_received) {
1840
1841 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1842 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1843 "TUN decaps failed");
1844 }
1845
1846 if (FD_ISSET(gsn->fd0, &fds))
1847 gtp_decaps0(gsn);
1848
1849 if (FD_ISSET(gsn->fd1c, &fds))
1850 gtp_decaps1c(gsn);
1851
1852 if (FD_ISSET(gsn->fd1u, &fds))
1853 gtp_decaps1u(gsn);
1854
Harald Weltebed35df2011-11-02 13:06:18 +01001855 }
Harald Weltebed35df2011-11-02 13:06:18 +01001856 }
1857
1858 gtp_free(gsn); /* Clean up the gsn instance */
1859
1860 if (options.createif)
1861 tun_free(tun);
1862
1863 if (0 == state)
1864 exit(1); /* Indicate error */
1865
1866 return 0;
jjako52c24142002-12-16 13:33:51 +00001867}