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.
17 #define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
20 #include "../config.h"
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
50 #include "../lib/tun.h"
51 #include "../lib/ippool.h"
52 #include "../lib/syserr.h"
53 #include "../gtp/pdp.h"
54 #include "../gtp/gtp.h"
58 int maxfd
= 0; /* For select() */
60 struct in_addr listen_
;
61 struct in_addr netaddr
, destaddr
, net
, mask
; /* Network interface */
62 struct in_addr dns1
, dns2
; /* PCO DNS address */
63 char *ipup
, *ipdown
; /* Filename of scripts */
64 int debug
; /* Print debug output */
69 struct gsn_t
*gsn
; /* GSN instance */
70 struct tun_t
*tun
; /* TUN instance */
71 struct ippool_t
*ippool
; /* Pool of IP addresses */
73 /* To exit gracefully. Used with GCC compilation flag -pg and gprof */
74 void signal_handler(int s
)
77 printf("Received signal %d, exiting.\n", s
);
81 /* Used to write process ID to file. Assume someone else will delete */
82 void log_pid(char *pidfile
)
88 file
= fopen(pidfile
, "w");
91 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
92 "Failed to create process ID file: %s!", pidfile
);
95 fprintf(file
, "%d\n", (int)getpid());
100 int daemon(int nochdir
, int noclose
)
119 if (!noclose
&& (fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
120 dup2(fd
, STDIN_FILENO
);
121 dup2(fd
, STDOUT_FILENO
);
122 dup2(fd
, STDERR_FILENO
);
130 int encaps_printf(void *p
, void *packet
, unsigned len
)
134 printf("The packet looks like this:\n");
135 for (i
= 0; i
< len
; i
++) {
136 printf("%02x ", (unsigned char)*(char *)(packet
+ i
));
145 int delete_context(struct pdp_t
*pdp
)
148 printf("Deleting PDP context\n");
150 ippool_freeip(ippool
, (struct ippoolm_t
*)pdp
->peer
);
152 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "Peer not defined!");
156 int create_context_ind(struct pdp_t
*pdp
)
159 struct ippoolm_t
*member
;
162 printf("Received create PDP context request\n");
164 pdp
->eua
.l
= 0; /* TODO: Indicates dynamic IP */
166 /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
167 memcpy(pdp
->qos_neg0
, pdp
->qos_req0
, sizeof(pdp
->qos_req0
));
168 memcpy(&pdp
->pco_neg
, &pco
, sizeof(pdp
->pco_neg
));
170 memcpy(pdp
->qos_neg
.v
, pdp
->qos_req
.v
, pdp
->qos_req
.l
); /* TODO */
171 pdp
->qos_neg
.l
= pdp
->qos_req
.l
;
173 if (pdp_euaton(&pdp
->eua
, &addr
)) {
174 addr
.s_addr
= 0; /* Request dynamic */
177 if (ippool_newip(ippool
, &member
, &addr
, 0)) {
178 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_NO_RESOURCES
);
179 return 0; /* Allready in use, or no more available */
182 pdp_ntoeua(&member
->addr
, &pdp
->eua
);
184 pdp
->ipif
= tun
; /* TODO */
187 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_ACC_REQ
);
188 return 0; /* Success */
191 /* Callback for receiving messages from tun */
192 int cb_tun_ind(struct tun_t
*tun
, void *pack
, unsigned len
)
194 struct ippoolm_t
*ipm
;
196 struct tun_packet_t
*iph
= (struct tun_packet_t
*)pack
;
198 dst
.s_addr
= iph
->dst
;
201 printf("Received packet from tun!\n");
203 if (ippool_getip(ippool
, &ipm
, &dst
)) {
205 printf("Received packet with no destination!!!\n");
209 if (ipm
->peer
) /* Check if a peer protocol is defined */
210 gtp_data_req(gsn
, (struct pdp_t
*)ipm
->peer
, pack
, len
);
214 int encaps_tun(struct pdp_t
*pdp
, void *pack
, unsigned len
)
217 printf("encaps_tun. Packet received: forwarding to tun\n");
218 return tun_encaps((struct tun_t
*)pdp
->ipif
, pack
, len
);
221 int main(int argc
, char **argv
)
223 /* gengeopt declarations */
224 struct gengetopt_args_info args_info
;
226 struct hostent
*host
;
228 /* Handle keyboard interrupt SIGINT */
230 s
.sa_handler
= (void *)signal_handler
;
231 if ((0 != sigemptyset(&s
.sa_mask
)) && debug
)
232 printf("sigemptyset failed.\n");
233 s
.sa_flags
= SA_RESETHAND
;
234 if ((sigaction(SIGINT
, &s
, NULL
) != 0) && debug
)
235 printf("Could not register SIGINT signal handler.\n");
237 fd_set fds
; /* For select() */
238 struct timeval idleTime
; /* How long to select() */
240 int timelimit
; /* Number of seconds to be connected */
241 int starttime
; /* Time program was started */
243 /* open a connection to the syslog daemon */
244 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON); */
246 /* TODO: Only use LOG__PERROR for linux */
248 openlog(PACKAGE
, (LOG_PID
| LOG_PERROR
), LOG_DAEMON
);
250 openlog(PACKAGE
, (LOG_PID
), LOG_DAEMON
);
253 if (cmdline_parser(argc
, argv
, &args_info
) != 0)
255 if (args_info
.debug_flag
) {
256 printf("listen: %s\n", args_info
.listen_arg
);
257 if (args_info
.conf_arg
)
258 printf("conf: %s\n", args_info
.conf_arg
);
259 printf("fg: %d\n", args_info
.fg_flag
);
260 printf("debug: %d\n", args_info
.debug_flag
);
261 printf("qos: %#08x\n", args_info
.qos_arg
);
262 if (args_info
.apn_arg
)
263 printf("apn: %s\n", args_info
.apn_arg
);
264 if (args_info
.net_arg
)
265 printf("net: %s\n", args_info
.net_arg
);
266 if (args_info
.dynip_arg
)
267 printf("dynip: %s\n", args_info
.dynip_arg
);
268 if (args_info
.statip_arg
)
269 printf("statip: %s\n", args_info
.statip_arg
);
270 if (args_info
.ipup_arg
)
271 printf("ipup: %s\n", args_info
.ipup_arg
);
272 if (args_info
.ipdown_arg
)
273 printf("ipdown: %s\n", args_info
.ipdown_arg
);
274 if (args_info
.pidfile_arg
)
275 printf("pidfile: %s\n", args_info
.pidfile_arg
);
276 if (args_info
.statedir_arg
)
277 printf("statedir: %s\n", args_info
.statedir_arg
);
278 printf("timelimit: %d\n", args_info
.timelimit_arg
);
281 /* Try out our new parser */
283 if (cmdline_parser_configfile(args_info
.conf_arg
, &args_info
, 0, 0, 0)
286 if (args_info
.debug_flag
) {
287 printf("cmdline_parser_configfile\n");
288 printf("listen: %s\n", args_info
.listen_arg
);
289 printf("conf: %s\n", args_info
.conf_arg
);
290 printf("fg: %d\n", args_info
.fg_flag
);
291 printf("debug: %d\n", args_info
.debug_flag
);
292 printf("qos: %#08x\n", args_info
.qos_arg
);
293 if (args_info
.apn_arg
)
294 printf("apn: %s\n", args_info
.apn_arg
);
295 if (args_info
.net_arg
)
296 printf("net: %s\n", args_info
.net_arg
);
297 if (args_info
.dynip_arg
)
298 printf("dynip: %s\n", args_info
.dynip_arg
);
299 if (args_info
.statip_arg
)
300 printf("statip: %s\n", args_info
.statip_arg
);
301 if (args_info
.ipup_arg
)
302 printf("ipup: %s\n", args_info
.ipup_arg
);
303 if (args_info
.ipdown_arg
)
304 printf("ipdown: %s\n", args_info
.ipdown_arg
);
305 if (args_info
.pidfile_arg
)
306 printf("pidfile: %s\n", args_info
.pidfile_arg
);
307 if (args_info
.statedir_arg
)
308 printf("statedir: %s\n", args_info
.statedir_arg
);
309 printf("timelimit: %d\n", args_info
.timelimit_arg
);
312 /* Handle each option */
315 debug
= args_info
.debug_flag
;
318 /* Do hostname lookup to translate hostname to IP address */
319 /* Any port listening is not possible as a valid address is */
320 /* required for create_pdp_context_response messages */
321 if (args_info
.listen_arg
) {
322 if (!(host
= gethostbyname(args_info
.listen_arg
))) {
323 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
324 "Invalid listening address: %s!",
325 args_info
.listen_arg
);
328 memcpy(&listen_
.s_addr
, host
->h_addr
, host
->h_length
);
331 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
332 "Listening address must be specified! "
333 "Please use command line option --listen or "
334 "edit %s configuration file\n", args_info
.conf_arg
);
339 /* Store net as in_addr net and mask */
340 if (args_info
.net_arg
) {
341 if (ippool_aton(&net
, &mask
, args_info
.net_arg
, 0)) {
342 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
343 "Invalid network address: %s!",
347 netaddr
.s_addr
= htonl(ntohl(net
.s_addr
) + 1);
348 destaddr
.s_addr
= htonl(ntohl(net
.s_addr
) + 1);
350 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
351 "Network address must be specified: %s!",
357 if (!args_info
.dynip_arg
) {
358 if (ippool_new(&ippool
, args_info
.net_arg
, NULL
, 1, 0,
359 IPPOOL_NONETWORK
| IPPOOL_NOGATEWAY
|
360 IPPOOL_NOBROADCAST
)) {
361 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
362 "Failed to allocate IP pool!");
366 if (ippool_new(&ippool
, args_info
.dynip_arg
, NULL
, 1, 0,
367 IPPOOL_NONETWORK
| IPPOOL_NOGATEWAY
|
368 IPPOOL_NOBROADCAST
)) {
369 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
370 "Failed to allocate IP pool!");
376 #ifdef HAVE_INET_ATON
378 if (args_info
.pcodns1_arg
) {
379 if (0 == inet_aton(args_info
.pcodns1_arg
, &dns1
)) {
380 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
381 "Failed to convert pcodns1!");
386 if (args_info
.pcodns2_arg
) {
387 if (0 == inet_aton(args_info
.pcodns2_arg
, &dns2
)) {
388 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
389 "Failed to convert pcodns2!");
395 if (args_info
.pcodns1_arg
) {
396 dns1
.s_addr
= inet_addr(args_info
.pcodns1_arg
);
397 if (dns1
.s_addr
== -1) {
398 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
399 "Failed to convert pcodns1!");
404 if (args_info
.pcodns2_arg
) {
405 dns2
.s_addr
= inet_addr(args_info
.pcodns2_arg
);
406 if (dns2
.s_addr
== -1) {
407 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
408 "Failed to convert pcodns2!");
415 pco
.v
[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
416 pco
.v
[1] = 0x80; /* IPCP */
418 pco
.v
[3] = 0x10; /* Length of contents */
419 pco
.v
[4] = 0x02; /* ACK */
420 pco
.v
[5] = 0x00; /* ID: Need to match request */
421 pco
.v
[6] = 0x00; /* Length */
423 pco
.v
[8] = 0x81; /* DNS 1 */
425 memcpy(&pco
.v
[10], &dns1
, sizeof(dns1
));
427 pco
.v
[15] = 0x06; /* DNS 2 */
428 memcpy(&pco
.v
[16], &dns2
, sizeof(dns2
));
431 ipup
= args_info
.ipup_arg
;
434 ipdown
= args_info
.ipdown_arg
;
437 timelimit
= args_info
.timelimit_arg
;
438 starttime
= time(NULL
);
442 qos
.v
[2] = (args_info
.qos_arg
) & 0xff;
443 qos
.v
[1] = ((args_info
.qos_arg
) >> 8) & 0xff;
444 qos
.v
[0] = ((args_info
.qos_arg
) >> 16) & 0xff;
447 if (strlen(args_info
.apn_arg
) > (sizeof(apn
.v
) - 1)) {
448 printf("Invalid APN\n");
451 apn
.l
= strlen(args_info
.apn_arg
) + 1;
452 apn
.v
[0] = (char)strlen(args_info
.apn_arg
);
453 strncpy((char *)&apn
.v
[1], args_info
.apn_arg
, sizeof(apn
.v
) - 1);
456 /* If flag not given run as a daemon */
457 if (!args_info
.fg_flag
) {
461 /* Close the standard file descriptors. */
462 /* Is this really needed ? */
463 f
= freopen("/dev/null", "w", stdout
);
465 sys_err(LOG_WARNING
, __FILE__
, __LINE__
, 0,
466 "Could not redirect stdout to /dev/null");
468 f
= freopen("/dev/null", "w", stderr
);
470 sys_err(LOG_WARNING
, __FILE__
, __LINE__
, 0,
471 "Could not redirect stderr to /dev/null");
473 f
= freopen("/dev/null", "r", stdin
);
475 sys_err(LOG_WARNING
, __FILE__
, __LINE__
, 0,
476 "Could not redirect stdin to /dev/null");
480 sys_err(LOG_ERR
, __FILE__
, __LINE__
, rc
,
481 "Could not daemonize");
484 /* Open log again. This time with new pid */
485 openlog(PACKAGE
, LOG_PID
, LOG_DAEMON
);
489 /* This has to be done after we have our final pid */
490 if (args_info
.pidfile_arg
) {
491 log_pid(args_info
.pidfile_arg
);
495 printf("gtpclient: Initialising GTP tunnel\n");
497 if (gtp_new(&gsn
, args_info
.statedir_arg
, &listen_
, GTP_MODE_GGSN
)) {
498 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "Failed to create gtp");
501 if (gsn
->fd0
> maxfd
)
503 if (gsn
->fd1c
> maxfd
)
505 if (gsn
->fd1u
> maxfd
)
508 gtp_set_cb_data_ind(gsn
, encaps_tun
);
509 gtp_set_cb_delete_context(gsn
, delete_context
);
510 gtp_set_cb_create_context_ind(gsn
, create_context_ind
);
512 /* Create a tunnel interface */
514 printf("Creating tun interface\n");
515 if (tun_new((struct tun_t
**)&tun
)) {
516 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0, "Failed to create tun");
518 printf("Failed to create tun\n");
523 printf("Setting tun IP address\n");
524 if (tun_setaddr(tun
, &netaddr
, &destaddr
, &mask
)) {
525 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
526 "Failed to set tun IP address");
528 printf("Failed to set tun IP address\n");
532 tun_set_cb_ind(tun
, cb_tun_ind
);
537 tun_runscript(tun
, ipup
);
539 /******************************************************************/
540 /* Main select loop */
541 /******************************************************************/
543 while ((((starttime
+ timelimit
) > time(NULL
)) || (0 == timelimit
))
548 FD_SET(tun
->fd
, &fds
);
549 FD_SET(gsn
->fd0
, &fds
);
550 FD_SET(gsn
->fd1c
, &fds
);
551 FD_SET(gsn
->fd1u
, &fds
);
553 gtp_retranstimeout(gsn
, &idleTime
);
554 switch (select(maxfd
+ 1, &fds
, NULL
, NULL
, &idleTime
)) {
555 case -1: /* errno == EINTR : unblocked signal */
556 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
557 "select() returned -1");
558 /* On error, select returns without modifying fds */
562 /* printf("Select returned 0\n"); */
563 gtp_retrans(gsn
); /* Only retransmit if nothing else */
569 if (tun
->fd
!= -1 && FD_ISSET(tun
->fd
, &fds
) &&
570 tun_decaps(tun
) < 0) {
571 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
572 "TUN read failed (fd)=(%d)", tun
->fd
);
575 if (FD_ISSET(gsn
->fd0
, &fds
))
578 if (FD_ISSET(gsn
->fd1c
, &fds
))
581 if (FD_ISSET(gsn
->fd1u
, &fds
))
586 cmdline_parser_free(&args_info
);