blob: 4915fcd4efebde5093d312324d704b601a285054 [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 }
jjako06e9f122004-01-19 18:37:58 +0000377
jjakod48c5ff2004-01-26 22:25:40 +0000378 options.imsi = 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +0000379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 0]-48));
jjakoa7cd2492003-04-11 09:40:12 +0000380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
390 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
391 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
392 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
393 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
394
jjako193e8b12003-11-10 12:31:41 +0000395 printf("IMSI is: %s (%#08llx)\n",
396 args_info.imsi_arg, options.imsi);
397
398
399 /* nsapi */
400 if ((args_info.nsapi_arg > 15) ||
401 (args_info.nsapi_arg < 0)) {
402 printf("Invalid NSAPI\n");
403 return -1;
404 }
405 options.nsapi = args_info.nsapi_arg;
406 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000407
408
409 /* qos */
410 options.qos.l = 3;
411 options.qos.v[2] = (args_info.qos_arg) & 0xff;
412 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
413 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
414
415 /* contexts */
416 if (args_info.contexts_arg > MAXCONTEXTS) {
417 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
418 return -1;
419 }
420 options.contexts = args_info.contexts_arg;
421
422 /* Timelimit */
423 options.timelimit = args_info.timelimit_arg;
424
jjako193e8b12003-11-10 12:31:41 +0000425 /* gtpversion */
426 if ((args_info.gtpversion_arg > 1) ||
427 (args_info.gtpversion_arg < 0)) {
428 printf("Invalid GTP version\n");
429 return -1;
430 }
431 options.gtpversion = args_info.gtpversion_arg;
432 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
433
434
jjakoa7cd2492003-04-11 09:40:12 +0000435 /* apn */
436 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
437 printf("Invalid APN\n");
438 return -1;
439 }
440 options.apn.l = strlen(args_info.apn_arg) + 1;
441 options.apn.v[0] = (char) strlen(args_info.apn_arg);
442 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
443 printf("Using APN: %s\n", args_info.apn_arg);
444
445 /* msisdn */
446 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
447 printf("Invalid MSISDN\n");
448 return -1;
449 }
450 options.msisdn.l = 1;
451 options.msisdn.v[0] = 0x91; /* International format */
452 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
453 if ((n%2) == 0) {
454 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
455 options.msisdn.l += 1;
456 }
457 else {
458 options.msisdn.v[((int)n/2)+1] =
459 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
460 (args_info.msisdn_arg[n] - 48) * 16;
461 }
462 }
463 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
464
465 /* UID and PWD */
466 /* Might need to also insert stuff like DNS etc. */
467 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
468 (sizeof(options.pco.v)-1)) {
469 printf("invalid UID and PWD\n");
470 return -1;
471 }
472 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
473 options.pco.v[0] = 0x80; /* PPP */
474 options.pco.v[1] = 0xc0; /* PAP */
475 options.pco.v[2] = 0x23;
476 options.pco.v[3] = 0x12; /* Length of protocol contents */
477 options.pco.v[4] = 0x01; /* Authenticate request */
478 options.pco.v[5] = 0x01;
479 options.pco.v[6] = 0x00; /* MSB of length */
480 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
481 options.pco.v[8] = strlen(args_info.uid_arg);
482 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
483 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
484 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
485 args_info.pwd_arg, strlen(args_info.pwd_arg));
486
487 /* createif */
488 options.createif = args_info.createif_flag;
489
jjako193e8b12003-11-10 12:31:41 +0000490 /* net */
491 /* Store net as in_addr net and mask */
492 if (args_info.net_arg) {
493 if(ippool_aton(&options.net, &options.mask, args_info.net_arg, 0)) {
494 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
495 "Invalid network address: %s!", args_info.net_arg);
496 exit(1);
497 }
498 }
499 else {
500 options.net.s_addr = 0;
501 options.mask.s_addr = 0;
502 }
503
jjakoa7cd2492003-04-11 09:40:12 +0000504 /* ipup */
505 options.ipup = args_info.ipup_arg;
506
507 /* ipdown */
508 options.ipdown = args_info.ipdown_arg;
509
510 /* statedir */
511 options.statedir = args_info.statedir_arg;
512
513 /* defaultroute */
514 options.defaultroute = args_info.defaultroute_flag;
515
516
jjako76032b92004-01-14 06:22:08 +0000517 /* pinghost */
jjakoa7cd2492003-04-11 09:40:12 +0000518 /* Store ping host as in_addr */
519 if (args_info.pinghost_arg) {
jjako76032b92004-01-14 06:22:08 +0000520 if (!(host = gethostbyname(args_info.pinghost_arg))) {
jjakoa7cd2492003-04-11 09:40:12 +0000521 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
522 "Invalid ping host: %s!", args_info.pinghost_arg);
523 return -1;
524 }
jjako76032b92004-01-14 06:22:08 +0000525 else {
526 memcpy(&options.pinghost.s_addr, host->h_addr, host->h_length);
527 printf("Using ping host: %s (%s)\n",
528 args_info.pinghost_arg, inet_ntoa(options.pinghost));
529 }
jjakoa7cd2492003-04-11 09:40:12 +0000530 }
531
532 /* Other ping parameters */
533 options.pingrate = args_info.pingrate_arg;
534 options.pingsize = args_info.pingsize_arg;
535 options.pingcount = args_info.pingcount_arg;
536 options.pingquiet = args_info.pingquiet_flag;
537
538 return 0;
539
540}
541
jjako5da68452003-01-28 16:08:47 +0000542
543int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000544 int i;
545 printf("The packet looks like this:\n");
546 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000547 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000548 if (!((i+1)%16)) printf("\n");
549 };
jjako5da68452003-01-28 16:08:47 +0000550 printf("\n");
551 return 0;
jjako52c24142002-12-16 13:33:51 +0000552}
553
jjako5da68452003-01-28 16:08:47 +0000554char * print_ipprot(int t) {
555 switch (t) {
556 case 1: return "ICMP";
557 case 6: return "TCP";
558 case 17: return "UDP";
559 default: return "Unknown";
560 };
561}
562
563
564char * print_icmptype(int t) {
565 static char *ttab[] = {
566 "Echo Reply",
567 "ICMP 1",
568 "ICMP 2",
569 "Dest Unreachable",
570 "Source Quench",
571 "Redirect",
572 "ICMP 6",
573 "ICMP 7",
574 "Echo",
575 "ICMP 9",
576 "ICMP 10",
577 "Time Exceeded",
578 "Parameter Problem",
579 "Timestamp",
580 "Timestamp Reply",
581 "Info Request",
582 "Info Reply"
583 };
584 if( t < 0 || t > 16 )
585 return("OUT-OF-RANGE");
586 return(ttab[t]);
587}
588
jjako193e8b12003-11-10 12:31:41 +0000589int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) {
590 int n;
591 uint64_t i64 = 0;
592 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
593 int msalen = 0;
594
595 /* Convert to uint64_t from ul16_t format (most significant digit first) */
596 /* ul16_t format always starts with 0x91 to indicate international format */
597 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
598 for (n=0; n< src->l; n++) {
599 if ((src->v[n] & 0x0f) != 0x0f) {
600 i64 *= 10;
601 i64 += src->v[n] & 0x0f;
602 }
603 if ((src->v[n] & 0xf0) != 0xf0) {
604 i64 *= 10;
605 i64 += (src->v[n] & 0xf0) >> 4;
606 }
607 }
608
609 i64 += add;
610
611 /* Generate array with least significant digit in first octet */
612 while (i64) {
613 msa[msalen++] = i64 % 10;
614 i64 = i64 / 10;
615 }
616
617 /* Convert back to ul16_t format */
618 for(n=0; n<msalen; n++) {
619 if ((n%2) == 0) {
620 dst->v[((int)n/2)] = msa[msalen-n-1] + 0xf0;
621 dst->l += 1;
622 }
623 else {
624 dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) +
625 msa[msalen-n-1] * 16;
626 }
627 }
628
629 return 0;
630
631}
632
633int imsi_add(uint64_t src, uint64_t *dst, int add) {
634 /* TODO: big endian / small endian ??? */
635 uint64_t i64 = 0;
636
637 /* Convert from uint64_t bcd to uint64_t integer format */
638 /* The resulting integer format is multiplied by 10 */
639 while (src) {
640 if ((src & 0x0f) != 0x0f) {
641 i64 *= 10;
642 i64 += (src & 0x0f);
643 }
644 if ((src & 0xf0) != 0xf0) {
645 i64 *= 10;
646 i64 += (src & 0xf0) >> 4;
647 }
648 src = src >> 8;
649 }
650
651 i64 += add * 10;
652
653 *dst = 0;
654 while (i64) {
655 *dst = *dst << 4;
656 *dst += (i64 % 10);
657 i64 = i64 / 10;
658 }
659
jjakod48c5ff2004-01-26 22:25:40 +0000660 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +0000661
jjako193e8b12003-11-10 12:31:41 +0000662 return 0;
663
664}
665
jjakoafb2a972003-01-29 21:04:13 +0000666/* Calculate time left until we have to send off next ping packet */
667int ping_timeout(struct timeval *tp) {
668 struct timezone tz;
669 struct timeval tv;
670 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000671 if ((options.pinghost.s_addr) && (2 == state) &&
672 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000673 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000674 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000675 1000000 * (tv.tv_sec - firstping.tv_sec) -
676 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
677 tp->tv_sec = 0;
678 if (diff > 0)
679 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000680 else {
jjakoafb2a972003-01-29 21:04:13 +0000681 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000682 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
683 tp->tv_usec = 0;
684 }
jjakoafb2a972003-01-29 21:04:13 +0000685 }
686 return 0;
687}
688
jjako5da68452003-01-28 16:08:47 +0000689/* Print out statistics when at the end of ping sequence */
690int ping_finish()
691{
jjakoafb2a972003-01-29 21:04:13 +0000692 struct timezone tz;
693 struct timeval tv;
694 int elapsed;
695 gettimeofday(&tv, &tz);
696 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
697 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000698 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000699 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000700 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
701 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000702 printf("%d packets received, ", nreceived );
703 if (ntransmitted) {
704 if( nreceived > ntransmitted)
705 printf("-- somebody's printing up packets!");
706 else
707 printf("%d%% packet loss",
708 (int) (((ntransmitted-nreceived)*100) /
709 ntransmitted));
710 }
711 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000712 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000713 if (nreceived && tsum)
714 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
715 tmin/1000.0,
716 tsum/1000.0/nreceived,
717 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000718 printf("%d packets transmitted \n", ntreceived );
719
jjako5da68452003-01-28 16:08:47 +0000720 ntransmitted = 0;
721 return 0;
722}
723
724/* Handle a received ping packet. Print out line and update statistics. */
725int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
726 struct timezone tz;
727 struct timeval tv;
728 struct timeval *tp;
729 struct ip_ping *pingpack = pack;
730 struct in_addr src;
731 int triptime;
732
733 src.s_addr = pingpack->src;
734
735 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000736 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000737
738 if (len < CREATEPING_IP + CREATEPING_ICMP) {
739 printf("packet too short (%d bytes) from %s\n", len,
740 inet_ntoa(src));
741 return 0;
742 }
743
744 ntreceived++;
745 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000746 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000747 len, inet_ntoa(src), pingpack->protocol,
748 print_ipprot(pingpack->protocol));
749 return 0;
750 }
751
752 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000753 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000754 len, inet_ntoa(src), pingpack->type,
755 print_icmptype(pingpack->type), pingpack->code);
756 return 0;
757 }
758
759 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000760 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000761 inet_ntoa(src), ntohs(pingpack->seq));
762
763 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
764 gettimeofday(&tv, &tz);
765 tp = (struct timeval *) pingpack->data;
766 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
767 tv.tv_sec--;
768 tv.tv_usec += 1000000;
769 }
770 tv.tv_sec -= tp->tv_sec;
771
772 triptime = tv.tv_sec*1000000+(tv.tv_usec);
773 tsum += triptime;
774 if( triptime < tmin )
775 tmin = triptime;
776 if( triptime > tmax )
777 tmax = triptime;
778
jjakoa7cd2492003-04-11 09:40:12 +0000779 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000780
781 }
782 else
jjakoa7cd2492003-04-11 09:40:12 +0000783 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000784 return 0;
785}
786
787/* Create a new ping packet and send it off to peer. */
788int create_ping(void *gsn, struct pdp_t *pdp,
789 struct in_addr *dst, int seq, int datasize) {
790
791 struct ip_ping pack;
jjako0141d202004-01-09 15:19:20 +0000792 uint16_t *p = (uint16_t *) &pack;
793 uint8_t *p8 = (uint8_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000794 struct in_addr src;
795 int n;
796 long int sum = 0;
797 int count = 0;
798
799 struct timezone tz;
800 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
801
802 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000803 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
804 "Ping size to large: %d!", datasize);
805 return -1;
jjako5da68452003-01-28 16:08:47 +0000806 }
807
808 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
809
810 pack.ipver = 0x45;
811 pack.tos = 0x00;
812 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
813 pack.fragid = 0x0000;
814 pack.offset = 0x0040;
815 pack.ttl = 0x40;
816 pack.protocol = 0x01;
817 pack.ipcheck = 0x0000;
818 pack.src = src.s_addr;
819 pack.dst = dst->s_addr;
820 pack.type = 0x08;
821 pack.code = 0x00;
822 pack.checksum = 0x0000;
823 pack.ident = 0x0000;
824 pack.seq = htons(seq);
825
826 /* Generate ICMP payload */
jjako0141d202004-01-09 15:19:20 +0000827 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
jjako5da68452003-01-28 16:08:47 +0000828 for (n=0; n<(datasize); n++) p8[n] = n;
829
830 if (datasize >= sizeof(struct timeval))
831 gettimeofday(tp, &tz);
832
833 /* Calculate IP header checksum */
jjako0141d202004-01-09 15:19:20 +0000834 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000835 count = CREATEPING_IP;
836 sum = 0;
837 while (count>1) {
838 sum += *p++;
839 count -= 2;
840 }
841 while (sum>>16)
842 sum = (sum & 0xffff) + (sum >> 16);
843 pack.ipcheck = ~sum;
844
845
846 /* Calculate ICMP checksum */
847 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
848 sum = 0;
jjako0141d202004-01-09 15:19:20 +0000849 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000850 p += CREATEPING_IP / 2;
851 while (count>1) {
852 sum += *p++;
853 count -= 2;
854 }
855 if (count>0)
856 sum += * (unsigned char *) p;
857 while (sum>>16)
858 sum = (sum & 0xffff) + (sum >> 16);
859 pack.checksum = ~sum;
860
861 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000862 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000863}
864
865
jjakoa7cd2492003-04-11 09:40:12 +0000866int delete_context(struct pdp_t *pdp) {
867
868 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
869
870 ipdel((struct iphash_t*) pdp->peer);
871 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000872
873 if (1 == options.contexts)
874 state = 5; /* Disconnected */
875
jjakoa7cd2492003-04-11 09:40:12 +0000876 return 0;
jjako52c24142002-12-16 13:33:51 +0000877}
878
jjakoa7cd2492003-04-11 09:40:12 +0000879
880/* Callback for receiving messages from tun */
881int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
882 struct iphash_t *ipm;
883 struct in_addr src;
884 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
885
886 src.s_addr = iph->src;
887
888 if (ipget(&ipm, &src)) {
889 printf("Received packet without a valid source address!!!\n");
890 return 0;
jjako52c24142002-12-16 13:33:51 +0000891 }
jjako5da68452003-01-28 16:08:47 +0000892
jjakoa7cd2492003-04-11 09:40:12 +0000893 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000894 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000895 return 0;
896}
897
jjako2c381332003-10-21 19:09:53 +0000898int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000899 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000900
jjako2c381332003-10-21 19:09:53 +0000901 struct iphash_t *iph = (struct iphash_t*) cbp;
902
903 if (cause < 0) {
904 printf("Create PDP Context Request timed out\n");
905 if (iph->pdp->version == 1) {
906 printf("Retrying with version 0\n");
907 iph->pdp->version = 0;
jjako193e8b12003-11-10 12:31:41 +0000908 gtp_create_context_req(gsn, iph->pdp, iph);
jjako2c381332003-10-21 19:09:53 +0000909 return 0;
910 }
911 else {
912 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000913 pdp_freepdp(iph->pdp);
914 iph->pdp = NULL;
jjako2c381332003-10-21 19:09:53 +0000915 return EOF;
916 }
917 }
918
jjakoa7cd2492003-04-11 09:40:12 +0000919 if (cause != 128) {
920 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000921 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000922 pdp_freepdp(iph->pdp);
923 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000924 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000925 }
926
jjakoa7cd2492003-04-11 09:40:12 +0000927 if (pdp_euaton(&pdp->eua, &addr)) {
928 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako0b076a32003-10-25 15:59:31 +0000929 pdp_freepdp(iph->pdp);
930 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000931 state = 0;
932 return EOF; /* Not a valid IP address */
933 }
934
935 printf("Received create PDP context response. IP address: %s\n",
936 inet_ntoa(addr));
937
jjako193e8b12003-11-10 12:31:41 +0000938 if ((options.createif) && (!options.net.s_addr)) {
jjakoa7cd2492003-04-11 09:40:12 +0000939 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +0000940#ifdef HAVE_INET_ATON
jjako1d3db972004-01-16 09:56:56 +0000941 inet_aton("255.255.255.255", &m);
942#else
jjakob73f23a2004-01-16 19:46:41 +0000943 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +0000944#endif
jjakoa7cd2492003-04-11 09:40:12 +0000945 /* printf("Setting up interface and routing\n");*/
946 tun_addaddr(tun, &addr, &addr, &m);
947 if (options.defaultroute) {
948 struct in_addr rm;
949 rm.s_addr = 0;
950 tun_addroute(tun, &rm, &addr, &rm);
951 }
952 if (options.ipup) tun_runscript(tun, options.ipup);
953 }
954
955 ipset((struct iphash_t*) pdp->peer, &addr);
956
957 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000958
959 return 0;
960}
961
jjako52c24142002-12-16 13:33:51 +0000962int delete_pdp_conf(struct pdp_t *pdp, int cause) {
963 printf("Received delete PDP context response. Cause value: %d\n", cause);
964 return 0;
965}
966
jjako08d331d2003-10-13 20:33:30 +0000967int echo_conf(int recovery) {
jjako91aaf222003-10-22 10:09:32 +0000968
969 if (recovery < 0) {
970 printf("Echo Request timed out\n");
971 if (echoversion == 1) {
972 printf("Retrying with version 0\n");
973 echoversion = 0;
974 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000975 return 0;
976 }
977 else {
978 state = 0;
979 return EOF;
980 }
jjako7b8fad42003-07-07 14:37:42 +0000981 }
jjako581c9f02003-10-22 11:28:20 +0000982 else {
jjako08d331d2003-10-13 20:33:30 +0000983 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +0000984 if (!options.contexts) state = 5;
985 }
jjako52c24142002-12-16 13:33:51 +0000986 return 0;
987}
988
jjako2c381332003-10-21 19:09:53 +0000989int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000990 /* if (cause < 0) return 0; Some error occurred. We don't care */
991 switch (type) {
992 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000993 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000994 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000995 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000996 case GTP_DELETE_PDP_REQ:
997 if (cause !=128) return 0; /* Request not accepted. We don't care */
998 return delete_pdp_conf(pdp, cause);
999 default:
1000 return 0;
1001 }
1002}
1003
jjako52c24142002-12-16 13:33:51 +00001004
1005int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
1006 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
1007 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
1008}
1009
1010int main(int argc, char **argv)
1011{
jjako52c24142002-12-16 13:33:51 +00001012 fd_set fds; /* For select() */
1013 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +00001014 struct pdp_t *pdp;
1015 int n;
1016 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +00001017 int stoptime = 0; /* Time to exit */
1018 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001019
1020 struct timezone tz; /* Used for calculating ping times */
1021 struct timeval tv;
1022 int diff;
jjako52c24142002-12-16 13:33:51 +00001023
jjako52c24142002-12-16 13:33:51 +00001024 /* open a connection to the syslog daemon */
1025 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
jjako0141d202004-01-09 15:19:20 +00001026 /* TODO: Only use LOG__PERROR for linux */
1027
1028#ifdef __linux__
jjako52c24142002-12-16 13:33:51 +00001029 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
jjako0141d202004-01-09 15:19:20 +00001030#else
1031 openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
1032#endif
1033
jjako52c24142002-12-16 13:33:51 +00001034
jjakoa7cd2492003-04-11 09:40:12 +00001035 /* Process options given in configuration file and command line */
1036 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +00001037 exit(1);
jjako52c24142002-12-16 13:33:51 +00001038
1039 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +00001040 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +00001041 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1042 "Failed to create gtp");
1043 exit(1);
1044 }
jjako08d331d2003-10-13 20:33:30 +00001045 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
1046 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
1047 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001048
jjakoa7cd2492003-04-11 09:40:12 +00001049 gtp_set_cb_delete_context(gsn, delete_context);
1050 gtp_set_cb_conf(gsn, conf);
1051 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +00001052 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +00001053 else
jjako08d331d2003-10-13 20:33:30 +00001054 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +00001055
1056 if (options.createif) {
1057 printf("Setting up interface\n");
1058 /* Create a tunnel interface */
1059 if (tun_new((struct tun_t**) &tun)) {
1060 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1061 "Failed to create tun");
1062 exit(1);
1063 }
1064 tun_set_cb_ind(tun, cb_tun_ind);
1065 if (tun->fd > maxfd) maxfd = tun->fd;
1066 }
1067
jjako193e8b12003-11-10 12:31:41 +00001068 if ((options.createif) && (options.net.s_addr)) {
1069 /* printf("Setting up interface and routing\n");*/
1070 tun_addaddr(tun, &options.net, &options.net, &options.mask);
1071 if (options.defaultroute) {
1072 struct in_addr rm;
1073 rm.s_addr = 0;
1074 tun_addroute(tun, &rm, &options.net, &rm);
1075 }
1076 if (options.ipup) tun_runscript(tun, options.ipup);
1077 }
1078
1079
jjakoa7cd2492003-04-11 09:40:12 +00001080 /* Initialise hash tables */
1081 memset(&iphash, 0, sizeof(iphash));
1082 memset(&iparr, 0, sizeof(iparr));
1083
jjako52c24142002-12-16 13:33:51 +00001084 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +00001085
1086 /* See if anybody is there */
1087 printf("Sending off echo request\n");
jjako193e8b12003-11-10 12:31:41 +00001088 echoversion = options.gtpversion;
jjako91aaf222003-10-22 10:09:32 +00001089 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +00001090
jjakoa7cd2492003-04-11 09:40:12 +00001091 for(n=0; n<options.contexts; n++) {
jjako193e8b12003-11-10 12:31:41 +00001092 uint64_t myimsi;
jjako52c24142002-12-16 13:33:51 +00001093 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +00001094 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001095
jjako193e8b12003-11-10 12:31:41 +00001096 imsi_add(options.imsi, &myimsi, n);
1097
jjako0b076a32003-10-25 15:59:31 +00001098 /* Allocated here. */
1099 /* If create context failes we have to deallocate ourselves. */
jjako193e8b12003-11-10 12:31:41 +00001100 /* Otherwise it is deallocated by gtplib */
1101 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjakoa7cd2492003-04-11 09:40:12 +00001102
1103 pdp->peer = &iparr[n];
1104 pdp->ipif = tun; /* TODO */
1105 iparr[n].pdp = pdp;
1106
1107 if (options.qos.l > sizeof(pdp->qos_req0)) {
1108 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +00001109 exit(1);
1110 }
1111 else {
jjakoa7cd2492003-04-11 09:40:12 +00001112 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001113 }
jjako08d331d2003-10-13 20:33:30 +00001114
1115 /* TODO */
1116 pdp->qos_req.l = 4;
1117 pdp->qos_req.v[0] = 0x00;
1118 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001119
jjakoa7cd2492003-04-11 09:40:12 +00001120 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +00001121
jjakoa7cd2492003-04-11 09:40:12 +00001122 if (options.apn.l > sizeof(pdp->apn_use.v)) {
1123 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +00001124 exit(1);
1125 }
1126 else {
jjakoa7cd2492003-04-11 09:40:12 +00001127 pdp->apn_use.l = options.apn.l;
1128 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +00001129 }
1130
jjakoa7cd2492003-04-11 09:40:12 +00001131 pdp->gsnlc.l = sizeof(options.listen);
1132 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1133 pdp->gsnlu.l = sizeof(options.listen);
1134 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +00001135
jjakoa7cd2492003-04-11 09:40:12 +00001136 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
1137 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +00001138 exit(1);
1139 }
1140 else {
jjako193e8b12003-11-10 12:31:41 +00001141 msisdn_add(&options.msisdn, &pdp->msisdn, n);
jjakoa7cd2492003-04-11 09:40:12 +00001142 }
1143
1144 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1145
1146 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1147 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1148 exit(1);
1149 }
1150 else {
1151 pdp->pco_req.l = options.pco.l;
1152 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001153 }
1154
jjako193e8b12003-11-10 12:31:41 +00001155 pdp->version = options.gtpversion;
1156
1157 pdp->hisaddr0 = options.remote;
1158 pdp->hisaddr1 = options.remote;
jjako08d331d2003-10-13 20:33:30 +00001159
jjako52c24142002-12-16 13:33:51 +00001160 /* Create context */
1161 /* We send this of once. Retransmissions are handled by gtplib */
jjako193e8b12003-11-10 12:31:41 +00001162 gtp_create_context_req(gsn, pdp, &iparr[n]);
jjako52c24142002-12-16 13:33:51 +00001163 }
1164
1165 state = 1; /* Enter wait_connection state */
1166
1167 printf("Waiting for response from ggsn........\n\n");
1168
jjako5da68452003-01-28 16:08:47 +00001169
jjako52c24142002-12-16 13:33:51 +00001170 /******************************************************************/
1171 /* Main select loop */
1172 /******************************************************************/
1173
jjako7b8fad42003-07-07 14:37:42 +00001174 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001175
jjako7b8fad42003-07-07 14:37:42 +00001176 /* Take down client after timeout after disconnect */
1177 if ((4 == state) && ((stoptime) <= time(NULL))) {
1178 state = 5;
1179 }
1180
1181 /* Take down client after timelimit timeout */
1182 if ((2 == state) && (options.timelimit) &&
1183 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001184 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001185 }
1186
1187 /* Take down client after ping timeout */
1188 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1189 state = 3;
1190 }
1191
1192 /* Set pingtimeout for later disconnection */
1193 if (options.pingcount && ntransmitted >= options.pingcount) {
1194 pingtimeout = time(NULL) + 5; /* Extra seconds */
1195 }
1196
1197 /* Print statistics if no more ping packets are missing */
1198 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1199 ping_finish();
1200 if (!options.createif)
1201 state = 3;
1202 }
1203
jjako2c381332003-10-21 19:09:53 +00001204 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001205 if (3 == state) {
1206 state = 4;
1207 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001208 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001209 /* Delete context */
1210 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001211 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001212 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001213 }
jjakoafb2a972003-01-29 21:04:13 +00001214 }
jjako7b8fad42003-07-07 14:37:42 +00001215
1216 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001217 diff = 0;
1218 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001219 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001220 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001221 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001222 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1223 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001224 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001225 1000000 * (tv.tv_sec - firstping.tv_sec) -
1226 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1227 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001228 if (options.debug) printf("Create_ping %d\n", diff);
1229 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1230 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001231 pingseq++;
1232 }
jjako52c24142002-12-16 13:33:51 +00001233 }
jjako5da68452003-01-28 16:08:47 +00001234
jjako52c24142002-12-16 13:33:51 +00001235 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001236 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001237 FD_SET(gsn->fd0, &fds);
1238 FD_SET(gsn->fd1c, &fds);
1239 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001240
1241 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001242 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001243
1244 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1245 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1246
jjako52c24142002-12-16 13:33:51 +00001247 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1248 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001249 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1250 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001251 break;
1252 case 0:
1253 gtp_retrans(gsn); /* Only retransmit if nothing else */
1254 break;
1255 default:
1256 break;
1257 }
jjakoa7cd2492003-04-11 09:40:12 +00001258
1259 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1260 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1261 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001262 }
1263
jjako08d331d2003-10-13 20:33:30 +00001264 if (FD_ISSET(gsn->fd0, &fds))
1265 gtp_decaps0(gsn);
1266
1267 if (FD_ISSET(gsn->fd1c, &fds))
1268 gtp_decaps1c(gsn);
1269
1270 if (FD_ISSET(gsn->fd1u, &fds))
1271 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001272 }
jjakoa7cd2492003-04-11 09:40:12 +00001273
jjako52c24142002-12-16 13:33:51 +00001274 gtp_free(gsn); /* Clean up the gsn instance */
1275
jjakoa7cd2492003-04-11 09:40:12 +00001276 if (options.createif)
1277 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001278
1279 if (0 == state)
1280 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001281
jjakoa7cd2492003-04-11 09:40:12 +00001282 return 0;
jjako52c24142002-12-16 13:33:51 +00001283}
1284