blob: 7d60c31a850f8e45200e3d2b306f2d11c76bcd9e [file] [log] [blame]
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001/*
Harald Welte632e8432017-09-05 18:12:14 +02002 * OsmoGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welte6748dc92017-09-24 21:54:59 +08004 * Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01005 *
jjako52c24142002-12-16 13:33:51 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +010010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/*
14 * sgsnemu.c
15 *
16 */
17
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020018#include "config.h"
19
jjako52c24142002-12-16 13:33:51 +000020#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010021#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000022#endif
23
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010024#include <osmocom/core/application.h>
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020025#include <osmocom/core/msgb.h>
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010026
jjako52c24142002-12-16 13:33:51 +000027#include <ctype.h>
28#include <netdb.h>
29#include <signal.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020036#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080037#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000038#include <arpa/inet.h>
39#include <sys/wait.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include <sys/socket.h>
43#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000044#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000045#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000046#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000047#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000048#include <resolv.h>
49#include <time.h>
50
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020051#if defined(__linux__)
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020052#if defined(HAVE_IN6_ADDR_GEN_MODE_NONE)
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020053#include <linux/if_link.h>
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +020054#endif // HAVE_IN6_ADDR_GEN_MODE_NONE
Pau Espin Pedrol98f81262020-04-14 18:38:52 +020055#endif
56
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020057#include "../lib/tun.h"
58#include "../lib/ippool.h"
59#include "../lib/syserr.h"
Andreas Schultzb6292402018-10-05 13:58:45 +010060#include "../lib/netns.h"
Pau Espin Pedrole2b09612020-04-15 15:09:30 +020061#include "../lib/icmpv6.h"
jjako52c24142002-12-16 13:33:51 +000062#include "../gtp/pdp.h"
63#include "../gtp/gtp.h"
64#include "cmdline.h"
65
Harald Weltebed35df2011-11-02 13:06:18 +010066#define IPADDRLEN 256 /* Character length of addresses */
67#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000068
jjakoa7cd2492003-04-11 09:40:12 +000069/* HASH tables for IP address allocation */
70struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010071 uint8_t inuse; /* 0=free. 1=used by somebody */
72 struct iphash_t *ipnext;
73 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020074 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000075};
76struct iphash_t iparr[MAXCONTEXTS];
77struct iphash_t *iphash[MAXCONTEXTS];
78
79/* State variable used for ping */
80/* 0: Idle */
81/* 1: Wait_connect */
82/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000083/* 3: Done */
84/* 4: Wait_disconnect */
85/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010086volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000087
Harald Weltebed35df2011-11-02 13:06:18 +010088struct gsn_t *gsn = NULL; /* GSN instance */
89struct tun_t *tun = NULL; /* TUN instance */
90int maxfd = 0; /* For select() */
91int echoversion = 1; /* First try this version */
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020092void *tall_sgsnemu_ctx; /* root talloc ctx */
Andreas Schultzb6292402018-10-05 13:58:45 +010093#if defined(__linux__)
94int netns = -1; /* network namespace */
95#endif
jjako52c24142002-12-16 13:33:51 +000096
jjakoa7cd2492003-04-11 09:40:12 +000097/* Struct with local versions of gengetopt options */
98struct {
Harald Weltebed35df2011-11-02 13:06:18 +010099 int debug; /* Print debug messages */
100 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +0800101 char *tun_dev_name;
Andreas Schultzb6292402018-10-05 13:58:45 +0100102 char *netns;
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +0200103 struct in46_addr netaddr; /* Network interface */
Harald Welted12eab92017-08-02 19:49:47 +0200104 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +0100105 char *ipup, *ipdown; /* Filename of scripts */
106 int defaultroute; /* Set up default route */
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200107 struct in46_addr pinghost; /* Remote ping host */
Harald Weltebed35df2011-11-02 13:06:18 +0100108 int pingrate;
109 int pingsize;
110 int pingcount;
111 int pingquiet;
112 struct in_addr listen;
113 struct in_addr remote;
114 struct in_addr dns;
115 int contexts; /* Number of contexts to create */
116 int timelimit; /* Number of seconds to be connected */
117 char *statedir;
118 uint64_t imsi;
119 uint8_t nsapi;
120 int gtpversion;
121 struct ul255_t pco;
122 struct ul255_t qos;
123 uint16_t cch;
124 struct ul255_t apn;
125 uint8_t selmode;
126 struct ul255_t rattype;
127 int rattype_given;
128 struct ul255_t userloc;
129 int userloc_given;
130 struct ul255_t rai;
131 int rai_given;
132 struct ul255_t mstz;
133 int mstz_given;
134 struct ul255_t imeisv;
135 int imeisv_given;
136 struct ul16_t msisdn;
137 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800138 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800139 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000140} options;
jjako52c24142002-12-16 13:33:51 +0000141
jjako5da68452003-01-28 16:08:47 +0000142/* Definitions to use for PING. Most of the ping code was derived from */
143/* the original ping program by Mike Muuss */
144
145/* IP header and ICMP echo header */
146#define CREATEPING_MAX 2048
147#define CREATEPING_IP 20
148#define CREATEPING_ICMP 8
149
150struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100151 uint8_t ipver; /* Type and header length */
152 uint8_t tos; /* Type of Service */
153 uint16_t length; /* Total length */
154 uint16_t fragid; /* Identifier */
155 uint16_t offset; /* Flags and fragment offset */
156 uint8_t ttl; /* Time to live */
157 uint8_t protocol; /* Protocol */
158 uint16_t ipcheck; /* Header checksum */
159 uint32_t src; /* Source address */
160 uint32_t dst; /* Destination */
161 uint8_t type; /* Type and header length */
162 uint8_t code; /* Code */
163 uint16_t checksum; /* Header checksum */
164 uint16_t ident; /* Identifier */
165 uint16_t seq; /* Sequence number */
166 uint8_t data[CREATEPING_MAX]; /* Data */
167} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000168
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200169struct ip6_ping {
170 struct icmpv6_echo_hdr hdr;
171 uint8_t data[CREATEPING_MAX]; /* Data */
172} __attribute__ ((packed));
173
jjako5da68452003-01-28 16:08:47 +0000174/* Statistical values for ping */
175int nreceived = 0;
176int ntreceived = 0;
177int ntransmitted = 0;
178int tmin = 999999999;
179int tmax = 0;
180int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100181int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000182struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000183
Harald Weltefed33892017-10-10 09:02:45 +0800184static void signal_handler(int signo)
bjovana8f71eb2017-02-24 17:39:20 +0100185{
186 if (state == 2)
187 state = 3; /* Tell main loop to finish. */
188}
189
Harald Weltefed33892017-10-10 09:02:45 +0800190static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100191{
Harald Welted12eab92017-08-02 19:49:47 +0200192 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100193 struct iphash_t *h;
194 struct iphash_t *prev = NULL;
195 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200196 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100197 for (h = iphash[hash]; h; h = h->ipnext)
198 prev = h;
199 if (!prev)
200 iphash[hash] = ipaddr;
201 else
202 prev->ipnext = ipaddr;
203 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000204}
205
Harald Weltefed33892017-10-10 09:02:45 +0800206static int ipdel(struct iphash_t *ipaddr)
Harald Weltebed35df2011-11-02 13:06:18 +0100207{
Harald Welted12eab92017-08-02 19:49:47 +0200208 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100209 struct iphash_t *h;
210 struct iphash_t *prev = NULL;
211 for (h = iphash[hash]; h; h = h->ipnext) {
212 if (h == ipaddr) {
213 if (!prev)
214 iphash[hash] = h->ipnext;
215 else
216 prev->ipnext = h->ipnext;
217 return 0;
218 }
219 prev = h;
220 }
221 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000222}
223
Harald Weltefed33892017-10-10 09:02:45 +0800224static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100225{
Harald Welted12eab92017-08-02 19:49:47 +0200226 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100227 struct iphash_t *h;
228 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200229 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100230 *ipaddr = h;
231 return 0;
232 }
233 }
234 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000235}
236
jjakoa7cd2492003-04-11 09:40:12 +0000237/* Used to write process ID to file. Assume someone else will delete */
Harald Weltefed33892017-10-10 09:02:45 +0800238static void log_pid(char *pidfile)
Harald Weltebed35df2011-11-02 13:06:18 +0100239{
240 FILE *file;
241 mode_t oldmask;
242
243 oldmask = umask(022);
244 file = fopen(pidfile, "w");
245 umask(oldmask);
246 if (!file)
247 return;
248 fprintf(file, "%d\n", (int)getpid());
249 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000250}
251
Harald Weltefed33892017-10-10 09:02:45 +0800252static int process_options(int argc, char **argv)
Harald Weltebed35df2011-11-02 13:06:18 +0100253{
254 /* gengeopt declarations */
255 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000256
Harald Weltebed35df2011-11-02 13:06:18 +0100257 struct hostent *host;
258 unsigned int n;
259 uint16_t i;
260 uint8_t a;
261 uint8_t b;
262 char *tmp;
263 char *pch;
264 char *type;
265 char *mcc;
266 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100267 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100268 char *lac;
269 int lac_d;
270 char *rest;
271 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
272 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
273 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
274 int sign;
275 int nbquarters;
276 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000277
Harald Weltebed35df2011-11-02 13:06:18 +0100278 if (cmdline_parser(argc, argv, &args_info) != 0)
279 return -1;
280 if (args_info.debug_flag) {
281 if (args_info.remote_arg)
282 printf("remote: %s\n", args_info.remote_arg);
283 if (args_info.listen_arg)
284 printf("listen: %s\n", args_info.listen_arg);
285 if (args_info.conf_arg)
286 printf("conf: %s\n", args_info.conf_arg);
287 printf("debug: %d\n", args_info.debug_flag);
288 if (args_info.imsi_arg)
289 printf("imsi: %s\n", args_info.imsi_arg);
290 printf("qos: %#08x\n", args_info.qos_arg);
291 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
292 printf("qose2: %#04x\n", args_info.qose2_arg);
293 printf("qose3: %#06x\n", args_info.qose3_arg);
294 printf("qose4: %#06x\n", args_info.qose4_arg);
295 printf("charging: %#04x\n", args_info.charging_arg);
296 if (args_info.apn_arg)
297 printf("apn: %s\n", args_info.apn_arg);
298 if (args_info.msisdn_arg)
299 printf("msisdn: %s\n", args_info.msisdn_arg);
300 if (args_info.uid_arg)
301 printf("uid: %s\n", args_info.uid_arg);
302 if (args_info.pwd_arg)
303 printf("pwd: %s\n", args_info.pwd_arg);
304 if (args_info.pidfile_arg)
305 printf("pidfile: %s\n", args_info.pidfile_arg);
306 if (args_info.statedir_arg)
307 printf("statedir: %s\n", args_info.statedir_arg);
308 if (args_info.dns_arg)
309 printf("dns: %s\n", args_info.dns_arg);
310 printf("contexts: %d\n", args_info.contexts_arg);
311 printf("timelimit: %d\n", args_info.timelimit_arg);
312 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800313 if (args_info.tun_device_arg)
Harald Welte7b9230a2018-10-21 13:09:21 +0200314 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100315 if (args_info.netns_arg)
316 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100317 if (args_info.ipup_arg)
318 printf("ipup: %s\n", args_info.ipup_arg);
319 if (args_info.ipdown_arg)
320 printf("ipdown: %s\n", args_info.ipdown_arg);
321 printf("defaultroute: %d\n", args_info.defaultroute_flag);
322 if (args_info.pinghost_arg)
323 printf("pinghost: %s\n", args_info.pinghost_arg);
324 printf("pingrate: %d\n", args_info.pingrate_arg);
325 printf("pingsize: %d\n", args_info.pingsize_arg);
326 printf("pingcount: %d\n", args_info.pingcount_arg);
327 printf("pingquiet: %d\n", args_info.pingquiet_flag);
328 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800329 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100330 }
jjakoa7cd2492003-04-11 09:40:12 +0000331
Harald Weltebed35df2011-11-02 13:06:18 +0100332 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000333
Harald Weltebed35df2011-11-02 13:06:18 +0100334 if (args_info.conf_arg) {
335 if (cmdline_parser_configfile
336 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
337 return -1;
338 if (args_info.debug_flag) {
339 printf("cmdline_parser_configfile\n");
340 if (args_info.remote_arg)
341 printf("remote: %s\n", args_info.remote_arg);
342 if (args_info.listen_arg)
343 printf("listen: %s\n", args_info.listen_arg);
344 if (args_info.conf_arg)
345 printf("conf: %s\n", args_info.conf_arg);
346 printf("debug: %d\n", args_info.debug_flag);
347 if (args_info.imsi_arg)
348 printf("imsi: %s\n", args_info.imsi_arg);
349 printf("qos: %#08x\n", args_info.qos_arg);
350 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
351 printf("qose2: %#04x\n", args_info.qose2_arg);
352 printf("qose3: %#06x\n", args_info.qose3_arg);
353 printf("qose4: %#06x\n", args_info.qose4_arg);
354 printf("charging: %#04x\n", args_info.charging_arg);
355 if (args_info.apn_arg)
356 printf("apn: %s\n", args_info.apn_arg);
357 if (args_info.msisdn_arg)
358 printf("msisdn: %s\n", args_info.msisdn_arg);
359 if (args_info.uid_arg)
360 printf("uid: %s\n", args_info.uid_arg);
361 if (args_info.pwd_arg)
362 printf("pwd: %s\n", args_info.pwd_arg);
363 if (args_info.pidfile_arg)
364 printf("pidfile: %s\n", args_info.pidfile_arg);
365 if (args_info.statedir_arg)
366 printf("statedir: %s\n",
367 args_info.statedir_arg);
368 if (args_info.dns_arg)
369 printf("dns: %s\n", args_info.dns_arg);
370 printf("contexts: %d\n", args_info.contexts_arg);
371 printf("timelimit: %d\n", args_info.timelimit_arg);
372 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800373 if (args_info.tun_device_arg)
Harald Welte9c332102017-11-06 02:44:42 +0900374 printf("tun-device: %s\n", args_info.tun_device_arg);
Andreas Schultzb6292402018-10-05 13:58:45 +0100375 if (args_info.netns_arg)
376 printf("netns: %s\n", args_info.netns_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100377 if (args_info.ipup_arg)
378 printf("ipup: %s\n", args_info.ipup_arg);
379 if (args_info.ipdown_arg)
380 printf("ipdown: %s\n", args_info.ipdown_arg);
381 printf("defaultroute: %d\n",
382 args_info.defaultroute_flag);
383 if (args_info.pinghost_arg)
384 printf("pinghost: %s\n",
385 args_info.pinghost_arg);
386 printf("pingrate: %d\n", args_info.pingrate_arg);
387 printf("pingsize: %d\n", args_info.pingsize_arg);
388 printf("pingcount: %d\n", args_info.pingcount_arg);
389 printf("pingquiet: %d\n", args_info.pingquiet_flag);
390 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800391 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100392 }
393 }
jjako193e8b12003-11-10 12:31:41 +0000394
Harald Weltebed35df2011-11-02 13:06:18 +0100395 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000396
Harald Weltebed35df2011-11-02 13:06:18 +0100397 /* foreground */
398 /* If fg flag not given run as a daemon */
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100399 /* Do not allow sgsnemu to run as deamon
Harald Weltebed35df2011-11-02 13:06:18 +0100400 if (!args_info.fg_flag)
401 {
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100402 closelog();
Harald Weltebed35df2011-11-02 13:06:18 +0100403 freopen("/dev/null", "w", stdout);
404 freopen("/dev/null", "w", stderr);
405 freopen("/dev/null", "r", stdin);
406 daemon(0, 0);
407 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
408 } */
jjako1a51df72004-07-20 08:30:21 +0000409
Harald Weltebed35df2011-11-02 13:06:18 +0100410 /* debug */
411 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000412
Harald Weltebed35df2011-11-02 13:06:18 +0100413 /* pidfile */
414 /* This has to be done after we have our final pid */
415 if (args_info.pidfile_arg) {
416 log_pid(args_info.pidfile_arg);
417 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200418
Harald Weltebed35df2011-11-02 13:06:18 +0100419 /* dns */
420 /* If no dns option is given use system default */
421 /* Do hostname lookup to translate hostname to IP address */
422 printf("\n");
423 if (args_info.dns_arg) {
424 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100425 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100426 "Invalid DNS address: %s!", args_info.dns_arg);
427 return -1;
428 } else {
429 memcpy(&options.dns.s_addr, host->h_addr,
430 host->h_length);
431 _res.nscount = 1;
432 _res.nsaddr_list[0].sin_addr = options.dns;
433 printf("Using DNS server: %s (%s)\n",
434 args_info.dns_arg, inet_ntoa(options.dns));
435 }
436 } else {
437 options.dns.s_addr = 0;
438 printf("Using default DNS server\n");
439 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200440
Harald Weltebed35df2011-11-02 13:06:18 +0100441 /* listen */
442 /* If no listen option is specified listen to any local port */
443 /* Do hostname lookup to translate hostname to IP address */
444 if (args_info.listen_arg) {
445 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100446 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100447 "Invalid listening address: %s!",
448 args_info.listen_arg);
449 return -1;
450 } else {
451 memcpy(&options.listen.s_addr, host->h_addr,
452 host->h_length);
453 printf("Local IP address is: %s (%s)\n",
454 args_info.listen_arg, inet_ntoa(options.listen));
455 }
456 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100457 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltefdf33582019-12-01 09:25:27 +0100458 "Listening address must be specified!");
Harald Weltebed35df2011-11-02 13:06:18 +0100459 return -1;
460 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200461
Harald Weltebed35df2011-11-02 13:06:18 +0100462 /* remote */
463 /* If no remote option is specified terminate */
464 /* Do hostname lookup to translate hostname to IP address */
465 if (args_info.remote_arg) {
466 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100467 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100468 "Invalid remote address: %s!",
469 args_info.remote_arg);
470 return -1;
471 } else {
472 memcpy(&options.remote.s_addr, host->h_addr,
473 host->h_length);
474 printf("Remote IP address is: %s (%s)\n",
475 args_info.remote_arg, inet_ntoa(options.remote));
476 }
477 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100478 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100479 "No remote address given!");
480 return -1;
481 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200482
Harald Weltebed35df2011-11-02 13:06:18 +0100483 /* imsi */
484 if (strlen(args_info.imsi_arg) != 15) {
485 printf("Invalid IMSI\n");
486 return -1;
487 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200488
Harald Weltebed35df2011-11-02 13:06:18 +0100489 options.imsi = 0xf000000000000000ull;
490 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
491 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
492 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
493 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
494 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
495 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
496 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
497 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
498 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
499 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
500 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
501 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
502 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
503 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
504 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200505
Harald Weltebed35df2011-11-02 13:06:18 +0100506 printf("IMSI is: %s (%#08llx)\n",
507 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200508
Harald Weltebed35df2011-11-02 13:06:18 +0100509 /* nsapi */
510 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
511 printf("Invalid NSAPI\n");
512 return -1;
513 }
514 options.nsapi = args_info.nsapi_arg;
515 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200516
Harald Weltebed35df2011-11-02 13:06:18 +0100517 /* qos */
518 options.qos.l = 4;
519 options.qos.v[3] = (args_info.qos_arg) & 0xff;
520 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
521 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
522 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
523 /* Extensions according to 3GPP TS 24.008 */
524 if (args_info.qose1_given == 1) {
525 options.qos.l = 12;
526 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
527 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
528 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
529 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
530 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
531 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
532 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
533 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
534 if (args_info.qose2_given == 1) {
535 options.qos.l = 13;
536 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
537 if (args_info.qose3_given == 1) {
538 options.qos.l = 15;
539 options.qos.v[14] =
540 (args_info.qose3_arg) & 0xff;
541 options.qos.v[13] =
542 ((args_info.qose3_arg) >> 8) & 0xff;
543 if (args_info.qose4_given == 1) {
544 options.qos.l = 17;
545 options.qos.v[16] =
546 (args_info.qose4_arg) & 0xff;
547 options.qos.v[15] =
548 ((args_info.qose4_arg) >> 8) & 0xff;
549 }
550 }
551 }
552 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200553
Harald Weltebed35df2011-11-02 13:06:18 +0100554 /* charging */
555 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200556
Harald Weltebed35df2011-11-02 13:06:18 +0100557 /* contexts */
558 if (args_info.contexts_arg > MAXCONTEXTS) {
559 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
560 return -1;
561 }
562 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200563
Harald Weltebed35df2011-11-02 13:06:18 +0100564 /* Timelimit */
565 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200566
Harald Weltebed35df2011-11-02 13:06:18 +0100567 /* gtpversion */
568 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
569 printf("Invalid GTP version\n");
570 return -1;
571 }
572 options.gtpversion = args_info.gtpversion_arg;
573 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200574
Harald Weltebed35df2011-11-02 13:06:18 +0100575 /* apn */
576 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
577 printf("Invalid APN\n");
578 return -1;
579 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100580 options.apn.l = strlen(args_info.apn_arg) + 1;
581
582 apn = (char *)options.apn.v;
583 for (tok = strtok(args_info.apn_arg, ".");
584 tok != NULL;
585 tok = strtok(NULL, ".")) {
586 size_t len = strlen(tok);
587
588 *apn++ = (char)len;
589 strncpy(apn, tok, len);
590 apn += len;
591 }
592
Harald Weltebed35df2011-11-02 13:06:18 +0100593 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200594
Harald Weltebed35df2011-11-02 13:06:18 +0100595 /* selmode */
596 options.selmode = args_info.selmode_arg;
597 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200598
Harald Weltebed35df2011-11-02 13:06:18 +0100599 /* rattype */
600 if (args_info.rattype_given == 1) {
601 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800602 options.rattype.l = 1;
603 options.rattype.v[0] = args_info.rattype_arg;
604 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100605 }
Harald Welte41af5692011-10-07 18:42:34 +0200606
Harald Weltebed35df2011-11-02 13:06:18 +0100607 /* userloc */
608 if (args_info.userloc_given == 1) {
609 printf("Using User Location Information: %s\n",
610 args_info.userloc_arg);
611 tmp = args_info.userloc_arg;
612 n = 0;
613 pch = strtok(tmp, ".");
614 while (pch != NULL) {
615 userloc_el[n] = pch;
616 pch = strtok(NULL, ".");
617 n++;
618 }
Harald Welte41af5692011-10-07 18:42:34 +0200619
Harald Weltebed35df2011-11-02 13:06:18 +0100620 options.userloc_given = 1;
621 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200622
Harald Weltebed35df2011-11-02 13:06:18 +0100623 /* 3GPP Geographic Location Type t0 / t1 / t2 */
624 type = userloc_el[0];
625 printf("->type : %c\n", type[0]);
626 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
627 printf("Invalid type \n");
628 return -1;
629 }
630 /* options.userloc.v[0] = 0x00 */
631 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200632
Harald Weltebed35df2011-11-02 13:06:18 +0100633 /* MCC */
634 mcc = userloc_el[1];
635 printf("->mcc : %s\n", mcc);
636 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200637 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100638 return -1;
639 }
Harald Welte41af5692011-10-07 18:42:34 +0200640
Harald Weltebed35df2011-11-02 13:06:18 +0100641 /* MNC */
642 mnc = userloc_el[2];
643 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200644
Harald Weltebed35df2011-11-02 13:06:18 +0100645 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
646 /* options.userloc.v[1] = 0x52 */
647 a = (uint8_t) (mcc[0] - 48);
648 b = (uint8_t) (mcc[1] - 48);
649 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200650
Harald Weltebed35df2011-11-02 13:06:18 +0100651 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
652 /* options.userloc.v[2] = 0xf0 */
653 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200654
Harald Weltebed35df2011-11-02 13:06:18 +0100655 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200656 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100657 return -1;
658 }
659 if (strlen(mnc) == 2) {
660 b = 15;
661 }
662 if (strlen(mnc) == 3) {
663 b = (uint8_t) (mnc[2] - 48);
664 }
665 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200666
Harald Weltebed35df2011-11-02 13:06:18 +0100667 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
668 /* options.userloc.v[3] = 0x99 */
669 a = (uint8_t) (mnc[0] - 48);
670 b = (uint8_t) (mnc[1] - 48);
671 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200672
Harald Weltebed35df2011-11-02 13:06:18 +0100673 /* LAC */
674 lac = userloc_el[3];
675 /*options.userloc.v[4] = 0x12 ; */
676 /*options.userloc.v[5] = 0x10 ; */
677 printf("->LAC: %s\n", lac);
678 lac_d = atoi(lac);
679 if (lac_d > 65535 || lac_d < 1) {
680 printf("Invalid LAC\n");
681 return -1;
682 }
683 i = lac_d >> 8;
684 options.userloc.v[4] = i; /* octet 8 - LAC */
685 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200686
Harald Weltebed35df2011-11-02 13:06:18 +0100687 /* CI/SAC/RAC */
688 rest = userloc_el[4];
689 printf("->CI/SAC/RAC : %s\n", rest);
690 lac_d = atoi(rest);
691 if (lac_d > 65535 || lac_d < 1) {
692 printf("Invalid CI/SAC/RAC\n");
693 return -1;
694 }
695 /*options.userloc.v[6] = 0x04 ; */
696 /*options.userloc.v[7] = 0xb7 ; */
697 i = lac_d >> 8;
698 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
699 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
700 }
jjakoa7cd2492003-04-11 09:40:12 +0000701
Harald Weltebed35df2011-11-02 13:06:18 +0100702 /* RAI */
703 if (args_info.rai_given == 1) {
704 printf("Using RAI: %s\n", args_info.rai_arg);
705 tmp = args_info.rai_arg;
706 n = 0;
707 pch = strtok(tmp, ".");
708 while (pch != NULL) {
709 rai_el[n] = pch;
710 pch = strtok(NULL, ".");
711 n++;
712 }
jjakoa7cd2492003-04-11 09:40:12 +0000713
Harald Weltebed35df2011-11-02 13:06:18 +0100714 options.rai_given = 1;
715 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000716
Harald Weltebed35df2011-11-02 13:06:18 +0100717 /* MCC */
718 mcc = rai_el[0];
719 printf("->mcc : %s\n", mcc);
720 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200721 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100722 return -1;
723 }
724
725 /* MNC */
726 mnc = rai_el[1];
727 printf("->mnc : %s\n", mnc);
728
729 a = (uint8_t) (mcc[0] - 48);
730 b = (uint8_t) (mcc[1] - 48);
731 options.rai.v[0] = 16 * b + a;
732
733 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
734 a = (uint8_t) (mcc[2] - 48);
735
736 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200737 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100738 return -1;
739 }
740 if (strlen(mnc) == 2) {
741 b = 15;
742 }
743 if (strlen(mnc) == 3) {
744 b = (uint8_t) (mnc[2] - 48);
745 }
746 options.rai.v[1] = 16 * b + a;
747
748 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
749 a = (uint8_t) (mnc[0] - 48);
750 b = (uint8_t) (mnc[1] - 48);
751 options.rai.v[2] = 16 * b + a;
752
753 /* LAC */
754 lac = rai_el[2];
755 printf("->LAC: %s\n", lac);
756 lac_d = atoi(lac);
757 if (lac_d > 65535 || lac_d < 1) {
758 printf("Invalid LAC\n");
759 return -1;
760 }
761 i = lac_d >> 8;
762 options.rai.v[3] = i; /* octet 5 - LAC */
763 options.rai.v[4] = lac_d; /* octet 6 - LAC */
764
765 /* RAC */
766 rest = rai_el[3];
767 printf("->RAC : %s\n", rest);
768 lac_d = atoi(rest);
769 if (lac_d > 255 || lac_d < 1) {
770 printf("Invalid RAC\n");
771 return -1;
772 }
773 options.rai.v[5] = lac_d; /* octet 7 - RAC */
774 }
775
776 /* mstz */
777 if (args_info.mstz_given == 1) {
778 options.mstz_given = 1;
779 options.mstz.l = 2;
780
781 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
782 tmp = args_info.mstz_arg;
783 n = 0;
784 pch = strtok(tmp, ".");
785 while (pch != NULL) {
786 mstz_el[n] = pch;
787 pch = strtok(NULL, ".");
788 n++;
789 }
790
791 /* sign */
792 sign = atoi(mstz_el[0]);
793 printf("->Sign (0=+ / 1=-): %d\n", sign);
794 if (sign != 0 && sign != 1) {
795 printf("Invalid Sign \n");
796 return -1;
797 }
798 /* nbquarters */
799 nbquarters = atoi(mstz_el[1]);
800 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
801 if (nbquarters < 0 || nbquarters > 79) {
802 printf("Invalid Number of Quarters \n");
803 return -1;
804 }
805 /* DST */
806 DST = atoi(mstz_el[2]);
807 printf("->Daylight Saving Time Adjustment : %d\n", DST);
808 if (DST < 0 || DST > 3) {
809 printf("Invalid DST Adjustment \n");
810 return -1;
811 }
812 /* 12345678
813 bits 123 = unit of # of quarters of an hour
814 bits 678 = # of quarters of an hour / 10
815 bit 5 = sign
816 */
817 i = nbquarters % 10;
818 i = i << 4;
819 i = i + nbquarters / 10 + 8 * sign;
820 /* options.mstz.v[0] = 0x69 ; */
821 /* options.mstz.v[1] = 0x01 ; */
822 options.mstz.v[0] = i;
823 options.mstz.v[1] = DST;
824 n = (i & 0x08) ? '-' : '+';
825 printf
826 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
827 n, nbquarters / 4, nbquarters % 4 * 15);
828 }
829
830 /* imeisv */
831 if (args_info.imeisv_given == 1) {
832 options.imeisv_given = 1;
833 if (strlen(args_info.imeisv_arg) != 16) {
834 printf("Invalid IMEI(SV)\n");
835 return -1;
836 }
837 options.imeisv.l = 8;
838 for (n = 0; n < 8; n++) {
839 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
840 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
841 options.imeisv.v[n] = 16 * b + a;
842 }
843 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
844 }
845
846 /* msisdn */
847 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
848 printf("Invalid MSISDN\n");
849 return -1;
850 }
851 options.msisdn.l = 1;
852 options.msisdn.v[0] = 0x91; /* International format */
853 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
854 if ((n % 2) == 0) {
855 options.msisdn.v[((int)n / 2) + 1] =
856 args_info.msisdn_arg[n] - 48 + 0xf0;
857 options.msisdn.l += 1;
858 } else {
859 options.msisdn.v[((int)n / 2) + 1] =
860 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
861 (args_info.msisdn_arg[n] - 48) * 16;
862 }
863 }
864 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
865
866 /* UID and PWD */
867 /* Might need to also insert stuff like DNS etc. */
868 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
869 (sizeof(options.pco.v) - 1)) {
870 printf("invalid UID and PWD\n");
871 return -1;
872 }
873 options.pco.l =
874 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
875 options.pco.v[0] = 0x80; /* PPP */
876 options.pco.v[1] = 0xc0; /* PAP */
877 options.pco.v[2] = 0x23;
878 options.pco.v[3] =
879 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
880 options.pco.v[4] = 0x01; /* Authenticate request */
881 options.pco.v[5] = 0x01;
882 options.pco.v[6] = 0x00; /* MSB of length */
883 options.pco.v[7] =
884 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
885 options.pco.v[8] = strlen(args_info.uid_arg);
886 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
887 options.pco.v[9 + strlen(args_info.uid_arg)] =
888 strlen(args_info.pwd_arg);
889 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
890 args_info.pwd_arg, strlen(args_info.pwd_arg));
891
892 /* createif */
893 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800894 options.tun_dev_name = args_info.tun_device_arg;
Andreas Schultzb6292402018-10-05 13:58:45 +0100895 options.netns = args_info.netns_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100896
897 /* net */
898 /* Store net as in_addr net and mask */
899 if (args_info.net_arg) {
900 if (ippool_aton
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +0200901 (&options.netaddr, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100902 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100903 "Invalid network address: %s!",
904 args_info.net_arg);
905 exit(1);
906 }
Harald Weltebed35df2011-11-02 13:06:18 +0100907 } else {
Harald Welted12eab92017-08-02 19:49:47 +0200908 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100909 memset(&options.netaddr, 0, sizeof(options.netaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100910 }
jjako193e8b12003-11-10 12:31:41 +0000911
Harald Weltebed35df2011-11-02 13:06:18 +0100912 /* ipup */
913 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000914
Harald Weltebed35df2011-11-02 13:06:18 +0100915 /* ipdown */
916 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000917
Harald Weltebed35df2011-11-02 13:06:18 +0100918 /* statedir */
919 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000920
Harald Weltebed35df2011-11-02 13:06:18 +0100921 /* defaultroute */
922 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000923
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200924 /* PDP Type */
925 if (!strcmp(args_info.pdp_type_arg, "v6"))
926 options.pdp_type = PDP_EUA_TYPE_v6;
927 else if (!strcmp(args_info.pdp_type_arg, "v4"))
928 options.pdp_type = PDP_EUA_TYPE_v4;
929 else {
930 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
931 args_info.pdp_type_arg);
932 return -1;
933 }
934
Harald Weltebed35df2011-11-02 13:06:18 +0100935 /* pinghost */
936 /* Store ping host as in_addr */
937 if (args_info.pinghost_arg) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200938 struct addrinfo hints;
939 struct addrinfo *result;
940 memset(&hints, 0, sizeof(struct addrinfo));
941 switch (options.pdp_type) {
942 case PDP_EUA_TYPE_v4:
943 hints.ai_family = AF_INET;
944 break;
945 case PDP_EUA_TYPE_v6:
946 hints.ai_family = AF_INET6;
947 break;
948 default:
949 SYS_ERR(DSGSN, LOGL_ERROR, 0, "lookup(AF_UNSPEC) %d", options.pdp_type);
950 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
951 }
952 hints.ai_socktype = SOCK_DGRAM;
953 hints.ai_flags = 0;
954 hints.ai_protocol = 0;
955 hints.ai_canonname = NULL;
956 hints.ai_addr = NULL;
957 hints.ai_next = NULL;
958 if ((i = getaddrinfo(args_info.pinghost_arg, NULL, &hints, &result)) != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100959 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200960 "Invalid ping host '%s': %s",
961 args_info.pinghost_arg, gai_strerror(i));
Harald Weltebed35df2011-11-02 13:06:18 +0100962 return -1;
963 } else {
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200964 switch (result->ai_family) {
965 case AF_INET:
966 options.pinghost.len = sizeof(struct in_addr);
967 options.pinghost.v4 = ((struct sockaddr_in*)result->ai_addr)->sin_addr;
968 SYS_ERR(DSGSN, LOGL_ERROR, 0, "AF_INET %d", options.pinghost.len);
969 break;
970 case AF_INET6:
971 options.pinghost.len = sizeof(struct in6_addr);
972 options.pinghost.v6 = ((struct sockaddr_in6*)result->ai_addr)->sin6_addr;
973 break;
974 }
Harald Weltebed35df2011-11-02 13:06:18 +0100975 printf("Using ping host: %s (%s)\n",
976 args_info.pinghost_arg,
Pau Espin Pedrol96214602020-04-14 19:39:09 +0200977 in46a_ntoa(&options.pinghost));
978 freeaddrinfo(result);
Harald Weltebed35df2011-11-02 13:06:18 +0100979 }
980 }
jjakoa7cd2492003-04-11 09:40:12 +0000981
Harald Weltebed35df2011-11-02 13:06:18 +0100982 /* Other ping parameters */
983 options.pingrate = args_info.pingrate_arg;
984 options.pingsize = args_info.pingsize_arg;
985 options.pingcount = args_info.pingcount_arg;
986 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000987
Harald Weltebed35df2011-11-02 13:06:18 +0100988 /* norecovery */
989 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000990
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800991 if (args_info.no_tx_gpdu_seq_flag)
992 options.tx_gpdu_seq = 0;
993 else
994 options.tx_gpdu_seq = 1;
995
Harald Weltebed35df2011-11-02 13:06:18 +0100996 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000997
998}
999
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001000/* write a single value to a /proc file */
1001static int proc_write(const char *path, const char *value)
1002{
1003 int ret;
1004 FILE *f;
1005
1006 f = fopen(path, "w");
1007 if (!f) {
1008 SYS_ERR(DSGSN, LOGL_ERROR, 0, "fopen(%s) failed!\n", path);
1009 return -1;
1010 }
1011
1012 if ((ret = fputs(value, f)) < 0) {
1013 SYS_ERR(DSGSN, LOGL_ERROR, 0, "proc_write(%s, %s) failed!\n", path, value);
1014 } else {
1015 ret = 0;
1016 }
1017 fclose(f);
1018 return ret;
1019}
1020
1021/* Write value of to /proc/sys/net/ipv6/conf file for given device.
1022 * Memory is dynamically allocated, caller must free it later. */
1023static int proc_ipv6_conf_write(const char *dev, const char *file, const char *value)
1024{
1025 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
1026 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
1027 snprintf(path, sizeof(path), fmt, dev, file);
1028 return proc_write(path, value);
1029}
1030
Harald Weltefed33892017-10-10 09:02:45 +08001031static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001032{
Harald Weltee37f48e2017-10-10 09:05:50 +08001033 struct protoent *pe = getprotobynumber(t);
1034
1035 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +01001036 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +08001037 else
1038 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001039}
1040
Harald Weltefed33892017-10-10 09:02:45 +08001041static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001042{
1043 static char *ttab[] = {
1044 "Echo Reply",
1045 "ICMP 1",
1046 "ICMP 2",
1047 "Dest Unreachable",
1048 "Source Quench",
1049 "Redirect",
1050 "ICMP 6",
1051 "ICMP 7",
1052 "Echo",
1053 "ICMP 9",
1054 "ICMP 10",
1055 "Time Exceeded",
1056 "Parameter Problem",
1057 "Timestamp",
1058 "Timestamp Reply",
1059 "Info Request",
1060 "Info Reply"
1061 };
1062 if (t < 0 || t > 16)
1063 return ("OUT-OF-RANGE");
1064 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001065}
1066
Harald Weltefed33892017-10-10 09:02:45 +08001067static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001068{
1069 unsigned int n;
1070 uint64_t i64 = 0;
1071 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1072 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001073
Harald Weltebed35df2011-11-02 13:06:18 +01001074 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1075 /* ul16_t format always starts with 0x91 to indicate international format */
1076 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1077 for (n = 0; n < src->l; n++) {
1078 if ((src->v[n] & 0x0f) != 0x0f) {
1079 i64 *= 10;
1080 i64 += src->v[n] & 0x0f;
1081 }
1082 if ((src->v[n] & 0xf0) != 0xf0) {
1083 i64 *= 10;
1084 i64 += (src->v[n] & 0xf0) >> 4;
1085 }
1086 }
jjako193e8b12003-11-10 12:31:41 +00001087
Harald Weltebed35df2011-11-02 13:06:18 +01001088 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001089
Harald Weltebed35df2011-11-02 13:06:18 +01001090 /* Generate array with least significant digit in first octet */
1091 while (i64) {
1092 msa[msalen++] = i64 % 10;
1093 i64 = i64 / 10;
1094 }
jjako193e8b12003-11-10 12:31:41 +00001095
Harald Weltebed35df2011-11-02 13:06:18 +01001096 /* Convert back to ul16_t format */
1097 for (n = 0; n < msalen; n++) {
1098 if ((n % 2) == 0) {
1099 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1100 dst->l += 1;
1101 } else {
1102 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1103 msa[msalen - n - 1] * 16;
1104 }
1105 }
jjako193e8b12003-11-10 12:31:41 +00001106
Harald Weltebed35df2011-11-02 13:06:18 +01001107 return 0;
jjako193e8b12003-11-10 12:31:41 +00001108
1109}
1110
Harald Weltefed33892017-10-10 09:02:45 +08001111static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001112{
1113 /* TODO: big endian / small endian ??? */
1114 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001115
Harald Weltebed35df2011-11-02 13:06:18 +01001116 /* Convert from uint64_t bcd to uint64_t integer format */
1117 /* The resulting integer format is multiplied by 10 */
1118 while (src) {
1119 if ((src & 0x0f) != 0x0f) {
1120 i64 *= 10;
1121 i64 += (src & 0x0f);
1122 }
1123 if ((src & 0xf0) != 0xf0) {
1124 i64 *= 10;
1125 i64 += (src & 0xf0) >> 4;
1126 }
1127 src = src >> 8;
1128 }
jjako193e8b12003-11-10 12:31:41 +00001129
Harald Weltebed35df2011-11-02 13:06:18 +01001130 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001131
Harald Weltebed35df2011-11-02 13:06:18 +01001132 *dst = 0;
1133 while (i64) {
1134 *dst = *dst << 4;
1135 *dst += (i64 % 10);
1136 i64 = i64 / 10;
1137 }
jjako193e8b12003-11-10 12:31:41 +00001138
Harald Weltebed35df2011-11-02 13:06:18 +01001139 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001140
Harald Weltebed35df2011-11-02 13:06:18 +01001141 return 0;
jjako193e8b12003-11-10 12:31:41 +00001142
1143}
1144
jjakoafb2a972003-01-29 21:04:13 +00001145/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001146static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001147{
1148 struct timezone tz;
1149 struct timeval tv;
1150 int diff;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001151 if ((options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01001152 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1153 gettimeofday(&tv, &tz);
1154 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1155 tp->tv_sec = 0;
1156 if (diff > 0)
1157 tp->tv_usec = diff;
1158 else {
1159 /* For some reason we get packet loss if set to zero */
1160 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1161 tp->tv_usec = 0;
1162 }
1163 }
1164 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001165}
1166
jjako5da68452003-01-28 16:08:47 +00001167/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001168static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001169{
Harald Weltebed35df2011-11-02 13:06:18 +01001170 struct timezone tz;
1171 struct timeval tv;
1172 int elapsed;
1173 gettimeofday(&tv, &tz);
1174 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1175 printf("\n");
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001176 printf("\n----%s PING Statistics----\n", in46a_ntoa(&options.pinghost));
Harald Weltebed35df2011-11-02 13:06:18 +01001177 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1178 elapsed / 1000000.0);
1179 printf("%d packets received, ", nreceived);
1180 if (ntransmitted) {
1181 if (nreceived > ntransmitted)
1182 printf("-- somebody's printing up packets!");
1183 else
1184 printf("%d%% packet loss",
1185 (int)(((ntransmitted - nreceived) * 100) /
1186 ntransmitted));
1187 }
1188 printf("\n");
1189 if (options.debug)
1190 printf("%d packets received in total\n", ntreceived);
1191 if (nreceived && tsum)
1192 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1193 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
Pau Espin Pedrolcdcaeda2020-04-15 16:37:58 +02001194 printf("%d packets transmitted \n", ntransmitted);
jjakoafb2a972003-01-29 21:04:13 +00001195
Harald Weltebed35df2011-11-02 13:06:18 +01001196 ntransmitted = 0;
1197 return 0;
jjako5da68452003-01-28 16:08:47 +00001198}
1199
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001200static int encaps_ping4(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001201{
Harald Weltebed35df2011-11-02 13:06:18 +01001202 struct timeval tv;
1203 struct timeval *tp;
1204 struct ip_ping *pingpack = pack;
1205 struct in_addr src;
1206 int triptime;
jjako5da68452003-01-28 16:08:47 +00001207
Harald Weltebed35df2011-11-02 13:06:18 +01001208 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001209
Harald Weltebed35df2011-11-02 13:06:18 +01001210 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1211 printf("packet too short (%d bytes) from %s\n", len,
1212 inet_ntoa(src));
1213 return 0;
1214 }
jjako5da68452003-01-28 16:08:47 +00001215
Harald Weltebed35df2011-11-02 13:06:18 +01001216 if (pingpack->protocol != 1) {
1217 if (!options.pingquiet)
1218 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1219 len, inet_ntoa(src), pingpack->protocol,
1220 print_ipprot(pingpack->protocol));
1221 return 0;
1222 }
jjako5da68452003-01-28 16:08:47 +00001223
Harald Weltebed35df2011-11-02 13:06:18 +01001224 if (pingpack->type != 0) {
1225 if (!options.pingquiet)
1226 printf
1227 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1228 len, inet_ntoa(src), pingpack->type,
1229 print_icmptype(pingpack->type), pingpack->code);
1230 return 0;
1231 }
jjako5da68452003-01-28 16:08:47 +00001232
Harald Weltebed35df2011-11-02 13:06:18 +01001233 nreceived++;
1234 if (!options.pingquiet)
1235 printf("%d bytes from %s: icmp_seq=%d", len,
1236 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001237
Harald Weltebed35df2011-11-02 13:06:18 +01001238 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001239 gettimeofday(&tv, NULL);
Harald Weltebed35df2011-11-02 13:06:18 +01001240 tp = (struct timeval *)pingpack->data;
1241 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1242 tv.tv_sec--;
1243 tv.tv_usec += 1000000;
1244 }
1245 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001246
Harald Weltebed35df2011-11-02 13:06:18 +01001247 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1248 tsum += triptime;
1249 if (triptime < tmin)
1250 tmin = triptime;
1251 if (triptime > tmax)
1252 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001253
Harald Weltebed35df2011-11-02 13:06:18 +01001254 if (!options.pingquiet)
1255 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001256
Harald Weltebed35df2011-11-02 13:06:18 +01001257 } else if (!options.pingquiet)
1258 printf("\n");
1259 return 0;
jjako5da68452003-01-28 16:08:47 +00001260}
1261
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001262static int encaps_ping6(struct pdp_t *pdp, struct ip6_hdr *ip6h, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001263{
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001264 const struct icmpv6_echo_hdr *ic6h = (struct icmpv6_echo_hdr *) ((uint8_t*)ip6h + sizeof(*ip6h));
1265 struct timeval tv;
1266 struct timeval tp;
1267 int triptime;
1268 char straddr[128];
jjako5da68452003-01-28 16:08:47 +00001269
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001270 if (len < sizeof(struct ip6_hdr)) {
1271 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain IPv6 header (%d)", len);
1272 return 0;
1273 }
1274
1275 if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_ICMPV6) {
1276 if (!options.pingquiet)
1277 printf("%d bytes from %s: ip6_protocol=%d (%s)\n", len,
1278 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1279 ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt,
1280 print_ipprot(ip6h->ip6_ctlun.ip6_un1.ip6_un1_nxt));
1281 return 0;
1282 }
1283
1284 if (len < sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr)) {
1285 LOGP(DSGSN, LOGL_ERROR, "Packet len too small to contain ICMPv6 echo header (%d)\n", len);
1286 return 0;
1287 }
1288
1289 if (ic6h->hdr.type != 129 || ic6h->hdr.code != 0) {
1290 if (!options.pingquiet)
1291 printf
1292 ("%d bytes from %s: icmp_type=%d icmp_code=%d\n", len,
1293 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1294 ic6h->hdr.type, ic6h->hdr.code);
1295 return 0;
1296 }
1297
1298 nreceived++;
1299 if (!options.pingquiet)
1300 printf("%d bytes from %s: icmp_seq=%d", len,
1301 inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)),
1302 ntohs(ic6h->seq));
1303
1304 if (len >= sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr) + sizeof(struct timeval)) {
1305 gettimeofday(&tv, NULL);
1306 memcpy(&tp, ic6h->data, sizeof(struct timeval));
1307 if ((tv.tv_usec -= tp.tv_usec) < 0) {
1308 tv.tv_sec--;
1309 tv.tv_usec += 1000000;
1310 }
1311 tv.tv_sec -= tp.tv_sec;
1312
1313 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1314 tsum += triptime;
1315 if (triptime < tmin)
1316 tmin = triptime;
1317 if (triptime > tmax)
1318 tmax = triptime;
1319
1320 if (!options.pingquiet)
1321 printf(" time=%.3f ms\n", triptime / 1000.0);
1322
1323 } else if (!options.pingquiet)
1324 printf("\n");
1325 return 0;
1326}
1327
1328/* Handle a received ping packet. Print out line and update statistics. */
1329static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1330{
1331 struct iphdr *iph = (struct iphdr *)pack;
1332 struct timeval tv;
1333
1334
1335 gettimeofday(&tv, NULL);
1336 if (options.debug)
1337 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
1338
1339 ntreceived++;
1340
1341 if (len < sizeof(struct iphdr)) {
1342 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Packet len too small to contain ip header (%d)", len);
1343 return -1;
1344 }
1345 switch(iph->version) {
1346 case 4:
1347 return encaps_ping4(pdp, pack, len);
1348 case 6:
1349 return encaps_ping6(pdp, (struct ip6_hdr *)pack, len);
1350 default:
1351 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unknown ip header version %d", iph->version);
1352 return -1;
1353 }
1354}
1355
1356static int create_ping4(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1357 struct in46_addr *dst, int seq, unsigned int datasize)
1358{
Harald Weltebed35df2011-11-02 13:06:18 +01001359 struct ip_ping pack;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001360 uint16_t v16;
Harald Weltebed35df2011-11-02 13:06:18 +01001361 uint8_t *p8 = (uint8_t *) & pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001362 unsigned int n;
1363 long int sum = 0;
1364 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001365
Harald Weltebed35df2011-11-02 13:06:18 +01001366 struct timezone tz;
1367 struct timeval *tp =
1368 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001369
Harald Weltebed35df2011-11-02 13:06:18 +01001370 pack.ipver = 0x45;
1371 pack.tos = 0x00;
1372 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1373 pack.fragid = 0x0000;
1374 pack.offset = 0x0040;
1375 pack.ttl = 0x40;
1376 pack.protocol = 0x01;
1377 pack.ipcheck = 0x0000;
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001378 pack.src = src->v4.s_addr;
1379 pack.dst = dst->v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +01001380 pack.type = 0x08;
1381 pack.code = 0x00;
1382 pack.checksum = 0x0000;
1383 pack.ident = 0x0000;
1384 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001385
Harald Weltebed35df2011-11-02 13:06:18 +01001386 /* Generate ICMP payload */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001387 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
Harald Weltebed35df2011-11-02 13:06:18 +01001388 for (n = 0; n < (datasize); n++)
1389 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001390
Harald Weltebed35df2011-11-02 13:06:18 +01001391 if (datasize >= sizeof(struct timeval))
1392 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001393
Harald Weltebed35df2011-11-02 13:06:18 +01001394 /* Calculate IP header checksum */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001395 p8 = (uint8_t *) &pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001396 count = CREATEPING_IP;
1397 sum = 0;
1398 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001399 memcpy(&v16, p8, 2);
1400 sum += v16;
1401 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001402 count -= 2;
1403 }
1404 while (sum >> 16)
1405 sum = (sum & 0xffff) + (sum >> 16);
1406 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001407
Harald Weltebed35df2011-11-02 13:06:18 +01001408 /* Calculate ICMP checksum */
1409 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1410 sum = 0;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001411 p8 = (uint8_t *) &pack;
1412 p8 += CREATEPING_IP;
Harald Weltebed35df2011-11-02 13:06:18 +01001413 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001414 memcpy(&v16, p8, 2);
1415 sum += v16;
1416 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001417 count -= 2;
1418 }
1419 if (count > 0)
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001420 sum += *(unsigned char *)p8;
Harald Weltebed35df2011-11-02 13:06:18 +01001421 while (sum >> 16)
1422 sum = (sum & 0xffff) + (sum >> 16);
1423 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001424
Harald Weltebed35df2011-11-02 13:06:18 +01001425 ntransmitted++;
1426 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001427}
1428
Pau Espin Pedrol96214602020-04-14 19:39:09 +02001429static int create_ping6(void *gsn, struct pdp_t *pdp, struct in46_addr *src,
1430 struct in46_addr *dst, int seq, unsigned int datasize)
1431{
1432 struct ip6_ping *pack;
1433 uint8_t *p8;
1434 unsigned int n;
1435 struct timezone tz;
1436 struct timeval *tp;
1437
1438 struct msgb *msg = msgb_alloc_headroom(sizeof(struct ip6_ping) + 128,128, "ICMPv6 echo");
1439 OSMO_ASSERT(msg);
1440 pack = (struct ip6_ping *) msgb_put(msg, sizeof(struct icmpv6_echo_hdr) + datasize);
1441 pack->hdr.hdr.type = 128;
1442 pack->hdr.hdr.code = 0;
1443 pack->hdr.hdr.csum = 0; /* updated below */
1444 pack->hdr.ident = 0x0000;
1445 pack->hdr.seq = htons(seq);
1446
1447 p8 = pack->data;
1448 for (n = 0; n < (datasize); n++)
1449 p8[n] = n;
1450
1451 if (datasize >= sizeof(struct timeval)) {
1452 tp = (struct timeval *)pack->data;
1453 gettimeofday(tp, &tz);
1454 }
1455
1456 pack->hdr.hdr.csum = icmpv6_prepend_ip6hdr(msg, &src->v6, &dst->v6);
1457
1458 ntransmitted++;
1459 return gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
1460}
1461
1462/* Create a new ping packet and send it off to peer. */
1463static int create_ping(void *gsn, struct pdp_t *pdp,
1464 struct in46_addr *dst, int seq, unsigned int datasize)
1465{
1466 int num_addr;
1467 struct in46_addr addr[2];
1468 struct in46_addr *src;
1469
1470 if (datasize > CREATEPING_MAX) {
1471 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1472 "Ping size to large: %d!", datasize);
1473 return -1;
1474 }
1475
1476 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
1477 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1478 "in46a_from_eua() failed! %d", num_addr);
1479 return -1;
1480 }
1481 if (dst->len == addr[0].len) {
1482 src = &addr[0];
1483 } else if (num_addr > 1 && dst->len == addr[1].len) {
1484 src = &addr[1];
1485 } else {
1486 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1487 "Mismaching source and destination IP addr types (%d vs %d)", dst->len, addr[0].len);
1488 return -1;
1489 }
1490 if (in46a_is_v4(dst))
1491 return create_ping4(gsn, pdp, src, dst, seq, datasize);
1492 else
1493 return create_ping6(gsn, pdp, src, dst, seq, datasize);
1494}
1495
Harald Weltefed33892017-10-10 09:02:45 +08001496static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001497{
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001498 int rc;
1499
Andreas Schultzb6292402018-10-05 13:58:45 +01001500 if (tun && options.ipdown) {
1501#if defined(__linux__)
1502 sigset_t oldmask;
Harald Weltebed35df2011-11-02 13:06:18 +01001503
Andreas Schultzb6292402018-10-05 13:58:45 +01001504 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001505 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1506 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1507 "Failed to switch to netns %s: %s\n",
1508 options.netns, strerror(-rc));
1509 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001510 }
1511#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001512 tun_runscript(tun, options.ipdown);
1513
Andreas Schultzb6292402018-10-05 13:58:45 +01001514#if defined(__linux__)
1515 if ((options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001516 if ((rc = restore_ns(&oldmask)) < 0) {
1517 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1518 "Failed to switch to original netns: %s\n",
1519 strerror(-rc));
1520 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001521 }
1522#endif
1523 }
1524
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001525 ipdel((struct iphash_t *)pdp->peer[0]);
1526 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001527
1528 if (1 == options.contexts)
1529 state = 5; /* Disconnected */
1530
1531 return 0;
1532}
jjakoa7cd2492003-04-11 09:40:12 +00001533
Harald Welte6748dc92017-09-24 21:54:59 +08001534/* Link-Local address prefix fe80::/64 */
1535static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1536
jjakoa7cd2492003-04-11 09:40:12 +00001537/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001538static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001539{
1540 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001541 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001542 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001543 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001544
Harald Welte6748dc92017-09-24 21:54:59 +08001545 if (iph->version == 4) {
1546 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1547 printf("Dropping packet with too short IP header\n");
1548 return 0;
1549 }
1550 src.len = 4;
1551 src.v4.s_addr = iph->saddr;
1552 } else if (iph->version == 6) {
1553 /* We only have a single entry in the hash table, and it consists of the link-local
1554 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1555 * addresses to that format before looking up the hash table via ippool_getip() */
1556 src.len = 16;
1557 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1558 /* is a link-local address, we can do the hash lookup 1:1 */
1559 src.v6 = ip6h->ip6_src;
1560 } else {
1561 /* it is not a link-local address, so we must convert from the /64 prefix
1562 * to the link-local format that's used in the hash table */
1563 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1564 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1565 }
1566 } else {
1567 printf("Dropping packet with invalid IP version %u\n", iph->version);
1568 return 0;
1569 }
jjakoa7cd2492003-04-11 09:40:12 +00001570
Harald Weltebed35df2011-11-02 13:06:18 +01001571 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001572 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001573 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001574 return 0;
1575 }
1576
1577 if (ipm->pdp) /* Check if a peer protocol is defined */
1578 gtp_data_req(gsn, ipm->pdp, pack, len);
1579 return 0;
jjako52c24142002-12-16 13:33:51 +00001580}
1581
Harald Weltefed33892017-10-10 09:02:45 +08001582static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001583{
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001584 int rc, i, num_addr;
1585 struct in46_addr addr[2];
Andreas Schultzb6292402018-10-05 13:58:45 +01001586#if defined(__linux__)
1587 sigset_t oldmask;
1588#endif
jjako52c24142002-12-16 13:33:51 +00001589
Harald Weltebed35df2011-11-02 13:06:18 +01001590 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001591
Harald Weltebed35df2011-11-02 13:06:18 +01001592 if (cause < 0) {
1593 printf("Create PDP Context Request timed out\n");
1594 if (iph->pdp->version == 1) {
1595 printf("Retrying with version 0\n");
1596 iph->pdp->version = 0;
1597 gtp_create_context_req(gsn, iph->pdp, iph);
1598 return 0;
1599 } else {
1600 state = 0;
1601 pdp_freepdp(iph->pdp);
1602 iph->pdp = NULL;
1603 return EOF;
1604 }
1605 }
jjako2c381332003-10-21 19:09:53 +00001606
Harald Weltebed35df2011-11-02 13:06:18 +01001607 if (cause != 128) {
1608 printf
1609 ("Received create PDP context response. Cause value: %d\n",
1610 cause);
1611 state = 0;
1612 pdp_freepdp(iph->pdp);
1613 iph->pdp = NULL;
1614 return EOF; /* Not what we expected */
1615 }
jjako52c24142002-12-16 13:33:51 +00001616
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001617 if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001618 printf
1619 ("Received create PDP context response. Cause value: %d\n",
1620 cause);
1621 pdp_freepdp(iph->pdp);
1622 iph->pdp = NULL;
1623 state = 0;
1624 return EOF; /* Not a valid IP address */
1625 }
jjakoa7cd2492003-04-11 09:40:12 +00001626
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001627 printf("Received create PDP context response.\n");
jjakoa7cd2492003-04-11 09:40:12 +00001628
Andreas Schultzb6292402018-10-05 13:58:45 +01001629#if defined(__linux__)
1630 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001631 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1632 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1633 "Failed to switch to netns %s: %s\n",
1634 options.netns, strerror(-rc));
1635 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001636 }
1637#endif
1638
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001639 for (i = 0; i < num_addr; i++) {
1640 printf("PDP ctx: received EUA with IP address: %s\n", in46a_ntoa(&addr[i]));
1641
1642 switch (addr[i].len) {
1643 case 16: /* IPv6 */
1644 /* we have to enable the kernel to perform stateless autoconfiguration,
1645 * i.e. send a router solicitation using the lover 64bits of the allocated
1646 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1647 memcpy(addr[i].v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1648 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr[i]));
1649 break;
1650 case 4: /* IPv4 */
1651 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001652 }
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001653
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001654 if ((options.createif) && (!options.netaddr.len)) {
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001655 size_t prefixlen = 32;
1656 if (addr[i].len == 16)
1657 prefixlen = 64;
1658 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrole5d71632020-04-15 14:43:50 +02001659 tun_addaddr(tun, &addr[i], NULL, prefixlen);
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001660 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001661 if (in46a_is_v4(&addr[i])) {
1662 struct in_addr rm;
1663 rm.s_addr = 0;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001664 if (netdev_addroute4(&rm, &addr[i].v4, &rm) < 0) {
1665 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", in46a_ntoa(&addr[i]));
1666 }
1667 } /* else: route will be set up once we have a global link address (Router Advertisement) */
Pau Espin Pedrol28c6a322020-04-09 17:52:19 +02001668 }
1669 if (options.ipup)
1670 tun_runscript(tun, options.ipup);
1671 }
1672
1673 ipset(iph, &addr[i]);
Harald Weltebed35df2011-11-02 13:06:18 +01001674 }
jjako52c24142002-12-16 13:33:51 +00001675
Harald Welte081f30c2017-10-10 09:36:35 +08001676 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001677 struct in6_addr *saddr6;
1678 struct msgb *msg;
1679 if (in46a_is_v6(&addr[0])) {
1680 saddr6 = &addr[0].v6;
1681 } else if (num_addr > 1 && in46a_is_v6(&addr[1])) {
1682 saddr6 = &addr[1].v6;
1683 } else {
1684 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to find IPv6 EUA on IPv6 APN");
1685 return EOF; /* Not a valid IP address */
Harald Welte081f30c2017-10-10 09:36:35 +08001686 }
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001687 SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN...");
1688 msg = icmpv6_construct_rs(saddr6);
1689 gtp_data_req(gsn, iph->pdp, msgb_data(msg), msgb_length(msg));
1690 msgb_free(msg);
Harald Welte081f30c2017-10-10 09:36:35 +08001691 }
1692
Andreas Schultzb6292402018-10-05 13:58:45 +01001693#if defined(__linux__)
1694 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001695 if ((rc = restore_ns(&oldmask)) < 0) {
1696 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1697 strerror(-rc));
1698 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001699 }
1700#endif
1701
Harald Weltebed35df2011-11-02 13:06:18 +01001702
1703 state = 2; /* Connected */
1704
1705 return 0;
jjako52c24142002-12-16 13:33:51 +00001706}
1707
Harald Weltefed33892017-10-10 09:02:45 +08001708static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001709{
1710 printf("Received delete PDP context response. Cause value: %d\n",
1711 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001712 if (pdp)
1713 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001714 return 0;
jjako52c24142002-12-16 13:33:51 +00001715}
1716
Harald Weltefed33892017-10-10 09:02:45 +08001717static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001718{
jjako91aaf222003-10-22 10:09:32 +00001719
Harald Weltebed35df2011-11-02 13:06:18 +01001720 if (recovery < 0) {
1721 printf("Echo Request timed out\n");
1722 if (echoversion == 1) {
1723 printf("Retrying with version 0\n");
1724 echoversion = 0;
1725 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1726 return 0;
1727 } else {
1728 state = 0;
1729 return EOF;
1730 }
1731 } else {
1732 printf("Received echo response\n");
1733 if (!options.contexts)
1734 state = 5;
1735 }
1736 return 0;
jjako52c24142002-12-16 13:33:51 +00001737}
1738
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001739static int _gtp_cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001740{
1741 /* if (cause < 0) return 0; Some error occurred. We don't care */
1742 switch (type) {
1743 case GTP_ECHO_REQ:
1744 return echo_conf(cause);
1745 case GTP_CREATE_PDP_REQ:
1746 return create_pdp_conf(pdp, cbp, cause);
1747 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001748 return delete_pdp_conf(pdp, cause);
1749 default:
1750 return 0;
1751 }
jjako52c24142002-12-16 13:33:51 +00001752}
1753
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001754static void handle_router_adv(struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len)
1755{
1756 struct icmpv6_opt_hdr *opt_hdr;
1757 struct icmpv6_opt_prefix *opt_prefix;
1758 int rc;
1759 sigset_t oldmask;
1760 struct in6_addr rm;
1761 char ip6strbuf[200];
1762 memset(&rm, 0, sizeof(rm));
1763
1764 SYS_ERR(DSGSN, LOGL_INFO, 0, "Received ICMPv6 Router Advertisement");
1765
1766 foreach_icmpv6_opt(ra, ra_len, opt_hdr) {
1767 if (opt_hdr->type == ICMPv6_OPT_TYPE_PREFIX_INFO) {
1768 opt_prefix = (struct icmpv6_opt_prefix *)opt_hdr;
1769 size_t prefix_len_bytes = (opt_prefix->prefix_len + 7)/8;
1770 SYS_ERR(DSGSN, LOGL_INFO, 0, "Parsing OPT Prefix info (prefix_len=%u): %s",
1771 opt_prefix->prefix_len,
1772 osmo_hexdump((const unsigned char *)opt_prefix->prefix, prefix_len_bytes));
1773 if ((options.createif) && (!options.netaddr.len)) {
1774 struct in46_addr addr;
1775 addr.len = 16;
1776 memcpy(addr.v6.s6_addr, opt_prefix->prefix, prefix_len_bytes);
1777 memset(&addr.v6.s6_addr[prefix_len_bytes], 0, 16 - prefix_len_bytes);
1778 addr.v6.s6_addr[15] = 0x02;
1779 SYS_ERR(DSGSN, LOGL_INFO, 0, "Adding addr %s to tun %s",
1780 in46a_ntoa(&addr), tun->devname);
1781
1782#if defined(__linux__)
1783 if ((options.netns)) {
1784 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1785 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1786 "Failed to switch to netns %s: %s",
1787 options.netns, strerror(-rc));
1788 }
1789 }
1790#endif
1791 rc = tun_addaddr(tun, &addr, NULL, opt_prefix->prefix_len);
1792 if (rc < 0) {
1793 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to add addr %s to tun %s",
1794 in46a_ntoa(&addr), tun->devname);
1795 }
1796
1797 struct in6_addr rm;
1798 memset(&rm, 0, sizeof(rm));
1799 if (netdev_addroute6(&rm, &ip6h->ip6_src, 0, tun->devname) < 0) {
1800 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", inet_ntop(AF_INET6, &ip6h->ip6_src, ip6strbuf, sizeof(ip6strbuf)));
1801 }
1802
1803#if defined(__linux__)
1804 if ((options.netns)) {
1805 if ((rc = restore_ns(&oldmask)) < 0) {
1806 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1807 "Failed to switch to original netns: %s",
1808 strerror(-rc));
1809 }
1810 }
1811#endif
1812 }
1813 }
1814 }
1815}
1816
Harald Weltefed33892017-10-10 09:02:45 +08001817static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001818{
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001819 struct iphdr *iph = (struct iphdr *)pack;
1820 struct icmpv6_radv_hdr *ra;
1821 switch (iph->version) {
1822 case 6:
1823 if ((ra = icmpv6_validate_router_adv(pack, len))) {
1824 size_t ra_len = (uint8_t*)ra - (uint8_t*)pack;
1825 handle_router_adv((struct ip6_hdr *)pack, ra, ra_len);
1826 return 0;
1827 }
1828 break;
1829 }
1830
Harald Weltebed35df2011-11-02 13:06:18 +01001831 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1832 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001833}
1834
1835int main(int argc, char **argv)
1836{
Harald Weltebed35df2011-11-02 13:06:18 +01001837 fd_set fds; /* For select() */
1838 struct timeval idleTime; /* How long to select() */
1839 struct pdp_t *pdp;
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001840 int n, rc;
Harald Weltebed35df2011-11-02 13:06:18 +01001841 int starttime = time(NULL); /* Time program was started */
1842 int stoptime = 0; /* Time to exit */
1843 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001844 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001845
Harald Weltebed35df2011-11-02 13:06:18 +01001846 struct timezone tz; /* Used for calculating ping times */
1847 struct timeval tv;
1848 int diff;
Andreas Schultzb6292402018-10-05 13:58:45 +01001849#if defined(__linux__)
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001850 char buf[10];
Andreas Schultzb6292402018-10-05 13:58:45 +01001851 sigset_t oldmask;
1852#endif
jjako52c24142002-12-16 13:33:51 +00001853
bjovana8f71eb2017-02-24 17:39:20 +01001854 signal(SIGTERM, signal_handler);
1855 signal(SIGHUP, signal_handler);
1856 signal(SIGINT, signal_handler);
1857
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001858 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1859 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1860 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001861
Andreas Schultzb6292402018-10-05 13:58:45 +01001862#if defined(__linux__)
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001863 if ((rc = init_netns()) < 0) {
1864 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
1865 exit(1);
1866 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001867#endif
1868
Harald Weltebed35df2011-11-02 13:06:18 +01001869 /* Process options given in configuration file and command line */
1870 if (process_options(argc, argv))
1871 exit(1);
jjako52c24142002-12-16 13:33:51 +00001872
Harald Weltebed35df2011-11-02 13:06:18 +01001873 printf("\nInitialising GTP library\n");
1874 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001875 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001876 exit(1);
1877 }
1878 if (gsn->fd0 > maxfd)
1879 maxfd = gsn->fd0;
1880 if (gsn->fd1c > maxfd)
1881 maxfd = gsn->fd1c;
1882 if (gsn->fd1u > maxfd)
1883 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001884
Harald Weltebed35df2011-11-02 13:06:18 +01001885 gtp_set_cb_delete_context(gsn, delete_context);
Pau Espin Pedrol9366f4c2020-04-09 18:01:42 +02001886 gtp_set_cb_conf(gsn, _gtp_cb_conf);
Harald Weltebed35df2011-11-02 13:06:18 +01001887 if (options.createif)
1888 gtp_set_cb_data_ind(gsn, encaps_tun);
1889 else
1890 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001891
Andreas Schultzb6292402018-10-05 13:58:45 +01001892#if defined(__linux__)
1893 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001894 if ((netns = get_nsfd(options.netns)) < 0) {
1895 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
1896 options.netns, strerror(-netns));
1897 exit(1);
1898 }
1899 if ((rc = switch_ns(netns, &oldmask)) < 0) {
1900 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
1901 options.netns, strerror(-rc));
1902 exit(1);
1903 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001904 }
1905#endif
1906
Harald Weltebed35df2011-11-02 13:06:18 +01001907 if (options.createif) {
1908 printf("Setting up interface\n");
1909 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001910 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001911 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001912 "Failed to create tun");
1913 exit(1);
1914 }
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001915
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001916#if defined(__linux__) && defined(HAVE_IN6_ADDR_GEN_MODE_NONE)
1917 /* Avoid tunnel setting its own link-local addr automatically,
1918 we don't need it. Don't exit on error since this sysctl is
1919 only available starting with linux 4.11. */
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001920 snprintf(buf, sizeof(buf), "%u", IN6_ADDR_GEN_MODE_NONE);
1921 if (proc_ipv6_conf_write(options.tun_dev_name, "addr_gen_mode", buf) < 0) {
1922 SYS_ERR(DSGSN, LOGL_ERROR, errno,
Pau Espin Pedrolff2ebee2020-04-18 23:47:06 +02001923 "Failed to disable addr_gen_mode on %s, an extra link-local "
1924 "ip address will appear on the tun device.\n",
1925 options.tun_dev_name);
Pau Espin Pedrol98f81262020-04-14 18:38:52 +02001926 }
1927#endif
1928
Harald Weltebed35df2011-11-02 13:06:18 +01001929 tun_set_cb_ind(tun, cb_tun_ind);
1930 if (tun->fd > maxfd)
1931 maxfd = tun->fd;
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001932
1933 if (proc_ipv6_conf_write(options.tun_dev_name, "accept_ra", "0") < 0) {
1934 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1935 "Failed to disable IPv6 SLAAC on %s\n", options.tun_dev_name);
1936 exit(1);
1937 }
Harald Weltebed35df2011-11-02 13:06:18 +01001938 }
jjakoa7cd2492003-04-11 09:40:12 +00001939
Pau Espin Pedrola1b3dee2020-04-15 14:39:10 +02001940 if ((options.createif) && (options.netaddr.len)) {
Pau Espin Pedrol964f08a2020-04-15 14:29:25 +02001941 tun_addaddr(tun, &options.netaddr, NULL, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001942 if (options.defaultroute) {
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001943 if (in46a_is_v4(&options.netaddr)) {
1944 struct in_addr rm;
1945 rm.s_addr = 0;
1946 netdev_addroute4(&rm, &options.netaddr.v4, &rm);
Pau Espin Pedrole2b09612020-04-15 15:09:30 +02001947 } else {
1948 struct in6_addr rm;
1949 memset(&rm, 0, sizeof(rm));
1950 netdev_addroute6(&rm, &options.netaddr.v6, 0, tun->devname);
Pau Espin Pedrol2a1cedd2020-04-15 15:21:58 +02001951 }
Harald Weltebed35df2011-11-02 13:06:18 +01001952 }
1953 if (options.ipup)
1954 tun_runscript(tun, options.ipup);
1955 }
jjakoa7cd2492003-04-11 09:40:12 +00001956
Andreas Schultzb6292402018-10-05 13:58:45 +01001957#if defined(__linux__)
1958 if ((options.createif) && (options.netns)) {
Pau Espin Pedrolad6eaa22020-02-25 12:17:29 +01001959 if ((rc = restore_ns(&oldmask)) < 0) {
1960 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
1961 strerror(-rc));
1962 exit(1);
1963 }
Andreas Schultzb6292402018-10-05 13:58:45 +01001964 }
1965#endif
1966
Harald Weltebed35df2011-11-02 13:06:18 +01001967 /* Initialise hash tables */
1968 memset(&iphash, 0, sizeof(iphash));
1969 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001970
Harald Weltebed35df2011-11-02 13:06:18 +01001971 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001972
Harald Weltebed35df2011-11-02 13:06:18 +01001973 /* See if anybody is there */
1974 printf("Sending off echo request\n");
1975 echoversion = options.gtpversion;
1976 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001977
Harald Weltebed35df2011-11-02 13:06:18 +01001978 for (n = 0; n < options.contexts; n++) {
1979 uint64_t myimsi;
1980 printf("Setting up PDP context #%d\n", n);
1981 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001982
Harald Weltebed35df2011-11-02 13:06:18 +01001983 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001984
Harald Weltebed35df2011-11-02 13:06:18 +01001985 /* Allocated here. */
1986 /* If create context failes we have to deallocate ourselves. */
1987 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001988 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001989
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001990 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001991 pdp->ipif = tun; /* TODO */
1992 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001993
Harald Weltebed35df2011-11-02 13:06:18 +01001994 if (options.gtpversion == 0) {
1995 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001996 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001997 "QoS length too big");
1998 exit(1);
1999 } else {
2000 memcpy(pdp->qos_req0, options.qos.v,
2001 options.qos.l);
2002 }
2003 }
jjakoa7cd2492003-04-11 09:40:12 +00002004
Harald Weltebed35df2011-11-02 13:06:18 +01002005 pdp->qos_req.l = options.qos.l;
2006 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00002007
Harald Weltebed35df2011-11-02 13:06:18 +01002008 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00002009
Harald Weltebed35df2011-11-02 13:06:18 +01002010 pdp->rattype.l = options.rattype.l;
2011 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
2012 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002013
Harald Weltebed35df2011-11-02 13:06:18 +01002014 pdp->userloc.l = options.userloc.l;
2015 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
2016 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002017
Harald Weltebed35df2011-11-02 13:06:18 +01002018 pdp->rai.l = options.rai.l;
2019 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
2020 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02002021
Harald Weltebed35df2011-11-02 13:06:18 +01002022 pdp->mstz.l = options.mstz.l;
2023 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
2024 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002025
Harald Weltebed35df2011-11-02 13:06:18 +01002026 pdp->imeisv.l = options.imeisv.l;
2027 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
2028 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02002029
Harald Weltebed35df2011-11-02 13:06:18 +01002030 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02002031
Harald Weltebed35df2011-11-02 13:06:18 +01002032 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002033 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002034 "APN length too big");
2035 exit(1);
2036 } else {
2037 pdp->apn_use.l = options.apn.l;
2038 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
2039 }
jjako193e8b12003-11-10 12:31:41 +00002040
Harald Weltebed35df2011-11-02 13:06:18 +01002041 pdp->gsnlc.l = sizeof(options.listen);
2042 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
2043 pdp->gsnlu.l = sizeof(options.listen);
2044 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00002045
Harald Weltebed35df2011-11-02 13:06:18 +01002046 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002047 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002048 "MSISDN length too big");
2049 exit(1);
2050 } else {
2051 msisdn_add(&options.msisdn, &pdp->msisdn, n);
2052 }
jjakob62c3dd2004-05-27 18:51:55 +00002053
Harald Welte840a8e92017-09-24 18:12:40 +08002054 /* Request dynamic IP address */
2055 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
2056 pdp->eua.v[1] = options.pdp_type;
2057 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00002058
Harald Weltebed35df2011-11-02 13:06:18 +01002059 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01002060 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01002061 "PCO length too big");
2062 exit(1);
2063 } else {
2064 pdp->pco_req.l = options.pco.l;
2065 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
2066 }
jjako52c24142002-12-16 13:33:51 +00002067
Harald Weltebed35df2011-11-02 13:06:18 +01002068 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00002069
Harald Weltebed35df2011-11-02 13:06:18 +01002070 pdp->hisaddr0 = options.remote;
2071 pdp->hisaddr1 = options.remote;
2072
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01002073 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01002074 512 = Flat rate, 256 = Hot billing */
2075
Harald Weltefbb9c7f2017-09-24 11:50:20 +08002076 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
2077
Harald Weltebed35df2011-11-02 13:06:18 +01002078 /* Create context */
2079 /* We send this of once. Retransmissions are handled by gtplib */
2080 gtp_create_context_req(gsn, pdp, &iparr[n]);
2081 }
2082
2083 state = 1; /* Enter wait_connection state */
2084
2085 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00002086
jjako52c24142002-12-16 13:33:51 +00002087 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01002088 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00002089 /******************************************************************/
2090
Harald Weltebed35df2011-11-02 13:06:18 +01002091 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00002092
Harald Weltebed35df2011-11-02 13:06:18 +01002093 /* Take down client after timeout after disconnect */
2094 if ((4 == state) && ((stoptime) <= time(NULL))) {
2095 state = 5;
2096 }
jjako7b8fad42003-07-07 14:37:42 +00002097
Harald Weltebed35df2011-11-02 13:06:18 +01002098 /* Take down client after timelimit timeout */
2099 if ((2 == state) && (options.timelimit) &&
2100 ((starttime + options.timelimit) <= time(NULL))) {
2101 state = 3;
2102 }
jjako7b8fad42003-07-07 14:37:42 +00002103
Harald Weltebed35df2011-11-02 13:06:18 +01002104 /* Take down client after ping timeout */
2105 if ((2 == state) && (pingtimeout)
2106 && (pingtimeout <= time(NULL))) {
2107 state = 3;
2108 }
jjako7b8fad42003-07-07 14:37:42 +00002109
Harald Weltebed35df2011-11-02 13:06:18 +01002110 /* Set pingtimeout for later disconnection */
2111 if (options.pingcount && ntransmitted >= options.pingcount) {
2112 pingtimeout = time(NULL) + 5; /* Extra seconds */
2113 }
jjako7b8fad42003-07-07 14:37:42 +00002114
Harald Weltebed35df2011-11-02 13:06:18 +01002115 /* Print statistics if no more ping packets are missing */
2116 if (ntransmitted && options.pingcount
2117 && nreceived >= options.pingcount) {
2118 ping_finish();
2119 if (!options.createif)
2120 state = 3;
2121 }
jjako7b8fad42003-07-07 14:37:42 +00002122
Harald Weltebed35df2011-11-02 13:06:18 +01002123 /* Send off disconnect */
2124 if (3 == state) {
2125 state = 4;
2126 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
2127 for (n = 0; n < options.contexts; n++) {
2128 /* Delete context */
2129 printf("Disconnecting PDP context #%d\n", n);
Oliver Smith1cde2c12019-05-13 11:35:03 +02002130 gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002131 if ((options.pinghost.len)
Harald Weltebed35df2011-11-02 13:06:18 +01002132 && ntransmitted)
2133 ping_finish();
2134 }
2135 }
jjako7b8fad42003-07-07 14:37:42 +00002136
Harald Weltebed35df2011-11-02 13:06:18 +01002137 /* Send of ping packets */
2138 diff = 0;
2139 while ((diff <= 0) &&
2140 /* Send off an ICMP ping packet */
Pau Espin Pedrol96214602020-04-14 19:39:09 +02002141 /*if ( */ (options.pinghost.len) && (2 == state) &&
Harald Weltebed35df2011-11-02 13:06:18 +01002142 ((pingseq < options.pingcount)
2143 || (options.pingcount == 0))) {
2144 if (!pingseq)
2145 gettimeofday(&firstping, &tz); /* Set time of first ping */
2146 gettimeofday(&tv, &tz);
2147 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
2148 if (diff <= 0) {
2149 if (options.debug)
2150 printf("Create_ping %d\n", diff);
2151 create_ping(gsn,
2152 iparr[pingseq %
2153 options.contexts].pdp,
2154 &options.pinghost, pingseq,
2155 options.pingsize);
2156 pingseq++;
2157 }
2158 }
jjako5da68452003-01-28 16:08:47 +00002159
Harald Weltebed35df2011-11-02 13:06:18 +01002160 FD_ZERO(&fds);
2161 if (tun)
2162 FD_SET(tun->fd, &fds);
2163 FD_SET(gsn->fd0, &fds);
2164 FD_SET(gsn->fd1c, &fds);
2165 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00002166
Pau Espin Pedrol1bf41e42019-08-28 19:44:54 +02002167 idleTime.tv_sec = 10;
2168 idleTime.tv_usec = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002169 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00002170
Harald Weltebed35df2011-11-02 13:06:18 +01002171 if (options.debug)
2172 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
2173 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00002174
bjovana8f71eb2017-02-24 17:39:20 +01002175 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002176 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
2177 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01002178 if (errno == EINTR)
2179 signal_received = 1;
2180 else
2181 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2182 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01002183 break;
Harald Weltebed35df2011-11-02 13:06:18 +01002184 default:
2185 break;
2186 }
2187
bjovana8f71eb2017-02-24 17:39:20 +01002188 if (!signal_received) {
2189
2190 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
2191 SYS_ERR(DSGSN, LOGL_ERROR, 0,
2192 "TUN decaps failed");
2193 }
2194
2195 if (FD_ISSET(gsn->fd0, &fds))
2196 gtp_decaps0(gsn);
2197
2198 if (FD_ISSET(gsn->fd1c, &fds))
2199 gtp_decaps1c(gsn);
2200
2201 if (FD_ISSET(gsn->fd1u, &fds))
2202 gtp_decaps1u(gsn);
2203
Harald Weltebed35df2011-11-02 13:06:18 +01002204 }
Harald Weltebed35df2011-11-02 13:06:18 +01002205 }
2206
2207 gtp_free(gsn); /* Clean up the gsn instance */
2208
2209 if (options.createif)
2210 tun_free(tun);
2211
2212 if (0 == state)
2213 exit(1); /* Indicate error */
2214
2215 return 0;
jjako52c24142002-12-16 13:33:51 +00002216}