blob: ac0633baf81532e34617fe9e9c27b9a287ddfc8b [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjakoa7cd2492003-04-11 09:40:12 +00003 * Copyright (C) 2002, 2003 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/*
18 * sgsnemu.c
19 *
20 */
21
22
23#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000024#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000025#endif
26
27
28#include <syslog.h>
29#include <ctype.h>
30#include <netdb.h>
31#include <signal.h>
32#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#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>
46#include <features.h>
47#include <errno.h>
48#include <asm/types.h>
49#include <sys/socket.h>
50#include <linux/netlink.h>
51#include <resolv.h>
52#include <time.h>
53
54#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000055#include "ippool.h"
56#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000057#include "../gtp/pdp.h"
58#include "../gtp/gtp.h"
59#include "cmdline.h"
60
jjakoa7cd2492003-04-11 09:40:12 +000061#define IPADDRLEN 256 /* Character length of addresses */
62#define MAXCONTEXTS 16 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000063
jjakoa7cd2492003-04-11 09:40:12 +000064/* HASH tables for IP address allocation */
65struct iphash_t {
66 uint8_t inuse; /* 0=free. 1=used by somebody */
67 struct iphash_t *ipnext;
68 struct pdp_t *pdp;
69 struct in_addr addr;
70};
71struct iphash_t iparr[MAXCONTEXTS];
72struct iphash_t *iphash[MAXCONTEXTS];
73
74/* State variable used for ping */
75/* 0: Idle */
76/* 1: Wait_connect */
77/* 2: Connected */
78/* 3: Wait_disconnect */
jjakoe607f742003-07-06 21:21:30 +000079/* 4: Disconnected */
jjako52c24142002-12-16 13:33:51 +000080int state = 0;
81
jjakoa7cd2492003-04-11 09:40:12 +000082struct gsn_t *gsn = NULL; /* GSN instance */
83struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000084int maxfd = 0; /* For select() */
jjako52c24142002-12-16 13:33:51 +000085
jjakoa7cd2492003-04-11 09:40:12 +000086/* Struct with local versions of gengetopt options */
87struct {
88 int debug; /* Print debug messages */
89 int createif; /* Create local network interface */
90 char *ipup, *ipdown; /* Filename of scripts */
91 int defaultroute; /* Set up default route */
92 struct in_addr pinghost; /* Remote ping host */
93 int pingrate;
94 int pingsize;
95 int pingcount;
96 int pingquiet;
97 struct in_addr listen;
98 struct in_addr remote;
99 struct in_addr dns;
100 int contexts; /* Number of contexts to create */
101 int timelimit; /* Number of seconds to be connected */
102 char *statedir;
103 uint64_t imsi;
104 struct ul255_t pco;
105 struct ul255_t qos;
106 struct ul255_t apn;
107 struct ul16_t msisdn;
108} options;
jjako52c24142002-12-16 13:33:51 +0000109
jjako5da68452003-01-28 16:08:47 +0000110
111/* Definitions to use for PING. Most of the ping code was derived from */
112/* the original ping program by Mike Muuss */
113
114/* IP header and ICMP echo header */
115#define CREATEPING_MAX 2048
116#define CREATEPING_IP 20
117#define CREATEPING_ICMP 8
118
119struct ip_ping {
120 u_int8_t ipver; /* Type and header length*/
121 u_int8_t tos; /* Type of Service */
122 u_int16_t length; /* Total length */
123 u_int16_t fragid; /* Identifier */
124 u_int16_t offset; /* Flags and fragment offset */
125 u_int8_t ttl; /* Time to live */
126 u_int8_t protocol; /* Protocol */
127 u_int16_t ipcheck; /* Header checksum */
128 u_int32_t src; /* Source address */
129 u_int32_t dst; /* Destination */
130 u_int8_t type; /* Type and header length*/
131 u_int8_t code; /* Code */
132 u_int16_t checksum; /* Header checksum */
133 u_int16_t ident; /* Identifier */
134 u_int16_t seq; /* Sequence number */
135 u_int8_t data[CREATEPING_MAX]; /* Data */
136} __attribute__((packed));
137
138/* Statistical values for ping */
139int nreceived = 0;
140int ntreceived = 0;
141int ntransmitted = 0;
142int tmin = 999999999;
143int tmax = 0;
144int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000145int pingseq = 0; /* Ping sequence counter */
146struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000147
jjakoa7cd2492003-04-11 09:40:12 +0000148int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
149 int hash = ippool_hash4(addr) % MAXCONTEXTS;
150 struct iphash_t *h;
151 struct iphash_t *prev = NULL;
152 ipaddr->ipnext = NULL;
153 ipaddr->addr.s_addr = addr->s_addr;
154 for (h = iphash[hash]; h; h = h->ipnext)
155 prev = h;
156 if (!prev)
157 iphash[hash] = ipaddr;
158 else
159 prev->ipnext = ipaddr;
160 return 0;
161}
162
163int ipdel(struct iphash_t *ipaddr) {
164 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
165 struct iphash_t *h;
166 struct iphash_t *prev = NULL;
167 for (h = iphash[hash]; h; h = h->ipnext) {
168 if (h == ipaddr) {
169 if (!prev)
170 iphash[hash] = h->ipnext;
171 else
172 prev->ipnext = h->ipnext;
173 return 0;
174 }
175 prev = h;
176 }
177 return EOF; /* End of linked list and not found */
178}
179
180int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
181 int hash = ippool_hash4(addr) % MAXCONTEXTS;
182 struct iphash_t *h;
183 for (h = iphash[hash]; h; h = h->ipnext) {
184 if ((h->addr.s_addr == addr->s_addr)) {
185 *ipaddr = h;
186 return 0;
187 }
188 }
189 return EOF; /* End of linked list and not found */
190}
191
192
193/* Used to write process ID to file. Assume someone else will delete */
194void log_pid(char *pidfile) {
195 FILE *file;
196 mode_t oldmask;
197
198 oldmask = umask(022);
199 file = fopen(pidfile, "w");
200 umask(oldmask);
201 if(!file)
202 return;
203 fprintf(file, "%d\n", getpid());
204 fclose(file);
205}
206
207
208int process_options(int argc, char **argv) {
209 /* gengeopt declarations */
210 struct gengetopt_args_info args_info;
211
212 struct hostent *host;
213 int n;
214
215 if (cmdline_parser (argc, argv, &args_info) != 0)
216 return -1;
217 if (args_info.debug_flag) {
218 printf("remote: %s\n", args_info.remote_arg);
219 printf("listen: %s\n", args_info.listen_arg);
220 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000221 printf("debug: %d\n", args_info.debug_flag);
222 printf("imsi: %s\n", args_info.imsi_arg);
223 printf("qos: %#08x\n", args_info.qos_arg);
224 printf("apn: %s\n", args_info.apn_arg);
225 printf("msisdn: %s\n", args_info.msisdn_arg);
226 printf("uid: %s\n", args_info.uid_arg);
227 printf("pwd: %s\n", args_info.pwd_arg);
228 printf("pidfile: %s\n", args_info.pidfile_arg);
229 printf("statedir: %s\n", args_info.statedir_arg);
230 printf("dns: %s\n", args_info.dns_arg);
231 printf("contexts: %d\n", args_info.contexts_arg);
232 printf("timelimit: %d\n", args_info.timelimit_arg);
233 printf("createif: %d\n", args_info.createif_flag);
234 printf("ipup: %s\n", args_info.ipup_arg);
235 printf("ipdown: %s\n", args_info.ipdown_arg);
236 printf("defaultroute: %d\n", args_info.defaultroute_flag);
237 printf("pinghost: %s\n", args_info.pinghost_arg);
238 printf("pingrate: %d\n", args_info.pingrate_arg);
239 printf("pingsize: %d\n", args_info.pingsize_arg);
240 printf("pingcount: %d\n", args_info.pingcount_arg);
241 printf("pingquiet: %d\n", args_info.pingquiet_flag);
242 }
243
244 /* Try out our new parser */
245
246 if (args_info.conf_arg) {
247 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
248 return -1;
249 if (args_info.debug_flag) {
250 printf("cmdline_parser_configfile\n");
251 printf("remote: %s\n", args_info.remote_arg);
252 printf("listen: %s\n", args_info.listen_arg);
253 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000254 printf("debug: %d\n", args_info.debug_flag);
255 printf("imsi: %s\n", args_info.imsi_arg);
256 printf("qos: %#08x\n", args_info.qos_arg);
257 printf("apn: %s\n", args_info.apn_arg);
258 printf("msisdn: %s\n", args_info.msisdn_arg);
259 printf("uid: %s\n", args_info.uid_arg);
260 printf("pwd: %s\n", args_info.pwd_arg);
261 printf("pidfile: %s\n", args_info.pidfile_arg);
262 printf("statedir: %s\n", args_info.statedir_arg);
263 printf("dns: %s\n", args_info.dns_arg);
264 printf("contexts: %d\n", args_info.contexts_arg);
265 printf("timelimit: %d\n", args_info.timelimit_arg);
266 printf("createif: %d\n", args_info.createif_flag);
267 printf("ipup: %s\n", args_info.ipup_arg);
268 printf("ipdown: %s\n", args_info.ipdown_arg);
269 printf("defaultroute: %d\n", args_info.defaultroute_flag);
270 printf("pinghost: %s\n", args_info.pinghost_arg);
271 printf("pingrate: %d\n", args_info.pingrate_arg);
272 printf("pingsize: %d\n", args_info.pingsize_arg);
273 printf("pingcount: %d\n", args_info.pingcount_arg);
274 printf("pingquiet: %d\n", args_info.pingquiet_flag);
275 }
276 }
277
278 /* Handle each option */
279
280 /* foreground */
jjakoe607f742003-07-06 21:21:30 +0000281 /* If fg flag not given run as a daemon */
282 /* Do not allow sgsnemu to run as deamon
jjakoa7cd2492003-04-11 09:40:12 +0000283 if (!args_info.fg_flag)
284 {
285 closelog();
jjakoa7cd2492003-04-11 09:40:12 +0000286 freopen("/dev/null", "w", stdout);
287 freopen("/dev/null", "w", stderr);
288 freopen("/dev/null", "r", stdin);
289 daemon(0, 0);
jjakoa7cd2492003-04-11 09:40:12 +0000290 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
jjakoe607f742003-07-06 21:21:30 +0000291 } */
jjakoa7cd2492003-04-11 09:40:12 +0000292
293 /* debug */
294 options.debug = args_info.debug_flag;
295
296 /* pidfile */
297 /* This has to be done after we have our final pid */
298 if (args_info.pidfile_arg) {
299 log_pid(args_info.pidfile_arg);
300 }
301
302 /* dns */
303 /* If no dns option is given use system default */
304 /* Do hostname lookup to translate hostname to IP address */
305 printf("\n");
306 if (args_info.dns_arg) {
307 if (!(host = gethostbyname(args_info.dns_arg))) {
308 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
309 "Invalid DNS address: %s!", args_info.dns_arg);
310 return -1;
311 }
312 else {
313 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
314 _res.nscount = 1;
315 _res.nsaddr_list[0].sin_addr = options.dns;
316 printf("Using DNS server: %s (%s)\n",
317 args_info.dns_arg, inet_ntoa(options.dns));
318 }
319 }
320 else {
321 options.dns.s_addr= 0;
322 printf("Using default DNS server\n");
323 }
324
325 /* listen */
326 /* If no listen option is specified listen to any local port */
327 /* Do hostname lookup to translate hostname to IP address */
328 if (args_info.listen_arg) {
329 if (!(host = gethostbyname(args_info.listen_arg))) {
330 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
331 "Invalid listening address: %s!", args_info.listen_arg);
332 return -1;
333 }
334 else {
335 memcpy(&options.listen.s_addr, host->h_addr, host->h_length);
336 printf("Local IP address is: %s (%s)\n",
337 args_info.listen_arg, inet_ntoa(options.listen));
338 }
339 }
340 else {
341 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
342 "Listening address must be specified: %s!", args_info.listen_arg);
343 return -1;
344 }
345
346
347 /* remote */
348 /* If no remote option is specified terminate */
349 /* Do hostname lookup to translate hostname to IP address */
350 if (args_info.remote_arg) {
351 if (!(host = gethostbyname(args_info.remote_arg))) {
352 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
353 "Invalid remote address: %s!", args_info.remote_arg);
354 return -1;
355 }
356 else {
357 memcpy(&options.remote.s_addr, host->h_addr, host->h_length);
358 printf("Remote IP address is: %s (%s)\n",
359 args_info.remote_arg, inet_ntoa(options.remote));
360 }
361 }
362 else {
363 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
364 "No remote address given!");
365 return -1;
366 }
367
368
369 /* imsi */
370 if (strlen(args_info.imsi_arg)!=15) {
371 printf("Invalid IMSI\n");
372 return -1;
373 }
374 options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48));
375 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
376 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
377 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
389
390 printf("IMSI is: %s (%#08llx)\n",
391 args_info.imsi_arg, options.imsi);
392
393
394 /* qos */
395 options.qos.l = 3;
396 options.qos.v[2] = (args_info.qos_arg) & 0xff;
397 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
398 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
399
400 /* contexts */
401 if (args_info.contexts_arg > MAXCONTEXTS) {
402 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
403 return -1;
404 }
405 options.contexts = args_info.contexts_arg;
406
407 /* Timelimit */
408 options.timelimit = args_info.timelimit_arg;
409
410 /* apn */
411 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
412 printf("Invalid APN\n");
413 return -1;
414 }
415 options.apn.l = strlen(args_info.apn_arg) + 1;
416 options.apn.v[0] = (char) strlen(args_info.apn_arg);
417 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
418 printf("Using APN: %s\n", args_info.apn_arg);
419
420 /* msisdn */
421 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
422 printf("Invalid MSISDN\n");
423 return -1;
424 }
425 options.msisdn.l = 1;
426 options.msisdn.v[0] = 0x91; /* International format */
427 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
428 if ((n%2) == 0) {
429 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
430 options.msisdn.l += 1;
431 }
432 else {
433 options.msisdn.v[((int)n/2)+1] =
434 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
435 (args_info.msisdn_arg[n] - 48) * 16;
436 }
437 }
438 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
439
440 /* UID and PWD */
441 /* Might need to also insert stuff like DNS etc. */
442 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
443 (sizeof(options.pco.v)-1)) {
444 printf("invalid UID and PWD\n");
445 return -1;
446 }
447 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
448 options.pco.v[0] = 0x80; /* PPP */
449 options.pco.v[1] = 0xc0; /* PAP */
450 options.pco.v[2] = 0x23;
451 options.pco.v[3] = 0x12; /* Length of protocol contents */
452 options.pco.v[4] = 0x01; /* Authenticate request */
453 options.pco.v[5] = 0x01;
454 options.pco.v[6] = 0x00; /* MSB of length */
455 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
456 options.pco.v[8] = strlen(args_info.uid_arg);
457 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
458 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
459 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
460 args_info.pwd_arg, strlen(args_info.pwd_arg));
461
462 /* createif */
463 options.createif = args_info.createif_flag;
464
465 /* ipup */
466 options.ipup = args_info.ipup_arg;
467
468 /* ipdown */
469 options.ipdown = args_info.ipdown_arg;
470
471 /* statedir */
472 options.statedir = args_info.statedir_arg;
473
474 /* defaultroute */
475 options.defaultroute = args_info.defaultroute_flag;
476
477
478 /* pinghost */
479 /* Store ping host as in_addr */
480 if (args_info.pinghost_arg) {
481 if (!inet_aton(args_info.pinghost_arg, &options.pinghost)) {
482 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
483 "Invalid ping host: %s!", args_info.pinghost_arg);
484 return -1;
485 }
486 }
487
488 /* Other ping parameters */
489 options.pingrate = args_info.pingrate_arg;
490 options.pingsize = args_info.pingsize_arg;
491 options.pingcount = args_info.pingcount_arg;
492 options.pingquiet = args_info.pingquiet_flag;
493
494 return 0;
495
496}
497
jjako5da68452003-01-28 16:08:47 +0000498
499int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000500 int i;
501 printf("The packet looks like this:\n");
502 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000503 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000504 if (!((i+1)%16)) printf("\n");
505 };
jjako5da68452003-01-28 16:08:47 +0000506 printf("\n");
507 return 0;
jjako52c24142002-12-16 13:33:51 +0000508}
509
jjako5da68452003-01-28 16:08:47 +0000510char * print_ipprot(int t) {
511 switch (t) {
512 case 1: return "ICMP";
513 case 6: return "TCP";
514 case 17: return "UDP";
515 default: return "Unknown";
516 };
517}
518
519
520char * print_icmptype(int t) {
521 static char *ttab[] = {
522 "Echo Reply",
523 "ICMP 1",
524 "ICMP 2",
525 "Dest Unreachable",
526 "Source Quench",
527 "Redirect",
528 "ICMP 6",
529 "ICMP 7",
530 "Echo",
531 "ICMP 9",
532 "ICMP 10",
533 "Time Exceeded",
534 "Parameter Problem",
535 "Timestamp",
536 "Timestamp Reply",
537 "Info Request",
538 "Info Reply"
539 };
540 if( t < 0 || t > 16 )
541 return("OUT-OF-RANGE");
542 return(ttab[t]);
543}
544
jjakoafb2a972003-01-29 21:04:13 +0000545/* Calculate time left until we have to send off next ping packet */
546int ping_timeout(struct timeval *tp) {
547 struct timezone tz;
548 struct timeval tv;
549 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000550 if ((options.pinghost.s_addr) && (2 == state) &&
551 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000552 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000553 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000554 1000000 * (tv.tv_sec - firstping.tv_sec) -
555 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
556 tp->tv_sec = 0;
557 if (diff > 0)
558 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000559 else {
jjakoafb2a972003-01-29 21:04:13 +0000560 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000561 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
562 tp->tv_usec = 0;
563 }
jjakoafb2a972003-01-29 21:04:13 +0000564 }
565 return 0;
566}
567
jjako5da68452003-01-28 16:08:47 +0000568/* Print out statistics when at the end of ping sequence */
569int ping_finish()
570{
jjakoafb2a972003-01-29 21:04:13 +0000571 struct timezone tz;
572 struct timeval tv;
573 int elapsed;
574 gettimeofday(&tv, &tz);
575 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
576 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000577 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000578 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000579 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
580 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000581 printf("%d packets received, ", nreceived );
582 if (ntransmitted) {
583 if( nreceived > ntransmitted)
584 printf("-- somebody's printing up packets!");
585 else
586 printf("%d%% packet loss",
587 (int) (((ntransmitted-nreceived)*100) /
588 ntransmitted));
589 }
590 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000591 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000592 if (nreceived && tsum)
593 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
594 tmin/1000.0,
595 tsum/1000.0/nreceived,
596 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000597 printf("%d packets transmitted \n", ntreceived );
598
jjako5da68452003-01-28 16:08:47 +0000599 ntransmitted = 0;
600 return 0;
601}
602
603/* Handle a received ping packet. Print out line and update statistics. */
604int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
605 struct timezone tz;
606 struct timeval tv;
607 struct timeval *tp;
608 struct ip_ping *pingpack = pack;
609 struct in_addr src;
610 int triptime;
611
612 src.s_addr = pingpack->src;
613
614 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000615 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000616
617 if (len < CREATEPING_IP + CREATEPING_ICMP) {
618 printf("packet too short (%d bytes) from %s\n", len,
619 inet_ntoa(src));
620 return 0;
621 }
622
623 ntreceived++;
624 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000625 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000626 len, inet_ntoa(src), pingpack->protocol,
627 print_ipprot(pingpack->protocol));
628 return 0;
629 }
630
631 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000632 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000633 len, inet_ntoa(src), pingpack->type,
634 print_icmptype(pingpack->type), pingpack->code);
635 return 0;
636 }
637
638 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000639 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000640 inet_ntoa(src), ntohs(pingpack->seq));
641
642 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
643 gettimeofday(&tv, &tz);
644 tp = (struct timeval *) pingpack->data;
645 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
646 tv.tv_sec--;
647 tv.tv_usec += 1000000;
648 }
649 tv.tv_sec -= tp->tv_sec;
650
651 triptime = tv.tv_sec*1000000+(tv.tv_usec);
652 tsum += triptime;
653 if( triptime < tmin )
654 tmin = triptime;
655 if( triptime > tmax )
656 tmax = triptime;
657
jjakoa7cd2492003-04-11 09:40:12 +0000658 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000659
660 }
661 else
jjakoa7cd2492003-04-11 09:40:12 +0000662 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000663 return 0;
664}
665
666/* Create a new ping packet and send it off to peer. */
667int create_ping(void *gsn, struct pdp_t *pdp,
668 struct in_addr *dst, int seq, int datasize) {
669
670 struct ip_ping pack;
671 u_int16_t *p = (u_int16_t *) &pack;
672 u_int8_t *p8 = (u_int8_t *) &pack;
673 struct in_addr src;
674 int n;
675 long int sum = 0;
676 int count = 0;
677
678 struct timezone tz;
679 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
680
681 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000682 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
683 "Ping size to large: %d!", datasize);
684 return -1;
jjako5da68452003-01-28 16:08:47 +0000685 }
686
687 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
688
689 pack.ipver = 0x45;
690 pack.tos = 0x00;
691 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
692 pack.fragid = 0x0000;
693 pack.offset = 0x0040;
694 pack.ttl = 0x40;
695 pack.protocol = 0x01;
696 pack.ipcheck = 0x0000;
697 pack.src = src.s_addr;
698 pack.dst = dst->s_addr;
699 pack.type = 0x08;
700 pack.code = 0x00;
701 pack.checksum = 0x0000;
702 pack.ident = 0x0000;
703 pack.seq = htons(seq);
704
705 /* Generate ICMP payload */
706 p8 = (u_int8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
707 for (n=0; n<(datasize); n++) p8[n] = n;
708
709 if (datasize >= sizeof(struct timeval))
710 gettimeofday(tp, &tz);
711
712 /* Calculate IP header checksum */
713 p = (u_int16_t *) &pack;
714 count = CREATEPING_IP;
715 sum = 0;
716 while (count>1) {
717 sum += *p++;
718 count -= 2;
719 }
720 while (sum>>16)
721 sum = (sum & 0xffff) + (sum >> 16);
722 pack.ipcheck = ~sum;
723
724
725 /* Calculate ICMP checksum */
726 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
727 sum = 0;
728 p = (u_int16_t *) &pack;
729 p += CREATEPING_IP / 2;
730 while (count>1) {
731 sum += *p++;
732 count -= 2;
733 }
734 if (count>0)
735 sum += * (unsigned char *) p;
736 while (sum>>16)
737 sum = (sum & 0xffff) + (sum >> 16);
738 pack.checksum = ~sum;
739
740 ntransmitted++;
jjako5da68452003-01-28 16:08:47 +0000741 return gtp_gpdu(gsn, pdp, &pack, 28 + datasize);
742}
743
744
jjakoa7cd2492003-04-11 09:40:12 +0000745int delete_context(struct pdp_t *pdp) {
746
747 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
748
749 ipdel((struct iphash_t*) pdp->peer);
750 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjakoe607f742003-07-06 21:21:30 +0000751 state = 4; /* Disconnected */
jjakoa7cd2492003-04-11 09:40:12 +0000752 return 0;
jjako52c24142002-12-16 13:33:51 +0000753}
754
jjakoa7cd2492003-04-11 09:40:12 +0000755
756/* Callback for receiving messages from tun */
757int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
758 struct iphash_t *ipm;
759 struct in_addr src;
760 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
761
762 src.s_addr = iph->src;
763
764 if (ipget(&ipm, &src)) {
765 printf("Received packet without a valid source address!!!\n");
766 return 0;
jjako52c24142002-12-16 13:33:51 +0000767 }
jjako5da68452003-01-28 16:08:47 +0000768
jjakoa7cd2492003-04-11 09:40:12 +0000769 if (ipm->pdp) /* Check if a peer protocol is defined */
770 gtp_gpdu(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000771 return 0;
772}
773
774int create_pdp_conf(struct pdp_t *pdp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000775 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000776
jjakoa7cd2492003-04-11 09:40:12 +0000777 if (cause != 128) {
778 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000779 state = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000780 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000781 }
782
jjakoa7cd2492003-04-11 09:40:12 +0000783 if (pdp_euaton(&pdp->eua, &addr)) {
784 printf("Received create PDP context response. Cause value: %d\n", cause);
785 state = 0;
786 return EOF; /* Not a valid IP address */
787 }
788
789 printf("Received create PDP context response. IP address: %s\n",
790 inet_ntoa(addr));
791
792 if (options.createif) {
793 struct in_addr m;
794 inet_aton("255.255.255.255", &m);
795 /* printf("Setting up interface and routing\n");*/
796 tun_addaddr(tun, &addr, &addr, &m);
797 if (options.defaultroute) {
798 struct in_addr rm;
799 rm.s_addr = 0;
800 tun_addroute(tun, &rm, &addr, &rm);
801 }
802 if (options.ipup) tun_runscript(tun, options.ipup);
803 }
804
805 ipset((struct iphash_t*) pdp->peer, &addr);
806
807 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000808
809 return 0;
810}
811
jjako52c24142002-12-16 13:33:51 +0000812int delete_pdp_conf(struct pdp_t *pdp, int cause) {
813 printf("Received delete PDP context response. Cause value: %d\n", cause);
jjako5da68452003-01-28 16:08:47 +0000814 state = 0; /* Idle */
jjako52c24142002-12-16 13:33:51 +0000815 return 0;
816}
817
818int echo_conf(struct pdp_t *pdp, int cause) {
jjako5da68452003-01-28 16:08:47 +0000819 if (cause <0)
820 printf("Echo request timed out\n");
821 else
822 printf("Received echo response.\n");
jjako52c24142002-12-16 13:33:51 +0000823 return 0;
824}
825
826int conf(int type, int cause, struct pdp_t* pdp, void *aid) {
827 /* if (cause < 0) return 0; Some error occurred. We don't care */
828 switch (type) {
829 case GTP_ECHO_REQ:
830 return echo_conf(pdp, cause);
831 case GTP_CREATE_PDP_REQ:
832 if (cause !=128) return 0; /* Request not accepted. We don't care */
833 return create_pdp_conf(pdp, cause);
834 case GTP_DELETE_PDP_REQ:
835 if (cause !=128) return 0; /* Request not accepted. We don't care */
836 return delete_pdp_conf(pdp, cause);
837 default:
838 return 0;
839 }
840}
841
jjako52c24142002-12-16 13:33:51 +0000842
843int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
844 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
845 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
846}
847
848int main(int argc, char **argv)
849{
jjako52c24142002-12-16 13:33:51 +0000850 fd_set fds; /* For select() */
851 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000852 struct pdp_t *pdp;
853 int n;
854 int starttime = time(NULL); /* Time program was started */
jjakoafb2a972003-01-29 21:04:13 +0000855
856 struct timezone tz; /* Used for calculating ping times */
857 struct timeval tv;
858 int diff;
jjako52c24142002-12-16 13:33:51 +0000859
jjako52c24142002-12-16 13:33:51 +0000860 /* open a connection to the syslog daemon */
861 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
862 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
863
jjakoa7cd2492003-04-11 09:40:12 +0000864 /* Process options given in configuration file and command line */
865 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000866 exit(1);
jjako52c24142002-12-16 13:33:51 +0000867
868 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +0000869 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +0000870 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
871 "Failed to create gtp");
872 exit(1);
873 }
874 if (gsn->fd > maxfd) maxfd = gsn->fd;
jjako52c24142002-12-16 13:33:51 +0000875
jjakoa7cd2492003-04-11 09:40:12 +0000876 gtp_set_cb_delete_context(gsn, delete_context);
877 gtp_set_cb_conf(gsn, conf);
878 if (options.createif)
jjako5da68452003-01-28 16:08:47 +0000879 gtp_set_cb_gpdu(gsn, encaps_tun);
880 else
881 gtp_set_cb_gpdu(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000882
883 if (options.createif) {
884 printf("Setting up interface\n");
885 /* Create a tunnel interface */
886 if (tun_new((struct tun_t**) &tun)) {
887 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
888 "Failed to create tun");
889 exit(1);
890 }
891 tun_set_cb_ind(tun, cb_tun_ind);
892 if (tun->fd > maxfd) maxfd = tun->fd;
893 }
894
895 /* Initialise hash tables */
896 memset(&iphash, 0, sizeof(iphash));
897 memset(&iparr, 0, sizeof(iparr));
898
jjako52c24142002-12-16 13:33:51 +0000899 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000900
901 /* See if anybody is there */
902 printf("Sending off echo request\n");
jjakoa7cd2492003-04-11 09:40:12 +0000903 gtp_echo_req(gsn, &options.remote); /* See if remote is alive ? */
jjako52c24142002-12-16 13:33:51 +0000904
jjakoa7cd2492003-04-11 09:40:12 +0000905 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000906 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000907 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000908
jjakoa7cd2492003-04-11 09:40:12 +0000909 /* Allocated here. Cleaned up in gtp.c:*/
910 pdp_newpdp(&pdp, options.imsi, n, NULL);
911
912 pdp->peer = &iparr[n];
913 pdp->ipif = tun; /* TODO */
914 iparr[n].pdp = pdp;
915
916 if (options.qos.l > sizeof(pdp->qos_req0)) {
917 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000918 exit(1);
919 }
920 else {
jjakoa7cd2492003-04-11 09:40:12 +0000921 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000922 }
923
jjakoa7cd2492003-04-11 09:40:12 +0000924 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000925
jjakoa7cd2492003-04-11 09:40:12 +0000926 if (options.apn.l > sizeof(pdp->apn_use.v)) {
927 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000928 exit(1);
929 }
930 else {
jjakoa7cd2492003-04-11 09:40:12 +0000931 pdp->apn_use.l = options.apn.l;
932 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000933 }
934
jjakoa7cd2492003-04-11 09:40:12 +0000935 pdp->gsnlc.l = sizeof(options.listen);
936 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
937 pdp->gsnlu.l = sizeof(options.listen);
938 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000939
jjakoa7cd2492003-04-11 09:40:12 +0000940 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
941 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000942 exit(1);
943 }
944 else {
jjakoa7cd2492003-04-11 09:40:12 +0000945 pdp->msisdn.l = options.msisdn.l;
946 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
947 }
948
949 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
950
951 if (options.pco.l > sizeof(pdp->pco_req.v)) {
952 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
953 exit(1);
954 }
955 else {
956 pdp->pco_req.l = options.pco.l;
957 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +0000958 }
959
960 /* Create context */
961 /* We send this of once. Retransmissions are handled by gtplib */
jjakoa7cd2492003-04-11 09:40:12 +0000962 gtp_create_context(gsn, pdp, NULL, &options.remote);
jjako52c24142002-12-16 13:33:51 +0000963 }
964
965 state = 1; /* Enter wait_connection state */
966
967 printf("Waiting for response from ggsn........\n\n");
968
jjako5da68452003-01-28 16:08:47 +0000969
jjako52c24142002-12-16 13:33:51 +0000970 /******************************************************************/
971 /* Main select loop */
972 /******************************************************************/
973
jjakoa7cd2492003-04-11 09:40:12 +0000974 while ((((starttime + options.timelimit + 10) > time(NULL))
975 || (0 == options.timelimit)) && (state!=0)) {
jjako52c24142002-12-16 13:33:51 +0000976
977 /* Take down client connections at some stage */
jjakoa7cd2492003-04-11 09:40:12 +0000978 if (((starttime + options.timelimit) <= time(NULL)) &&
979 (0 != options.timelimit) && (2 == state)) {
jjako52c24142002-12-16 13:33:51 +0000980 state = 3;
jjakoa7cd2492003-04-11 09:40:12 +0000981 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000982 /* Delete context */
983 printf("Disconnecting PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000984 gtp_delete_context(gsn, iparr[n].pdp, NULL);
985 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +0000986 }
jjakoafb2a972003-01-29 21:04:13 +0000987 }
jjakoa7cd2492003-04-11 09:40:12 +0000988
989 diff = 0;
990 while (( diff<=0 ) &&
jjakoafb2a972003-01-29 21:04:13 +0000991 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +0000992 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
993 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000994 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
995 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000996 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000997 1000000 * (tv.tv_sec - firstping.tv_sec) -
998 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
999 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001000 if (options.debug) printf("Create_ping %d\n", diff);
1001 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1002 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001003 pingseq++;
1004 }
jjako52c24142002-12-16 13:33:51 +00001005 }
jjakoa7cd2492003-04-11 09:40:12 +00001006
jjako52c24142002-12-16 13:33:51 +00001007
jjakoa7cd2492003-04-11 09:40:12 +00001008 if (ntransmitted && options.pingcount && nreceived >= options.pingcount)
jjako5da68452003-01-28 16:08:47 +00001009 ping_finish();
jjakoa7cd2492003-04-11 09:40:12 +00001010
jjako5da68452003-01-28 16:08:47 +00001011
jjako52c24142002-12-16 13:33:51 +00001012 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001013 if (tun) FD_SET(tun->fd, &fds);
1014 FD_SET(gsn->fd, &fds);
jjako52c24142002-12-16 13:33:51 +00001015
1016 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001017 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001018
1019 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1020 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1021
jjako52c24142002-12-16 13:33:51 +00001022 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1023 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001024 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1025 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001026 break;
1027 case 0:
1028 gtp_retrans(gsn); /* Only retransmit if nothing else */
1029 break;
1030 default:
1031 break;
1032 }
jjakoa7cd2492003-04-11 09:40:12 +00001033
1034 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1035 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1036 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001037 }
1038
jjakoa7cd2492003-04-11 09:40:12 +00001039 if (FD_ISSET(gsn->fd, &fds))
1040 gtp_decaps(gsn);
jjako52c24142002-12-16 13:33:51 +00001041
jjako5da68452003-01-28 16:08:47 +00001042 }
jjakoa7cd2492003-04-11 09:40:12 +00001043
jjako52c24142002-12-16 13:33:51 +00001044 gtp_free(gsn); /* Clean up the gsn instance */
1045
jjakoa7cd2492003-04-11 09:40:12 +00001046 if (options.createif)
1047 tun_free(tun);
jjako52c24142002-12-16 13:33:51 +00001048
jjakoa7cd2492003-04-11 09:40:12 +00001049 return 0;
jjako52c24142002-12-16 13:33:51 +00001050}
1051