blob: 2675c0feb88d5a53894f181c802c0f5902f5905a [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 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 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * sgsnemu.c
14 *
15 */
16
17
18#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000019#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000020#endif
21
22
23#include <syslog.h>
24#include <ctype.h>
25#include <netdb.h>
26#include <signal.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <sys/wait.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <sys/socket.h>
38#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000039#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000040#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000041#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000042#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000043#include <resolv.h>
44#include <time.h>
45
jjakoff9985c2004-01-16 11:05:22 +000046#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020047#include "../lib/tun.h"
48#include "../lib/ippool.h"
49#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000050#include "../gtp/pdp.h"
51#include "../gtp/gtp.h"
52#include "cmdline.h"
53
jjakoa7cd2492003-04-11 09:40:12 +000054#define IPADDRLEN 256 /* Character length of addresses */
jjako193e8b12003-11-10 12:31:41 +000055#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000056
jjakoa7cd2492003-04-11 09:40:12 +000057/* HASH tables for IP address allocation */
58struct iphash_t {
59 uint8_t inuse; /* 0=free. 1=used by somebody */
60 struct iphash_t *ipnext;
61 struct pdp_t *pdp;
62 struct in_addr addr;
63};
64struct iphash_t iparr[MAXCONTEXTS];
65struct iphash_t *iphash[MAXCONTEXTS];
66
67/* State variable used for ping */
68/* 0: Idle */
69/* 1: Wait_connect */
70/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000071/* 3: Done */
72/* 4: Wait_disconnect */
73/* 5: Disconnected */
jjako581c9f02003-10-22 11:28:20 +000074int state = 0;
jjako52c24142002-12-16 13:33:51 +000075
jjakoa7cd2492003-04-11 09:40:12 +000076struct gsn_t *gsn = NULL; /* GSN instance */
77struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000078int maxfd = 0; /* For select() */
jjako91aaf222003-10-22 10:09:32 +000079int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000080
jjakoa7cd2492003-04-11 09:40:12 +000081/* Struct with local versions of gengetopt options */
82struct {
83 int debug; /* Print debug messages */
84 int createif; /* Create local network interface */
jjakoc6762cf2004-04-28 14:52:58 +000085 struct in_addr netaddr, destaddr, net, mask; /* Network interface */
jjakoa7cd2492003-04-11 09:40:12 +000086 char *ipup, *ipdown; /* Filename of scripts */
87 int defaultroute; /* Set up default route */
88 struct in_addr pinghost; /* Remote ping host */
89 int pingrate;
90 int pingsize;
91 int pingcount;
92 int pingquiet;
93 struct in_addr listen;
94 struct in_addr remote;
95 struct in_addr dns;
96 int contexts; /* Number of contexts to create */
97 int timelimit; /* Number of seconds to be connected */
98 char *statedir;
99 uint64_t imsi;
jjako193e8b12003-11-10 12:31:41 +0000100 uint8_t nsapi;
101 int gtpversion;
jjakoa7cd2492003-04-11 09:40:12 +0000102 struct ul255_t pco;
103 struct ul255_t qos;
jjako7e051d32004-05-27 20:06:36 +0000104 uint16_t cch;
jjakoa7cd2492003-04-11 09:40:12 +0000105 struct ul255_t apn;
jjako1a51df72004-07-20 08:30:21 +0000106 uint8_t selmode;
jjakoa7cd2492003-04-11 09:40:12 +0000107 struct ul16_t msisdn;
108} options;
jjako52c24142002-12-16 13:33:51 +0000109
jjako5da68452003-01-28 16:08:47 +0000110
111/* Definitions to use for PING. Most of the ping code was derived from */
112/* the original ping program by Mike Muuss */
113
114/* IP header and ICMP echo header */
115#define CREATEPING_MAX 2048
116#define CREATEPING_IP 20
117#define CREATEPING_ICMP 8
118
119struct ip_ping {
jjako0141d202004-01-09 15:19:20 +0000120 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 */
jjako5da68452003-01-28 16:08:47 +0000136} __attribute__((packed));
137
138/* Statistical values for ping */
139int nreceived = 0;
140int ntreceived = 0;
141int ntransmitted = 0;
142int tmin = 999999999;
143int tmax = 0;
144int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000145int pingseq = 0; /* Ping sequence counter */
146struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000147
jjakoa7cd2492003-04-11 09:40:12 +0000148int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
149 int hash = ippool_hash4(addr) % MAXCONTEXTS;
150 struct iphash_t *h;
151 struct iphash_t *prev = NULL;
152 ipaddr->ipnext = NULL;
153 ipaddr->addr.s_addr = addr->s_addr;
154 for (h = iphash[hash]; h; h = h->ipnext)
155 prev = h;
156 if (!prev)
157 iphash[hash] = ipaddr;
158 else
159 prev->ipnext = ipaddr;
160 return 0;
161}
162
163int ipdel(struct iphash_t *ipaddr) {
164 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
165 struct iphash_t *h;
166 struct iphash_t *prev = NULL;
167 for (h = iphash[hash]; h; h = h->ipnext) {
168 if (h == ipaddr) {
169 if (!prev)
170 iphash[hash] = h->ipnext;
171 else
172 prev->ipnext = h->ipnext;
173 return 0;
174 }
175 prev = h;
176 }
177 return EOF; /* End of linked list and not found */
178}
179
180int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
181 int hash = ippool_hash4(addr) % MAXCONTEXTS;
182 struct iphash_t *h;
183 for (h = iphash[hash]; h; h = h->ipnext) {
184 if ((h->addr.s_addr == addr->s_addr)) {
185 *ipaddr = h;
186 return 0;
187 }
188 }
189 return EOF; /* End of linked list and not found */
190}
191
192
193/* Used to write process ID to file. Assume someone else will delete */
194void log_pid(char *pidfile) {
195 FILE *file;
196 mode_t oldmask;
197
198 oldmask = umask(022);
199 file = fopen(pidfile, "w");
200 umask(oldmask);
201 if(!file)
202 return;
jjako0141d202004-01-09 15:19:20 +0000203 fprintf(file, "%d\n", (int) getpid());
jjakoa7cd2492003-04-11 09:40:12 +0000204 fclose(file);
205}
206
207
208int process_options(int argc, char **argv) {
209 /* gengeopt declarations */
210 struct gengetopt_args_info args_info;
211
212 struct hostent *host;
Harald Weltef54a1f42010-05-04 11:08:38 +0200213 unsigned int n;
jjakoa7cd2492003-04-11 09:40:12 +0000214
215 if (cmdline_parser (argc, argv, &args_info) != 0)
216 return -1;
217 if (args_info.debug_flag) {
jjakoc6762cf2004-04-28 14:52:58 +0000218 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);
jjakoa7cd2492003-04-11 09:40:12 +0000221 printf("debug: %d\n", args_info.debug_flag);
jjakoc6762cf2004-04-28 14:52:58 +0000222 if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000223 printf("qos: %#08x\n", args_info.qos_arg);
jjako7e051d32004-05-27 20:06:36 +0000224 printf("charging: %#04x\n", args_info.charging_arg);
jjakoc6762cf2004-04-28 14:52:58 +0000225 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);
jjakoa7cd2492003-04-11 09:40:12 +0000232 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);
jjakoc6762cf2004-04-28 14:52:58 +0000235 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);
jjakoa7cd2492003-04-11 09:40:12 +0000237 printf("defaultroute: %d\n", args_info.defaultroute_flag);
jjakoc6762cf2004-04-28 14:52:58 +0000238 if (args_info.pinghost_arg) printf("pinghost: %s\n", args_info.pinghost_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000239 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);
243 }
244
245 /* Try out our new parser */
246
247 if (args_info.conf_arg) {
Harald Welte1b3e5772010-05-04 11:13:56 +0200248 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
jjakoa7cd2492003-04-11 09:40:12 +0000249 return -1;
250 if (args_info.debug_flag) {
251 printf("cmdline_parser_configfile\n");
jjakoc6762cf2004-04-28 14:52:58 +0000252 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);
jjakoa7cd2492003-04-11 09:40:12 +0000255 printf("debug: %d\n", args_info.debug_flag);
jjakoc6762cf2004-04-28 14:52:58 +0000256 if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000257 printf("qos: %#08x\n", args_info.qos_arg);
jjako7e051d32004-05-27 20:06:36 +0000258 printf("charging: %#04x\n", args_info.charging_arg);
jjakoc6762cf2004-04-28 14:52:58 +0000259 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);
jjakoa7cd2492003-04-11 09:40:12 +0000266 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);
jjakoc6762cf2004-04-28 14:52:58 +0000269 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);
jjakoa7cd2492003-04-11 09:40:12 +0000271 printf("defaultroute: %d\n", args_info.defaultroute_flag);
jjakoc6762cf2004-04-28 14:52:58 +0000272 if (args_info.pinghost_arg) printf("pinghost: %s\n", args_info.pinghost_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000273 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);
277 }
278 }
279
280 /* Handle each option */
281
282 /* foreground */
jjakoe607f742003-07-06 21:21:30 +0000283 /* If fg flag not given run as a daemon */
284 /* Do not allow sgsnemu to run as deamon
jjakoa7cd2492003-04-11 09:40:12 +0000285 if (!args_info.fg_flag)
286 {
287 closelog();
jjakoa7cd2492003-04-11 09:40:12 +0000288 freopen("/dev/null", "w", stdout);
289 freopen("/dev/null", "w", stderr);
290 freopen("/dev/null", "r", stdin);
291 daemon(0, 0);
jjakoa7cd2492003-04-11 09:40:12 +0000292 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
jjakoe607f742003-07-06 21:21:30 +0000293 } */
jjakoa7cd2492003-04-11 09:40:12 +0000294
295 /* debug */
296 options.debug = args_info.debug_flag;
297
298 /* pidfile */
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);
302 }
303
304 /* dns */
305 /* If no dns option is given use system default */
306 /* Do hostname lookup to translate hostname to IP address */
307 printf("\n");
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);
312 return -1;
313 }
314 else {
315 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
316 _res.nscount = 1;
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));
320 }
321 }
322 else {
323 options.dns.s_addr= 0;
324 printf("Using default DNS server\n");
325 }
326
327 /* listen */
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);
334 return -1;
335 }
336 else {
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));
340 }
341 }
342 else {
343 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
344 "Listening address must be specified: %s!", args_info.listen_arg);
345 return -1;
346 }
347
348
349 /* remote */
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);
356 return -1;
357 }
358 else {
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));
362 }
363 }
364 else {
365 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
366 "No remote address given!");
367 return -1;
368 }
369
370
371 /* imsi */
372 if (strlen(args_info.imsi_arg)!=15) {
373 printf("Invalid IMSI\n");
374 return -1;
375 }
jjako06e9f122004-01-19 18:37:58 +0000376
jjakod48c5ff2004-01-26 22:25:40 +0000377 options.imsi = 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +0000378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 0]-48));
jjakoa7cd2492003-04-11 09:40:12 +0000379 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;
393
jjako193e8b12003-11-10 12:31:41 +0000394 printf("IMSI is: %s (%#08llx)\n",
395 args_info.imsi_arg, options.imsi);
396
397
398 /* nsapi */
399 if ((args_info.nsapi_arg > 15) ||
400 (args_info.nsapi_arg < 0)) {
401 printf("Invalid NSAPI\n");
402 return -1;
403 }
404 options.nsapi = args_info.nsapi_arg;
405 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000406
407
408 /* qos */
409 options.qos.l = 3;
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;
jjako7e051d32004-05-27 20:06:36 +0000413
414 /* charging */
415 options.cch = args_info.charging_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000416
417 /* contexts */
418 if (args_info.contexts_arg > MAXCONTEXTS) {
419 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
420 return -1;
421 }
422 options.contexts = args_info.contexts_arg;
423
424 /* Timelimit */
425 options.timelimit = args_info.timelimit_arg;
426
jjako193e8b12003-11-10 12:31:41 +0000427 /* gtpversion */
428 if ((args_info.gtpversion_arg > 1) ||
429 (args_info.gtpversion_arg < 0)) {
430 printf("Invalid GTP version\n");
431 return -1;
432 }
433 options.gtpversion = args_info.gtpversion_arg;
434 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
435
436
jjakoa7cd2492003-04-11 09:40:12 +0000437 /* apn */
438 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
439 printf("Invalid APN\n");
440 return -1;
441 }
jjako9f26b952005-03-14 22:03:05 +0000442 options.apn.l = strlen(args_info.apn_arg);
Emmanuel Bretelle2a7cad52010-09-07 15:56:02 +0200443 strncpy((char *)options.apn.v, args_info.apn_arg, sizeof(options.apn.v));
jjako9f26b952005-03-14 22:03:05 +0000444 options.apn.v[sizeof(options.apn.v)-1] = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000445 printf("Using APN: %s\n", args_info.apn_arg);
jjako1a51df72004-07-20 08:30:21 +0000446
447
448 /* selmode */
449 options.selmode = args_info.selmode_arg;
450 printf("Using selection mode: %d\n", args_info.selmode_arg);
451
jjakoa7cd2492003-04-11 09:40:12 +0000452
453 /* msisdn */
454 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
455 printf("Invalid MSISDN\n");
456 return -1;
457 }
458 options.msisdn.l = 1;
459 options.msisdn.v[0] = 0x91; /* International format */
460 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
461 if ((n%2) == 0) {
462 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
463 options.msisdn.l += 1;
464 }
465 else {
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;
469 }
470 }
471 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
472
473 /* UID and PWD */
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");
478 return -1;
479 }
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;
jjakob62c3dd2004-05-27 18:51:55 +0000484 options.pco.v[3] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
jjakoa7cd2492003-04-11 09:40:12 +0000485 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));
494
495 /* createif */
496 options.createif = args_info.createif_flag;
497
jjako193e8b12003-11-10 12:31:41 +0000498 /* net */
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);
504 exit(1);
505 }
jjakoc6762cf2004-04-28 14:52:58 +0000506
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);
510#else
511 options.netaddr.s_addr = options.net.s_addr;
512 options.destaddr.s_addr = options.net.s_addr;
513#endif
514
jjako193e8b12003-11-10 12:31:41 +0000515 }
516 else {
517 options.net.s_addr = 0;
518 options.mask.s_addr = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000519 options.netaddr.s_addr = 0;
520 options.destaddr.s_addr = 0;
jjako193e8b12003-11-10 12:31:41 +0000521 }
522
jjakoa7cd2492003-04-11 09:40:12 +0000523 /* ipup */
524 options.ipup = args_info.ipup_arg;
525
526 /* ipdown */
527 options.ipdown = args_info.ipdown_arg;
528
529 /* statedir */
530 options.statedir = args_info.statedir_arg;
531
532 /* defaultroute */
533 options.defaultroute = args_info.defaultroute_flag;
534
535
jjako76032b92004-01-14 06:22:08 +0000536 /* pinghost */
jjakoa7cd2492003-04-11 09:40:12 +0000537 /* Store ping host as in_addr */
538 if (args_info.pinghost_arg) {
jjako76032b92004-01-14 06:22:08 +0000539 if (!(host = gethostbyname(args_info.pinghost_arg))) {
jjakoa7cd2492003-04-11 09:40:12 +0000540 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
541 "Invalid ping host: %s!", args_info.pinghost_arg);
542 return -1;
543 }
jjako76032b92004-01-14 06:22:08 +0000544 else {
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));
548 }
jjakoa7cd2492003-04-11 09:40:12 +0000549 }
550
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;
556
557 return 0;
558
559}
560
jjako5da68452003-01-28 16:08:47 +0000561
562int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
Harald Weltef54a1f42010-05-04 11:08:38 +0200563 unsigned int i;
jjako52c24142002-12-16 13:33:51 +0000564 printf("The packet looks like this:\n");
565 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000566 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000567 if (!((i+1)%16)) printf("\n");
568 };
jjako5da68452003-01-28 16:08:47 +0000569 printf("\n");
570 return 0;
jjako52c24142002-12-16 13:33:51 +0000571}
572
jjako5da68452003-01-28 16:08:47 +0000573char * print_ipprot(int t) {
574 switch (t) {
575 case 1: return "ICMP";
576 case 6: return "TCP";
577 case 17: return "UDP";
578 default: return "Unknown";
579 };
580}
581
582
583char * print_icmptype(int t) {
584 static char *ttab[] = {
585 "Echo Reply",
586 "ICMP 1",
587 "ICMP 2",
588 "Dest Unreachable",
589 "Source Quench",
590 "Redirect",
591 "ICMP 6",
592 "ICMP 7",
593 "Echo",
594 "ICMP 9",
595 "ICMP 10",
596 "Time Exceeded",
597 "Parameter Problem",
598 "Timestamp",
599 "Timestamp Reply",
600 "Info Request",
601 "Info Reply"
602 };
603 if( t < 0 || t > 16 )
604 return("OUT-OF-RANGE");
605 return(ttab[t]);
606}
607
jjako193e8b12003-11-10 12:31:41 +0000608int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) {
Harald Weltef54a1f42010-05-04 11:08:38 +0200609 unsigned int n;
jjako193e8b12003-11-10 12:31:41 +0000610 uint64_t i64 = 0;
611 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
Harald Weltef54a1f42010-05-04 11:08:38 +0200612 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000613
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) {
619 i64 *= 10;
620 i64 += src->v[n] & 0x0f;
621 }
622 if ((src->v[n] & 0xf0) != 0xf0) {
623 i64 *= 10;
624 i64 += (src->v[n] & 0xf0) >> 4;
625 }
626 }
627
628 i64 += add;
629
630 /* Generate array with least significant digit in first octet */
631 while (i64) {
632 msa[msalen++] = i64 % 10;
633 i64 = i64 / 10;
634 }
635
636 /* Convert back to ul16_t format */
637 for(n=0; n<msalen; n++) {
638 if ((n%2) == 0) {
639 dst->v[((int)n/2)] = msa[msalen-n-1] + 0xf0;
640 dst->l += 1;
641 }
642 else {
643 dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) +
644 msa[msalen-n-1] * 16;
645 }
646 }
647
648 return 0;
649
650}
651
652int imsi_add(uint64_t src, uint64_t *dst, int add) {
653 /* TODO: big endian / small endian ??? */
654 uint64_t i64 = 0;
655
656 /* Convert from uint64_t bcd to uint64_t integer format */
657 /* The resulting integer format is multiplied by 10 */
658 while (src) {
659 if ((src & 0x0f) != 0x0f) {
660 i64 *= 10;
661 i64 += (src & 0x0f);
662 }
663 if ((src & 0xf0) != 0xf0) {
664 i64 *= 10;
665 i64 += (src & 0xf0) >> 4;
666 }
667 src = src >> 8;
668 }
669
670 i64 += add * 10;
671
672 *dst = 0;
673 while (i64) {
674 *dst = *dst << 4;
675 *dst += (i64 % 10);
676 i64 = i64 / 10;
677 }
678
jjakod48c5ff2004-01-26 22:25:40 +0000679 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +0000680
jjako193e8b12003-11-10 12:31:41 +0000681 return 0;
682
683}
684
jjakoafb2a972003-01-29 21:04:13 +0000685/* Calculate time left until we have to send off next ping packet */
686int ping_timeout(struct timeval *tp) {
687 struct timezone tz;
688 struct timeval tv;
689 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000690 if ((options.pinghost.s_addr) && (2 == state) &&
691 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000692 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000693 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000694 1000000 * (tv.tv_sec - firstping.tv_sec) -
695 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
696 tp->tv_sec = 0;
697 if (diff > 0)
698 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000699 else {
jjakoafb2a972003-01-29 21:04:13 +0000700 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000701 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
702 tp->tv_usec = 0;
703 }
jjakoafb2a972003-01-29 21:04:13 +0000704 }
705 return 0;
706}
707
jjako5da68452003-01-28 16:08:47 +0000708/* Print out statistics when at the end of ping sequence */
709int ping_finish()
710{
jjakoafb2a972003-01-29 21:04:13 +0000711 struct timezone tz;
712 struct timeval tv;
713 int elapsed;
714 gettimeofday(&tv, &tz);
715 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
716 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000717 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000718 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000719 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
720 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000721 printf("%d packets received, ", nreceived );
722 if (ntransmitted) {
723 if( nreceived > ntransmitted)
724 printf("-- somebody's printing up packets!");
725 else
726 printf("%d%% packet loss",
727 (int) (((ntransmitted-nreceived)*100) /
728 ntransmitted));
729 }
730 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000731 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000732 if (nreceived && tsum)
733 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
734 tmin/1000.0,
735 tsum/1000.0/nreceived,
736 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000737 printf("%d packets transmitted \n", ntreceived );
738
jjako5da68452003-01-28 16:08:47 +0000739 ntransmitted = 0;
740 return 0;
741}
742
743/* Handle a received ping packet. Print out line and update statistics. */
744int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
745 struct timezone tz;
746 struct timeval tv;
747 struct timeval *tp;
748 struct ip_ping *pingpack = pack;
749 struct in_addr src;
750 int triptime;
751
752 src.s_addr = pingpack->src;
753
754 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000755 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000756
757 if (len < CREATEPING_IP + CREATEPING_ICMP) {
758 printf("packet too short (%d bytes) from %s\n", len,
759 inet_ntoa(src));
760 return 0;
761 }
762
763 ntreceived++;
764 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000765 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000766 len, inet_ntoa(src), pingpack->protocol,
767 print_ipprot(pingpack->protocol));
768 return 0;
769 }
770
771 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000772 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000773 len, inet_ntoa(src), pingpack->type,
774 print_icmptype(pingpack->type), pingpack->code);
775 return 0;
776 }
777
778 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000779 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000780 inet_ntoa(src), ntohs(pingpack->seq));
781
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 ) {
786 tv.tv_sec--;
787 tv.tv_usec += 1000000;
788 }
789 tv.tv_sec -= tp->tv_sec;
790
791 triptime = tv.tv_sec*1000000+(tv.tv_usec);
792 tsum += triptime;
793 if( triptime < tmin )
794 tmin = triptime;
795 if( triptime > tmax )
796 tmax = triptime;
797
jjakoa7cd2492003-04-11 09:40:12 +0000798 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000799
800 }
801 else
jjakoa7cd2492003-04-11 09:40:12 +0000802 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000803 return 0;
804}
805
806/* Create a new ping packet and send it off to peer. */
807int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltef54a1f42010-05-04 11:08:38 +0200808 struct in_addr *dst, int seq, unsigned int datasize) {
jjako5da68452003-01-28 16:08:47 +0000809
810 struct ip_ping pack;
jjako0141d202004-01-09 15:19:20 +0000811 uint16_t *p = (uint16_t *) &pack;
812 uint8_t *p8 = (uint8_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000813 struct in_addr src;
Harald Weltef54a1f42010-05-04 11:08:38 +0200814 unsigned int n;
jjako5da68452003-01-28 16:08:47 +0000815 long int sum = 0;
816 int count = 0;
817
818 struct timezone tz;
819 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
820
821 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000822 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
823 "Ping size to large: %d!", datasize);
824 return -1;
jjako5da68452003-01-28 16:08:47 +0000825 }
826
827 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
828
829 pack.ipver = 0x45;
830 pack.tos = 0x00;
831 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
832 pack.fragid = 0x0000;
833 pack.offset = 0x0040;
834 pack.ttl = 0x40;
835 pack.protocol = 0x01;
836 pack.ipcheck = 0x0000;
837 pack.src = src.s_addr;
838 pack.dst = dst->s_addr;
839 pack.type = 0x08;
840 pack.code = 0x00;
841 pack.checksum = 0x0000;
842 pack.ident = 0x0000;
843 pack.seq = htons(seq);
844
845 /* Generate ICMP payload */
jjako0141d202004-01-09 15:19:20 +0000846 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
jjako5da68452003-01-28 16:08:47 +0000847 for (n=0; n<(datasize); n++) p8[n] = n;
848
849 if (datasize >= sizeof(struct timeval))
850 gettimeofday(tp, &tz);
851
852 /* Calculate IP header checksum */
jjako0141d202004-01-09 15:19:20 +0000853 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000854 count = CREATEPING_IP;
855 sum = 0;
856 while (count>1) {
857 sum += *p++;
858 count -= 2;
859 }
860 while (sum>>16)
861 sum = (sum & 0xffff) + (sum >> 16);
862 pack.ipcheck = ~sum;
863
864
865 /* Calculate ICMP checksum */
866 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
867 sum = 0;
jjako0141d202004-01-09 15:19:20 +0000868 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000869 p += CREATEPING_IP / 2;
870 while (count>1) {
871 sum += *p++;
872 count -= 2;
873 }
874 if (count>0)
875 sum += * (unsigned char *) p;
876 while (sum>>16)
877 sum = (sum & 0xffff) + (sum >> 16);
878 pack.checksum = ~sum;
879
880 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000881 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000882}
883
884
jjakoa7cd2492003-04-11 09:40:12 +0000885int delete_context(struct pdp_t *pdp) {
886
887 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
888
889 ipdel((struct iphash_t*) pdp->peer);
890 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000891
892 if (1 == options.contexts)
893 state = 5; /* Disconnected */
894
jjakoa7cd2492003-04-11 09:40:12 +0000895 return 0;
jjako52c24142002-12-16 13:33:51 +0000896}
897
jjakoa7cd2492003-04-11 09:40:12 +0000898
899/* Callback for receiving messages from tun */
900int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
901 struct iphash_t *ipm;
902 struct in_addr src;
903 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
904
905 src.s_addr = iph->src;
906
907 if (ipget(&ipm, &src)) {
908 printf("Received packet without a valid source address!!!\n");
909 return 0;
jjako52c24142002-12-16 13:33:51 +0000910 }
jjako5da68452003-01-28 16:08:47 +0000911
jjakoa7cd2492003-04-11 09:40:12 +0000912 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000913 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000914 return 0;
915}
916
jjako2c381332003-10-21 19:09:53 +0000917int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000918 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000919
jjako2c381332003-10-21 19:09:53 +0000920 struct iphash_t *iph = (struct iphash_t*) cbp;
921
922 if (cause < 0) {
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;
jjako193e8b12003-11-10 12:31:41 +0000927 gtp_create_context_req(gsn, iph->pdp, iph);
jjako2c381332003-10-21 19:09:53 +0000928 return 0;
929 }
930 else {
931 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000932 pdp_freepdp(iph->pdp);
933 iph->pdp = NULL;
jjako2c381332003-10-21 19:09:53 +0000934 return EOF;
935 }
936 }
937
jjakoa7cd2492003-04-11 09:40:12 +0000938 if (cause != 128) {
939 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000940 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000941 pdp_freepdp(iph->pdp);
942 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000943 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000944 }
945
jjakoa7cd2492003-04-11 09:40:12 +0000946 if (pdp_euaton(&pdp->eua, &addr)) {
947 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako0b076a32003-10-25 15:59:31 +0000948 pdp_freepdp(iph->pdp);
949 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000950 state = 0;
951 return EOF; /* Not a valid IP address */
952 }
953
954 printf("Received create PDP context response. IP address: %s\n",
955 inet_ntoa(addr));
956
jjako193e8b12003-11-10 12:31:41 +0000957 if ((options.createif) && (!options.net.s_addr)) {
jjakoa7cd2492003-04-11 09:40:12 +0000958 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +0000959#ifdef HAVE_INET_ATON
jjako1d3db972004-01-16 09:56:56 +0000960 inet_aton("255.255.255.255", &m);
961#else
jjakob73f23a2004-01-16 19:46:41 +0000962 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +0000963#endif
jjakoa7cd2492003-04-11 09:40:12 +0000964 /* printf("Setting up interface and routing\n");*/
965 tun_addaddr(tun, &addr, &addr, &m);
966 if (options.defaultroute) {
967 struct in_addr rm;
968 rm.s_addr = 0;
969 tun_addroute(tun, &rm, &addr, &rm);
970 }
971 if (options.ipup) tun_runscript(tun, options.ipup);
972 }
973
974 ipset((struct iphash_t*) pdp->peer, &addr);
975
976 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000977
978 return 0;
979}
980
jjako52c24142002-12-16 13:33:51 +0000981int delete_pdp_conf(struct pdp_t *pdp, int cause) {
982 printf("Received delete PDP context response. Cause value: %d\n", cause);
983 return 0;
984}
985
jjako08d331d2003-10-13 20:33:30 +0000986int echo_conf(int recovery) {
jjako91aaf222003-10-22 10:09:32 +0000987
988 if (recovery < 0) {
989 printf("Echo Request timed out\n");
990 if (echoversion == 1) {
991 printf("Retrying with version 0\n");
992 echoversion = 0;
993 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000994 return 0;
995 }
996 else {
997 state = 0;
998 return EOF;
999 }
jjako7b8fad42003-07-07 14:37:42 +00001000 }
jjako581c9f02003-10-22 11:28:20 +00001001 else {
jjako08d331d2003-10-13 20:33:30 +00001002 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +00001003 if (!options.contexts) state = 5;
1004 }
jjako52c24142002-12-16 13:33:51 +00001005 return 0;
1006}
1007
jjako2c381332003-10-21 19:09:53 +00001008int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +00001009 /* if (cause < 0) return 0; Some error occurred. We don't care */
1010 switch (type) {
1011 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +00001012 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +00001013 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +00001014 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +00001015 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);
1018 default:
1019 return 0;
1020 }
1021}
1022
jjako52c24142002-12-16 13:33:51 +00001023
1024int 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);
1027}
1028
1029int main(int argc, char **argv)
1030{
jjako52c24142002-12-16 13:33:51 +00001031 fd_set fds; /* For select() */
1032 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +00001033 struct pdp_t *pdp;
1034 int n;
1035 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +00001036 int stoptime = 0; /* Time to exit */
1037 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001038
1039 struct timezone tz; /* Used for calculating ping times */
1040 struct timeval tv;
1041 int diff;
jjako52c24142002-12-16 13:33:51 +00001042
jjako52c24142002-12-16 13:33:51 +00001043 /* open a connection to the syslog daemon */
1044 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
jjako0141d202004-01-09 15:19:20 +00001045 /* TODO: Only use LOG__PERROR for linux */
1046
1047#ifdef __linux__
jjako52c24142002-12-16 13:33:51 +00001048 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
jjako0141d202004-01-09 15:19:20 +00001049#else
1050 openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
1051#endif
1052
jjako52c24142002-12-16 13:33:51 +00001053
jjakoa7cd2492003-04-11 09:40:12 +00001054 /* Process options given in configuration file and command line */
1055 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +00001056 exit(1);
jjako52c24142002-12-16 13:33:51 +00001057
1058 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +00001059 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +00001060 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1061 "Failed to create gtp");
1062 exit(1);
1063 }
jjako08d331d2003-10-13 20:33:30 +00001064 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
1065 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
1066 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001067
jjakoa7cd2492003-04-11 09:40:12 +00001068 gtp_set_cb_delete_context(gsn, delete_context);
1069 gtp_set_cb_conf(gsn, conf);
1070 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +00001071 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +00001072 else
jjako08d331d2003-10-13 20:33:30 +00001073 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +00001074
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");
1081 exit(1);
1082 }
1083 tun_set_cb_ind(tun, cb_tun_ind);
1084 if (tun->fd > maxfd) maxfd = tun->fd;
1085 }
1086
jjako193e8b12003-11-10 12:31:41 +00001087 if ((options.createif) && (options.net.s_addr)) {
1088 /* printf("Setting up interface and routing\n");*/
jjakoc6762cf2004-04-28 14:52:58 +00001089 tun_addaddr(tun, &options.netaddr, &options.destaddr, &options.mask);
jjako193e8b12003-11-10 12:31:41 +00001090 if (options.defaultroute) {
1091 struct in_addr rm;
1092 rm.s_addr = 0;
jjakoc6762cf2004-04-28 14:52:58 +00001093 tun_addroute(tun, &rm, &options.destaddr, &rm);
jjako193e8b12003-11-10 12:31:41 +00001094 }
1095 if (options.ipup) tun_runscript(tun, options.ipup);
1096 }
1097
1098
jjakoa7cd2492003-04-11 09:40:12 +00001099 /* Initialise hash tables */
1100 memset(&iphash, 0, sizeof(iphash));
1101 memset(&iparr, 0, sizeof(iparr));
1102
jjako52c24142002-12-16 13:33:51 +00001103 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +00001104
1105 /* See if anybody is there */
1106 printf("Sending off echo request\n");
jjako193e8b12003-11-10 12:31:41 +00001107 echoversion = options.gtpversion;
jjako91aaf222003-10-22 10:09:32 +00001108 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +00001109
jjakoa7cd2492003-04-11 09:40:12 +00001110 for(n=0; n<options.contexts; n++) {
jjako193e8b12003-11-10 12:31:41 +00001111 uint64_t myimsi;
jjako52c24142002-12-16 13:33:51 +00001112 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +00001113 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001114
jjako193e8b12003-11-10 12:31:41 +00001115 imsi_add(options.imsi, &myimsi, n);
1116
jjako0b076a32003-10-25 15:59:31 +00001117 /* Allocated here. */
1118 /* If create context failes we have to deallocate ourselves. */
jjako193e8b12003-11-10 12:31:41 +00001119 /* Otherwise it is deallocated by gtplib */
1120 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjakoa7cd2492003-04-11 09:40:12 +00001121
1122 pdp->peer = &iparr[n];
1123 pdp->ipif = tun; /* TODO */
1124 iparr[n].pdp = pdp;
1125
1126 if (options.qos.l > sizeof(pdp->qos_req0)) {
1127 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +00001128 exit(1);
1129 }
1130 else {
jjakoa7cd2492003-04-11 09:40:12 +00001131 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001132 }
jjako08d331d2003-10-13 20:33:30 +00001133
1134 /* TODO */
1135 pdp->qos_req.l = 4;
1136 pdp->qos_req.v[0] = 0x00;
1137 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001138
jjako1a51df72004-07-20 08:30:21 +00001139 pdp->selmode = options.selmode;
jjako52c24142002-12-16 13:33:51 +00001140
jjakoa7cd2492003-04-11 09:40:12 +00001141 if (options.apn.l > sizeof(pdp->apn_use.v)) {
1142 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +00001143 exit(1);
1144 }
1145 else {
jjakoa7cd2492003-04-11 09:40:12 +00001146 pdp->apn_use.l = options.apn.l;
1147 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +00001148 }
1149
jjakoa7cd2492003-04-11 09:40:12 +00001150 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));
jjako52c24142002-12-16 13:33:51 +00001154
jjakoa7cd2492003-04-11 09:40:12 +00001155 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
1156 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +00001157 exit(1);
1158 }
1159 else {
jjako193e8b12003-11-10 12:31:41 +00001160 msisdn_add(&options.msisdn, &pdp->msisdn, n);
jjakoa7cd2492003-04-11 09:40:12 +00001161 }
1162
1163 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1164
1165 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1166 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1167 exit(1);
1168 }
1169 else {
1170 pdp->pco_req.l = options.pco.l;
1171 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001172 }
1173
jjako193e8b12003-11-10 12:31:41 +00001174 pdp->version = options.gtpversion;
1175
1176 pdp->hisaddr0 = options.remote;
1177 pdp->hisaddr1 = options.remote;
jjako08d331d2003-10-13 20:33:30 +00001178
jjako7e051d32004-05-27 20:06:36 +00001179 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1180 512 = Flat rate, 256 = Hot billing */
jjakob62c3dd2004-05-27 18:51:55 +00001181
jjako52c24142002-12-16 13:33:51 +00001182 /* Create context */
1183 /* We send this of once. Retransmissions are handled by gtplib */
jjako193e8b12003-11-10 12:31:41 +00001184 gtp_create_context_req(gsn, pdp, &iparr[n]);
jjako52c24142002-12-16 13:33:51 +00001185 }
1186
1187 state = 1; /* Enter wait_connection state */
1188
1189 printf("Waiting for response from ggsn........\n\n");
1190
jjako5da68452003-01-28 16:08:47 +00001191
jjako52c24142002-12-16 13:33:51 +00001192 /******************************************************************/
1193 /* Main select loop */
1194 /******************************************************************/
1195
jjako7b8fad42003-07-07 14:37:42 +00001196 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001197
jjako7b8fad42003-07-07 14:37:42 +00001198 /* Take down client after timeout after disconnect */
1199 if ((4 == state) && ((stoptime) <= time(NULL))) {
1200 state = 5;
1201 }
1202
1203 /* Take down client after timelimit timeout */
1204 if ((2 == state) && (options.timelimit) &&
1205 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001206 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001207 }
1208
1209 /* Take down client after ping timeout */
1210 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1211 state = 3;
1212 }
1213
1214 /* Set pingtimeout for later disconnection */
1215 if (options.pingcount && ntransmitted >= options.pingcount) {
1216 pingtimeout = time(NULL) + 5; /* Extra seconds */
1217 }
1218
1219 /* Print statistics if no more ping packets are missing */
1220 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1221 ping_finish();
1222 if (!options.createif)
1223 state = 3;
1224 }
1225
jjako2c381332003-10-21 19:09:53 +00001226 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001227 if (3 == state) {
1228 state = 4;
1229 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001230 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001231 /* Delete context */
1232 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001233 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001234 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001235 }
jjakoafb2a972003-01-29 21:04:13 +00001236 }
jjako7b8fad42003-07-07 14:37:42 +00001237
1238 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001239 diff = 0;
1240 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001241 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001242 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001243 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001244 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1245 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001246 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001247 1000000 * (tv.tv_sec - firstping.tv_sec) -
1248 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1249 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001250 if (options.debug) printf("Create_ping %d\n", diff);
1251 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1252 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001253 pingseq++;
1254 }
jjako52c24142002-12-16 13:33:51 +00001255 }
jjako5da68452003-01-28 16:08:47 +00001256
jjako52c24142002-12-16 13:33:51 +00001257 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001258 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001259 FD_SET(gsn->fd0, &fds);
1260 FD_SET(gsn->fd1c, &fds);
1261 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001262
1263 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001264 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001265
1266 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1267 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1268
jjako52c24142002-12-16 13:33:51 +00001269 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1270 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001271 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1272 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001273 break;
1274 case 0:
1275 gtp_retrans(gsn); /* Only retransmit if nothing else */
1276 break;
1277 default:
1278 break;
1279 }
jjakoa7cd2492003-04-11 09:40:12 +00001280
1281 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1282 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1283 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001284 }
1285
jjako08d331d2003-10-13 20:33:30 +00001286 if (FD_ISSET(gsn->fd0, &fds))
1287 gtp_decaps0(gsn);
1288
1289 if (FD_ISSET(gsn->fd1c, &fds))
1290 gtp_decaps1c(gsn);
1291
1292 if (FD_ISSET(gsn->fd1u, &fds))
1293 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001294 }
jjakoa7cd2492003-04-11 09:40:12 +00001295
jjako52c24142002-12-16 13:33:51 +00001296 gtp_free(gsn); /* Clean up the gsn instance */
1297
jjakoa7cd2492003-04-11 09:40:12 +00001298 if (options.createif)
1299 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001300
1301 if (0 == state)
1302 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001303
jjakoa7cd2492003-04-11 09:40:12 +00001304 return 0;
jjako52c24142002-12-16 13:33:51 +00001305}
1306