blob: ecf8ee83ab19510118b9edcfbd97014846161501 [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>
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
jjakoff9985c2004-01-16 11:05:22 +000051#include "config.h"
jjako52c24142002-12-16 13:33:51 +000052#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000053#include "ippool.h"
54#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000055#include "../gtp/pdp.h"
56#include "../gtp/gtp.h"
57#include "cmdline.h"
58
jjakoa7cd2492003-04-11 09:40:12 +000059#define IPADDRLEN 256 /* Character length of addresses */
jjako193e8b12003-11-10 12:31:41 +000060#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000061
jjakoa7cd2492003-04-11 09:40:12 +000062/* HASH tables for IP address allocation */
63struct iphash_t {
64 uint8_t inuse; /* 0=free. 1=used by somebody */
65 struct iphash_t *ipnext;
66 struct pdp_t *pdp;
67 struct in_addr addr;
68};
69struct iphash_t iparr[MAXCONTEXTS];
70struct iphash_t *iphash[MAXCONTEXTS];
71
72/* State variable used for ping */
73/* 0: Idle */
74/* 1: Wait_connect */
75/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000076/* 3: Done */
77/* 4: Wait_disconnect */
78/* 5: Disconnected */
jjako581c9f02003-10-22 11:28:20 +000079int state = 0;
jjako52c24142002-12-16 13:33:51 +000080
jjakoa7cd2492003-04-11 09:40:12 +000081struct gsn_t *gsn = NULL; /* GSN instance */
82struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000083int maxfd = 0; /* For select() */
jjako91aaf222003-10-22 10:09:32 +000084int echoversion = 1; /* First try this version */
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 */
jjako193e8b12003-11-10 12:31:41 +000090 struct in_addr net, mask; /* Network interface */
jjakoa7cd2492003-04-11 09:40:12 +000091 char *ipup, *ipdown; /* Filename of scripts */
92 int defaultroute; /* Set up default route */
93 struct in_addr pinghost; /* Remote ping host */
94 int pingrate;
95 int pingsize;
96 int pingcount;
97 int pingquiet;
98 struct in_addr listen;
99 struct in_addr remote;
100 struct in_addr dns;
101 int contexts; /* Number of contexts to create */
102 int timelimit; /* Number of seconds to be connected */
103 char *statedir;
104 uint64_t imsi;
jjako193e8b12003-11-10 12:31:41 +0000105 uint8_t nsapi;
106 int gtpversion;
jjakoa7cd2492003-04-11 09:40:12 +0000107 struct ul255_t pco;
108 struct ul255_t qos;
109 struct ul255_t apn;
110 struct ul16_t msisdn;
111} options;
jjako52c24142002-12-16 13:33:51 +0000112
jjako5da68452003-01-28 16:08:47 +0000113
114/* Definitions to use for PING. Most of the ping code was derived from */
115/* the original ping program by Mike Muuss */
116
117/* IP header and ICMP echo header */
118#define CREATEPING_MAX 2048
119#define CREATEPING_IP 20
120#define CREATEPING_ICMP 8
121
122struct ip_ping {
jjako0141d202004-01-09 15:19:20 +0000123 uint8_t ipver; /* Type and header length*/
124 uint8_t tos; /* Type of Service */
125 uint16_t length; /* Total length */
126 uint16_t fragid; /* Identifier */
127 uint16_t offset; /* Flags and fragment offset */
128 uint8_t ttl; /* Time to live */
129 uint8_t protocol; /* Protocol */
130 uint16_t ipcheck; /* Header checksum */
131 uint32_t src; /* Source address */
132 uint32_t dst; /* Destination */
133 uint8_t type; /* Type and header length*/
134 uint8_t code; /* Code */
135 uint16_t checksum; /* Header checksum */
136 uint16_t ident; /* Identifier */
137 uint16_t seq; /* Sequence number */
138 uint8_t data[CREATEPING_MAX]; /* Data */
jjako5da68452003-01-28 16:08:47 +0000139} __attribute__((packed));
140
141/* Statistical values for ping */
142int nreceived = 0;
143int ntreceived = 0;
144int ntransmitted = 0;
145int tmin = 999999999;
146int tmax = 0;
147int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000148int pingseq = 0; /* Ping sequence counter */
149struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000150
jjakoa7cd2492003-04-11 09:40:12 +0000151int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
152 int hash = ippool_hash4(addr) % MAXCONTEXTS;
153 struct iphash_t *h;
154 struct iphash_t *prev = NULL;
155 ipaddr->ipnext = NULL;
156 ipaddr->addr.s_addr = addr->s_addr;
157 for (h = iphash[hash]; h; h = h->ipnext)
158 prev = h;
159 if (!prev)
160 iphash[hash] = ipaddr;
161 else
162 prev->ipnext = ipaddr;
163 return 0;
164}
165
166int ipdel(struct iphash_t *ipaddr) {
167 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
168 struct iphash_t *h;
169 struct iphash_t *prev = NULL;
170 for (h = iphash[hash]; h; h = h->ipnext) {
171 if (h == ipaddr) {
172 if (!prev)
173 iphash[hash] = h->ipnext;
174 else
175 prev->ipnext = h->ipnext;
176 return 0;
177 }
178 prev = h;
179 }
180 return EOF; /* End of linked list and not found */
181}
182
183int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
184 int hash = ippool_hash4(addr) % MAXCONTEXTS;
185 struct iphash_t *h;
186 for (h = iphash[hash]; h; h = h->ipnext) {
187 if ((h->addr.s_addr == addr->s_addr)) {
188 *ipaddr = h;
189 return 0;
190 }
191 }
192 return EOF; /* End of linked list and not found */
193}
194
195
196/* Used to write process ID to file. Assume someone else will delete */
197void log_pid(char *pidfile) {
198 FILE *file;
199 mode_t oldmask;
200
201 oldmask = umask(022);
202 file = fopen(pidfile, "w");
203 umask(oldmask);
204 if(!file)
205 return;
jjako0141d202004-01-09 15:19:20 +0000206 fprintf(file, "%d\n", (int) getpid());
jjakoa7cd2492003-04-11 09:40:12 +0000207 fclose(file);
208}
209
210
211int process_options(int argc, char **argv) {
212 /* gengeopt declarations */
213 struct gengetopt_args_info args_info;
214
215 struct hostent *host;
216 int n;
217
218 if (cmdline_parser (argc, argv, &args_info) != 0)
219 return -1;
220 if (args_info.debug_flag) {
221 printf("remote: %s\n", args_info.remote_arg);
222 printf("listen: %s\n", args_info.listen_arg);
223 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000224 printf("debug: %d\n", args_info.debug_flag);
225 printf("imsi: %s\n", args_info.imsi_arg);
226 printf("qos: %#08x\n", args_info.qos_arg);
227 printf("apn: %s\n", args_info.apn_arg);
228 printf("msisdn: %s\n", args_info.msisdn_arg);
229 printf("uid: %s\n", args_info.uid_arg);
230 printf("pwd: %s\n", args_info.pwd_arg);
231 printf("pidfile: %s\n", args_info.pidfile_arg);
232 printf("statedir: %s\n", args_info.statedir_arg);
233 printf("dns: %s\n", args_info.dns_arg);
234 printf("contexts: %d\n", args_info.contexts_arg);
235 printf("timelimit: %d\n", args_info.timelimit_arg);
236 printf("createif: %d\n", args_info.createif_flag);
237 printf("ipup: %s\n", args_info.ipup_arg);
238 printf("ipdown: %s\n", args_info.ipdown_arg);
239 printf("defaultroute: %d\n", args_info.defaultroute_flag);
240 printf("pinghost: %s\n", args_info.pinghost_arg);
241 printf("pingrate: %d\n", args_info.pingrate_arg);
242 printf("pingsize: %d\n", args_info.pingsize_arg);
243 printf("pingcount: %d\n", args_info.pingcount_arg);
244 printf("pingquiet: %d\n", args_info.pingquiet_flag);
245 }
246
247 /* Try out our new parser */
248
249 if (args_info.conf_arg) {
250 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
251 return -1;
252 if (args_info.debug_flag) {
253 printf("cmdline_parser_configfile\n");
254 printf("remote: %s\n", args_info.remote_arg);
255 printf("listen: %s\n", args_info.listen_arg);
256 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000257 printf("debug: %d\n", args_info.debug_flag);
258 printf("imsi: %s\n", args_info.imsi_arg);
259 printf("qos: %#08x\n", args_info.qos_arg);
260 printf("apn: %s\n", args_info.apn_arg);
261 printf("msisdn: %s\n", args_info.msisdn_arg);
262 printf("uid: %s\n", args_info.uid_arg);
263 printf("pwd: %s\n", args_info.pwd_arg);
264 printf("pidfile: %s\n", args_info.pidfile_arg);
265 printf("statedir: %s\n", args_info.statedir_arg);
266 printf("dns: %s\n", args_info.dns_arg);
267 printf("contexts: %d\n", args_info.contexts_arg);
268 printf("timelimit: %d\n", args_info.timelimit_arg);
269 printf("createif: %d\n", args_info.createif_flag);
270 printf("ipup: %s\n", args_info.ipup_arg);
271 printf("ipdown: %s\n", args_info.ipdown_arg);
272 printf("defaultroute: %d\n", args_info.defaultroute_flag);
273 printf("pinghost: %s\n", args_info.pinghost_arg);
274 printf("pingrate: %d\n", args_info.pingrate_arg);
275 printf("pingsize: %d\n", args_info.pingsize_arg);
276 printf("pingcount: %d\n", args_info.pingcount_arg);
277 printf("pingquiet: %d\n", args_info.pingquiet_flag);
278 }
279 }
280
281 /* Handle each option */
282
283 /* foreground */
jjakoe607f742003-07-06 21:21:30 +0000284 /* If fg flag not given run as a daemon */
285 /* Do not allow sgsnemu to run as deamon
jjakoa7cd2492003-04-11 09:40:12 +0000286 if (!args_info.fg_flag)
287 {
288 closelog();
jjakoa7cd2492003-04-11 09:40:12 +0000289 freopen("/dev/null", "w", stdout);
290 freopen("/dev/null", "w", stderr);
291 freopen("/dev/null", "r", stdin);
292 daemon(0, 0);
jjakoa7cd2492003-04-11 09:40:12 +0000293 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
jjakoe607f742003-07-06 21:21:30 +0000294 } */
jjakoa7cd2492003-04-11 09:40:12 +0000295
296 /* debug */
297 options.debug = args_info.debug_flag;
298
299 /* pidfile */
300 /* This has to be done after we have our final pid */
301 if (args_info.pidfile_arg) {
302 log_pid(args_info.pidfile_arg);
303 }
304
305 /* dns */
306 /* If no dns option is given use system default */
307 /* Do hostname lookup to translate hostname to IP address */
308 printf("\n");
309 if (args_info.dns_arg) {
310 if (!(host = gethostbyname(args_info.dns_arg))) {
311 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
312 "Invalid DNS address: %s!", args_info.dns_arg);
313 return -1;
314 }
315 else {
316 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
317 _res.nscount = 1;
318 _res.nsaddr_list[0].sin_addr = options.dns;
319 printf("Using DNS server: %s (%s)\n",
320 args_info.dns_arg, inet_ntoa(options.dns));
321 }
322 }
323 else {
324 options.dns.s_addr= 0;
325 printf("Using default DNS server\n");
326 }
327
328 /* listen */
329 /* If no listen option is specified listen to any local port */
330 /* Do hostname lookup to translate hostname to IP address */
331 if (args_info.listen_arg) {
332 if (!(host = gethostbyname(args_info.listen_arg))) {
333 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
334 "Invalid listening address: %s!", args_info.listen_arg);
335 return -1;
336 }
337 else {
338 memcpy(&options.listen.s_addr, host->h_addr, host->h_length);
339 printf("Local IP address is: %s (%s)\n",
340 args_info.listen_arg, inet_ntoa(options.listen));
341 }
342 }
343 else {
344 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
345 "Listening address must be specified: %s!", args_info.listen_arg);
346 return -1;
347 }
348
349
350 /* remote */
351 /* If no remote option is specified terminate */
352 /* Do hostname lookup to translate hostname to IP address */
353 if (args_info.remote_arg) {
354 if (!(host = gethostbyname(args_info.remote_arg))) {
355 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
356 "Invalid remote address: %s!", args_info.remote_arg);
357 return -1;
358 }
359 else {
360 memcpy(&options.remote.s_addr, host->h_addr, host->h_length);
361 printf("Remote IP address is: %s (%s)\n",
362 args_info.remote_arg, inet_ntoa(options.remote));
363 }
364 }
365 else {
366 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
367 "No remote address given!");
368 return -1;
369 }
370
371
372 /* imsi */
373 if (strlen(args_info.imsi_arg)!=15) {
374 printf("Invalid IMSI\n");
375 return -1;
376 }
377 options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48));
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
390 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
391 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
392
jjako193e8b12003-11-10 12:31:41 +0000393 printf("IMSI is: %s (%#08llx)\n",
394 args_info.imsi_arg, options.imsi);
395
396
397 /* nsapi */
398 if ((args_info.nsapi_arg > 15) ||
399 (args_info.nsapi_arg < 0)) {
400 printf("Invalid NSAPI\n");
401 return -1;
402 }
403 options.nsapi = args_info.nsapi_arg;
404 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000405
406
407 /* qos */
408 options.qos.l = 3;
409 options.qos.v[2] = (args_info.qos_arg) & 0xff;
410 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
411 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
412
413 /* contexts */
414 if (args_info.contexts_arg > MAXCONTEXTS) {
415 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
416 return -1;
417 }
418 options.contexts = args_info.contexts_arg;
419
420 /* Timelimit */
421 options.timelimit = args_info.timelimit_arg;
422
jjako193e8b12003-11-10 12:31:41 +0000423 /* gtpversion */
424 if ((args_info.gtpversion_arg > 1) ||
425 (args_info.gtpversion_arg < 0)) {
426 printf("Invalid GTP version\n");
427 return -1;
428 }
429 options.gtpversion = args_info.gtpversion_arg;
430 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
431
432
jjakoa7cd2492003-04-11 09:40:12 +0000433 /* apn */
434 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
435 printf("Invalid APN\n");
436 return -1;
437 }
438 options.apn.l = strlen(args_info.apn_arg) + 1;
439 options.apn.v[0] = (char) strlen(args_info.apn_arg);
440 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
441 printf("Using APN: %s\n", args_info.apn_arg);
442
443 /* msisdn */
444 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
445 printf("Invalid MSISDN\n");
446 return -1;
447 }
448 options.msisdn.l = 1;
449 options.msisdn.v[0] = 0x91; /* International format */
450 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
451 if ((n%2) == 0) {
452 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
453 options.msisdn.l += 1;
454 }
455 else {
456 options.msisdn.v[((int)n/2)+1] =
457 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
458 (args_info.msisdn_arg[n] - 48) * 16;
459 }
460 }
461 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
462
463 /* UID and PWD */
464 /* Might need to also insert stuff like DNS etc. */
465 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
466 (sizeof(options.pco.v)-1)) {
467 printf("invalid UID and PWD\n");
468 return -1;
469 }
470 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
471 options.pco.v[0] = 0x80; /* PPP */
472 options.pco.v[1] = 0xc0; /* PAP */
473 options.pco.v[2] = 0x23;
474 options.pco.v[3] = 0x12; /* Length of protocol contents */
475 options.pco.v[4] = 0x01; /* Authenticate request */
476 options.pco.v[5] = 0x01;
477 options.pco.v[6] = 0x00; /* MSB of length */
478 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
479 options.pco.v[8] = strlen(args_info.uid_arg);
480 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
481 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
482 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
483 args_info.pwd_arg, strlen(args_info.pwd_arg));
484
485 /* createif */
486 options.createif = args_info.createif_flag;
487
jjako193e8b12003-11-10 12:31:41 +0000488 /* net */
489 /* Store net as in_addr net and mask */
490 if (args_info.net_arg) {
491 if(ippool_aton(&options.net, &options.mask, args_info.net_arg, 0)) {
492 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
493 "Invalid network address: %s!", args_info.net_arg);
494 exit(1);
495 }
496 }
497 else {
498 options.net.s_addr = 0;
499 options.mask.s_addr = 0;
500 }
501
jjakoa7cd2492003-04-11 09:40:12 +0000502 /* ipup */
503 options.ipup = args_info.ipup_arg;
504
505 /* ipdown */
506 options.ipdown = args_info.ipdown_arg;
507
508 /* statedir */
509 options.statedir = args_info.statedir_arg;
510
511 /* defaultroute */
512 options.defaultroute = args_info.defaultroute_flag;
513
514
jjako76032b92004-01-14 06:22:08 +0000515 /* pinghost */
jjakoa7cd2492003-04-11 09:40:12 +0000516 /* Store ping host as in_addr */
517 if (args_info.pinghost_arg) {
jjako76032b92004-01-14 06:22:08 +0000518 if (!(host = gethostbyname(args_info.pinghost_arg))) {
jjakoa7cd2492003-04-11 09:40:12 +0000519 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
520 "Invalid ping host: %s!", args_info.pinghost_arg);
521 return -1;
522 }
jjako76032b92004-01-14 06:22:08 +0000523 else {
524 memcpy(&options.pinghost.s_addr, host->h_addr, host->h_length);
525 printf("Using ping host: %s (%s)\n",
526 args_info.pinghost_arg, inet_ntoa(options.pinghost));
527 }
jjakoa7cd2492003-04-11 09:40:12 +0000528 }
529
530 /* Other ping parameters */
531 options.pingrate = args_info.pingrate_arg;
532 options.pingsize = args_info.pingsize_arg;
533 options.pingcount = args_info.pingcount_arg;
534 options.pingquiet = args_info.pingquiet_flag;
535
536 return 0;
537
538}
539
jjako5da68452003-01-28 16:08:47 +0000540
541int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000542 int i;
543 printf("The packet looks like this:\n");
544 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000545 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000546 if (!((i+1)%16)) printf("\n");
547 };
jjako5da68452003-01-28 16:08:47 +0000548 printf("\n");
549 return 0;
jjako52c24142002-12-16 13:33:51 +0000550}
551
jjako5da68452003-01-28 16:08:47 +0000552char * print_ipprot(int t) {
553 switch (t) {
554 case 1: return "ICMP";
555 case 6: return "TCP";
556 case 17: return "UDP";
557 default: return "Unknown";
558 };
559}
560
561
562char * print_icmptype(int t) {
563 static char *ttab[] = {
564 "Echo Reply",
565 "ICMP 1",
566 "ICMP 2",
567 "Dest Unreachable",
568 "Source Quench",
569 "Redirect",
570 "ICMP 6",
571 "ICMP 7",
572 "Echo",
573 "ICMP 9",
574 "ICMP 10",
575 "Time Exceeded",
576 "Parameter Problem",
577 "Timestamp",
578 "Timestamp Reply",
579 "Info Request",
580 "Info Reply"
581 };
582 if( t < 0 || t > 16 )
583 return("OUT-OF-RANGE");
584 return(ttab[t]);
585}
586
jjako193e8b12003-11-10 12:31:41 +0000587int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) {
588 int n;
589 uint64_t i64 = 0;
590 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
591 int msalen = 0;
592
593 /* Convert to uint64_t from ul16_t format (most significant digit first) */
594 /* ul16_t format always starts with 0x91 to indicate international format */
595 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
596 for (n=0; n< src->l; n++) {
597 if ((src->v[n] & 0x0f) != 0x0f) {
598 i64 *= 10;
599 i64 += src->v[n] & 0x0f;
600 }
601 if ((src->v[n] & 0xf0) != 0xf0) {
602 i64 *= 10;
603 i64 += (src->v[n] & 0xf0) >> 4;
604 }
605 }
606
607 i64 += add;
608
609 /* Generate array with least significant digit in first octet */
610 while (i64) {
611 msa[msalen++] = i64 % 10;
612 i64 = i64 / 10;
613 }
614
615 /* Convert back to ul16_t format */
616 for(n=0; n<msalen; n++) {
617 if ((n%2) == 0) {
618 dst->v[((int)n/2)] = msa[msalen-n-1] + 0xf0;
619 dst->l += 1;
620 }
621 else {
622 dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) +
623 msa[msalen-n-1] * 16;
624 }
625 }
626
627 return 0;
628
629}
630
631int imsi_add(uint64_t src, uint64_t *dst, int add) {
632 /* TODO: big endian / small endian ??? */
633 uint64_t i64 = 0;
634
635 /* Convert from uint64_t bcd to uint64_t integer format */
636 /* The resulting integer format is multiplied by 10 */
637 while (src) {
638 if ((src & 0x0f) != 0x0f) {
639 i64 *= 10;
640 i64 += (src & 0x0f);
641 }
642 if ((src & 0xf0) != 0xf0) {
643 i64 *= 10;
644 i64 += (src & 0xf0) >> 4;
645 }
646 src = src >> 8;
647 }
648
649 i64 += add * 10;
650
651 *dst = 0;
652 while (i64) {
653 *dst = *dst << 4;
654 *dst += (i64 % 10);
655 i64 = i64 / 10;
656 }
657
658 return 0;
659
660}
661
jjakoafb2a972003-01-29 21:04:13 +0000662/* Calculate time left until we have to send off next ping packet */
663int ping_timeout(struct timeval *tp) {
664 struct timezone tz;
665 struct timeval tv;
666 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000667 if ((options.pinghost.s_addr) && (2 == state) &&
668 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000669 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000670 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000671 1000000 * (tv.tv_sec - firstping.tv_sec) -
672 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
673 tp->tv_sec = 0;
674 if (diff > 0)
675 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000676 else {
jjakoafb2a972003-01-29 21:04:13 +0000677 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000678 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
679 tp->tv_usec = 0;
680 }
jjakoafb2a972003-01-29 21:04:13 +0000681 }
682 return 0;
683}
684
jjako5da68452003-01-28 16:08:47 +0000685/* Print out statistics when at the end of ping sequence */
686int ping_finish()
687{
jjakoafb2a972003-01-29 21:04:13 +0000688 struct timezone tz;
689 struct timeval tv;
690 int elapsed;
691 gettimeofday(&tv, &tz);
692 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
693 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000694 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000695 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000696 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
697 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000698 printf("%d packets received, ", nreceived );
699 if (ntransmitted) {
700 if( nreceived > ntransmitted)
701 printf("-- somebody's printing up packets!");
702 else
703 printf("%d%% packet loss",
704 (int) (((ntransmitted-nreceived)*100) /
705 ntransmitted));
706 }
707 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000708 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000709 if (nreceived && tsum)
710 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
711 tmin/1000.0,
712 tsum/1000.0/nreceived,
713 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000714 printf("%d packets transmitted \n", ntreceived );
715
jjako5da68452003-01-28 16:08:47 +0000716 ntransmitted = 0;
717 return 0;
718}
719
720/* Handle a received ping packet. Print out line and update statistics. */
721int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
722 struct timezone tz;
723 struct timeval tv;
724 struct timeval *tp;
725 struct ip_ping *pingpack = pack;
726 struct in_addr src;
727 int triptime;
728
729 src.s_addr = pingpack->src;
730
731 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000732 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000733
734 if (len < CREATEPING_IP + CREATEPING_ICMP) {
735 printf("packet too short (%d bytes) from %s\n", len,
736 inet_ntoa(src));
737 return 0;
738 }
739
740 ntreceived++;
741 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000742 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000743 len, inet_ntoa(src), pingpack->protocol,
744 print_ipprot(pingpack->protocol));
745 return 0;
746 }
747
748 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000749 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000750 len, inet_ntoa(src), pingpack->type,
751 print_icmptype(pingpack->type), pingpack->code);
752 return 0;
753 }
754
755 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000756 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000757 inet_ntoa(src), ntohs(pingpack->seq));
758
759 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
760 gettimeofday(&tv, &tz);
761 tp = (struct timeval *) pingpack->data;
762 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
763 tv.tv_sec--;
764 tv.tv_usec += 1000000;
765 }
766 tv.tv_sec -= tp->tv_sec;
767
768 triptime = tv.tv_sec*1000000+(tv.tv_usec);
769 tsum += triptime;
770 if( triptime < tmin )
771 tmin = triptime;
772 if( triptime > tmax )
773 tmax = triptime;
774
jjakoa7cd2492003-04-11 09:40:12 +0000775 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000776
777 }
778 else
jjakoa7cd2492003-04-11 09:40:12 +0000779 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000780 return 0;
781}
782
783/* Create a new ping packet and send it off to peer. */
784int create_ping(void *gsn, struct pdp_t *pdp,
785 struct in_addr *dst, int seq, int datasize) {
786
787 struct ip_ping pack;
jjako0141d202004-01-09 15:19:20 +0000788 uint16_t *p = (uint16_t *) &pack;
789 uint8_t *p8 = (uint8_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000790 struct in_addr src;
791 int n;
792 long int sum = 0;
793 int count = 0;
794
795 struct timezone tz;
796 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
797
798 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000799 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
800 "Ping size to large: %d!", datasize);
801 return -1;
jjako5da68452003-01-28 16:08:47 +0000802 }
803
804 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
805
806 pack.ipver = 0x45;
807 pack.tos = 0x00;
808 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
809 pack.fragid = 0x0000;
810 pack.offset = 0x0040;
811 pack.ttl = 0x40;
812 pack.protocol = 0x01;
813 pack.ipcheck = 0x0000;
814 pack.src = src.s_addr;
815 pack.dst = dst->s_addr;
816 pack.type = 0x08;
817 pack.code = 0x00;
818 pack.checksum = 0x0000;
819 pack.ident = 0x0000;
820 pack.seq = htons(seq);
821
822 /* Generate ICMP payload */
jjako0141d202004-01-09 15:19:20 +0000823 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
jjako5da68452003-01-28 16:08:47 +0000824 for (n=0; n<(datasize); n++) p8[n] = n;
825
826 if (datasize >= sizeof(struct timeval))
827 gettimeofday(tp, &tz);
828
829 /* Calculate IP header checksum */
jjako0141d202004-01-09 15:19:20 +0000830 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000831 count = CREATEPING_IP;
832 sum = 0;
833 while (count>1) {
834 sum += *p++;
835 count -= 2;
836 }
837 while (sum>>16)
838 sum = (sum & 0xffff) + (sum >> 16);
839 pack.ipcheck = ~sum;
840
841
842 /* Calculate ICMP checksum */
843 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
844 sum = 0;
jjako0141d202004-01-09 15:19:20 +0000845 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000846 p += CREATEPING_IP / 2;
847 while (count>1) {
848 sum += *p++;
849 count -= 2;
850 }
851 if (count>0)
852 sum += * (unsigned char *) p;
853 while (sum>>16)
854 sum = (sum & 0xffff) + (sum >> 16);
855 pack.checksum = ~sum;
856
857 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000858 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000859}
860
861
jjakoa7cd2492003-04-11 09:40:12 +0000862int delete_context(struct pdp_t *pdp) {
863
864 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
865
866 ipdel((struct iphash_t*) pdp->peer);
867 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000868
869 if (1 == options.contexts)
870 state = 5; /* Disconnected */
871
jjakoa7cd2492003-04-11 09:40:12 +0000872 return 0;
jjako52c24142002-12-16 13:33:51 +0000873}
874
jjakoa7cd2492003-04-11 09:40:12 +0000875
876/* Callback for receiving messages from tun */
877int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
878 struct iphash_t *ipm;
879 struct in_addr src;
880 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
881
882 src.s_addr = iph->src;
883
884 if (ipget(&ipm, &src)) {
885 printf("Received packet without a valid source address!!!\n");
886 return 0;
jjako52c24142002-12-16 13:33:51 +0000887 }
jjako5da68452003-01-28 16:08:47 +0000888
jjakoa7cd2492003-04-11 09:40:12 +0000889 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000890 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000891 return 0;
892}
893
jjako2c381332003-10-21 19:09:53 +0000894int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000895 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000896
jjako2c381332003-10-21 19:09:53 +0000897 struct iphash_t *iph = (struct iphash_t*) cbp;
898
899 if (cause < 0) {
900 printf("Create PDP Context Request timed out\n");
901 if (iph->pdp->version == 1) {
902 printf("Retrying with version 0\n");
903 iph->pdp->version = 0;
jjako193e8b12003-11-10 12:31:41 +0000904 gtp_create_context_req(gsn, iph->pdp, iph);
jjako2c381332003-10-21 19:09:53 +0000905 return 0;
906 }
907 else {
908 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000909 pdp_freepdp(iph->pdp);
910 iph->pdp = NULL;
jjako2c381332003-10-21 19:09:53 +0000911 return EOF;
912 }
913 }
914
jjakoa7cd2492003-04-11 09:40:12 +0000915 if (cause != 128) {
916 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000917 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000918 pdp_freepdp(iph->pdp);
919 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000920 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000921 }
922
jjakoa7cd2492003-04-11 09:40:12 +0000923 if (pdp_euaton(&pdp->eua, &addr)) {
924 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako0b076a32003-10-25 15:59:31 +0000925 pdp_freepdp(iph->pdp);
926 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000927 state = 0;
928 return EOF; /* Not a valid IP address */
929 }
930
931 printf("Received create PDP context response. IP address: %s\n",
932 inet_ntoa(addr));
933
jjako193e8b12003-11-10 12:31:41 +0000934 if ((options.createif) && (!options.net.s_addr)) {
jjakoa7cd2492003-04-11 09:40:12 +0000935 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +0000936#ifdef HAVE_INET_ATON
jjako1d3db972004-01-16 09:56:56 +0000937 inet_aton("255.255.255.255", &m);
938#else
jjakob73f23a2004-01-16 19:46:41 +0000939 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +0000940#endif
jjakoa7cd2492003-04-11 09:40:12 +0000941 /* printf("Setting up interface and routing\n");*/
942 tun_addaddr(tun, &addr, &addr, &m);
943 if (options.defaultroute) {
944 struct in_addr rm;
945 rm.s_addr = 0;
946 tun_addroute(tun, &rm, &addr, &rm);
947 }
948 if (options.ipup) tun_runscript(tun, options.ipup);
949 }
950
951 ipset((struct iphash_t*) pdp->peer, &addr);
952
953 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000954
955 return 0;
956}
957
jjako52c24142002-12-16 13:33:51 +0000958int delete_pdp_conf(struct pdp_t *pdp, int cause) {
959 printf("Received delete PDP context response. Cause value: %d\n", cause);
960 return 0;
961}
962
jjako08d331d2003-10-13 20:33:30 +0000963int echo_conf(int recovery) {
jjako91aaf222003-10-22 10:09:32 +0000964
965 if (recovery < 0) {
966 printf("Echo Request timed out\n");
967 if (echoversion == 1) {
968 printf("Retrying with version 0\n");
969 echoversion = 0;
970 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000971 return 0;
972 }
973 else {
974 state = 0;
975 return EOF;
976 }
jjako7b8fad42003-07-07 14:37:42 +0000977 }
jjako581c9f02003-10-22 11:28:20 +0000978 else {
jjako08d331d2003-10-13 20:33:30 +0000979 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +0000980 if (!options.contexts) state = 5;
981 }
jjako52c24142002-12-16 13:33:51 +0000982 return 0;
983}
984
jjako2c381332003-10-21 19:09:53 +0000985int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000986 /* if (cause < 0) return 0; Some error occurred. We don't care */
987 switch (type) {
988 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000989 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000990 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000991 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000992 case GTP_DELETE_PDP_REQ:
993 if (cause !=128) return 0; /* Request not accepted. We don't care */
994 return delete_pdp_conf(pdp, cause);
995 default:
996 return 0;
997 }
998}
999
jjako52c24142002-12-16 13:33:51 +00001000
1001int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
1002 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
1003 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
1004}
1005
1006int main(int argc, char **argv)
1007{
jjako52c24142002-12-16 13:33:51 +00001008 fd_set fds; /* For select() */
1009 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +00001010 struct pdp_t *pdp;
1011 int n;
1012 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +00001013 int stoptime = 0; /* Time to exit */
1014 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001015
1016 struct timezone tz; /* Used for calculating ping times */
1017 struct timeval tv;
1018 int diff;
jjako52c24142002-12-16 13:33:51 +00001019
jjako52c24142002-12-16 13:33:51 +00001020 /* open a connection to the syslog daemon */
1021 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
jjako0141d202004-01-09 15:19:20 +00001022 /* TODO: Only use LOG__PERROR for linux */
1023
1024#ifdef __linux__
jjako52c24142002-12-16 13:33:51 +00001025 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
jjako0141d202004-01-09 15:19:20 +00001026#else
1027 openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
1028#endif
1029
jjako52c24142002-12-16 13:33:51 +00001030
jjakoa7cd2492003-04-11 09:40:12 +00001031 /* Process options given in configuration file and command line */
1032 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +00001033 exit(1);
jjako52c24142002-12-16 13:33:51 +00001034
1035 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +00001036 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +00001037 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1038 "Failed to create gtp");
1039 exit(1);
1040 }
jjako08d331d2003-10-13 20:33:30 +00001041 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
1042 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
1043 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001044
jjakoa7cd2492003-04-11 09:40:12 +00001045 gtp_set_cb_delete_context(gsn, delete_context);
1046 gtp_set_cb_conf(gsn, conf);
1047 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +00001048 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +00001049 else
jjako08d331d2003-10-13 20:33:30 +00001050 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +00001051
1052 if (options.createif) {
1053 printf("Setting up interface\n");
1054 /* Create a tunnel interface */
1055 if (tun_new((struct tun_t**) &tun)) {
1056 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1057 "Failed to create tun");
1058 exit(1);
1059 }
1060 tun_set_cb_ind(tun, cb_tun_ind);
1061 if (tun->fd > maxfd) maxfd = tun->fd;
1062 }
1063
jjako193e8b12003-11-10 12:31:41 +00001064 if ((options.createif) && (options.net.s_addr)) {
1065 /* printf("Setting up interface and routing\n");*/
1066 tun_addaddr(tun, &options.net, &options.net, &options.mask);
1067 if (options.defaultroute) {
1068 struct in_addr rm;
1069 rm.s_addr = 0;
1070 tun_addroute(tun, &rm, &options.net, &rm);
1071 }
1072 if (options.ipup) tun_runscript(tun, options.ipup);
1073 }
1074
1075
jjakoa7cd2492003-04-11 09:40:12 +00001076 /* Initialise hash tables */
1077 memset(&iphash, 0, sizeof(iphash));
1078 memset(&iparr, 0, sizeof(iparr));
1079
jjako52c24142002-12-16 13:33:51 +00001080 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +00001081
1082 /* See if anybody is there */
1083 printf("Sending off echo request\n");
jjako193e8b12003-11-10 12:31:41 +00001084 echoversion = options.gtpversion;
jjako91aaf222003-10-22 10:09:32 +00001085 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +00001086
jjakoa7cd2492003-04-11 09:40:12 +00001087 for(n=0; n<options.contexts; n++) {
jjako193e8b12003-11-10 12:31:41 +00001088 uint64_t myimsi;
jjako52c24142002-12-16 13:33:51 +00001089 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +00001090 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001091
jjako193e8b12003-11-10 12:31:41 +00001092 imsi_add(options.imsi, &myimsi, n);
1093
jjako0b076a32003-10-25 15:59:31 +00001094 /* Allocated here. */
1095 /* If create context failes we have to deallocate ourselves. */
jjako193e8b12003-11-10 12:31:41 +00001096 /* Otherwise it is deallocated by gtplib */
1097 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjakoa7cd2492003-04-11 09:40:12 +00001098
1099 pdp->peer = &iparr[n];
1100 pdp->ipif = tun; /* TODO */
1101 iparr[n].pdp = pdp;
1102
1103 if (options.qos.l > sizeof(pdp->qos_req0)) {
1104 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +00001105 exit(1);
1106 }
1107 else {
jjakoa7cd2492003-04-11 09:40:12 +00001108 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001109 }
jjako08d331d2003-10-13 20:33:30 +00001110
1111 /* TODO */
1112 pdp->qos_req.l = 4;
1113 pdp->qos_req.v[0] = 0x00;
1114 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001115
jjakoa7cd2492003-04-11 09:40:12 +00001116 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +00001117
jjakoa7cd2492003-04-11 09:40:12 +00001118 if (options.apn.l > sizeof(pdp->apn_use.v)) {
1119 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +00001120 exit(1);
1121 }
1122 else {
jjakoa7cd2492003-04-11 09:40:12 +00001123 pdp->apn_use.l = options.apn.l;
1124 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +00001125 }
1126
jjakoa7cd2492003-04-11 09:40:12 +00001127 pdp->gsnlc.l = sizeof(options.listen);
1128 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1129 pdp->gsnlu.l = sizeof(options.listen);
1130 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +00001131
jjakoa7cd2492003-04-11 09:40:12 +00001132 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
1133 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +00001134 exit(1);
1135 }
1136 else {
jjako193e8b12003-11-10 12:31:41 +00001137 msisdn_add(&options.msisdn, &pdp->msisdn, n);
jjakoa7cd2492003-04-11 09:40:12 +00001138 }
1139
1140 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1141
1142 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1143 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1144 exit(1);
1145 }
1146 else {
1147 pdp->pco_req.l = options.pco.l;
1148 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001149 }
1150
jjako193e8b12003-11-10 12:31:41 +00001151 pdp->version = options.gtpversion;
1152
1153 pdp->hisaddr0 = options.remote;
1154 pdp->hisaddr1 = options.remote;
jjako08d331d2003-10-13 20:33:30 +00001155
jjako52c24142002-12-16 13:33:51 +00001156 /* Create context */
1157 /* We send this of once. Retransmissions are handled by gtplib */
jjako193e8b12003-11-10 12:31:41 +00001158 gtp_create_context_req(gsn, pdp, &iparr[n]);
jjako52c24142002-12-16 13:33:51 +00001159 }
1160
1161 state = 1; /* Enter wait_connection state */
1162
1163 printf("Waiting for response from ggsn........\n\n");
1164
jjako5da68452003-01-28 16:08:47 +00001165
jjako52c24142002-12-16 13:33:51 +00001166 /******************************************************************/
1167 /* Main select loop */
1168 /******************************************************************/
1169
jjako7b8fad42003-07-07 14:37:42 +00001170 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001171
jjako7b8fad42003-07-07 14:37:42 +00001172 /* Take down client after timeout after disconnect */
1173 if ((4 == state) && ((stoptime) <= time(NULL))) {
1174 state = 5;
1175 }
1176
1177 /* Take down client after timelimit timeout */
1178 if ((2 == state) && (options.timelimit) &&
1179 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001180 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001181 }
1182
1183 /* Take down client after ping timeout */
1184 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1185 state = 3;
1186 }
1187
1188 /* Set pingtimeout for later disconnection */
1189 if (options.pingcount && ntransmitted >= options.pingcount) {
1190 pingtimeout = time(NULL) + 5; /* Extra seconds */
1191 }
1192
1193 /* Print statistics if no more ping packets are missing */
1194 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1195 ping_finish();
1196 if (!options.createif)
1197 state = 3;
1198 }
1199
jjako2c381332003-10-21 19:09:53 +00001200 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001201 if (3 == state) {
1202 state = 4;
1203 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001204 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001205 /* Delete context */
1206 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001207 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001208 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001209 }
jjakoafb2a972003-01-29 21:04:13 +00001210 }
jjako7b8fad42003-07-07 14:37:42 +00001211
1212 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001213 diff = 0;
1214 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001215 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001216 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001217 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001218 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1219 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001220 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001221 1000000 * (tv.tv_sec - firstping.tv_sec) -
1222 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1223 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001224 if (options.debug) printf("Create_ping %d\n", diff);
1225 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1226 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001227 pingseq++;
1228 }
jjako52c24142002-12-16 13:33:51 +00001229 }
jjako5da68452003-01-28 16:08:47 +00001230
jjako52c24142002-12-16 13:33:51 +00001231 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001232 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001233 FD_SET(gsn->fd0, &fds);
1234 FD_SET(gsn->fd1c, &fds);
1235 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001236
1237 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001238 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001239
1240 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1241 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1242
jjako52c24142002-12-16 13:33:51 +00001243 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1244 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001245 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1246 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001247 break;
1248 case 0:
1249 gtp_retrans(gsn); /* Only retransmit if nothing else */
1250 break;
1251 default:
1252 break;
1253 }
jjakoa7cd2492003-04-11 09:40:12 +00001254
1255 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1256 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1257 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001258 }
1259
jjako08d331d2003-10-13 20:33:30 +00001260 if (FD_ISSET(gsn->fd0, &fds))
1261 gtp_decaps0(gsn);
1262
1263 if (FD_ISSET(gsn->fd1c, &fds))
1264 gtp_decaps1c(gsn);
1265
1266 if (FD_ISSET(gsn->fd1u, &fds))
1267 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001268 }
jjakoa7cd2492003-04-11 09:40:12 +00001269
jjako52c24142002-12-16 13:33:51 +00001270 gtp_free(gsn); /* Clean up the gsn instance */
1271
jjakoa7cd2492003-04-11 09:40:12 +00001272 if (options.createif)
1273 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001274
1275 if (0 == state)
1276 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001277
jjakoa7cd2492003-04-11 09:40:12 +00001278 return 0;
jjako52c24142002-12-16 13:33:51 +00001279}
1280