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"
22 #include <osmocom/core/application.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 #include <netinet/ip6.h>
39 #include <arpa/inet.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
54 #include <osmocom/core/select.h>
55 #include <osmocom/ctrl/control_if.h>
56 #include <osmocom/ctrl/control_cmd.h>
57 #include <osmocom/ctrl/ports.h>
59 #include "../lib/tun.h"
60 #include "../lib/ippool.h"
61 #include "../lib/syserr.h"
62 #include "../lib/in46_addr.h"
63 #include "../gtp/pdp.h"
64 #include "../gtp/gtp.h"
66 #include "gtp-kernel.h"
70 int maxfd
= 0; /* For select() */
72 struct in_addr listen_
;
73 struct in46_addr netaddr
, destaddr
, net
; /* Network interface */
75 struct in46_addr dns1
, dns2
; /* PCO DNS address */
76 char *ipup
, *ipdown
; /* Filename of scripts */
77 int debug
; /* Print debug output */
82 struct gsn_t
*gsn
; /* GSN instance */
83 struct tun_t
*tun
; /* TUN instance */
84 struct ippool_t
*ippool
; /* Pool of IP addresses */
86 /* To exit gracefully. Used with GCC compilation flag -pg and gprof */
87 void signal_handler(int s
)
89 DEBUGP(DGGSN
, "Received signal %d, exiting.\n", s
);
93 /* Used to write process ID to file. Assume someone else will delete */
94 void log_pid(char *pidfile
)
100 file
= fopen(pidfile
, "w");
103 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
104 "Failed to create process ID file: %s!", pidfile
);
107 fprintf(file
, "%d\n", (int)getpid());
112 int daemon(int nochdir
, int noclose
)
131 if (!noclose
&& (fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
132 dup2(fd
, STDIN_FILENO
);
133 dup2(fd
, STDOUT_FILENO
);
134 dup2(fd
, STDERR_FILENO
);
142 static bool send_trap(const struct gsn_t
*gsn
, const struct pdp_t
*pdp
, const struct ippoolm_t
*member
, const char *var
)
147 const char *addrstr
= in46a_ntop(&member
->addr
, addrbuf
, sizeof(addrbuf
));
149 snprintf(val
, sizeof(val
), "%s,%s", imsi_gtp2str(&pdp
->imsi
), addrstr
);
151 if (ctrl_cmd_send_trap(gsn
->priv
, var
, val
) < 0) {
152 LOGP(DGGSN
, LOGL_ERROR
, "Failed to create and send TRAP for IMSI %" PRIu64
" [%s].\n", pdp
->imsi
, var
);
158 int delete_context(struct pdp_t
*pdp
)
160 DEBUGP(DGGSN
, "Deleting PDP context\n");
161 struct ippoolm_t
*member
= pdp
->peer
;
164 send_trap(gsn
, pdp
, member
, "imsi-rem-ip"); /* TRAP with IP removal */
165 ippool_freeip(ippool
, (struct ippoolm_t
*)pdp
->peer
);
167 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Peer not defined!");
169 if (gtp_kernel_tunnel_del(pdp
)) {
170 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
171 "Cannot delete tunnel from kernel: %s\n",
178 #include <osmocom/gsm/tlv.h>
180 /* 3GPP TS 24.008 10.6.5.3 */
186 PCO_P_PCSCF_ADDR
= 0x0001,
187 PCO_P_IM_CN_SS_F
= 0x0002,
188 PCO_P_DNS_IPv6_ADDR
= 0x0003,
189 PCO_P_POLICY_CTRL_REJ
= 0x0004, /* only in Network->MS */
190 PCO_P_MS_SUP_NETREQ_BCI
= 0x0005,
192 PCO_P_DSMIPv6_HA_ADDR
= 0x0007,
193 PCO_P_DSMIPv6_HN_PREF
= 0x0008,
194 PCO_P_DSMIPv6_v4_HA_ADDR
= 0x0009,
195 PCO_P_IP_ADDR_VIA_NAS
= 0x000a, /* only MS->Network */
196 PCO_P_IPv4_ADDR_VIA_DHCP
= 0x000b, /* only MS->Netowrk */
197 PCO_P_PCSCF_IPv4_ADDR
= 0x000c,
198 PCO_P_DNS_IPv4_ADDR
= 0x000d,
199 PCO_P_MSISDN
= 0x000e,
200 PCO_P_IFOM_SUPPORT
= 0x000f,
201 PCO_P_IPv4_LINK_MTU
= 0x0010,
202 PCO_P_MS_SUPP_LOC_A_TFT
= 0x0011,
203 PCO_P_PCSCF_RESEL_SUP
= 0x0012, /* only MS->Network */
204 PCO_P_NBIFOM_REQ
= 0x0013,
205 PCO_P_NBIFOM_MODE
= 0x0014,
206 PCO_P_NONIP_LINK_MTU
= 0x0015,
207 PCO_P_APN_RATE_CTRL_SUP
= 0x0016,
208 PCO_P_PS_DATA_OFF_UE
= 0x0017,
209 PCO_P_REL_DATA_SVC
= 0x0018,
212 /* determine if PCO contains given protocol */
213 static bool pco_contains_proto(struct ul255_t
*pco
, uint16_t prot
)
215 uint8_t *cur
= pco
->v
+ 1;
217 /* iterate over PCO and check if protocol contained */
218 while (cur
+ 3 <= pco
->v
+ pco
->l
) {
219 uint16_t cur_prot
= osmo_load16be(cur
);
220 uint8_t cur_len
= cur
[2];
221 if (cur_prot
== prot
)
230 /* determine if PDP context has IPv6 support */
231 static bool pdp_has_v4(struct pdp_t
*pdp
)
233 if (pdp
->eua
.l
== 4+2)
239 /* process one PCO request from a MS/UE, putting together the proper responses */
240 static void process_pco(struct pdp_t
*pdp
)
242 struct msgb
*msg
= msgb_alloc(256, "PCO");
243 msgb_put_u8(msg
, 0x80); /* ext-bit + configuration protocol byte */
245 /* FIXME: also check if primary / secondary DNS was requested */
246 if (pdp_has_v4(pdp
) && pco_contains_proto(&pdp
->pco_req
, PCO_P_IPCP
)) {
247 /* FIXME: properly implement this for IPCP */
248 uint8_t *cur
= msgb_put(msg
, pco
.l
-1);
249 memcpy(cur
, pco
.v
+1, pco
.l
-1);
252 if (pco_contains_proto(&pdp
->pco_req
, PCO_P_DNS_IPv6_ADDR
)) {
254 msgb_t16lv_put(msg
, PCO_P_DNS_IPv6_ADDR
, dns1
.len
, dns1
.v6
.s6_addr
);
256 msgb_t16lv_put(msg
, PCO_P_DNS_IPv6_ADDR
, dns2
.len
, dns2
.v6
.s6_addr
);
259 if (pco_contains_proto(&pdp
->pco_req
, PCO_P_DNS_IPv4_ADDR
)) {
261 msgb_t16lv_put(msg
, PCO_P_DNS_IPv4_ADDR
, dns1
.len
, (uint8_t *)&dns1
.v4
);
263 msgb_t16lv_put(msg
, PCO_P_DNS_IPv4_ADDR
, dns2
.len
, (uint8_t *)&dns2
.v4
);
266 if (msgb_length(msg
) > 1) {
267 memcpy(pdp
->pco_neg
.v
, msgb_data(msg
), msgb_length(msg
));
268 pdp
->pco_neg
.l
= msgb_length(msg
);
275 int create_context_ind(struct pdp_t
*pdp
)
277 struct in46_addr addr
;
278 struct ippoolm_t
*member
;
281 DEBUGP(DGGSN
, "Received create PDP context request\n");
283 /* FIXME: we manually force all context requests to dynamic here! */
287 memcpy(pdp
->qos_neg0
, pdp
->qos_req0
, sizeof(pdp
->qos_req0
));
289 memcpy(pdp
->qos_neg
.v
, pdp
->qos_req
.v
, pdp
->qos_req
.l
); /* TODO */
290 pdp
->qos_neg
.l
= pdp
->qos_req
.l
;
292 if (in46a_from_eua(&pdp
->eua
, &addr
)) {
293 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Cannot decode EUA from MS/SGSN: %s",
294 osmo_hexdump(pdp
->eua
.v
, pdp
->eua
.l
));
295 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_UNKNOWN_PDP
);
299 rc
= ippool_newip(ippool
, &member
, &addr
, 0);
301 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Cannot allocate IP address in pool\n");
302 gtp_create_context_resp(gsn
, pdp
, -rc
);
303 return 0; /* Allready in use, or no more available */
306 if (addr
.len
== sizeof(struct in6_addr
)) {
307 struct in46_addr tmp
;
308 /* IPv6 doesn't really send the real/allocated address at this point, but just
309 * the link-identifier which the MS shall use for router solicitation */
311 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
312 memcpy(tmp
.v6
.s6_addr
, &member
->addr
.v6
, 8);
313 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
314 memcpy(tmp
.v6
.s6_addr
+8, &member
->addr
.v6
, 8);
315 in46a_to_eua(&tmp
, &pdp
->eua
);
317 in46a_to_eua(&member
->addr
, &pdp
->eua
);
319 pdp
->ipif
= tun
; /* TODO */
322 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
323 if (gtp_kernel_tunnel_add(pdp
) < 0) {
324 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
325 "Cannot add tunnel to kernel: %s\n", strerror(errno
));
326 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_SYS_FAIL
);
330 if (!send_trap(gsn
, pdp
, member
, "imsi-ass-ip")) { /* TRAP with IP assignment */
331 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_NO_RESOURCES
);
337 gtp_create_context_resp(gsn
, pdp
, GTPCAUSE_ACC_REQ
);
338 return 0; /* Success */
341 /* Callback for receiving messages from tun */
342 int cb_tun_ind(struct tun_t
*tun
, void *pack
, unsigned len
)
344 struct ippoolm_t
*ipm
;
345 struct in46_addr dst
;
346 struct iphdr
*iph
= (struct iphdr
*)pack
;
347 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*)pack
;
349 if (iph
->version
== 4) {
350 if (len
< sizeof(*iph
) || len
< 4*iph
->ihl
)
353 dst
.v4
.s_addr
= iph
->daddr
;
354 } else if (iph
->version
== 6) {
355 /* Due to the fact that 3GPP requires an allocation of a
356 * /64 prefix to each MS, we must instruct
357 * ippool_getip() below to match only the leading /64
358 * prefix, i.e. the first 8 bytes of the address */
360 dst
.v6
= ip6h
->ip6_dst
;
362 LOGP(DGGSN
, LOGL_NOTICE
, "non-IPv packet received from tun\n");
366 DEBUGP(DGGSN
, "Received packet from tun!\n");
368 if (ippool_getip(ippool
, &ipm
, &dst
)) {
369 DEBUGP(DGGSN
, "Received packet with no destination!!!\n");
373 if (ipm
->peer
) /* Check if a peer protocol is defined */
374 gtp_data_req(gsn
, (struct pdp_t
*)ipm
->peer
, pack
, len
);
378 /* RFC3307 link-local scope multicast address */
379 static const struct in6_addr all_router_mcast_addr
= {
380 .s6_addr
= { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
383 int encaps_tun(struct pdp_t
*pdp
, void *pack
, unsigned len
)
385 struct iphdr
*iph
= (struct iphdr
*)pack
;
386 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*)pack
;
388 DEBUGP(DGGSN
, "encaps_tun. Packet received: forwarding to tun\n");
390 switch (iph
->version
) {
392 /* daddr: all-routers multicast addr */
393 if (IN6_ARE_ADDR_EQUAL(&ip6h
->ip6_dst
, &all_router_mcast_addr
))
394 return handle_router_mcast(gsn
, pdp
, pack
, len
);
399 LOGP(DGGSN
, LOGL_ERROR
, "Packet from MS is neither IPv4 nor IPv6\n");
402 return tun_encaps((struct tun_t
*)pdp
->ipif
, pack
, len
);
405 int main(int argc
, char **argv
)
407 /* gengeopt declarations */
408 struct gengetopt_args_info args_info
;
410 struct hostent
*host
;
412 /* Handle keyboard interrupt SIGINT */
414 s
.sa_handler
= (void *)signal_handler
;
415 if ((0 != sigemptyset(&s
.sa_mask
)) && debug
)
416 printf("sigemptyset failed.\n");
417 s
.sa_flags
= SA_RESETHAND
;
418 if ((sigaction(SIGINT
, &s
, NULL
) != 0) && debug
)
419 printf("Could not register SIGINT signal handler.\n");
421 fd_set fds
; /* For select() */
422 struct timeval idleTime
; /* How long to select() */
424 int timelimit
; /* Number of seconds to be connected */
425 int starttime
; /* Time program was started */
427 osmo_init_logging(&log_info
);
429 if (cmdline_parser(argc
, argv
, &args_info
) != 0)
431 if (args_info
.debug_flag
) {
432 printf("listen: %s\n", args_info
.listen_arg
);
433 if (args_info
.conf_arg
)
434 printf("conf: %s\n", args_info
.conf_arg
);
435 printf("fg: %d\n", args_info
.fg_flag
);
436 printf("debug: %d\n", args_info
.debug_flag
);
437 printf("qos: %#08x\n", args_info
.qos_arg
);
438 if (args_info
.apn_arg
)
439 printf("apn: %s\n", args_info
.apn_arg
);
440 if (args_info
.net_arg
)
441 printf("net: %s\n", args_info
.net_arg
);
442 if (args_info
.dynip_arg
)
443 printf("dynip: %s\n", args_info
.dynip_arg
);
444 if (args_info
.statip_arg
)
445 printf("statip: %s\n", args_info
.statip_arg
);
446 if (args_info
.ipup_arg
)
447 printf("ipup: %s\n", args_info
.ipup_arg
);
448 if (args_info
.ipdown_arg
)
449 printf("ipdown: %s\n", args_info
.ipdown_arg
);
450 if (args_info
.pidfile_arg
)
451 printf("pidfile: %s\n", args_info
.pidfile_arg
);
452 if (args_info
.statedir_arg
)
453 printf("statedir: %s\n", args_info
.statedir_arg
);
454 if (args_info
.gtp_linux_flag
)
455 printf("gtp_linux: %d\n", args_info
.gtp_linux_flag
);
456 printf("timelimit: %d\n", args_info
.timelimit_arg
);
459 /* Try out our new parser */
461 if (cmdline_parser_configfile(args_info
.conf_arg
, &args_info
, 0, 0, 0)
465 /* Open a log file */
466 if (args_info
.logfile_arg
) {
467 struct log_target
*tgt
;
470 tgt
= log_target_find(LOG_TGT_TYPE_FILE
, args_info
.logfile_arg
);
472 tgt
= log_target_create_file(args_info
.logfile_arg
);
474 LOGP(DGGSN
, LOGL_ERROR
,
475 "Failed to create logfile: %s\n",
476 args_info
.logfile_arg
);
481 log_set_all_filter(tgt
, 1);
482 log_set_use_color(tgt
, 0);
484 if (args_info
.loglevel_arg
) {
485 lvl
= log_parse_level(args_info
.loglevel_arg
);
486 log_set_log_level(tgt
, lvl
);
487 LOGP(DGGSN
, LOGL_NOTICE
,
488 "Set file log level to %s\n",
493 if (args_info
.debug_flag
) {
494 printf("cmdline_parser_configfile\n");
495 printf("listen: %s\n", args_info
.listen_arg
);
496 printf("conf: %s\n", args_info
.conf_arg
);
497 printf("fg: %d\n", args_info
.fg_flag
);
498 printf("debug: %d\n", args_info
.debug_flag
);
499 printf("qos: %#08x\n", args_info
.qos_arg
);
500 if (args_info
.apn_arg
)
501 printf("apn: %s\n", args_info
.apn_arg
);
502 if (args_info
.net_arg
)
503 printf("net: %s\n", args_info
.net_arg
);
504 if (args_info
.dynip_arg
)
505 printf("dynip: %s\n", args_info
.dynip_arg
);
506 if (args_info
.statip_arg
)
507 printf("statip: %s\n", args_info
.statip_arg
);
508 if (args_info
.ipup_arg
)
509 printf("ipup: %s\n", args_info
.ipup_arg
);
510 if (args_info
.ipdown_arg
)
511 printf("ipdown: %s\n", args_info
.ipdown_arg
);
512 if (args_info
.pidfile_arg
)
513 printf("pidfile: %s\n", args_info
.pidfile_arg
);
514 if (args_info
.statedir_arg
)
515 printf("statedir: %s\n", args_info
.statedir_arg
);
516 if (args_info
.gtp_linux_flag
)
517 printf("gtp-linux: %d\n", args_info
.gtp_linux_flag
);
518 printf("timelimit: %d\n", args_info
.timelimit_arg
);
521 /* Handle each option */
524 debug
= args_info
.debug_flag
;
527 /* Do hostname lookup to translate hostname to IP address */
528 /* Any port listening is not possible as a valid address is */
529 /* required for create_pdp_context_response messages */
530 if (args_info
.listen_arg
) {
531 if (!(host
= gethostbyname(args_info
.listen_arg
))) {
532 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
533 "Invalid listening address: %s!",
534 args_info
.listen_arg
);
537 memcpy(&listen_
.s_addr
, host
->h_addr
, host
->h_length
);
540 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
541 "Listening address must be specified! "
542 "Please use command line option --listen or "
543 "edit %s configuration file\n", args_info
.conf_arg
);
548 /* Store net as in_addr net and mask */
549 if (args_info
.net_arg
) {
550 if (ippool_aton(&net
, &prefixlen
, args_info
.net_arg
, 0)) {
551 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
552 "Invalid network address: %s!",
556 /* default for network + destination address = net + 1 */
561 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
562 "Network address must be specified: %s!",
568 struct in46_prefix i46p
;
570 if (!args_info
.dynip_arg
) {
571 if (ippool_aton(&i46p
.addr
, &prefixlen
, args_info
.net_arg
, 0)) {
572 SYS_ERR(DIP
, LOGL_ERROR
, 0, "Failed to parse dynamic pool");
576 if (ippool_aton(&i46p
.addr
, &prefixlen
, args_info
.dynip_arg
, 0)) {
577 SYS_ERR(DIP
, LOGL_ERROR
, 0, "Failed to parse dynamic pool");
581 i46p
.prefixlen
= prefixlen
;
582 if (ippool_new(&ippool
, &i46p
, NULL
, IPPOOL_NONETWORK
| IPPOOL_NOGATEWAY
| IPPOOL_NOBROADCAST
)) {
583 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Failed to allocate IP pool!");
588 memset(&dns1
, 0, sizeof(dns1
));
589 if (args_info
.pcodns1_arg
) {
591 if (ippool_aton(&dns1
, &tmp
, args_info
.pcodns1_arg
, 0) != 0) {
592 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
593 "Failed to convert pcodns1!");
597 memset(&dns2
, 0, sizeof(dns2
));
598 if (args_info
.pcodns2_arg
) {
600 if (ippool_aton(&dns2
, &tmp
, args_info
.pcodns2_arg
, 0) != 0) {
601 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
602 "Failed to convert pcodns2!");
607 unsigned int cur
= 0;
608 pco
.v
[cur
++] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
609 pco
.v
[cur
++] = 0x80; /* IPCP */
611 pco
.v
[cur
++] = 0xFF; /* Length of contents */
612 pco
.v
[cur
++] = 0x02; /* ACK */
613 pco
.v
[cur
++] = 0x00; /* ID: Need to match request */
614 pco
.v
[cur
++] = 0x00; /* Length */
615 pco
.v
[cur
++] = 0xFF; /* overwritten */
617 pco
.v
[cur
++] = 0x81; /* DNS 1 */
618 pco
.v
[cur
++] = 2 + dns1
.len
;
620 memcpy(&pco
.v
[cur
], &dns1
.v4
, dns1
.len
);
622 memcpy(&pco
.v
[cur
], &dns1
.v6
, dns1
.len
);
627 pco
.v
[cur
++] = 2 + dns2
.len
; /* DNS 2 */
629 memcpy(&pco
.v
[cur
], &dns2
.v4
, dns2
.len
);
631 memcpy(&pco
.v
[cur
], &dns2
.v6
, dns2
.len
);
635 /* patch in length values */
636 pco
.v
[3] = pco
.l
- 4;
637 pco
.v
[7] = pco
.l
- 4;
640 ipup
= args_info
.ipup_arg
;
643 ipdown
= args_info
.ipdown_arg
;
646 timelimit
= args_info
.timelimit_arg
;
647 starttime
= time(NULL
);
651 qos
.v
[2] = (args_info
.qos_arg
) & 0xff;
652 qos
.v
[1] = ((args_info
.qos_arg
) >> 8) & 0xff;
653 qos
.v
[0] = ((args_info
.qos_arg
) >> 16) & 0xff;
656 if (strlen(args_info
.apn_arg
) > (sizeof(apn
.v
) - 1)) {
657 LOGP(DGGSN
, LOGL_ERROR
, "Invalid APN\n");
660 apn
.l
= strlen(args_info
.apn_arg
) + 1;
661 apn
.v
[0] = (char)strlen(args_info
.apn_arg
);
662 strncpy((char *)&apn
.v
[1], args_info
.apn_arg
, sizeof(apn
.v
) - 1);
665 /* If flag not given run as a daemon */
666 if (!args_info
.fg_flag
) {
669 /* Close the standard file descriptors. */
670 /* Is this really needed ? */
671 f
= freopen("/dev/null", "w", stdout
);
673 SYS_ERR(DGGSN
, LOGL_NOTICE
, 0,
674 "Could not redirect stdout to /dev/null");
676 f
= freopen("/dev/null", "w", stderr
);
678 SYS_ERR(DGGSN
, LOGL_NOTICE
, 0,
679 "Could not redirect stderr to /dev/null");
681 f
= freopen("/dev/null", "r", stdin
);
683 SYS_ERR(DGGSN
, LOGL_NOTICE
, 0,
684 "Could not redirect stdin to /dev/null");
688 SYS_ERR(DGGSN
, LOGL_ERROR
, rc
,
689 "Could not daemonize");
695 /* This has to be done after we have our final pid */
696 if (args_info
.pidfile_arg
) {
697 log_pid(args_info
.pidfile_arg
);
700 DEBUGP(DGGSN
, "gtpclient: Initialising GTP tunnel\n");
702 if (gtp_new(&gsn
, args_info
.statedir_arg
, &listen_
, GTP_MODE_GGSN
)) {
703 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Failed to create gtp");
706 if (gsn
->fd0
> maxfd
)
708 if (gsn
->fd1c
> maxfd
)
710 if (gsn
->fd1u
> maxfd
)
713 /* use GTP kernel module for data packet encapsulation */
714 if (args_info
.gtp_linux_given
) {
715 if (gtp_kernel_init(gsn
, &net
.v4
, prefixlen
, args_info
.net_arg
) < 0) {
716 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Failed to initialize kernel GTP\n");
721 gtp_set_cb_data_ind(gsn
, encaps_tun
);
722 gtp_set_cb_delete_context(gsn
, delete_context
);
723 gtp_set_cb_create_context_ind(gsn
, create_context_ind
);
725 gsn
->priv
= ctrl_interface_setup(NULL
, OSMO_CTRL_PORT_GGSN
, NULL
);
727 LOGP(DGGSN
, LOGL_ERROR
, "Failed to create CTRL interface.\n");
731 /* skip the configuration of the tun0 if we're using the gtp0 device */
732 if (gtp_kernel_enabled())
735 /* Create a tunnel interface */
736 DEBUGP(DGGSN
, "Creating tun interface\n");
737 if (tun_new((struct tun_t
**)&tun
)) {
738 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Failed to create tun");
742 DEBUGP(DGGSN
, "Setting tun IP address\n");
743 if (tun_setaddr(tun
, &netaddr
, &destaddr
, prefixlen
)) {
744 SYS_ERR(DGGSN
, LOGL_ERROR
, 0, "Failed to set tun IP address");
748 tun_set_cb_ind(tun
, cb_tun_ind
);
753 tun_runscript(tun
, ipup
);
757 /******************************************************************/
758 /* Main select loop */
759 /******************************************************************/
761 while ((((starttime
+ timelimit
) > time(NULL
)) || (0 == timelimit
))
766 FD_SET(tun
->fd
, &fds
);
767 FD_SET(gsn
->fd0
, &fds
);
768 FD_SET(gsn
->fd1c
, &fds
);
769 FD_SET(gsn
->fd1u
, &fds
);
771 gtp_retranstimeout(gsn
, &idleTime
);
772 switch (select(maxfd
+ 1, &fds
, NULL
, NULL
, &idleTime
)) {
773 case -1: /* errno == EINTR : unblocked signal */
774 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
775 "select() returned -1");
776 /* On error, select returns without modifying fds */
780 /* printf("Select returned 0\n"); */
781 gtp_retrans(gsn
); /* Only retransmit if nothing else */
787 if (tun
&& tun
->fd
!= -1 && FD_ISSET(tun
->fd
, &fds
) &&
788 tun_decaps(tun
) < 0) {
789 SYS_ERR(DGGSN
, LOGL_ERROR
, 0,
790 "TUN read failed (fd)=(%d)", tun
->fd
);
793 if (FD_ISSET(gsn
->fd0
, &fds
))
796 if (FD_ISSET(gsn
->fd1c
, &fds
))
799 if (FD_ISSET(gsn
->fd1u
, &fds
))
806 cmdline_parser_free(&args_info
);