2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
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.
19 #define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
42 #include <sys/socket.h>
47 #include "../lib/tun.h"
48 #include "../lib/ippool.h"
49 #include "../lib/syserr.h"
50 #include "../gtp/pdp.h"
51 #include "../gtp/gtp.h"
54 #define IPADDRLEN 256 /* Character length of addresses */
55 #define MAXCONTEXTS 1024 /* Max number of allowed contexts */
57 /* HASH tables for IP address allocation */
59 uint8_t inuse
; /* 0=free. 1=used by somebody */
60 struct iphash_t
*ipnext
;
64 struct iphash_t iparr
[MAXCONTEXTS
];
65 struct iphash_t
*iphash
[MAXCONTEXTS
];
67 /* State variable used for ping */
72 /* 4: Wait_disconnect */
76 struct gsn_t
*gsn
= NULL
; /* GSN instance */
77 struct tun_t
*tun
= NULL
; /* TUN instance */
78 int maxfd
= 0; /* For select() */
79 int echoversion
= 1; /* First try this version */
81 /* Struct with local versions of gengetopt options */
83 int debug
; /* Print debug messages */
84 int createif
; /* Create local network interface */
85 struct in_addr netaddr
, destaddr
, net
, mask
; /* Network interface */
86 char *ipup
, *ipdown
; /* Filename of scripts */
87 int defaultroute
; /* Set up default route */
88 struct in_addr pinghost
; /* Remote ping host */
93 struct in_addr listen
;
94 struct in_addr remote
;
96 int contexts
; /* Number of contexts to create */
97 int timelimit
; /* Number of seconds to be connected */
107 struct ul16_t msisdn
;
111 /* Definitions to use for PING. Most of the ping code was derived from */
112 /* the original ping program by Mike Muuss */
114 /* IP header and ICMP echo header */
115 #define CREATEPING_MAX 2048
116 #define CREATEPING_IP 20
117 #define CREATEPING_ICMP 8
120 uint8_t ipver
; /* Type and header length*/
121 uint8_t tos
; /* Type of Service */
122 uint16_t length
; /* Total length */
123 uint16_t fragid
; /* Identifier */
124 uint16_t offset
; /* Flags and fragment offset */
125 uint8_t ttl
; /* Time to live */
126 uint8_t protocol
; /* Protocol */
127 uint16_t ipcheck
; /* Header checksum */
128 uint32_t src
; /* Source address */
129 uint32_t dst
; /* Destination */
130 uint8_t type
; /* Type and header length*/
131 uint8_t code
; /* Code */
132 uint16_t checksum
; /* Header checksum */
133 uint16_t ident
; /* Identifier */
134 uint16_t seq
; /* Sequence number */
135 uint8_t data
[CREATEPING_MAX
]; /* Data */
136 } __attribute__((packed
));
138 /* Statistical values for ping */
141 int ntransmitted
= 0;
142 int tmin
= 999999999;
145 int pingseq
= 0; /* Ping sequence counter */
146 struct timeval firstping
;
148 int ipset(struct iphash_t
*ipaddr
, struct in_addr
*addr
) {
149 int hash
= ippool_hash4(addr
) % MAXCONTEXTS
;
151 struct iphash_t
*prev
= NULL
;
152 ipaddr
->ipnext
= NULL
;
153 ipaddr
->addr
.s_addr
= addr
->s_addr
;
154 for (h
= iphash
[hash
]; h
; h
= h
->ipnext
)
157 iphash
[hash
] = ipaddr
;
159 prev
->ipnext
= ipaddr
;
163 int ipdel(struct iphash_t
*ipaddr
) {
164 int hash
= ippool_hash4(&ipaddr
->addr
) % MAXCONTEXTS
;
166 struct iphash_t
*prev
= NULL
;
167 for (h
= iphash
[hash
]; h
; h
= h
->ipnext
) {
170 iphash
[hash
] = h
->ipnext
;
172 prev
->ipnext
= h
->ipnext
;
177 return EOF
; /* End of linked list and not found */
180 int ipget(struct iphash_t
**ipaddr
, struct in_addr
*addr
) {
181 int hash
= ippool_hash4(addr
) % MAXCONTEXTS
;
183 for (h
= iphash
[hash
]; h
; h
= h
->ipnext
) {
184 if ((h
->addr
.s_addr
== addr
->s_addr
)) {
189 return EOF
; /* End of linked list and not found */
193 /* Used to write process ID to file. Assume someone else will delete */
194 void log_pid(char *pidfile
) {
198 oldmask
= umask(022);
199 file
= fopen(pidfile
, "w");
203 fprintf(file
, "%d\n", (int) getpid());
208 int process_options(int argc
, char **argv
) {
209 /* gengeopt declarations */
210 struct gengetopt_args_info args_info
;
212 struct hostent
*host
;
215 if (cmdline_parser (argc
, argv
, &args_info
) != 0)
217 if (args_info
.debug_flag
) {
218 if (args_info
.remote_arg
) printf("remote: %s\n", args_info
.remote_arg
);
219 if (args_info
.listen_arg
) printf("listen: %s\n", args_info
.listen_arg
);
220 if (args_info
.conf_arg
) printf("conf: %s\n", args_info
.conf_arg
);
221 printf("debug: %d\n", args_info
.debug_flag
);
222 if (args_info
.imsi_arg
) printf("imsi: %s\n", args_info
.imsi_arg
);
223 printf("qos: %#08x\n", args_info
.qos_arg
);
224 printf("charging: %#04x\n", args_info
.charging_arg
);
225 if (args_info
.apn_arg
) printf("apn: %s\n", args_info
.apn_arg
);
226 if (args_info
.msisdn_arg
) printf("msisdn: %s\n", args_info
.msisdn_arg
);
227 if (args_info
.uid_arg
) printf("uid: %s\n", args_info
.uid_arg
);
228 if (args_info
.pwd_arg
) printf("pwd: %s\n", args_info
.pwd_arg
);
229 if (args_info
.pidfile_arg
) printf("pidfile: %s\n", args_info
.pidfile_arg
);
230 if (args_info
.statedir_arg
) printf("statedir: %s\n", args_info
.statedir_arg
);
231 if (args_info
.dns_arg
) printf("dns: %s\n", args_info
.dns_arg
);
232 printf("contexts: %d\n", args_info
.contexts_arg
);
233 printf("timelimit: %d\n", args_info
.timelimit_arg
);
234 printf("createif: %d\n", args_info
.createif_flag
);
235 if (args_info
.ipup_arg
) printf("ipup: %s\n", args_info
.ipup_arg
);
236 if (args_info
.ipdown_arg
) printf("ipdown: %s\n", args_info
.ipdown_arg
);
237 printf("defaultroute: %d\n", args_info
.defaultroute_flag
);
238 if (args_info
.pinghost_arg
) printf("pinghost: %s\n", args_info
.pinghost_arg
);
239 printf("pingrate: %d\n", args_info
.pingrate_arg
);
240 printf("pingsize: %d\n", args_info
.pingsize_arg
);
241 printf("pingcount: %d\n", args_info
.pingcount_arg
);
242 printf("pingquiet: %d\n", args_info
.pingquiet_flag
);
245 /* Try out our new parser */
247 if (args_info
.conf_arg
) {
248 if (cmdline_parser_configfile (args_info
.conf_arg
, &args_info
, 0, 0, 0) != 0)
250 if (args_info
.debug_flag
) {
251 printf("cmdline_parser_configfile\n");
252 if (args_info
.remote_arg
) printf("remote: %s\n", args_info
.remote_arg
);
253 if (args_info
.listen_arg
) printf("listen: %s\n", args_info
.listen_arg
);
254 if (args_info
.conf_arg
) printf("conf: %s\n", args_info
.conf_arg
);
255 printf("debug: %d\n", args_info
.debug_flag
);
256 if (args_info
.imsi_arg
) printf("imsi: %s\n", args_info
.imsi_arg
);
257 printf("qos: %#08x\n", args_info
.qos_arg
);
258 printf("charging: %#04x\n", args_info
.charging_arg
);
259 if (args_info
.apn_arg
) printf("apn: %s\n", args_info
.apn_arg
);
260 if (args_info
.msisdn_arg
) printf("msisdn: %s\n", args_info
.msisdn_arg
);
261 if (args_info
.uid_arg
) printf("uid: %s\n", args_info
.uid_arg
);
262 if (args_info
.pwd_arg
) printf("pwd: %s\n", args_info
.pwd_arg
);
263 if (args_info
.pidfile_arg
) printf("pidfile: %s\n", args_info
.pidfile_arg
);
264 if (args_info
.statedir_arg
) printf("statedir: %s\n", args_info
.statedir_arg
);
265 if (args_info
.dns_arg
) printf("dns: %s\n", args_info
.dns_arg
);
266 printf("contexts: %d\n", args_info
.contexts_arg
);
267 printf("timelimit: %d\n", args_info
.timelimit_arg
);
268 printf("createif: %d\n", args_info
.createif_flag
);
269 if (args_info
.ipup_arg
) printf("ipup: %s\n", args_info
.ipup_arg
);
270 if (args_info
.ipdown_arg
) printf("ipdown: %s\n", args_info
.ipdown_arg
);
271 printf("defaultroute: %d\n", args_info
.defaultroute_flag
);
272 if (args_info
.pinghost_arg
) printf("pinghost: %s\n", args_info
.pinghost_arg
);
273 printf("pingrate: %d\n", args_info
.pingrate_arg
);
274 printf("pingsize: %d\n", args_info
.pingsize_arg
);
275 printf("pingcount: %d\n", args_info
.pingcount_arg
);
276 printf("pingquiet: %d\n", args_info
.pingquiet_flag
);
280 /* Handle each option */
283 /* If fg flag not given run as a daemon */
284 /* Do not allow sgsnemu to run as deamon
285 if (!args_info.fg_flag)
288 freopen("/dev/null", "w", stdout);
289 freopen("/dev/null", "w", stderr);
290 freopen("/dev/null", "r", stdin);
292 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
296 options
.debug
= args_info
.debug_flag
;
299 /* This has to be done after we have our final pid */
300 if (args_info
.pidfile_arg
) {
301 log_pid(args_info
.pidfile_arg
);
305 /* If no dns option is given use system default */
306 /* Do hostname lookup to translate hostname to IP address */
308 if (args_info
.dns_arg
) {
309 if (!(host
= gethostbyname(args_info
.dns_arg
))) {
310 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
311 "Invalid DNS address: %s!", args_info
.dns_arg
);
315 memcpy(&options
.dns
.s_addr
, host
->h_addr
, host
->h_length
);
317 _res
.nsaddr_list
[0].sin_addr
= options
.dns
;
318 printf("Using DNS server: %s (%s)\n",
319 args_info
.dns_arg
, inet_ntoa(options
.dns
));
323 options
.dns
.s_addr
= 0;
324 printf("Using default DNS server\n");
328 /* If no listen option is specified listen to any local port */
329 /* Do hostname lookup to translate hostname to IP address */
330 if (args_info
.listen_arg
) {
331 if (!(host
= gethostbyname(args_info
.listen_arg
))) {
332 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
333 "Invalid listening address: %s!", args_info
.listen_arg
);
337 memcpy(&options
.listen
.s_addr
, host
->h_addr
, host
->h_length
);
338 printf("Local IP address is: %s (%s)\n",
339 args_info
.listen_arg
, inet_ntoa(options
.listen
));
343 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
344 "Listening address must be specified: %s!", args_info
.listen_arg
);
350 /* If no remote option is specified terminate */
351 /* Do hostname lookup to translate hostname to IP address */
352 if (args_info
.remote_arg
) {
353 if (!(host
= gethostbyname(args_info
.remote_arg
))) {
354 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
355 "Invalid remote address: %s!", args_info
.remote_arg
);
359 memcpy(&options
.remote
.s_addr
, host
->h_addr
, host
->h_length
);
360 printf("Remote IP address is: %s (%s)\n",
361 args_info
.remote_arg
, inet_ntoa(options
.remote
));
365 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
366 "No remote address given!");
372 if (strlen(args_info
.imsi_arg
)!=15) {
373 printf("Invalid IMSI\n");
377 options
.imsi
= 0xf000000000000000ull
;
378 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 0]-48));
379 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 1]-48)) << 4;
380 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 2]-48)) << 8;
381 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 3]-48)) << 12;
382 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 4]-48)) << 16;
383 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 5]-48)) << 20;
384 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 6]-48)) << 24;
385 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 7]-48)) << 28;
386 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 8]-48)) << 32;
387 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[ 9]-48)) << 36;
388 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[10]-48)) << 40;
389 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[11]-48)) << 44;
390 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[12]-48)) << 48;
391 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[13]-48)) << 52;
392 options
.imsi
|= ((uint64_t) (args_info
.imsi_arg
[14]-48)) << 56;
394 printf("IMSI is: %s (%#08llx)\n",
395 args_info
.imsi_arg
, options
.imsi
);
399 if ((args_info
.nsapi_arg
> 15) ||
400 (args_info
.nsapi_arg
< 0)) {
401 printf("Invalid NSAPI\n");
404 options
.nsapi
= args_info
.nsapi_arg
;
405 printf("Using NSAPI: %d\n", args_info
.nsapi_arg
);
410 options
.qos
.v
[2] = (args_info
.qos_arg
) & 0xff;
411 options
.qos
.v
[1] = ((args_info
.qos_arg
) >> 8) & 0xff;
412 options
.qos
.v
[0] = ((args_info
.qos_arg
) >> 16) & 0xff;
415 options
.cch
= args_info
.charging_arg
;
418 if (args_info
.contexts_arg
> MAXCONTEXTS
) {
419 printf("Contexts has to be less than %d\n", MAXCONTEXTS
);
422 options
.contexts
= args_info
.contexts_arg
;
425 options
.timelimit
= args_info
.timelimit_arg
;
428 if ((args_info
.gtpversion_arg
> 1) ||
429 (args_info
.gtpversion_arg
< 0)) {
430 printf("Invalid GTP version\n");
433 options
.gtpversion
= args_info
.gtpversion_arg
;
434 printf("Using GTP version: %d\n", args_info
.gtpversion_arg
);
438 if (strlen(args_info
.apn_arg
) > (sizeof(options
.apn
.v
)-1)) {
439 printf("Invalid APN\n");
442 options
.apn
.l
= strlen(args_info
.apn_arg
);
443 strncpy((char *)options
.apn
.v
, args_info
.apn_arg
, sizeof(options
.apn
.v
));
444 options
.apn
.v
[sizeof(options
.apn
.v
)-1] = 0;
445 printf("Using APN: %s\n", args_info
.apn_arg
);
449 options
.selmode
= args_info
.selmode_arg
;
450 printf("Using selection mode: %d\n", args_info
.selmode_arg
);
454 if (strlen(args_info
.msisdn_arg
)>(sizeof(options
.msisdn
.v
)-1)) {
455 printf("Invalid MSISDN\n");
458 options
.msisdn
.l
= 1;
459 options
.msisdn
.v
[0] = 0x91; /* International format */
460 for(n
=0; n
<strlen(args_info
.msisdn_arg
); n
++) {
462 options
.msisdn
.v
[((int)n
/2)+1] = args_info
.msisdn_arg
[n
] - 48 + 0xf0;
463 options
.msisdn
.l
+= 1;
466 options
.msisdn
.v
[((int)n
/2)+1] =
467 (options
.msisdn
.v
[((int)n
/2)+1] & 0x0f) +
468 (args_info
.msisdn_arg
[n
] - 48) * 16;
471 printf("Using MSISDN: %s\n", args_info
.msisdn_arg
);
474 /* Might need to also insert stuff like DNS etc. */
475 if ((strlen(args_info
.uid_arg
) + strlen(args_info
.pwd_arg
) + 10)>
476 (sizeof(options
.pco
.v
)-1)) {
477 printf("invalid UID and PWD\n");
480 options
.pco
.l
= strlen(args_info
.uid_arg
) + strlen(args_info
.pwd_arg
) + 10;
481 options
.pco
.v
[0] = 0x80; /* PPP */
482 options
.pco
.v
[1] = 0xc0; /* PAP */
483 options
.pco
.v
[2] = 0x23;
484 options
.pco
.v
[3] = strlen(args_info
.uid_arg
) + strlen(args_info
.pwd_arg
) + 6;
485 options
.pco
.v
[4] = 0x01; /* Authenticate request */
486 options
.pco
.v
[5] = 0x01;
487 options
.pco
.v
[6] = 0x00; /* MSB of length */
488 options
.pco
.v
[7] = strlen(args_info
.uid_arg
) + strlen(args_info
.pwd_arg
) + 6;
489 options
.pco
.v
[8] = strlen(args_info
.uid_arg
);
490 memcpy(&options
.pco
.v
[9], args_info
.uid_arg
, strlen(args_info
.uid_arg
));
491 options
.pco
.v
[9+strlen(args_info
.uid_arg
)] = strlen(args_info
.pwd_arg
);
492 memcpy(&options
.pco
.v
[10+strlen(args_info
.uid_arg
)],
493 args_info
.pwd_arg
, strlen(args_info
.pwd_arg
));
496 options
.createif
= args_info
.createif_flag
;
499 /* Store net as in_addr net and mask */
500 if (args_info
.net_arg
) {
501 if(ippool_aton(&options
.net
, &options
.mask
, args_info
.net_arg
, 0)) {
502 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
503 "Invalid network address: %s!", args_info
.net_arg
);
507 #if defined (__sun__)
508 options
.netaddr
.s_addr
= htonl(ntohl(options
.net
.s_addr
) + 1);
509 options
.destaddr
.s_addr
= htonl(ntohl(options
.net
.s_addr
) + 1);
511 options
.netaddr
.s_addr
= options
.net
.s_addr
;
512 options
.destaddr
.s_addr
= options
.net
.s_addr
;
517 options
.net
.s_addr
= 0;
518 options
.mask
.s_addr
= 0;
519 options
.netaddr
.s_addr
= 0;
520 options
.destaddr
.s_addr
= 0;
524 options
.ipup
= args_info
.ipup_arg
;
527 options
.ipdown
= args_info
.ipdown_arg
;
530 options
.statedir
= args_info
.statedir_arg
;
533 options
.defaultroute
= args_info
.defaultroute_flag
;
537 /* Store ping host as in_addr */
538 if (args_info
.pinghost_arg
) {
539 if (!(host
= gethostbyname(args_info
.pinghost_arg
))) {
540 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
541 "Invalid ping host: %s!", args_info
.pinghost_arg
);
545 memcpy(&options
.pinghost
.s_addr
, host
->h_addr
, host
->h_length
);
546 printf("Using ping host: %s (%s)\n",
547 args_info
.pinghost_arg
, inet_ntoa(options
.pinghost
));
551 /* Other ping parameters */
552 options
.pingrate
= args_info
.pingrate_arg
;
553 options
.pingsize
= args_info
.pingsize_arg
;
554 options
.pingcount
= args_info
.pingcount_arg
;
555 options
.pingquiet
= args_info
.pingquiet_flag
;
562 int encaps_printf(struct pdp_t
*pdp
, void *pack
, unsigned len
) {
564 printf("The packet looks like this:\n");
565 for( i
=0; i
<len
; i
++) {
566 printf("%02x ", (unsigned char)*(char *)(pack
+i
));
567 if (!((i
+1)%16)) printf("\n");
573 char * print_ipprot(int t
) {
575 case 1: return "ICMP";
576 case 6: return "TCP";
577 case 17: return "UDP";
578 default: return "Unknown";
583 char * print_icmptype(int t
) {
584 static char *ttab
[] = {
603 if( t
< 0 || t
> 16 )
604 return("OUT-OF-RANGE");
608 int msisdn_add(struct ul16_t
*src
, struct ul16_t
*dst
, int add
) {
611 uint8_t msa
[sizeof(i64
) * 3]; /* Allocate 3 digits per octet (0..255) */
612 unsigned int msalen
= 0;
614 /* Convert to uint64_t from ul16_t format (most significant digit first) */
615 /* ul16_t format always starts with 0x91 to indicate international format */
616 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
617 for (n
=0; n
< src
->l
; n
++) {
618 if ((src
->v
[n
] & 0x0f) != 0x0f) {
620 i64
+= src
->v
[n
] & 0x0f;
622 if ((src
->v
[n
] & 0xf0) != 0xf0) {
624 i64
+= (src
->v
[n
] & 0xf0) >> 4;
630 /* Generate array with least significant digit in first octet */
632 msa
[msalen
++] = i64
% 10;
636 /* Convert back to ul16_t format */
637 for(n
=0; n
<msalen
; n
++) {
639 dst
->v
[((int)n
/2)] = msa
[msalen
-n
-1] + 0xf0;
643 dst
->v
[((int)n
/2)] = (dst
->v
[((int)n
/2)] & 0x0f) +
644 msa
[msalen
-n
-1] * 16;
652 int imsi_add(uint64_t src
, uint64_t *dst
, int add
) {
653 /* TODO: big endian / small endian ??? */
656 /* Convert from uint64_t bcd to uint64_t integer format */
657 /* The resulting integer format is multiplied by 10 */
659 if ((src
& 0x0f) != 0x0f) {
663 if ((src
& 0xf0) != 0xf0) {
665 i64
+= (src
& 0xf0) >> 4;
679 *dst
|= 0xf000000000000000ull
;
685 /* Calculate time left until we have to send off next ping packet */
686 int ping_timeout(struct timeval
*tp
) {
690 if ((options
.pinghost
.s_addr
) && (2 == state
) &&
691 ((pingseq
< options
.pingcount
) || (options
.pingcount
== 0))) {
692 gettimeofday(&tv
, &tz
);
693 diff
= 1000000 / options
.pingrate
* pingseq
-
694 1000000 * (tv
.tv_sec
- firstping
.tv_sec
) -
695 (tv
.tv_usec
- firstping
.tv_usec
); /* Microseconds safe up to 500 sec */
700 /* For some reason we get packet loss if set to zero */
701 tp
->tv_usec
= 100000 / options
.pingrate
; /* 10 times pingrate */
708 /* Print out statistics when at the end of ping sequence */
714 gettimeofday(&tv
, &tz
);
715 elapsed
= 1000000 * (tv
.tv_sec
- firstping
.tv_sec
) +
716 (tv
.tv_usec
- firstping
.tv_usec
); /* Microseconds */
718 printf("\n----%s PING Statistics----\n", inet_ntoa(options
.pinghost
));
719 printf("%d packets transmitted in %.3f seconds, ", ntransmitted
,
720 elapsed
/ 1000000.0);
721 printf("%d packets received, ", nreceived
);
723 if( nreceived
> ntransmitted
)
724 printf("-- somebody's printing up packets!");
726 printf("%d%% packet loss",
727 (int) (((ntransmitted
-nreceived
)*100) /
731 if (options
.debug
) printf("%d packets received in total\n", ntreceived
);
732 if (nreceived
&& tsum
)
733 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
735 tsum
/1000.0/nreceived
,
737 printf("%d packets transmitted \n", ntreceived
);
743 /* Handle a received ping packet. Print out line and update statistics. */
744 int encaps_ping(struct pdp_t
*pdp
, void *pack
, unsigned len
) {
748 struct ip_ping
*pingpack
= pack
;
752 src
.s_addr
= pingpack
->src
;
754 gettimeofday(&tv
, &tz
);
755 if (options
.debug
) printf("%d.%6d ", (int) tv
.tv_sec
, (int) tv
.tv_usec
);
757 if (len
< CREATEPING_IP
+ CREATEPING_ICMP
) {
758 printf("packet too short (%d bytes) from %s\n", len
,
764 if (pingpack
->protocol
!= 1) {
765 if (!options
.pingquiet
) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
766 len
, inet_ntoa(src
), pingpack
->protocol
,
767 print_ipprot(pingpack
->protocol
));
771 if (pingpack
->type
!= 0) {
772 if (!options
.pingquiet
) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
773 len
, inet_ntoa(src
), pingpack
->type
,
774 print_icmptype(pingpack
->type
), pingpack
->code
);
779 if (!options
.pingquiet
) printf("%d bytes from %s: icmp_seq=%d", len
,
780 inet_ntoa(src
), ntohs(pingpack
->seq
));
782 if (len
>= sizeof(struct timeval
) + CREATEPING_IP
+ CREATEPING_ICMP
) {
783 gettimeofday(&tv
, &tz
);
784 tp
= (struct timeval
*) pingpack
->data
;
785 if( (tv
.tv_usec
-= tp
->tv_usec
) < 0 ) {
787 tv
.tv_usec
+= 1000000;
789 tv
.tv_sec
-= tp
->tv_sec
;
791 triptime
= tv
.tv_sec
*1000000+(tv
.tv_usec
);
793 if( triptime
< tmin
)
795 if( triptime
> tmax
)
798 if (!options
.pingquiet
) printf(" time=%.3f ms\n", triptime
/1000.0);
802 if (!options
.pingquiet
) printf("\n");
806 /* Create a new ping packet and send it off to peer. */
807 int create_ping(void *gsn
, struct pdp_t
*pdp
,
808 struct in_addr
*dst
, int seq
, unsigned int datasize
) {
811 uint16_t *p
= (uint16_t *) &pack
;
812 uint8_t *p8
= (uint8_t *) &pack
;
819 struct timeval
*tp
= (struct timeval
*) &p8
[CREATEPING_IP
+ CREATEPING_ICMP
];
821 if (datasize
> CREATEPING_MAX
) {
822 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
823 "Ping size to large: %d!", datasize
);
827 memcpy(&src
, &(pdp
->eua
.v
[2]), 4); /* Copy a 4 byte address */
831 pack
.length
= htons(CREATEPING_IP
+ CREATEPING_ICMP
+ datasize
);
832 pack
.fragid
= 0x0000;
833 pack
.offset
= 0x0040;
835 pack
.protocol
= 0x01;
836 pack
.ipcheck
= 0x0000;
837 pack
.src
= src
.s_addr
;
838 pack
.dst
= dst
->s_addr
;
841 pack
.checksum
= 0x0000;
843 pack
.seq
= htons(seq
);
845 /* Generate ICMP payload */
846 p8
= (uint8_t *) &pack
+ CREATEPING_IP
+ CREATEPING_ICMP
;
847 for (n
=0; n
<(datasize
); n
++) p8
[n
] = n
;
849 if (datasize
>= sizeof(struct timeval
))
850 gettimeofday(tp
, &tz
);
852 /* Calculate IP header checksum */
853 p
= (uint16_t *) &pack
;
854 count
= CREATEPING_IP
;
861 sum
= (sum
& 0xffff) + (sum
>> 16);
865 /* Calculate ICMP checksum */
866 count
= CREATEPING_ICMP
+ datasize
; /* Length of ICMP message */
868 p
= (uint16_t *) &pack
;
869 p
+= CREATEPING_IP
/ 2;
875 sum
+= * (unsigned char *) p
;
877 sum
= (sum
& 0xffff) + (sum
>> 16);
878 pack
.checksum
= ~sum
;
881 return gtp_data_req(gsn
, pdp
, &pack
, 28 + datasize
);
885 int delete_context(struct pdp_t
*pdp
) {
887 if (tun
&& options
.ipdown
) tun_runscript(tun
, options
.ipdown
);
889 ipdel((struct iphash_t
*) pdp
->peer
);
890 memset(pdp
->peer
, 0, sizeof(struct iphash_t
)); /* To be sure */
892 if (1 == options
.contexts
)
893 state
= 5; /* Disconnected */
899 /* Callback for receiving messages from tun */
900 int cb_tun_ind(struct tun_t
*tun
, void *pack
, unsigned len
) {
901 struct iphash_t
*ipm
;
903 struct tun_packet_t
*iph
= (struct tun_packet_t
*) pack
;
905 src
.s_addr
= iph
->src
;
907 if (ipget(&ipm
, &src
)) {
908 printf("Received packet without a valid source address!!!\n");
912 if (ipm
->pdp
) /* Check if a peer protocol is defined */
913 gtp_data_req(gsn
, ipm
->pdp
, pack
, len
);
917 int create_pdp_conf(struct pdp_t
*pdp
, void *cbp
, int cause
) {
920 struct iphash_t
*iph
= (struct iphash_t
*) cbp
;
923 printf("Create PDP Context Request timed out\n");
924 if (iph
->pdp
->version
== 1) {
925 printf("Retrying with version 0\n");
926 iph
->pdp
->version
= 0;
927 gtp_create_context_req(gsn
, iph
->pdp
, iph
);
932 pdp_freepdp(iph
->pdp
);
939 printf("Received create PDP context response. Cause value: %d\n", cause
);
941 pdp_freepdp(iph
->pdp
);
943 return EOF
; /* Not what we expected */
946 if (pdp_euaton(&pdp
->eua
, &addr
)) {
947 printf("Received create PDP context response. Cause value: %d\n", cause
);
948 pdp_freepdp(iph
->pdp
);
951 return EOF
; /* Not a valid IP address */
954 printf("Received create PDP context response. IP address: %s\n",
957 if ((options
.createif
) && (!options
.net
.s_addr
)) {
959 #ifdef HAVE_INET_ATON
960 inet_aton("255.255.255.255", &m
);
964 /* printf("Setting up interface and routing\n");*/
965 tun_addaddr(tun
, &addr
, &addr
, &m
);
966 if (options
.defaultroute
) {
969 tun_addroute(tun
, &rm
, &addr
, &rm
);
971 if (options
.ipup
) tun_runscript(tun
, options
.ipup
);
974 ipset((struct iphash_t
*) pdp
->peer
, &addr
);
976 state
= 2; /* Connected */
981 int delete_pdp_conf(struct pdp_t
*pdp
, int cause
) {
982 printf("Received delete PDP context response. Cause value: %d\n", cause
);
986 int echo_conf(int recovery
) {
989 printf("Echo Request timed out\n");
990 if (echoversion
== 1) {
991 printf("Retrying with version 0\n");
993 gtp_echo_req(gsn
, echoversion
, NULL
, &options
.remote
);
1002 printf("Received echo response\n");
1003 if (!options
.contexts
) state
= 5;
1008 int conf(int type
, int cause
, struct pdp_t
* pdp
, void *cbp
) {
1009 /* if (cause < 0) return 0; Some error occurred. We don't care */
1012 return echo_conf(cause
);
1013 case GTP_CREATE_PDP_REQ
:
1014 return create_pdp_conf(pdp
, cbp
, cause
);
1015 case GTP_DELETE_PDP_REQ
:
1016 if (cause
!=128) return 0; /* Request not accepted. We don't care */
1017 return delete_pdp_conf(pdp
, cause
);
1024 int encaps_tun(struct pdp_t
*pdp
, void *pack
, unsigned len
) {
1025 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
1026 return tun_encaps((struct tun_t
*) pdp
->ipif
, pack
, len
);
1029 int main(int argc
, char **argv
)
1031 fd_set fds
; /* For select() */
1032 struct timeval idleTime
; /* How long to select() */
1035 int starttime
= time(NULL
); /* Time program was started */
1036 int stoptime
= 0; /* Time to exit */
1037 int pingtimeout
= 0; /* Time to print ping statistics */
1039 struct timezone tz
; /* Used for calculating ping times */
1043 /* open a connection to the syslog daemon */
1044 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
1045 /* TODO: Only use LOG__PERROR for linux */
1048 openlog(PACKAGE
, (LOG_PID
| LOG_PERROR
), LOG_DAEMON
);
1050 openlog(PACKAGE
, (LOG_PID
), LOG_DAEMON
);
1054 /* Process options given in configuration file and command line */
1055 if (process_options(argc
, argv
))
1058 printf("\nInitialising GTP library\n");
1059 if (gtp_new(&gsn
, options
.statedir
, &options
.listen
, GTP_MODE_SGSN
)) {
1060 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
1061 "Failed to create gtp");
1064 if (gsn
->fd0
> maxfd
) maxfd
= gsn
->fd0
;
1065 if (gsn
->fd1c
> maxfd
) maxfd
= gsn
->fd1c
;
1066 if (gsn
->fd1u
> maxfd
) maxfd
= gsn
->fd1u
;
1068 gtp_set_cb_delete_context(gsn
, delete_context
);
1069 gtp_set_cb_conf(gsn
, conf
);
1070 if (options
.createif
)
1071 gtp_set_cb_data_ind(gsn
, encaps_tun
);
1073 gtp_set_cb_data_ind(gsn
, encaps_ping
);
1075 if (options
.createif
) {
1076 printf("Setting up interface\n");
1077 /* Create a tunnel interface */
1078 if (tun_new((struct tun_t
**) &tun
)) {
1079 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
1080 "Failed to create tun");
1083 tun_set_cb_ind(tun
, cb_tun_ind
);
1084 if (tun
->fd
> maxfd
) maxfd
= tun
->fd
;
1087 if ((options
.createif
) && (options
.net
.s_addr
)) {
1088 /* printf("Setting up interface and routing\n");*/
1089 tun_addaddr(tun
, &options
.netaddr
, &options
.destaddr
, &options
.mask
);
1090 if (options
.defaultroute
) {
1093 tun_addroute(tun
, &rm
, &options
.destaddr
, &rm
);
1095 if (options
.ipup
) tun_runscript(tun
, options
.ipup
);
1099 /* Initialise hash tables */
1100 memset(&iphash
, 0, sizeof(iphash
));
1101 memset(&iparr
, 0, sizeof(iparr
));
1103 printf("Done initialising GTP library\n\n");
1105 /* See if anybody is there */
1106 printf("Sending off echo request\n");
1107 echoversion
= options
.gtpversion
;
1108 gtp_echo_req(gsn
, echoversion
, NULL
, &options
.remote
); /* Is remote alive? */
1110 for(n
=0; n
<options
.contexts
; n
++) {
1112 printf("Setting up PDP context #%d\n", n
);
1113 iparr
[n
].inuse
= 1; /* TODO */
1115 imsi_add(options
.imsi
, &myimsi
, n
);
1117 /* Allocated here. */
1118 /* If create context failes we have to deallocate ourselves. */
1119 /* Otherwise it is deallocated by gtplib */
1120 pdp_newpdp(&pdp
, myimsi
, options
.nsapi
, NULL
);
1122 pdp
->peer
= &iparr
[n
];
1123 pdp
->ipif
= tun
; /* TODO */
1126 if (options
.qos
.l
> sizeof(pdp
->qos_req0
)) {
1127 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "QoS length too big");
1131 memcpy(pdp
->qos_req0
, options
.qos
.v
, options
.qos
.l
);
1136 pdp
->qos_req
.v
[0] = 0x00;
1137 memcpy(pdp
->qos_req
.v
+1, options
.qos
.v
, options
.qos
.l
);
1139 pdp
->selmode
= options
.selmode
;
1141 if (options
.apn
.l
> sizeof(pdp
->apn_use
.v
)) {
1142 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "APN length too big");
1146 pdp
->apn_use
.l
= options
.apn
.l
;
1147 memcpy(pdp
->apn_use
.v
, options
.apn
.v
, options
.apn
.l
);
1150 pdp
->gsnlc
.l
= sizeof(options
.listen
);
1151 memcpy(pdp
->gsnlc
.v
, &options
.listen
, sizeof(options
.listen
));
1152 pdp
->gsnlu
.l
= sizeof(options
.listen
);
1153 memcpy(pdp
->gsnlu
.v
, &options
.listen
, sizeof(options
.listen
));
1155 if (options
.msisdn
.l
> sizeof(pdp
->msisdn
.v
)) {
1156 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "MSISDN length too big");
1160 msisdn_add(&options
.msisdn
, &pdp
->msisdn
, n
);
1163 ipv42eua(&pdp
->eua
, NULL
); /* Request dynamic IP address */
1165 if (options
.pco
.l
> sizeof(pdp
->pco_req
.v
)) {
1166 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "PCO length too big");
1170 pdp
->pco_req
.l
= options
.pco
.l
;
1171 memcpy(pdp
->pco_req
.v
, options
.pco
.v
, options
.pco
.l
);
1174 pdp
->version
= options
.gtpversion
;
1176 pdp
->hisaddr0
= options
.remote
;
1177 pdp
->hisaddr1
= options
.remote
;
1179 pdp
->cch_pdp
= options
.cch
; /* 2048 = Normal, 1024 = Prepaid,
1180 512 = Flat rate, 256 = Hot billing */
1182 /* Create context */
1183 /* We send this of once. Retransmissions are handled by gtplib */
1184 gtp_create_context_req(gsn
, pdp
, &iparr
[n
]);
1187 state
= 1; /* Enter wait_connection state */
1189 printf("Waiting for response from ggsn........\n\n");
1192 /******************************************************************/
1193 /* Main select loop */
1194 /******************************************************************/
1196 while ((0 != state
) && (5 != state
)) {
1198 /* Take down client after timeout after disconnect */
1199 if ((4 == state
) && ((stoptime
) <= time(NULL
))) {
1203 /* Take down client after timelimit timeout */
1204 if ((2 == state
) && (options
.timelimit
) &&
1205 ((starttime
+ options
.timelimit
) <= time(NULL
))) {
1209 /* Take down client after ping timeout */
1210 if ((2 == state
) && (pingtimeout
) && (pingtimeout
<= time(NULL
))) {
1214 /* Set pingtimeout for later disconnection */
1215 if (options
.pingcount
&& ntransmitted
>= options
.pingcount
) {
1216 pingtimeout
= time(NULL
) + 5; /* Extra seconds */
1219 /* Print statistics if no more ping packets are missing */
1220 if (ntransmitted
&& options
.pingcount
&& nreceived
>= options
.pingcount
) {
1222 if (!options
.createif
)
1226 /* Send off disconnect */
1229 stoptime
= time(NULL
) + 5; /* Extra seconds to allow disconnect */
1230 for(n
=0; n
<options
.contexts
; n
++) {
1231 /* Delete context */
1232 printf("Disconnecting PDP context #%d\n", n
);
1233 gtp_delete_context_req(gsn
, iparr
[n
].pdp
, NULL
, 1);
1234 if ((options
.pinghost
.s_addr
!=0) && ntransmitted
) ping_finish();
1238 /* Send of ping packets */
1240 while (( diff
<=0 ) &&
1241 /* Send off an ICMP ping packet */
1242 /*if (*/(options
.pinghost
.s_addr
) && (2 == state
) &&
1243 ((pingseq
< options
.pingcount
) || (options
.pingcount
== 0))) {
1244 if (!pingseq
) gettimeofday(&firstping
, &tz
); /* Set time of first ping */
1245 gettimeofday(&tv
, &tz
);
1246 diff
= 1000000 / options
.pingrate
* pingseq
-
1247 1000000 * (tv
.tv_sec
- firstping
.tv_sec
) -
1248 (tv
.tv_usec
- firstping
.tv_usec
); /* Microseconds safe up to 500 sec */
1250 if (options
.debug
) printf("Create_ping %d\n", diff
);
1251 create_ping(gsn
, iparr
[pingseq
% options
.contexts
].pdp
,
1252 &options
.pinghost
, pingseq
, options
.pingsize
);
1258 if (tun
) FD_SET(tun
->fd
, &fds
);
1259 FD_SET(gsn
->fd0
, &fds
);
1260 FD_SET(gsn
->fd1c
, &fds
);
1261 FD_SET(gsn
->fd1u
, &fds
);
1263 gtp_retranstimeout(gsn
, &idleTime
);
1264 ping_timeout(&idleTime
);
1266 if (options
.debug
) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1267 (int) idleTime
.tv_sec
, (int) idleTime
.tv_usec
);
1269 switch (select(maxfd
+ 1, &fds
, NULL
, NULL
, &idleTime
)) {
1271 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
1272 "Select returned -1");
1275 gtp_retrans(gsn
); /* Only retransmit if nothing else */
1281 if ((tun
) && FD_ISSET(tun
->fd
, &fds
) && tun_decaps(tun
) < 0) {
1282 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
1283 "TUN decaps failed");
1286 if (FD_ISSET(gsn
->fd0
, &fds
))
1289 if (FD_ISSET(gsn
->fd1c
, &fds
))
1292 if (FD_ISSET(gsn
->fd1u
, &fds
))
1296 gtp_free(gsn
); /* Clean up the gsn instance */
1298 if (options
.createif
)
1302 exit(1); /* Indicate error */