blob: fa295da2a17d774e2a63259c15f04accf1505f2e [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 Welted12eab92017-08-02 19:49:47 +020087 struct in_addr netaddr, destaddr, net; /* Network interface */
88 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010089 char *ipup, *ipdown; /* Filename of scripts */
90 int defaultroute; /* Set up default route */
91 struct in_addr pinghost; /* Remote ping host */
92 int pingrate;
93 int pingsize;
94 int pingcount;
95 int pingquiet;
96 struct in_addr listen;
97 struct in_addr remote;
98 struct in_addr dns;
99 int contexts; /* Number of contexts to create */
100 int timelimit; /* Number of seconds to be connected */
101 char *statedir;
102 uint64_t imsi;
103 uint8_t nsapi;
104 int gtpversion;
105 struct ul255_t pco;
106 struct ul255_t qos;
107 uint16_t cch;
108 struct ul255_t apn;
109 uint8_t selmode;
110 struct ul255_t rattype;
111 int rattype_given;
112 struct ul255_t userloc;
113 int userloc_given;
114 struct ul255_t rai;
115 int rai_given;
116 struct ul255_t mstz;
117 int mstz_given;
118 struct ul255_t imeisv;
119 int imeisv_given;
120 struct ul16_t msisdn;
121 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800122 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800123 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000124} options;
jjako52c24142002-12-16 13:33:51 +0000125
jjako5da68452003-01-28 16:08:47 +0000126/* Definitions to use for PING. Most of the ping code was derived from */
127/* the original ping program by Mike Muuss */
128
129/* IP header and ICMP echo header */
130#define CREATEPING_MAX 2048
131#define CREATEPING_IP 20
132#define CREATEPING_ICMP 8
133
134struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100135 uint8_t ipver; /* Type and header length */
136 uint8_t tos; /* Type of Service */
137 uint16_t length; /* Total length */
138 uint16_t fragid; /* Identifier */
139 uint16_t offset; /* Flags and fragment offset */
140 uint8_t ttl; /* Time to live */
141 uint8_t protocol; /* Protocol */
142 uint16_t ipcheck; /* Header checksum */
143 uint32_t src; /* Source address */
144 uint32_t dst; /* Destination */
145 uint8_t type; /* Type and header length */
146 uint8_t code; /* Code */
147 uint16_t checksum; /* Header checksum */
148 uint16_t ident; /* Identifier */
149 uint16_t seq; /* Sequence number */
150 uint8_t data[CREATEPING_MAX]; /* Data */
151} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000152
153/* Statistical values for ping */
154int nreceived = 0;
155int ntreceived = 0;
156int ntransmitted = 0;
157int tmin = 999999999;
158int tmax = 0;
159int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100160int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000161struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000162
bjovana8f71eb2017-02-24 17:39:20 +0100163void signal_handler(int signo)
164{
165 if (state == 2)
166 state = 3; /* Tell main loop to finish. */
167}
168
Harald Welted12eab92017-08-02 19:49:47 +0200169int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100170{
Harald Welted12eab92017-08-02 19:49:47 +0200171 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100172 struct iphash_t *h;
173 struct iphash_t *prev = NULL;
174 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200175 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100176 for (h = iphash[hash]; h; h = h->ipnext)
177 prev = h;
178 if (!prev)
179 iphash[hash] = ipaddr;
180 else
181 prev->ipnext = ipaddr;
182 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000183}
184
Harald Weltebed35df2011-11-02 13:06:18 +0100185int ipdel(struct iphash_t *ipaddr)
186{
Harald Welted12eab92017-08-02 19:49:47 +0200187 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100188 struct iphash_t *h;
189 struct iphash_t *prev = NULL;
190 for (h = iphash[hash]; h; h = h->ipnext) {
191 if (h == ipaddr) {
192 if (!prev)
193 iphash[hash] = h->ipnext;
194 else
195 prev->ipnext = h->ipnext;
196 return 0;
197 }
198 prev = h;
199 }
200 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000201}
202
Harald Welted12eab92017-08-02 19:49:47 +0200203int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100204{
Harald Welted12eab92017-08-02 19:49:47 +0200205 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100206 struct iphash_t *h;
207 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200208 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100209 *ipaddr = h;
210 return 0;
211 }
212 }
213 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000214}
215
jjakoa7cd2492003-04-11 09:40:12 +0000216/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100217void log_pid(char *pidfile)
218{
219 FILE *file;
220 mode_t oldmask;
221
222 oldmask = umask(022);
223 file = fopen(pidfile, "w");
224 umask(oldmask);
225 if (!file)
226 return;
227 fprintf(file, "%d\n", (int)getpid());
228 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000229}
230
Harald Weltebed35df2011-11-02 13:06:18 +0100231int process_options(int argc, char **argv)
232{
233 /* gengeopt declarations */
234 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000235
Harald Weltebed35df2011-11-02 13:06:18 +0100236 struct hostent *host;
237 unsigned int n;
238 uint16_t i;
239 uint8_t a;
240 uint8_t b;
241 char *tmp;
242 char *pch;
243 char *type;
244 char *mcc;
245 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100246 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100247 char *lac;
248 int lac_d;
249 char *rest;
250 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
251 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
252 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
253 int sign;
254 int nbquarters;
255 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000256
Harald Weltebed35df2011-11-02 13:06:18 +0100257 if (cmdline_parser(argc, argv, &args_info) != 0)
258 return -1;
259 if (args_info.debug_flag) {
260 if (args_info.remote_arg)
261 printf("remote: %s\n", args_info.remote_arg);
262 if (args_info.listen_arg)
263 printf("listen: %s\n", args_info.listen_arg);
264 if (args_info.conf_arg)
265 printf("conf: %s\n", args_info.conf_arg);
266 printf("debug: %d\n", args_info.debug_flag);
267 if (args_info.imsi_arg)
268 printf("imsi: %s\n", args_info.imsi_arg);
269 printf("qos: %#08x\n", args_info.qos_arg);
270 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
271 printf("qose2: %#04x\n", args_info.qose2_arg);
272 printf("qose3: %#06x\n", args_info.qose3_arg);
273 printf("qose4: %#06x\n", args_info.qose4_arg);
274 printf("charging: %#04x\n", args_info.charging_arg);
275 if (args_info.apn_arg)
276 printf("apn: %s\n", args_info.apn_arg);
277 if (args_info.msisdn_arg)
278 printf("msisdn: %s\n", args_info.msisdn_arg);
279 if (args_info.uid_arg)
280 printf("uid: %s\n", args_info.uid_arg);
281 if (args_info.pwd_arg)
282 printf("pwd: %s\n", args_info.pwd_arg);
283 if (args_info.pidfile_arg)
284 printf("pidfile: %s\n", args_info.pidfile_arg);
285 if (args_info.statedir_arg)
286 printf("statedir: %s\n", args_info.statedir_arg);
287 if (args_info.dns_arg)
288 printf("dns: %s\n", args_info.dns_arg);
289 printf("contexts: %d\n", args_info.contexts_arg);
290 printf("timelimit: %d\n", args_info.timelimit_arg);
291 printf("createif: %d\n", args_info.createif_flag);
292 if (args_info.ipup_arg)
293 printf("ipup: %s\n", args_info.ipup_arg);
294 if (args_info.ipdown_arg)
295 printf("ipdown: %s\n", args_info.ipdown_arg);
296 printf("defaultroute: %d\n", args_info.defaultroute_flag);
297 if (args_info.pinghost_arg)
298 printf("pinghost: %s\n", args_info.pinghost_arg);
299 printf("pingrate: %d\n", args_info.pingrate_arg);
300 printf("pingsize: %d\n", args_info.pingsize_arg);
301 printf("pingcount: %d\n", args_info.pingcount_arg);
302 printf("pingquiet: %d\n", args_info.pingquiet_flag);
303 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800304 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100305 }
jjakoa7cd2492003-04-11 09:40:12 +0000306
Harald Weltebed35df2011-11-02 13:06:18 +0100307 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000308
Harald Weltebed35df2011-11-02 13:06:18 +0100309 if (args_info.conf_arg) {
310 if (cmdline_parser_configfile
311 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
312 return -1;
313 if (args_info.debug_flag) {
314 printf("cmdline_parser_configfile\n");
315 if (args_info.remote_arg)
316 printf("remote: %s\n", args_info.remote_arg);
317 if (args_info.listen_arg)
318 printf("listen: %s\n", args_info.listen_arg);
319 if (args_info.conf_arg)
320 printf("conf: %s\n", args_info.conf_arg);
321 printf("debug: %d\n", args_info.debug_flag);
322 if (args_info.imsi_arg)
323 printf("imsi: %s\n", args_info.imsi_arg);
324 printf("qos: %#08x\n", args_info.qos_arg);
325 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
326 printf("qose2: %#04x\n", args_info.qose2_arg);
327 printf("qose3: %#06x\n", args_info.qose3_arg);
328 printf("qose4: %#06x\n", args_info.qose4_arg);
329 printf("charging: %#04x\n", args_info.charging_arg);
330 if (args_info.apn_arg)
331 printf("apn: %s\n", args_info.apn_arg);
332 if (args_info.msisdn_arg)
333 printf("msisdn: %s\n", args_info.msisdn_arg);
334 if (args_info.uid_arg)
335 printf("uid: %s\n", args_info.uid_arg);
336 if (args_info.pwd_arg)
337 printf("pwd: %s\n", args_info.pwd_arg);
338 if (args_info.pidfile_arg)
339 printf("pidfile: %s\n", args_info.pidfile_arg);
340 if (args_info.statedir_arg)
341 printf("statedir: %s\n",
342 args_info.statedir_arg);
343 if (args_info.dns_arg)
344 printf("dns: %s\n", args_info.dns_arg);
345 printf("contexts: %d\n", args_info.contexts_arg);
346 printf("timelimit: %d\n", args_info.timelimit_arg);
347 printf("createif: %d\n", args_info.createif_flag);
348 if (args_info.ipup_arg)
349 printf("ipup: %s\n", args_info.ipup_arg);
350 if (args_info.ipdown_arg)
351 printf("ipdown: %s\n", args_info.ipdown_arg);
352 printf("defaultroute: %d\n",
353 args_info.defaultroute_flag);
354 if (args_info.pinghost_arg)
355 printf("pinghost: %s\n",
356 args_info.pinghost_arg);
357 printf("pingrate: %d\n", args_info.pingrate_arg);
358 printf("pingsize: %d\n", args_info.pingsize_arg);
359 printf("pingcount: %d\n", args_info.pingcount_arg);
360 printf("pingquiet: %d\n", args_info.pingquiet_flag);
361 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800362 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100363 }
364 }
jjako193e8b12003-11-10 12:31:41 +0000365
Harald Weltebed35df2011-11-02 13:06:18 +0100366 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000367
Harald Weltebed35df2011-11-02 13:06:18 +0100368 /* foreground */
369 /* If fg flag not given run as a daemon */
370 /* Do not allow sgsnemu to run as deamon
371 if (!args_info.fg_flag)
372 {
373 closelog();
374 freopen("/dev/null", "w", stdout);
375 freopen("/dev/null", "w", stderr);
376 freopen("/dev/null", "r", stdin);
377 daemon(0, 0);
378 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
379 } */
jjako1a51df72004-07-20 08:30:21 +0000380
Harald Weltebed35df2011-11-02 13:06:18 +0100381 /* debug */
382 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000383
Harald Weltebed35df2011-11-02 13:06:18 +0100384 /* pidfile */
385 /* This has to be done after we have our final pid */
386 if (args_info.pidfile_arg) {
387 log_pid(args_info.pidfile_arg);
388 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200389
Harald Weltebed35df2011-11-02 13:06:18 +0100390 /* dns */
391 /* If no dns option is given use system default */
392 /* Do hostname lookup to translate hostname to IP address */
393 printf("\n");
394 if (args_info.dns_arg) {
395 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100396 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100397 "Invalid DNS address: %s!", args_info.dns_arg);
398 return -1;
399 } else {
400 memcpy(&options.dns.s_addr, host->h_addr,
401 host->h_length);
402 _res.nscount = 1;
403 _res.nsaddr_list[0].sin_addr = options.dns;
404 printf("Using DNS server: %s (%s)\n",
405 args_info.dns_arg, inet_ntoa(options.dns));
406 }
407 } else {
408 options.dns.s_addr = 0;
409 printf("Using default DNS server\n");
410 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200411
Harald Weltebed35df2011-11-02 13:06:18 +0100412 /* listen */
413 /* If no listen option is specified listen to any local port */
414 /* Do hostname lookup to translate hostname to IP address */
415 if (args_info.listen_arg) {
416 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100417 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100418 "Invalid listening address: %s!",
419 args_info.listen_arg);
420 return -1;
421 } else {
422 memcpy(&options.listen.s_addr, host->h_addr,
423 host->h_length);
424 printf("Local IP address is: %s (%s)\n",
425 args_info.listen_arg, inet_ntoa(options.listen));
426 }
427 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100428 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100429 "Listening address must be specified: %s!",
430 args_info.listen_arg);
431 return -1;
432 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200433
Harald Weltebed35df2011-11-02 13:06:18 +0100434 /* remote */
435 /* If no remote option is specified terminate */
436 /* Do hostname lookup to translate hostname to IP address */
437 if (args_info.remote_arg) {
438 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100439 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100440 "Invalid remote address: %s!",
441 args_info.remote_arg);
442 return -1;
443 } else {
444 memcpy(&options.remote.s_addr, host->h_addr,
445 host->h_length);
446 printf("Remote IP address is: %s (%s)\n",
447 args_info.remote_arg, inet_ntoa(options.remote));
448 }
449 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100450 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100451 "No remote address given!");
452 return -1;
453 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200454
Harald Weltebed35df2011-11-02 13:06:18 +0100455 /* imsi */
456 if (strlen(args_info.imsi_arg) != 15) {
457 printf("Invalid IMSI\n");
458 return -1;
459 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200460
Harald Weltebed35df2011-11-02 13:06:18 +0100461 options.imsi = 0xf000000000000000ull;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
463 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
464 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
465 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
466 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
474 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
475 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
476 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200477
Harald Weltebed35df2011-11-02 13:06:18 +0100478 printf("IMSI is: %s (%#08llx)\n",
479 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200480
Harald Weltebed35df2011-11-02 13:06:18 +0100481 /* nsapi */
482 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
483 printf("Invalid NSAPI\n");
484 return -1;
485 }
486 options.nsapi = args_info.nsapi_arg;
487 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200488
Harald Weltebed35df2011-11-02 13:06:18 +0100489 /* qos */
490 options.qos.l = 4;
491 options.qos.v[3] = (args_info.qos_arg) & 0xff;
492 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
493 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
494 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
495 /* Extensions according to 3GPP TS 24.008 */
496 if (args_info.qose1_given == 1) {
497 options.qos.l = 12;
498 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
499 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
500 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
501 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
502 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
503 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
504 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
505 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
506 if (args_info.qose2_given == 1) {
507 options.qos.l = 13;
508 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
509 if (args_info.qose3_given == 1) {
510 options.qos.l = 15;
511 options.qos.v[14] =
512 (args_info.qose3_arg) & 0xff;
513 options.qos.v[13] =
514 ((args_info.qose3_arg) >> 8) & 0xff;
515 if (args_info.qose4_given == 1) {
516 options.qos.l = 17;
517 options.qos.v[16] =
518 (args_info.qose4_arg) & 0xff;
519 options.qos.v[15] =
520 ((args_info.qose4_arg) >> 8) & 0xff;
521 }
522 }
523 }
524 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200525
Harald Weltebed35df2011-11-02 13:06:18 +0100526 /* charging */
527 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200528
Harald Weltebed35df2011-11-02 13:06:18 +0100529 /* contexts */
530 if (args_info.contexts_arg > MAXCONTEXTS) {
531 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
532 return -1;
533 }
534 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200535
Harald Weltebed35df2011-11-02 13:06:18 +0100536 /* Timelimit */
537 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200538
Harald Weltebed35df2011-11-02 13:06:18 +0100539 /* gtpversion */
540 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
541 printf("Invalid GTP version\n");
542 return -1;
543 }
544 options.gtpversion = args_info.gtpversion_arg;
545 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200546
Harald Weltebed35df2011-11-02 13:06:18 +0100547 /* apn */
548 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
549 printf("Invalid APN\n");
550 return -1;
551 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100552 options.apn.l = strlen(args_info.apn_arg) + 1;
553
554 apn = (char *)options.apn.v;
555 for (tok = strtok(args_info.apn_arg, ".");
556 tok != NULL;
557 tok = strtok(NULL, ".")) {
558 size_t len = strlen(tok);
559
560 *apn++ = (char)len;
561 strncpy(apn, tok, len);
562 apn += len;
563 }
564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200566
Harald Weltebed35df2011-11-02 13:06:18 +0100567 /* selmode */
568 options.selmode = args_info.selmode_arg;
569 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200570
Harald Weltebed35df2011-11-02 13:06:18 +0100571 /* rattype */
572 if (args_info.rattype_given == 1) {
573 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800574 options.rattype.l = 1;
575 options.rattype.v[0] = args_info.rattype_arg;
576 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100577 }
Harald Welte41af5692011-10-07 18:42:34 +0200578
Harald Weltebed35df2011-11-02 13:06:18 +0100579 /* userloc */
580 if (args_info.userloc_given == 1) {
581 printf("Using User Location Information: %s\n",
582 args_info.userloc_arg);
583 tmp = args_info.userloc_arg;
584 n = 0;
585 pch = strtok(tmp, ".");
586 while (pch != NULL) {
587 userloc_el[n] = pch;
588 pch = strtok(NULL, ".");
589 n++;
590 }
Harald Welte41af5692011-10-07 18:42:34 +0200591
Harald Weltebed35df2011-11-02 13:06:18 +0100592 options.userloc_given = 1;
593 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200594
Harald Weltebed35df2011-11-02 13:06:18 +0100595 /* 3GPP Geographic Location Type t0 / t1 / t2 */
596 type = userloc_el[0];
597 printf("->type : %c\n", type[0]);
598 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
599 printf("Invalid type \n");
600 return -1;
601 }
602 /* options.userloc.v[0] = 0x00 */
603 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200604
Harald Weltebed35df2011-11-02 13:06:18 +0100605 /* MCC */
606 mcc = userloc_el[1];
607 printf("->mcc : %s\n", mcc);
608 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200609 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100610 return -1;
611 }
Harald Welte41af5692011-10-07 18:42:34 +0200612
Harald Weltebed35df2011-11-02 13:06:18 +0100613 /* MNC */
614 mnc = userloc_el[2];
615 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200616
Harald Weltebed35df2011-11-02 13:06:18 +0100617 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
618 /* options.userloc.v[1] = 0x52 */
619 a = (uint8_t) (mcc[0] - 48);
620 b = (uint8_t) (mcc[1] - 48);
621 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200622
Harald Weltebed35df2011-11-02 13:06:18 +0100623 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
624 /* options.userloc.v[2] = 0xf0 */
625 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200626
Harald Weltebed35df2011-11-02 13:06:18 +0100627 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200628 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100629 return -1;
630 }
631 if (strlen(mnc) == 2) {
632 b = 15;
633 }
634 if (strlen(mnc) == 3) {
635 b = (uint8_t) (mnc[2] - 48);
636 }
637 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200638
Harald Weltebed35df2011-11-02 13:06:18 +0100639 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
640 /* options.userloc.v[3] = 0x99 */
641 a = (uint8_t) (mnc[0] - 48);
642 b = (uint8_t) (mnc[1] - 48);
643 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200644
Harald Weltebed35df2011-11-02 13:06:18 +0100645 /* LAC */
646 lac = userloc_el[3];
647 /*options.userloc.v[4] = 0x12 ; */
648 /*options.userloc.v[5] = 0x10 ; */
649 printf("->LAC: %s\n", lac);
650 lac_d = atoi(lac);
651 if (lac_d > 65535 || lac_d < 1) {
652 printf("Invalid LAC\n");
653 return -1;
654 }
655 i = lac_d >> 8;
656 options.userloc.v[4] = i; /* octet 8 - LAC */
657 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200658
Harald Weltebed35df2011-11-02 13:06:18 +0100659 /* CI/SAC/RAC */
660 rest = userloc_el[4];
661 printf("->CI/SAC/RAC : %s\n", rest);
662 lac_d = atoi(rest);
663 if (lac_d > 65535 || lac_d < 1) {
664 printf("Invalid CI/SAC/RAC\n");
665 return -1;
666 }
667 /*options.userloc.v[6] = 0x04 ; */
668 /*options.userloc.v[7] = 0xb7 ; */
669 i = lac_d >> 8;
670 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
671 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
672 }
jjakoa7cd2492003-04-11 09:40:12 +0000673
Harald Weltebed35df2011-11-02 13:06:18 +0100674 /* RAI */
675 if (args_info.rai_given == 1) {
676 printf("Using RAI: %s\n", args_info.rai_arg);
677 tmp = args_info.rai_arg;
678 n = 0;
679 pch = strtok(tmp, ".");
680 while (pch != NULL) {
681 rai_el[n] = pch;
682 pch = strtok(NULL, ".");
683 n++;
684 }
jjakoa7cd2492003-04-11 09:40:12 +0000685
Harald Weltebed35df2011-11-02 13:06:18 +0100686 options.rai_given = 1;
687 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000688
Harald Weltebed35df2011-11-02 13:06:18 +0100689 /* MCC */
690 mcc = rai_el[0];
691 printf("->mcc : %s\n", mcc);
692 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200693 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100694 return -1;
695 }
696
697 /* MNC */
698 mnc = rai_el[1];
699 printf("->mnc : %s\n", mnc);
700
701 a = (uint8_t) (mcc[0] - 48);
702 b = (uint8_t) (mcc[1] - 48);
703 options.rai.v[0] = 16 * b + a;
704
705 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
706 a = (uint8_t) (mcc[2] - 48);
707
708 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200709 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100710 return -1;
711 }
712 if (strlen(mnc) == 2) {
713 b = 15;
714 }
715 if (strlen(mnc) == 3) {
716 b = (uint8_t) (mnc[2] - 48);
717 }
718 options.rai.v[1] = 16 * b + a;
719
720 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
721 a = (uint8_t) (mnc[0] - 48);
722 b = (uint8_t) (mnc[1] - 48);
723 options.rai.v[2] = 16 * b + a;
724
725 /* LAC */
726 lac = rai_el[2];
727 printf("->LAC: %s\n", lac);
728 lac_d = atoi(lac);
729 if (lac_d > 65535 || lac_d < 1) {
730 printf("Invalid LAC\n");
731 return -1;
732 }
733 i = lac_d >> 8;
734 options.rai.v[3] = i; /* octet 5 - LAC */
735 options.rai.v[4] = lac_d; /* octet 6 - LAC */
736
737 /* RAC */
738 rest = rai_el[3];
739 printf("->RAC : %s\n", rest);
740 lac_d = atoi(rest);
741 if (lac_d > 255 || lac_d < 1) {
742 printf("Invalid RAC\n");
743 return -1;
744 }
745 options.rai.v[5] = lac_d; /* octet 7 - RAC */
746 }
747
748 /* mstz */
749 if (args_info.mstz_given == 1) {
750 options.mstz_given = 1;
751 options.mstz.l = 2;
752
753 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
754 tmp = args_info.mstz_arg;
755 n = 0;
756 pch = strtok(tmp, ".");
757 while (pch != NULL) {
758 mstz_el[n] = pch;
759 pch = strtok(NULL, ".");
760 n++;
761 }
762
763 /* sign */
764 sign = atoi(mstz_el[0]);
765 printf("->Sign (0=+ / 1=-): %d\n", sign);
766 if (sign != 0 && sign != 1) {
767 printf("Invalid Sign \n");
768 return -1;
769 }
770 /* nbquarters */
771 nbquarters = atoi(mstz_el[1]);
772 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
773 if (nbquarters < 0 || nbquarters > 79) {
774 printf("Invalid Number of Quarters \n");
775 return -1;
776 }
777 /* DST */
778 DST = atoi(mstz_el[2]);
779 printf("->Daylight Saving Time Adjustment : %d\n", DST);
780 if (DST < 0 || DST > 3) {
781 printf("Invalid DST Adjustment \n");
782 return -1;
783 }
784 /* 12345678
785 bits 123 = unit of # of quarters of an hour
786 bits 678 = # of quarters of an hour / 10
787 bit 5 = sign
788 */
789 i = nbquarters % 10;
790 i = i << 4;
791 i = i + nbquarters / 10 + 8 * sign;
792 /* options.mstz.v[0] = 0x69 ; */
793 /* options.mstz.v[1] = 0x01 ; */
794 options.mstz.v[0] = i;
795 options.mstz.v[1] = DST;
796 n = (i & 0x08) ? '-' : '+';
797 printf
798 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
799 n, nbquarters / 4, nbquarters % 4 * 15);
800 }
801
802 /* imeisv */
803 if (args_info.imeisv_given == 1) {
804 options.imeisv_given = 1;
805 if (strlen(args_info.imeisv_arg) != 16) {
806 printf("Invalid IMEI(SV)\n");
807 return -1;
808 }
809 options.imeisv.l = 8;
810 for (n = 0; n < 8; n++) {
811 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
812 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
813 options.imeisv.v[n] = 16 * b + a;
814 }
815 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
816 }
817
818 /* msisdn */
819 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
820 printf("Invalid MSISDN\n");
821 return -1;
822 }
823 options.msisdn.l = 1;
824 options.msisdn.v[0] = 0x91; /* International format */
825 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
826 if ((n % 2) == 0) {
827 options.msisdn.v[((int)n / 2) + 1] =
828 args_info.msisdn_arg[n] - 48 + 0xf0;
829 options.msisdn.l += 1;
830 } else {
831 options.msisdn.v[((int)n / 2) + 1] =
832 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
833 (args_info.msisdn_arg[n] - 48) * 16;
834 }
835 }
836 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
837
838 /* UID and PWD */
839 /* Might need to also insert stuff like DNS etc. */
840 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
841 (sizeof(options.pco.v) - 1)) {
842 printf("invalid UID and PWD\n");
843 return -1;
844 }
845 options.pco.l =
846 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
847 options.pco.v[0] = 0x80; /* PPP */
848 options.pco.v[1] = 0xc0; /* PAP */
849 options.pco.v[2] = 0x23;
850 options.pco.v[3] =
851 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
852 options.pco.v[4] = 0x01; /* Authenticate request */
853 options.pco.v[5] = 0x01;
854 options.pco.v[6] = 0x00; /* MSB of length */
855 options.pco.v[7] =
856 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
857 options.pco.v[8] = strlen(args_info.uid_arg);
858 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
859 options.pco.v[9 + strlen(args_info.uid_arg)] =
860 strlen(args_info.pwd_arg);
861 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
862 args_info.pwd_arg, strlen(args_info.pwd_arg));
863
864 /* createif */
865 options.createif = args_info.createif_flag;
866
867 /* net */
868 /* Store net as in_addr net and mask */
869 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200870 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100871 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200872 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100873 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100874 "Invalid network address: %s!",
875 args_info.net_arg);
876 exit(1);
877 }
Harald Welted12eab92017-08-02 19:49:47 +0200878 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100879 options.netaddr.s_addr = options.net.s_addr;
880 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000881
Harald Weltebed35df2011-11-02 13:06:18 +0100882 } else {
883 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200884 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100885 options.netaddr.s_addr = 0;
886 options.destaddr.s_addr = 0;
887 }
jjako193e8b12003-11-10 12:31:41 +0000888
Harald Weltebed35df2011-11-02 13:06:18 +0100889 /* ipup */
890 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000891
Harald Weltebed35df2011-11-02 13:06:18 +0100892 /* ipdown */
893 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* statedir */
896 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000897
Harald Weltebed35df2011-11-02 13:06:18 +0100898 /* defaultroute */
899 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000900
Harald Weltebed35df2011-11-02 13:06:18 +0100901 /* pinghost */
902 /* Store ping host as in_addr */
903 if (args_info.pinghost_arg) {
904 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100905 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100906 "Invalid ping host: %s!",
907 args_info.pinghost_arg);
908 return -1;
909 } else {
910 memcpy(&options.pinghost.s_addr, host->h_addr,
911 host->h_length);
912 printf("Using ping host: %s (%s)\n",
913 args_info.pinghost_arg,
914 inet_ntoa(options.pinghost));
915 }
916 }
jjakoa7cd2492003-04-11 09:40:12 +0000917
Harald Weltebed35df2011-11-02 13:06:18 +0100918 /* Other ping parameters */
919 options.pingrate = args_info.pingrate_arg;
920 options.pingsize = args_info.pingsize_arg;
921 options.pingcount = args_info.pingcount_arg;
922 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000923
Harald Weltebed35df2011-11-02 13:06:18 +0100924 /* norecovery */
925 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000926
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800927 if (args_info.no_tx_gpdu_seq_flag)
928 options.tx_gpdu_seq = 0;
929 else
930 options.tx_gpdu_seq = 1;
931
Harald Welte840a8e92017-09-24 18:12:40 +0800932 /* PDP Type */
933 if (!strcmp(args_info.pdp_type_arg, "v6"))
934 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800935 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800936 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800937 else {
938 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
939 args_info.pdp_type_arg);
940 return -1;
941 }
942
943 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
944 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
945 return -1;
946 }
Harald Welte840a8e92017-09-24 18:12:40 +0800947
Harald Weltebed35df2011-11-02 13:06:18 +0100948 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000949
950}
951
Harald Weltebed35df2011-11-02 13:06:18 +0100952int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
953{
954 unsigned int i;
955 printf("The packet looks like this:\n");
956 for (i = 0; i < len; i++) {
957 printf("%02x ", (unsigned char)*(char *)(pack + i));
958 if (!((i + 1) % 16))
959 printf("\n");
960 };
961 printf("\n");
962 return 0;
jjako52c24142002-12-16 13:33:51 +0000963}
964
Harald Weltebed35df2011-11-02 13:06:18 +0100965char *print_ipprot(int t)
966{
967 switch (t) {
968 case 1:
969 return "ICMP";
970 case 6:
971 return "TCP";
972 case 17:
973 return "UDP";
974 default:
975 return "Unknown";
976 };
jjako5da68452003-01-28 16:08:47 +0000977}
978
Harald Weltebed35df2011-11-02 13:06:18 +0100979char *print_icmptype(int t)
980{
981 static char *ttab[] = {
982 "Echo Reply",
983 "ICMP 1",
984 "ICMP 2",
985 "Dest Unreachable",
986 "Source Quench",
987 "Redirect",
988 "ICMP 6",
989 "ICMP 7",
990 "Echo",
991 "ICMP 9",
992 "ICMP 10",
993 "Time Exceeded",
994 "Parameter Problem",
995 "Timestamp",
996 "Timestamp Reply",
997 "Info Request",
998 "Info Reply"
999 };
1000 if (t < 0 || t > 16)
1001 return ("OUT-OF-RANGE");
1002 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001003}
1004
Harald Weltebed35df2011-11-02 13:06:18 +01001005int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
1006{
1007 unsigned int n;
1008 uint64_t i64 = 0;
1009 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1010 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001011
Harald Weltebed35df2011-11-02 13:06:18 +01001012 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1013 /* ul16_t format always starts with 0x91 to indicate international format */
1014 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1015 for (n = 0; n < src->l; n++) {
1016 if ((src->v[n] & 0x0f) != 0x0f) {
1017 i64 *= 10;
1018 i64 += src->v[n] & 0x0f;
1019 }
1020 if ((src->v[n] & 0xf0) != 0xf0) {
1021 i64 *= 10;
1022 i64 += (src->v[n] & 0xf0) >> 4;
1023 }
1024 }
jjako193e8b12003-11-10 12:31:41 +00001025
Harald Weltebed35df2011-11-02 13:06:18 +01001026 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001027
Harald Weltebed35df2011-11-02 13:06:18 +01001028 /* Generate array with least significant digit in first octet */
1029 while (i64) {
1030 msa[msalen++] = i64 % 10;
1031 i64 = i64 / 10;
1032 }
jjako193e8b12003-11-10 12:31:41 +00001033
Harald Weltebed35df2011-11-02 13:06:18 +01001034 /* Convert back to ul16_t format */
1035 for (n = 0; n < msalen; n++) {
1036 if ((n % 2) == 0) {
1037 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1038 dst->l += 1;
1039 } else {
1040 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1041 msa[msalen - n - 1] * 16;
1042 }
1043 }
jjako193e8b12003-11-10 12:31:41 +00001044
Harald Weltebed35df2011-11-02 13:06:18 +01001045 return 0;
jjako193e8b12003-11-10 12:31:41 +00001046
1047}
1048
Harald Weltebed35df2011-11-02 13:06:18 +01001049int imsi_add(uint64_t src, uint64_t * dst, int add)
1050{
1051 /* TODO: big endian / small endian ??? */
1052 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001053
Harald Weltebed35df2011-11-02 13:06:18 +01001054 /* Convert from uint64_t bcd to uint64_t integer format */
1055 /* The resulting integer format is multiplied by 10 */
1056 while (src) {
1057 if ((src & 0x0f) != 0x0f) {
1058 i64 *= 10;
1059 i64 += (src & 0x0f);
1060 }
1061 if ((src & 0xf0) != 0xf0) {
1062 i64 *= 10;
1063 i64 += (src & 0xf0) >> 4;
1064 }
1065 src = src >> 8;
1066 }
jjako193e8b12003-11-10 12:31:41 +00001067
Harald Weltebed35df2011-11-02 13:06:18 +01001068 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001069
Harald Weltebed35df2011-11-02 13:06:18 +01001070 *dst = 0;
1071 while (i64) {
1072 *dst = *dst << 4;
1073 *dst += (i64 % 10);
1074 i64 = i64 / 10;
1075 }
jjako193e8b12003-11-10 12:31:41 +00001076
Harald Weltebed35df2011-11-02 13:06:18 +01001077 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001078
Harald Weltebed35df2011-11-02 13:06:18 +01001079 return 0;
jjako193e8b12003-11-10 12:31:41 +00001080
1081}
1082
jjakoafb2a972003-01-29 21:04:13 +00001083/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001084int ping_timeout(struct timeval *tp)
1085{
1086 struct timezone tz;
1087 struct timeval tv;
1088 int diff;
1089 if ((options.pinghost.s_addr) && (2 == state) &&
1090 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1091 gettimeofday(&tv, &tz);
1092 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1093 tp->tv_sec = 0;
1094 if (diff > 0)
1095 tp->tv_usec = diff;
1096 else {
1097 /* For some reason we get packet loss if set to zero */
1098 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1099 tp->tv_usec = 0;
1100 }
1101 }
1102 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001103}
1104
jjako5da68452003-01-28 16:08:47 +00001105/* Print out statistics when at the end of ping sequence */
1106int ping_finish()
1107{
Harald Weltebed35df2011-11-02 13:06:18 +01001108 struct timezone tz;
1109 struct timeval tv;
1110 int elapsed;
1111 gettimeofday(&tv, &tz);
1112 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1113 printf("\n");
1114 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1115 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1116 elapsed / 1000000.0);
1117 printf("%d packets received, ", nreceived);
1118 if (ntransmitted) {
1119 if (nreceived > ntransmitted)
1120 printf("-- somebody's printing up packets!");
1121 else
1122 printf("%d%% packet loss",
1123 (int)(((ntransmitted - nreceived) * 100) /
1124 ntransmitted));
1125 }
1126 printf("\n");
1127 if (options.debug)
1128 printf("%d packets received in total\n", ntreceived);
1129 if (nreceived && tsum)
1130 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1131 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1132 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001133
Harald Weltebed35df2011-11-02 13:06:18 +01001134 ntransmitted = 0;
1135 return 0;
jjako5da68452003-01-28 16:08:47 +00001136}
1137
1138/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001139int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1140{
1141 struct timezone tz;
1142 struct timeval tv;
1143 struct timeval *tp;
1144 struct ip_ping *pingpack = pack;
1145 struct in_addr src;
1146 int triptime;
jjako5da68452003-01-28 16:08:47 +00001147
Harald Weltebed35df2011-11-02 13:06:18 +01001148 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001149
Harald Weltebed35df2011-11-02 13:06:18 +01001150 gettimeofday(&tv, &tz);
1151 if (options.debug)
1152 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001153
Harald Weltebed35df2011-11-02 13:06:18 +01001154 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1155 printf("packet too short (%d bytes) from %s\n", len,
1156 inet_ntoa(src));
1157 return 0;
1158 }
jjako5da68452003-01-28 16:08:47 +00001159
Harald Weltebed35df2011-11-02 13:06:18 +01001160 ntreceived++;
1161 if (pingpack->protocol != 1) {
1162 if (!options.pingquiet)
1163 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1164 len, inet_ntoa(src), pingpack->protocol,
1165 print_ipprot(pingpack->protocol));
1166 return 0;
1167 }
jjako5da68452003-01-28 16:08:47 +00001168
Harald Weltebed35df2011-11-02 13:06:18 +01001169 if (pingpack->type != 0) {
1170 if (!options.pingquiet)
1171 printf
1172 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1173 len, inet_ntoa(src), pingpack->type,
1174 print_icmptype(pingpack->type), pingpack->code);
1175 return 0;
1176 }
jjako5da68452003-01-28 16:08:47 +00001177
Harald Weltebed35df2011-11-02 13:06:18 +01001178 nreceived++;
1179 if (!options.pingquiet)
1180 printf("%d bytes from %s: icmp_seq=%d", len,
1181 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001182
Harald Weltebed35df2011-11-02 13:06:18 +01001183 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1184 gettimeofday(&tv, &tz);
1185 tp = (struct timeval *)pingpack->data;
1186 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1187 tv.tv_sec--;
1188 tv.tv_usec += 1000000;
1189 }
1190 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001191
Harald Weltebed35df2011-11-02 13:06:18 +01001192 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1193 tsum += triptime;
1194 if (triptime < tmin)
1195 tmin = triptime;
1196 if (triptime > tmax)
1197 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001198
Harald Weltebed35df2011-11-02 13:06:18 +01001199 if (!options.pingquiet)
1200 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 } else if (!options.pingquiet)
1203 printf("\n");
1204 return 0;
jjako5da68452003-01-28 16:08:47 +00001205}
1206
1207/* Create a new ping packet and send it off to peer. */
1208int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001209 struct in_addr *dst, int seq, unsigned int datasize)
1210{
jjako5da68452003-01-28 16:08:47 +00001211
Harald Weltebed35df2011-11-02 13:06:18 +01001212 struct ip_ping pack;
1213 uint16_t *p = (uint16_t *) & pack;
1214 uint8_t *p8 = (uint8_t *) & pack;
1215 struct in_addr src;
1216 unsigned int n;
1217 long int sum = 0;
1218 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001219
Harald Weltebed35df2011-11-02 13:06:18 +01001220 struct timezone tz;
1221 struct timeval *tp =
1222 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001223
Harald Weltebed35df2011-11-02 13:06:18 +01001224 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001225 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001226 "Ping size to large: %d!", datasize);
1227 return -1;
1228 }
jjako5da68452003-01-28 16:08:47 +00001229
Harald Weltebed35df2011-11-02 13:06:18 +01001230 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001231
Harald Weltebed35df2011-11-02 13:06:18 +01001232 pack.ipver = 0x45;
1233 pack.tos = 0x00;
1234 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1235 pack.fragid = 0x0000;
1236 pack.offset = 0x0040;
1237 pack.ttl = 0x40;
1238 pack.protocol = 0x01;
1239 pack.ipcheck = 0x0000;
1240 pack.src = src.s_addr;
1241 pack.dst = dst->s_addr;
1242 pack.type = 0x08;
1243 pack.code = 0x00;
1244 pack.checksum = 0x0000;
1245 pack.ident = 0x0000;
1246 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001247
Harald Weltebed35df2011-11-02 13:06:18 +01001248 /* Generate ICMP payload */
1249 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1250 for (n = 0; n < (datasize); n++)
1251 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001252
Harald Weltebed35df2011-11-02 13:06:18 +01001253 if (datasize >= sizeof(struct timeval))
1254 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 /* Calculate IP header checksum */
1257 p = (uint16_t *) & pack;
1258 count = CREATEPING_IP;
1259 sum = 0;
1260 while (count > 1) {
1261 sum += *p++;
1262 count -= 2;
1263 }
1264 while (sum >> 16)
1265 sum = (sum & 0xffff) + (sum >> 16);
1266 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001267
Harald Weltebed35df2011-11-02 13:06:18 +01001268 /* Calculate ICMP checksum */
1269 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1270 sum = 0;
1271 p = (uint16_t *) & pack;
1272 p += CREATEPING_IP / 2;
1273 while (count > 1) {
1274 sum += *p++;
1275 count -= 2;
1276 }
1277 if (count > 0)
1278 sum += *(unsigned char *)p;
1279 while (sum >> 16)
1280 sum = (sum & 0xffff) + (sum >> 16);
1281 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001282
Harald Weltebed35df2011-11-02 13:06:18 +01001283 ntransmitted++;
1284 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001285}
1286
Harald Weltebed35df2011-11-02 13:06:18 +01001287int delete_context(struct pdp_t *pdp)
1288{
1289
1290 if (tun && options.ipdown)
1291 tun_runscript(tun, options.ipdown);
1292
1293 ipdel((struct iphash_t *)pdp->peer);
1294 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1295
1296 if (1 == options.contexts)
1297 state = 5; /* Disconnected */
1298
1299 return 0;
1300}
jjakoa7cd2492003-04-11 09:40:12 +00001301
Harald Welte6748dc92017-09-24 21:54:59 +08001302/* Link-Local address prefix fe80::/64 */
1303static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1304
jjakoa7cd2492003-04-11 09:40:12 +00001305/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001306int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1307{
1308 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001309 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001310 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001311 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001312
Harald Welte6748dc92017-09-24 21:54:59 +08001313 if (iph->version == 4) {
1314 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1315 printf("Dropping packet with too short IP header\n");
1316 return 0;
1317 }
1318 src.len = 4;
1319 src.v4.s_addr = iph->saddr;
1320 } else if (iph->version == 6) {
1321 /* We only have a single entry in the hash table, and it consists of the link-local
1322 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1323 * addresses to that format before looking up the hash table via ippool_getip() */
1324 src.len = 16;
1325 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1326 /* is a link-local address, we can do the hash lookup 1:1 */
1327 src.v6 = ip6h->ip6_src;
1328 } else {
1329 /* it is not a link-local address, so we must convert from the /64 prefix
1330 * to the link-local format that's used in the hash table */
1331 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1332 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1333 }
1334 } else {
1335 printf("Dropping packet with invalid IP version %u\n", iph->version);
1336 return 0;
1337 }
jjakoa7cd2492003-04-11 09:40:12 +00001338
Harald Weltebed35df2011-11-02 13:06:18 +01001339 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001340 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001341 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001342 return 0;
1343 }
1344
1345 if (ipm->pdp) /* Check if a peer protocol is defined */
1346 gtp_data_req(gsn, ipm->pdp, pack, len);
1347 return 0;
jjako52c24142002-12-16 13:33:51 +00001348}
1349
Harald Weltebed35df2011-11-02 13:06:18 +01001350int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1351{
Harald Welted12eab92017-08-02 19:49:47 +02001352 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001353
Harald Weltebed35df2011-11-02 13:06:18 +01001354 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001355
Harald Weltebed35df2011-11-02 13:06:18 +01001356 if (cause < 0) {
1357 printf("Create PDP Context Request timed out\n");
1358 if (iph->pdp->version == 1) {
1359 printf("Retrying with version 0\n");
1360 iph->pdp->version = 0;
1361 gtp_create_context_req(gsn, iph->pdp, iph);
1362 return 0;
1363 } else {
1364 state = 0;
1365 pdp_freepdp(iph->pdp);
1366 iph->pdp = NULL;
1367 return EOF;
1368 }
1369 }
jjako2c381332003-10-21 19:09:53 +00001370
Harald Weltebed35df2011-11-02 13:06:18 +01001371 if (cause != 128) {
1372 printf
1373 ("Received create PDP context response. Cause value: %d\n",
1374 cause);
1375 state = 0;
1376 pdp_freepdp(iph->pdp);
1377 iph->pdp = NULL;
1378 return EOF; /* Not what we expected */
1379 }
jjako52c24142002-12-16 13:33:51 +00001380
Harald Weltea0d281d2017-08-02 21:48:16 +02001381 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001382 printf
1383 ("Received create PDP context response. Cause value: %d\n",
1384 cause);
1385 pdp_freepdp(iph->pdp);
1386 iph->pdp = NULL;
1387 state = 0;
1388 return EOF; /* Not a valid IP address */
1389 }
jjakoa7cd2492003-04-11 09:40:12 +00001390
Harald Weltebed35df2011-11-02 13:06:18 +01001391 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001392 in46a_ntoa(&addr));
1393
1394 switch (addr.len) {
1395 case 16: /* IPv6 */
1396 /* we have to enable the kernel to perform stateless autoconfiguration,
1397 * i.e. send a router solicitation using the lover 64bits of the allocated
1398 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1399 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1400 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1401 break;
1402 case 4: /* IPv4 */
1403 break;
1404 }
jjakoa7cd2492003-04-11 09:40:12 +00001405
Harald Weltebed35df2011-11-02 13:06:18 +01001406 if ((options.createif) && (!options.net.s_addr)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001407 size_t prefixlen = 32;
1408 if (addr.len == 16)
1409 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001410 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001411 /* FIXME: use tun_addattr() not tun_setaddr() */
1412 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001413 if (options.defaultroute) {
1414 struct in_addr rm;
1415 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001416 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001417 }
1418 if (options.ipup)
1419 tun_runscript(tun, options.ipup);
1420 }
jjako52c24142002-12-16 13:33:51 +00001421
Harald Weltebed35df2011-11-02 13:06:18 +01001422 ipset((struct iphash_t *)pdp->peer, &addr);
1423
1424 state = 2; /* Connected */
1425
1426 return 0;
jjako52c24142002-12-16 13:33:51 +00001427}
1428
Harald Weltebed35df2011-11-02 13:06:18 +01001429int delete_pdp_conf(struct pdp_t *pdp, int cause)
1430{
1431 printf("Received delete PDP context response. Cause value: %d\n",
1432 cause);
1433 return 0;
jjako52c24142002-12-16 13:33:51 +00001434}
1435
Harald Weltebed35df2011-11-02 13:06:18 +01001436int echo_conf(int recovery)
1437{
jjako91aaf222003-10-22 10:09:32 +00001438
Harald Weltebed35df2011-11-02 13:06:18 +01001439 if (recovery < 0) {
1440 printf("Echo Request timed out\n");
1441 if (echoversion == 1) {
1442 printf("Retrying with version 0\n");
1443 echoversion = 0;
1444 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1445 return 0;
1446 } else {
1447 state = 0;
1448 return EOF;
1449 }
1450 } else {
1451 printf("Received echo response\n");
1452 if (!options.contexts)
1453 state = 5;
1454 }
1455 return 0;
jjako52c24142002-12-16 13:33:51 +00001456}
1457
Harald Weltebed35df2011-11-02 13:06:18 +01001458int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1459{
1460 /* if (cause < 0) return 0; Some error occurred. We don't care */
1461 switch (type) {
1462 case GTP_ECHO_REQ:
1463 return echo_conf(cause);
1464 case GTP_CREATE_PDP_REQ:
1465 return create_pdp_conf(pdp, cbp, cause);
1466 case GTP_DELETE_PDP_REQ:
1467 if (cause != 128)
1468 return 0; /* Request not accepted. We don't care */
1469 return delete_pdp_conf(pdp, cause);
1470 default:
1471 return 0;
1472 }
jjako52c24142002-12-16 13:33:51 +00001473}
1474
Harald Weltebed35df2011-11-02 13:06:18 +01001475int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1476{
1477 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1478 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001479}
1480
1481int main(int argc, char **argv)
1482{
Harald Weltebed35df2011-11-02 13:06:18 +01001483 fd_set fds; /* For select() */
1484 struct timeval idleTime; /* How long to select() */
1485 struct pdp_t *pdp;
1486 int n;
1487 int starttime = time(NULL); /* Time program was started */
1488 int stoptime = 0; /* Time to exit */
1489 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001490 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001491
Harald Weltebed35df2011-11-02 13:06:18 +01001492 struct timezone tz; /* Used for calculating ping times */
1493 struct timeval tv;
1494 int diff;
jjako52c24142002-12-16 13:33:51 +00001495
bjovana8f71eb2017-02-24 17:39:20 +01001496 signal(SIGTERM, signal_handler);
1497 signal(SIGHUP, signal_handler);
1498 signal(SIGINT, signal_handler);
1499
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001500 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001501
Harald Weltebed35df2011-11-02 13:06:18 +01001502 /* Process options given in configuration file and command line */
1503 if (process_options(argc, argv))
1504 exit(1);
jjako52c24142002-12-16 13:33:51 +00001505
Harald Weltebed35df2011-11-02 13:06:18 +01001506 printf("\nInitialising GTP library\n");
1507 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001508 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001509 exit(1);
1510 }
1511 if (gsn->fd0 > maxfd)
1512 maxfd = gsn->fd0;
1513 if (gsn->fd1c > maxfd)
1514 maxfd = gsn->fd1c;
1515 if (gsn->fd1u > maxfd)
1516 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001517
Harald Weltebed35df2011-11-02 13:06:18 +01001518 gtp_set_cb_delete_context(gsn, delete_context);
1519 gtp_set_cb_conf(gsn, conf);
1520 if (options.createif)
1521 gtp_set_cb_data_ind(gsn, encaps_tun);
1522 else
1523 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001524
Harald Weltebed35df2011-11-02 13:06:18 +01001525 if (options.createif) {
1526 printf("Setting up interface\n");
1527 /* Create a tunnel interface */
Harald Weltedda21ed2017-08-12 15:07:02 +02001528 if (tun_new((struct tun_t **)&tun, NULL)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001529 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001530 "Failed to create tun");
1531 exit(1);
1532 }
1533 tun_set_cb_ind(tun, cb_tun_ind);
1534 if (tun->fd > maxfd)
1535 maxfd = tun->fd;
1536 }
jjakoa7cd2492003-04-11 09:40:12 +00001537
Harald Weltebed35df2011-11-02 13:06:18 +01001538 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001539 struct in_addr mask;
1540 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001541 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001542 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001543 if (options.defaultroute) {
1544 struct in_addr rm;
1545 rm.s_addr = 0;
1546 tun_addroute(tun, &rm, &options.destaddr, &rm);
1547 }
1548 if (options.ipup)
1549 tun_runscript(tun, options.ipup);
1550 }
jjakoa7cd2492003-04-11 09:40:12 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 /* Initialise hash tables */
1553 memset(&iphash, 0, sizeof(iphash));
1554 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001555
Harald Weltebed35df2011-11-02 13:06:18 +01001556 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001557
Harald Weltebed35df2011-11-02 13:06:18 +01001558 /* See if anybody is there */
1559 printf("Sending off echo request\n");
1560 echoversion = options.gtpversion;
1561 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001562
Harald Weltebed35df2011-11-02 13:06:18 +01001563 for (n = 0; n < options.contexts; n++) {
1564 uint64_t myimsi;
1565 printf("Setting up PDP context #%d\n", n);
1566 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001567
Harald Weltebed35df2011-11-02 13:06:18 +01001568 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001569
Harald Weltebed35df2011-11-02 13:06:18 +01001570 /* Allocated here. */
1571 /* If create context failes we have to deallocate ourselves. */
1572 /* Otherwise it is deallocated by gtplib */
1573 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001574
Harald Weltebed35df2011-11-02 13:06:18 +01001575 pdp->peer = &iparr[n];
1576 pdp->ipif = tun; /* TODO */
1577 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001578
Harald Weltebed35df2011-11-02 13:06:18 +01001579 if (options.gtpversion == 0) {
1580 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001581 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001582 "QoS length too big");
1583 exit(1);
1584 } else {
1585 memcpy(pdp->qos_req0, options.qos.v,
1586 options.qos.l);
1587 }
1588 }
jjakoa7cd2492003-04-11 09:40:12 +00001589
Harald Weltebed35df2011-11-02 13:06:18 +01001590 pdp->qos_req.l = options.qos.l;
1591 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001592
Harald Weltebed35df2011-11-02 13:06:18 +01001593 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001594
Harald Weltebed35df2011-11-02 13:06:18 +01001595 pdp->rattype.l = options.rattype.l;
1596 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1597 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001598
Harald Weltebed35df2011-11-02 13:06:18 +01001599 pdp->userloc.l = options.userloc.l;
1600 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1601 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001602
Harald Weltebed35df2011-11-02 13:06:18 +01001603 pdp->rai.l = options.rai.l;
1604 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1605 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001606
Harald Weltebed35df2011-11-02 13:06:18 +01001607 pdp->mstz.l = options.mstz.l;
1608 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1609 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001610
Harald Weltebed35df2011-11-02 13:06:18 +01001611 pdp->imeisv.l = options.imeisv.l;
1612 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1613 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001614
Harald Weltebed35df2011-11-02 13:06:18 +01001615 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001616
Harald Weltebed35df2011-11-02 13:06:18 +01001617 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001618 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001619 "APN length too big");
1620 exit(1);
1621 } else {
1622 pdp->apn_use.l = options.apn.l;
1623 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1624 }
jjako193e8b12003-11-10 12:31:41 +00001625
Harald Weltebed35df2011-11-02 13:06:18 +01001626 pdp->gsnlc.l = sizeof(options.listen);
1627 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1628 pdp->gsnlu.l = sizeof(options.listen);
1629 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001632 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001633 "MSISDN length too big");
1634 exit(1);
1635 } else {
1636 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1637 }
jjakob62c3dd2004-05-27 18:51:55 +00001638
Harald Welte840a8e92017-09-24 18:12:40 +08001639 /* Request dynamic IP address */
1640 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1641 pdp->eua.v[1] = options.pdp_type;
1642 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001643
Harald Weltebed35df2011-11-02 13:06:18 +01001644 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001645 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001646 "PCO length too big");
1647 exit(1);
1648 } else {
1649 pdp->pco_req.l = options.pco.l;
1650 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1651 }
jjako52c24142002-12-16 13:33:51 +00001652
Harald Weltebed35df2011-11-02 13:06:18 +01001653 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001654
Harald Weltebed35df2011-11-02 13:06:18 +01001655 pdp->hisaddr0 = options.remote;
1656 pdp->hisaddr1 = options.remote;
1657
1658 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1659 512 = Flat rate, 256 = Hot billing */
1660
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001661 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1662
Harald Weltebed35df2011-11-02 13:06:18 +01001663 /* Create context */
1664 /* We send this of once. Retransmissions are handled by gtplib */
1665 gtp_create_context_req(gsn, pdp, &iparr[n]);
1666 }
1667
1668 state = 1; /* Enter wait_connection state */
1669
1670 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001671
jjako52c24142002-12-16 13:33:51 +00001672 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001673 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001674 /******************************************************************/
1675
Harald Weltebed35df2011-11-02 13:06:18 +01001676 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001677
Harald Weltebed35df2011-11-02 13:06:18 +01001678 /* Take down client after timeout after disconnect */
1679 if ((4 == state) && ((stoptime) <= time(NULL))) {
1680 state = 5;
1681 }
jjako7b8fad42003-07-07 14:37:42 +00001682
Harald Weltebed35df2011-11-02 13:06:18 +01001683 /* Take down client after timelimit timeout */
1684 if ((2 == state) && (options.timelimit) &&
1685 ((starttime + options.timelimit) <= time(NULL))) {
1686 state = 3;
1687 }
jjako7b8fad42003-07-07 14:37:42 +00001688
Harald Weltebed35df2011-11-02 13:06:18 +01001689 /* Take down client after ping timeout */
1690 if ((2 == state) && (pingtimeout)
1691 && (pingtimeout <= time(NULL))) {
1692 state = 3;
1693 }
jjako7b8fad42003-07-07 14:37:42 +00001694
Harald Weltebed35df2011-11-02 13:06:18 +01001695 /* Set pingtimeout for later disconnection */
1696 if (options.pingcount && ntransmitted >= options.pingcount) {
1697 pingtimeout = time(NULL) + 5; /* Extra seconds */
1698 }
jjako7b8fad42003-07-07 14:37:42 +00001699
Harald Weltebed35df2011-11-02 13:06:18 +01001700 /* Print statistics if no more ping packets are missing */
1701 if (ntransmitted && options.pingcount
1702 && nreceived >= options.pingcount) {
1703 ping_finish();
1704 if (!options.createif)
1705 state = 3;
1706 }
jjako7b8fad42003-07-07 14:37:42 +00001707
Harald Weltebed35df2011-11-02 13:06:18 +01001708 /* Send off disconnect */
1709 if (3 == state) {
1710 state = 4;
1711 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1712 for (n = 0; n < options.contexts; n++) {
1713 /* Delete context */
1714 printf("Disconnecting PDP context #%d\n", n);
1715 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1716 1);
1717 if ((options.pinghost.s_addr != 0)
1718 && ntransmitted)
1719 ping_finish();
1720 }
1721 }
jjako7b8fad42003-07-07 14:37:42 +00001722
Harald Weltebed35df2011-11-02 13:06:18 +01001723 /* Send of ping packets */
1724 diff = 0;
1725 while ((diff <= 0) &&
1726 /* Send off an ICMP ping packet */
1727 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1728 ((pingseq < options.pingcount)
1729 || (options.pingcount == 0))) {
1730 if (!pingseq)
1731 gettimeofday(&firstping, &tz); /* Set time of first ping */
1732 gettimeofday(&tv, &tz);
1733 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1734 if (diff <= 0) {
1735 if (options.debug)
1736 printf("Create_ping %d\n", diff);
1737 create_ping(gsn,
1738 iparr[pingseq %
1739 options.contexts].pdp,
1740 &options.pinghost, pingseq,
1741 options.pingsize);
1742 pingseq++;
1743 }
1744 }
jjako5da68452003-01-28 16:08:47 +00001745
Harald Weltebed35df2011-11-02 13:06:18 +01001746 FD_ZERO(&fds);
1747 if (tun)
1748 FD_SET(tun->fd, &fds);
1749 FD_SET(gsn->fd0, &fds);
1750 FD_SET(gsn->fd1c, &fds);
1751 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001752
Harald Weltebed35df2011-11-02 13:06:18 +01001753 gtp_retranstimeout(gsn, &idleTime);
1754 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001755
Harald Weltebed35df2011-11-02 13:06:18 +01001756 if (options.debug)
1757 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1758 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001759
bjovana8f71eb2017-02-24 17:39:20 +01001760 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001761 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1762 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001763 if (errno == EINTR)
1764 signal_received = 1;
1765 else
1766 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1767 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001768 break;
1769 case 0:
1770 gtp_retrans(gsn); /* Only retransmit if nothing else */
1771 break;
1772 default:
1773 break;
1774 }
1775
bjovana8f71eb2017-02-24 17:39:20 +01001776 if (!signal_received) {
1777
1778 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1779 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1780 "TUN decaps failed");
1781 }
1782
1783 if (FD_ISSET(gsn->fd0, &fds))
1784 gtp_decaps0(gsn);
1785
1786 if (FD_ISSET(gsn->fd1c, &fds))
1787 gtp_decaps1c(gsn);
1788
1789 if (FD_ISSET(gsn->fd1u, &fds))
1790 gtp_decaps1u(gsn);
1791
Harald Weltebed35df2011-11-02 13:06:18 +01001792 }
Harald Weltebed35df2011-11-02 13:06:18 +01001793 }
1794
1795 gtp_free(gsn); /* Clean up the gsn instance */
1796
1797 if (options.createif)
1798 tun_free(tun);
1799
1800 if (0 == state)
1801 exit(1); /* Indicate error */
1802
1803 return 0;
jjako52c24142002-12-16 13:33:51 +00001804}