9
0
Fork 0

added ippool.h and ippool.c

This commit is contained in:
jjako 2003-04-11 09:40:12 +00:00
parent afb2a970de
commit a7cd249501
28 changed files with 3248 additions and 1258 deletions

View File

@ -36,13 +36,8 @@ listen 10.0.0.240
# TAG: net
# IP network address of external packet data network
# Used to allocate dynamic IP addresses and set up routing.
#net 192.168.0.0
# TAG: mask
# IP network mask of external packet data network
# Used to allocate dynamic IP addresses and set up routing.
#mask 255.255.255.0
# Used to set up network interface.
#net 192.168.0.0/24
# TAG: ipup
# Script executed after network interface has been brought up.
@ -54,12 +49,36 @@ listen 10.0.0.240
# Executed with the following parameters: <devicename> <ip address>
#ipdown /etc/ggsn/ip-down
# TAG: dynip
# Dynamic IP address pool.
# Used for allocation of dynamic IP address when address is not given
# by HLR or radius server.
#dynip 192.168.0.0/24
# TAG: statip
# Use of this tag is currently UNSUPPORTED
# Static IP address pool.
# Used for allocation of static IP address by means of either HLR or
# radius server.
#statip 192.168.1.0/24
# TAG: pcodns1
# Protocol configuration option domain name system server 1.
#pcodns1 0.0.0.0
# TAG: pcodns2
# Protocol configuration option domain name system server 2.
#pcodns2 0.0.0.0
# TAG: timelimit
# Exit after timelimit seconds.
# Setting timelimit to zero will cause the program not to exit.
#timelimit 0
# TAG: apn
# Use of this tag is EXPERIMENTAL
# Access point name to connect to when run in client mode.
#apn internet
# TAG: qos
# Use of this tag is EXPERIMENTAL
@ -67,12 +86,6 @@ listen 10.0.0.240
# 3 bytes corresponding to ????
#qos 0x0b921f
# TAG: apn
# Use of this tag is EXPERIMENTAL
# Access point name to connect to when run in client mode.
#apn internet

View File

@ -27,13 +27,13 @@ fg
# TAG: statedir
# Directory to use for nonvolatile storage.
# The program must have write access to this directory.
#pidfile ./sgsnemu.pid
#statedir ./
# TAG: dns
# DNS server to use for ns lookups.
# If this tag is not set the system default DNS will be used.
#pidfile ./sgsnemu.pid
#dns 10.1.2.3
# TAG: listen
# Specifies the local IP address to listen to
@ -46,17 +46,10 @@ listen 10.0.0.217
remote 10.0.0.240
# TAG: contexts
# Use of this tag is EXPERIMENTAL
# Number of contexts to establish from the emulator to the ggsn.
# Set this tag to zero to not establish any contexts.
#contexts 1
# TAG: static
# Use of this tag is EXPERIMENTAL
# Use this flag if you do not want to set dynamic tun interfaces.
# If this flag is set a single network interface is established.
#static
# TAG: timelimit
# Disconnect contexts after timelimit seconds, and exit the program.
# Setting timelimit to zero will cause the program not to disconnect.
@ -88,11 +81,17 @@ remote 10.0.0.240
# Password used when run in client mode.
#pwd hemlig
# TAG: createif
# Use this flag if you want to set up a local network interface after
# a PDP context has been established.
#createif
# TAG: defaultroute
# Use this flag if you want to add a default route after a network interface
# had been established.
#defaultroute
# TAG: ipup
# Script executed after network interface has been brought up.
# Executed with the following parameters: <devicename> <ip address>
@ -103,16 +102,6 @@ remote 10.0.0.240
# Executed with the following parameters: <devicename> <ip address>
#ipdown /etc/sgsnemu/ip-down
# TAG: net
# IP network address of external packet data network.
# Only used if the defaultroute flag is set.
#net 0.0.0.0
# TAG: mask
# IP network mask of external packet data network.
# Only used if the defaultroute flag is set.
#mask 0.0.0.0
# TAG: pinghost
# Ping a remote host through a PDP context by using ICMP echo messages.
# If more than one PDP context has been established the ICMP messages will

View File

@ -2,9 +2,9 @@ bin_PROGRAMS = ggsn
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -lgtp -L../gtp
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb -lgtp -L../gtp
ggsn_SOURCES = ggsn.c tun.c tun.h cmdline.c cmdline.h
ggsn_SOURCES = ggsn.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c

View File

@ -89,9 +89,9 @@ bin_PROGRAMS = ggsn
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -lgtp -L../gtp
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb -lgtp -L../gtp
ggsn_SOURCES = ggsn.c tun.c tun.h cmdline.c cmdline.h
ggsn_SOURCES = ggsn.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c
subdir = ggsn
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
@ -99,7 +99,8 @@ CONFIG_CLEAN_FILES =
bin_PROGRAMS = ggsn$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
am_ggsn_OBJECTS = ggsn.$(OBJEXT) tun.$(OBJEXT) cmdline.$(OBJEXT)
am_ggsn_OBJECTS = ggsn.$(OBJEXT) tun.$(OBJEXT) cmdline.$(OBJEXT) \
ippool.$(OBJEXT) syserr.$(OBJEXT)
ggsn_OBJECTS = $(am_ggsn_OBJECTS)
ggsn_LDADD = $(LDADD)
ggsn_DEPENDENCIES =
@ -112,6 +113,7 @@ LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/cmdline.Po ./$(DEPDIR)/ggsn.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/ippool.Po ./$(DEPDIR)/syserr.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/tun.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -174,6 +176,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmdline.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ggsn.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ippool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syserr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Po@am__quote@
distclean-depend:

View File

@ -1,7 +1,7 @@
/*
File autogenerated by gengetopt version 2.8rc
File autogenerated by gengetopt version 2.8
generated with the following command:
../../gengetopt-2.8rc/src/gengetopt --conf-parser
gengetopt --conf-parser
The developers of gengetopt consider the fixed text that goes in all
gengetopt output files to be in the public domain:
@ -50,13 +50,16 @@ cmdline_parser_print_help (void)
printf(" --pidfile=STRING Filename of process id file (default='/var/run/ggsn.pid')\n");
printf(" --statedir=STRING Directory of nonvolatile data (default='/var/lib/ggsn/')\n");
printf(" -lSTRING --listen=STRING Local interface\n");
printf(" -nSTRING --net=STRING Network (default='192.168.0.0')\n");
printf(" --mask=STRING Network mask (default='255.255.255.0')\n");
printf(" -nSTRING --net=STRING Network (default='192.168.0.0/24')\n");
printf(" --ipup=STRING Script to run after link-up\n");
printf(" --ipdown=STRING Script to run after link-down\n");
printf(" --dynip=STRING Dynamic IP address pool (default='192.168.0.0/24')\n");
printf(" --statip=STRING Static IP address pool (default='192.168.1.0/24')\n");
printf(" --pcodns1=STRING PCO DNS Server 1 (default='0.0.0.0')\n");
printf(" --pcodns2=STRING PCO DNS Server 2 (default='0.0.0.0')\n");
printf(" --timelimit=INT Exit after timelimit seconds (default='0')\n");
printf(" -aSTRING --apn=STRING Access point name (default='internet')\n");
printf(" -qINT --qos=INT Requested quality of service (default='0x0b921f')\n");
printf(" --ipup=STRING Script to run after link-up\n");
printf(" --ipdown=STRING Script to run after link-down\n");
}
@ -89,12 +92,15 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->statedir_given = 0 ;
args_info->listen_given = 0 ;
args_info->net_given = 0 ;
args_info->mask_given = 0 ;
args_info->ipup_given = 0 ;
args_info->ipdown_given = 0 ;
args_info->dynip_given = 0 ;
args_info->statip_given = 0 ;
args_info->pcodns1_given = 0 ;
args_info->pcodns2_given = 0 ;
args_info->timelimit_given = 0 ;
args_info->apn_given = 0 ;
args_info->qos_given = 0 ;
args_info->ipup_given = 0 ;
args_info->ipdown_given = 0 ;
#define clear_args() { \
args_info->fg_flag = 0;\
args_info->debug_flag = 0;\
@ -102,13 +108,16 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->pidfile_arg = strdup("/var/run/ggsn.pid") ;\
args_info->statedir_arg = strdup("/var/lib/ggsn/") ;\
args_info->listen_arg = NULL; \
args_info->net_arg = strdup("192.168.0.0") ;\
args_info->mask_arg = strdup("255.255.255.0") ;\
args_info->net_arg = strdup("192.168.0.0/24") ;\
args_info->ipup_arg = NULL; \
args_info->ipdown_arg = NULL; \
args_info->dynip_arg = strdup("192.168.0.0/24") ;\
args_info->statip_arg = strdup("192.168.1.0/24") ;\
args_info->pcodns1_arg = strdup("0.0.0.0") ;\
args_info->pcodns2_arg = strdup("0.0.0.0") ;\
args_info->timelimit_arg = 0 ;\
args_info->apn_arg = strdup("internet") ;\
args_info->qos_arg = 0x0b921f ;\
args_info->ipup_arg = NULL; \
args_info->ipdown_arg = NULL; \
}
clear_args();
@ -132,12 +141,15 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
{ "statedir", 1, NULL, 0 },
{ "listen", 1, NULL, 'l' },
{ "net", 1, NULL, 'n' },
{ "mask", 1, NULL, 0 },
{ "ipup", 1, NULL, 0 },
{ "ipdown", 1, NULL, 0 },
{ "dynip", 1, NULL, 0 },
{ "statip", 1, NULL, 0 },
{ "pcodns1", 1, NULL, 0 },
{ "pcodns2", 1, NULL, 0 },
{ "timelimit", 1, NULL, 0 },
{ "apn", 1, NULL, 'a' },
{ "qos", 1, NULL, 'q' },
{ "ipup", 1, NULL, 0 },
{ "ipdown", 1, NULL, 0 },
{ NULL, 0, NULL, 0 }
};
@ -262,32 +274,6 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->statedir_arg = strdup (optarg);
break;
}
/* Network mask. */
else if (strcmp (long_options[option_index].name, "mask") == 0)
{
if (args_info->mask_given)
{
fprintf (stderr, "%s: `--mask' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->mask_given = 1;
args_info->mask_arg = strdup (optarg);
break;
}
/* Exit after timelimit seconds. */
else if (strcmp (long_options[option_index].name, "timelimit") == 0)
{
if (args_info->timelimit_given)
{
fprintf (stderr, "%s: `--timelimit' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->timelimit_given = 1;
args_info->timelimit_arg = strtol (optarg,&stop_char,0);
break;
}
/* Script to run after link-up. */
else if (strcmp (long_options[option_index].name, "ipup") == 0)
{
@ -314,6 +300,71 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->ipdown_arg = strdup (optarg);
break;
}
/* Dynamic IP address pool. */
else if (strcmp (long_options[option_index].name, "dynip") == 0)
{
if (args_info->dynip_given)
{
fprintf (stderr, "%s: `--dynip' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->dynip_given = 1;
args_info->dynip_arg = strdup (optarg);
break;
}
/* Static IP address pool. */
else if (strcmp (long_options[option_index].name, "statip") == 0)
{
if (args_info->statip_given)
{
fprintf (stderr, "%s: `--statip' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->statip_given = 1;
args_info->statip_arg = strdup (optarg);
break;
}
/* PCO DNS Server 1. */
else if (strcmp (long_options[option_index].name, "pcodns1") == 0)
{
if (args_info->pcodns1_given)
{
fprintf (stderr, "%s: `--pcodns1' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->pcodns1_given = 1;
args_info->pcodns1_arg = strdup (optarg);
break;
}
/* PCO DNS Server 2. */
else if (strcmp (long_options[option_index].name, "pcodns2") == 0)
{
if (args_info->pcodns2_given)
{
fprintf (stderr, "%s: `--pcodns2' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->pcodns2_given = 1;
args_info->pcodns2_arg = strdup (optarg);
break;
}
/* Exit after timelimit seconds. */
else if (strcmp (long_options[option_index].name, "timelimit") == 0)
{
if (args_info->timelimit_given)
{
fprintf (stderr, "%s: `--timelimit' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->timelimit_given = 1;
args_info->timelimit_arg = strtol (optarg,&stop_char,0);
break;
}
case '?': /* Invalid option. */
/* `getopt_long' already printed an error message. */
@ -485,13 +536,93 @@ cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *ar
}
continue;
}
if (!strcmp(fopt, "mask"))
if (!strcmp(fopt, "ipup"))
{
if (override || !args_info->mask_given)
if (override || !args_info->ipup_given)
{
args_info->mask_given = 1;
args_info->ipup_given = 1;
if (fnum == 2)
args_info->mask_arg = strdup (farg);
args_info->ipup_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "ipdown"))
{
if (override || !args_info->ipdown_given)
{
args_info->ipdown_given = 1;
if (fnum == 2)
args_info->ipdown_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "dynip"))
{
if (override || !args_info->dynip_given)
{
args_info->dynip_given = 1;
if (fnum == 2)
args_info->dynip_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "statip"))
{
if (override || !args_info->statip_given)
{
args_info->statip_given = 1;
if (fnum == 2)
args_info->statip_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "pcodns1"))
{
if (override || !args_info->pcodns1_given)
{
args_info->pcodns1_given = 1;
if (fnum == 2)
args_info->pcodns1_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "pcodns2"))
{
if (override || !args_info->pcodns2_given)
{
args_info->pcodns2_given = 1;
if (fnum == 2)
args_info->pcodns2_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
@ -549,38 +680,6 @@ cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *ar
}
continue;
}
if (!strcmp(fopt, "ipup"))
{
if (override || !args_info->ipup_given)
{
args_info->ipup_given = 1;
if (fnum == 2)
args_info->ipup_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "ipdown"))
{
if (override || !args_info->ipdown_given)
{
args_info->ipdown_given = 1;
if (fnum == 2)
args_info->ipdown_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
/* Tried all known options. This one is unknown! */

View File

@ -1,15 +1,15 @@
# OpenGGSN - Gateway GPRS Support Node
# Copyright (C) 2002 Mondru AB.
# OpenGGSN - Gateway GPRS Support Node
# Copyright (C) 2002, 2003 Mondru AB.
#
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
#
# The initial developer of the original code is
# Jens Jakobsen <jj@openggsn.org>
# The initial developer of the original code is
# Jens Jakobsen <jj@openggsn.org>
#
# Contributor(s):
# Contributor(s):
option "fg" f "Run in foreground" flag off
@ -20,14 +20,19 @@ option "pidfile" - "Filename of process id file" string default="/var/run
option "statedir" - "Directory of nonvolatile data" string default="/var/lib/ggsn/" no
option "listen" l "Local interface" string no
option "net" n "Network" string default="192.168.0.0" no
option "mask" - "Network mask" string default="255.255.255.0" no
option "net" n "Network" string default="192.168.0.0/24" no
option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no
option "dynip" - "Dynamic IP address pool" string default="192.168.0.0/24" no
option "statip" - "Static IP address pool" string default="192.168.1.0/24" no
option "pcodns1" - "PCO DNS Server 1" string default="0.0.0.0" no
option "pcodns2" - "PCO DNS Server 2" string default="0.0.0.0" no
option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "apn" a "Access point name" string default="internet" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no

View File

@ -1,6 +1,6 @@
/* cmdline.h */
/* File autogenerated by gengetopt version 2.8rc */
/* File autogenerated by gengetopt version 2.8 */
#ifndef _cmdline_h
#define _cmdline_h
@ -26,13 +26,16 @@ struct gengetopt_args_info
char * pidfile_arg; /* Filename of process id file (default='/var/run/ggsn.pid'). */
char * statedir_arg; /* Directory of nonvolatile data (default='/var/lib/ggsn/'). */
char * listen_arg; /* Local interface. */
char * net_arg; /* Network (default='192.168.0.0'). */
char * mask_arg; /* Network mask (default='255.255.255.0'). */
char * net_arg; /* Network (default='192.168.0.0/24'). */
char * ipup_arg; /* Script to run after link-up. */
char * ipdown_arg; /* Script to run after link-down. */
char * dynip_arg; /* Dynamic IP address pool (default='192.168.0.0/24'). */
char * statip_arg; /* Static IP address pool (default='192.168.1.0/24'). */
char * pcodns1_arg; /* PCO DNS Server 1 (default='0.0.0.0'). */
char * pcodns2_arg; /* PCO DNS Server 2 (default='0.0.0.0'). */
int timelimit_arg; /* Exit after timelimit seconds (default='0'). */
char * apn_arg; /* Access point name (default='internet'). */
int qos_arg; /* Requested quality of service (default='0x0b921f'). */
char * ipup_arg; /* Script to run after link-up. */
char * ipdown_arg; /* Script to run after link-down. */
int help_given ; /* Whether help was given. */
int version_given ; /* Whether version was given. */
@ -43,12 +46,15 @@ struct gengetopt_args_info
int statedir_given ; /* Whether statedir was given. */
int listen_given ; /* Whether listen was given. */
int net_given ; /* Whether net was given. */
int mask_given ; /* Whether mask was given. */
int ipup_given ; /* Whether ipup was given. */
int ipdown_given ; /* Whether ipdown was given. */
int dynip_given ; /* Whether dynip was given. */
int statip_given ; /* Whether statip was given. */
int pcodns1_given ; /* Whether pcodns1 was given. */
int pcodns2_given ; /* Whether pcodns2 was given. */
int timelimit_given ; /* Whether timelimit was given. */
int apn_given ; /* Whether apn was given. */
int qos_given ; /* Whether qos was given. */
int ipup_given ; /* Whether ipup was given. */
int ipdown_given ; /* Whether ipdown was given. */
} ;

View File

@ -1,16 +1,16 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
* Contributor(s):
*
*/
@ -52,17 +52,29 @@
#include <time.h>
#include "tun.h"
#include "ippool.h"
#include "syserr.h"
#include "../gtp/pdp.h"
#include "../gtp/gtp.h"
#include "cmdline.h"
int maxfd = 0; /* For select() */
int tun_fd = -1; /* Network file descriptor */
int maxfd = 0; /* For select() */
struct tun_t *tun; /* TUN instance */
struct in_addr listen_;
struct in_addr net, mask; /* Network interface */
char *ipup, *ipdown; /* Filename of scripts */
int debug; /* Print debug output */
struct in_addr dns1, dns2; /* PCO DNS address */
char *ipup, *ipdown; /* Filename of scripts */
int debug; /* Print debug output */
struct ul255_t pco;
struct ul255_t qos;
struct ul255_t apn;
struct tun_t *tun; /* TUN instance */
struct ippool_t *ippool; /* Pool of IP addresses */
struct gsn_t *gsn; /* GSN instance */
/* Used to write process ID to file. Assume someone else will delete */
@ -94,60 +106,16 @@ int encaps_printf(void *p, void *packet, unsigned len)
return 0;
}
int getip(struct pdp_t *pdp, void* ipif, struct ul66_t *eua,
struct in_addr *net, struct in_addr *mask) {
struct in_addr addr;
uint32_t ip_start, ip_end, ip_cur;
struct pdp_t *pdp_;
struct ul66_t eua_;
if (debug) {
printf("Begin getip %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
}
ip_start = ntoh32(net->s_addr & mask->s_addr);
ip_end = ntoh32(hton32(ip_start) | ~mask->s_addr);
/* By convention the first address is the network address, and the last */
/* address is the broadcast address. This way two IP addresses are "lost" */
ip_start++;
if (eua->l == 0) { /* No address supplied. Find one that is available! */
/* This routine does linear search. In order to support millions of
* addresses we should instead keep a linked list of available adresses */
for (ip_cur = ip_start; ip_cur < ip_end; ip_cur++) {
addr.s_addr = hton32(ip_cur);
pdp_ntoeua(&addr, &eua_);
if (pdp_ipget(&pdp_, ipif, &eua_) == -1) {
pdp_ntoeua(&addr, &pdp->eua);
pdp->ipif = ipif;
return 0;
};
}
return EOF; /* No addresses available */
}
else { /* Address supplied */
if (pdp_ipget(&pdp_, ipif, eua) == -1) {
pdp->ipif = ipif;
pdp->eua.l = eua->l;
memcpy(pdp->eua.v, eua->v, eua->l);
return 0;
}
else return EOF; /* Specified address not available */
}
}
int delete_context(struct pdp_t *pdp) {
if (debug) printf("Deleting PDP context\n");
pdp_ipdel(pdp);
ippool_freeip((struct ippoolm_t *) pdp->peer);
return 0;
}
int create_context(struct pdp_t *pdp) {
struct in_addr addr;
struct ippoolm_t *member;
if (debug) printf("Received create PDP context request\n");
@ -155,69 +123,43 @@ int create_context(struct pdp_t *pdp) {
/* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_neg));
memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
getip(pdp, tun, &pdp->eua, &net, &mask);
pdp_ipset(pdp, pdp->ipif, &pdp->eua);
if (pdp_euaton(&pdp->eua, &addr)) {
addr.s_addr = 0; /* Request dynamic */
}
if (ippool_newip(ippool, &member, &addr)) {
return EOF; /* Allready in use, or no more available */
}
pdp_ntoeua(&member->addr, &pdp->eua);
pdp->peer = &member;
pdp->ipif = tun; /* TODO */
member->peer = pdp;
return 0; /* Success */
}
int create_tun() {
char buf[1024];
char snet[100], smask[100];
if ((tun_fd = tun_newtun((struct tun_t**) &tun)) > maxfd)
maxfd = tun_fd;
if (tun_fd == -1) {
printf("Failed to open tun\n");
exit(1);
}
strncpy(snet, inet_ntoa(net), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(mask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu 1450 netmask %s",
tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
if (debug) printf("%s\n", buf);
system(buf);
if (ipup) {
/* system("ipup /dev/tun0 192.168.0.10"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
ipup, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
if (debug) printf("%s\n", buf);
system(buf);
}
return 0;
}
int encaps_gtp(void *gsn, struct tun_t *tun, void *pack, unsigned len) {
struct pdp_t *pdp;
struct in_addr addr;
struct ul66_t eua;
/*printf("encaps_gtp. Packet received: forwarding to gtp.\n");*/
/* First we need to extract the IP destination address */
memcpy(&addr.s_addr, pack+16, 4); /* This ought to be dest addr */
pdp_ntoeua(&addr, &eua);
if (pdp_ipget(&pdp, tun, &eua) == 0) {
return gtp_gpdu((struct gsn_t*) gsn, pdp, pack, len);
}
else {
/* Callback for receiving messages from tun */
int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
struct ippoolm_t *ipm;
struct in_addr dst;
struct tun_packet_t *iph = (struct tun_packet_t*) pack;
dst.s_addr = iph->dst;
if (ippool_getip(ippool, &ipm, &dst)) {
if (debug) printf("Received packet with no destination!!!\n");
return 0;
}
if (ipm->peer) /* Check if a peer protocol is defined */
gtp_gpdu(gsn, (struct pdp_t*) ipm->peer, pack, len);
return 0;
}
int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
/* printf("encaps_tun. Packet received: forwarding to tun\n");*/
return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
@ -231,16 +173,10 @@ int main(int argc, char **argv)
struct hostent *host;
struct in_addr listen;
int gtpfd = -1; /* Network file descriptor */
struct gsn_t *gsn; /* GSN instance */
fd_set fds; /* For select() */
struct timeval idleTime; /* How long to select() */
struct ul_t qos, apn;
unsigned char qosh[3], apnh[256];
int timelimit; /* Number of seconds to be connected */
int starttime; /* Time program was started */
@ -259,7 +195,8 @@ int main(int argc, char **argv)
printf("qos: %#08x\n", args_info.qos_arg);
printf("apn: %s\n", args_info.apn_arg);
printf("net: %s\n", args_info.net_arg);
printf("mask: %s\n", args_info.mask_arg);
printf("dynip: %s\n", args_info.dynip_arg);
printf("statip: %s\n", args_info.statip_arg);
printf("ipup: %s\n", args_info.ipup_arg);
printf("ipdown: %s\n", args_info.ipdown_arg);
printf("pidfile: %s\n", args_info.pidfile_arg);
@ -280,7 +217,8 @@ int main(int argc, char **argv)
printf("qos: %#08x\n", args_info.qos_arg);
printf("apn: %s\n", args_info.apn_arg);
printf("net: %s\n", args_info.net_arg);
printf("mask: %s\n", args_info.mask_arg);
printf("dynip: %s\n", args_info.dynip_arg);
printf("statip: %s\n", args_info.statip_arg);
printf("ipup: %s\n", args_info.ipup_arg);
printf("ipdown: %s\n", args_info.ipdown_arg);
printf("pidfile: %s\n", args_info.pidfile_arg);
@ -326,37 +264,62 @@ int main(int argc, char **argv)
return 1;
}
else {
memcpy(&listen.s_addr, host->h_addr, host->h_length);
memcpy(&listen_.s_addr, host->h_addr, host->h_length);
}
}
else {
listen.s_addr = htonl(INADDR_ANY);
listen_.s_addr = htonl(INADDR_ANY);
}
/* net */
/* Store net as in_addr */
/* Store net as in_addr net and mask */
if (args_info.net_arg) {
if (!inet_aton(args_info.net_arg, &net)) {
fprintf(stderr, "%s: Invalid network address: %s!\n",
PACKAGE, args_info.net_arg);
syslog(LOG_ERR, "Invalid network address: %s!",
args_info.net_arg);
return 1;
if(ippool_aton(&net, &mask, args_info.net_arg, 0)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Invalid network address: %s!", args_info.net_arg);
return -1;
}
}
/* mask */
/* Store mask as in_addr */
if (args_info.mask_arg) {
if (!inet_aton(args_info.mask_arg, &mask)) {
fprintf(stderr, "%s: Invalid network mask: %s!\n",
PACKAGE, args_info.mask_arg);
syslog(LOG_ERR, "Invalid network mask: %s!",
args_info.mask_arg);
return 1;
/* dynip */
if (!args_info.dynip_arg) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"No dynamic address pool given!");
return -1;
}
else {
if (ippool_new(&ippool, args_info.dynip_arg,
IPPOOL_NONETWORK | IPPOOL_NOBROADCAST)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to allocate IP pool!");
}
}
/* DNS1 and DNS2 */
dns1.s_addr = 0;
if (args_info.pcodns1_arg)
inet_aton(args_info.pcodns1_arg, &dns1);
dns2.s_addr = 0;
if (args_info.pcodns2_arg)
inet_aton(args_info.pcodns2_arg, &dns2);
pco.l = 20;
pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
pco.v[1] = 0x80; /* IPCP */
pco.v[2] = 0x21;
pco.v[3] = 0x10; /* Length of contents */
pco.v[4] = 0x02; /* ACK */
pco.v[5] = 0x00; /* ID: Need to match request */
pco.v[6] = 0x00; /* Length */
pco.v[7] = 0x10;
pco.v[8] = 0x81; /* DNS 1 */
pco.v[9] = 0x06;
memcpy(&pco.v[10], &dns1, sizeof(dns1));
pco.v[14] = 0x83;
pco.v[15] = 0x06; /* DNS 2 */
memcpy(&pco.v[16], &dns2, sizeof(dns2));
/* ipup */
ipup = args_info.ipup_arg;
@ -369,35 +332,64 @@ int main(int argc, char **argv)
/* qos */
qos.l = 3;
qos.v = qosh;
qos.v[2] = (args_info.qos_arg) & 0xff;
qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
/* apn */
if (strlen(args_info.apn_arg)>(sizeof(apnh)-1)) {
printf("invalid APN\n");
exit(1);
if (strlen(args_info.apn_arg) > (sizeof(apn.v)-1)) {
printf("Invalid APN\n");
return -1;
}
apn.l = strlen(args_info.apn_arg) + 1;
apn.v = apnh;
apn.v[0] = (char) strlen(args_info.apn_arg);
strncpy(&apn.v[1], args_info.apn_arg, (sizeof(apnh)-1));
strncpy(&apn.v[1], args_info.apn_arg, sizeof(apn.v)-1);
if (debug) printf("gtpclient: Initialising GTP tunnel\n");
if ((gtpfd = gtp_new(&gsn, args_info.statedir_arg, &listen)) > maxfd)
maxfd = gtpfd;
if ((gtpfd = gtp_fd(gsn)) > maxfd)
maxfd = gtpfd;
if (gtp_new(&gsn, args_info.statedir_arg, &listen_)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to create gtp");
exit(1);
}
if (gsn->fd > maxfd) maxfd = gsn->fd;
gtp_set_cb_gpdu(gsn, encaps_tun);
gtp_set_cb_delete_context(gsn, delete_context);
gtp_set_cb_create_context(gsn, create_context);
create_tun();
/* Create a tunnel interface */
if (tun_new((struct tun_t**) &tun)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Failed to create tun");
exit(1);
}
tun_setaddr(tun, &net, &net, &mask);
tun_set_cb_ind(tun, cb_tun_ind);
if (tun->fd > maxfd) maxfd = tun->fd;
if (ipup) {
char buf[1024];
char snet[100];
char smask[100];
strncpy(snet, inet_ntoa(net), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(mask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
/* system("ipup /dev/tun0 192.168.0.10"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
ipup, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
if (debug) printf("%s\n", buf);
system(buf);
}
/******************************************************************/
/* Main select loop */
@ -406,8 +398,8 @@ int main(int argc, char **argv)
while (((starttime + timelimit) > time(NULL)) || (0 == timelimit)) {
FD_ZERO(&fds);
if (tun_fd != -1) FD_SET(tun_fd, &fds);
if (gtpfd != -1) FD_SET(gtpfd, &fds);
if (tun) FD_SET(tun->fd, &fds);
FD_SET(gsn->fd, &fds);
gtp_retranstimeout(gsn, &idleTime);
switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
@ -418,26 +410,25 @@ int main(int argc, char **argv)
syslog(LOG_ERR, "GGSN: select = -1");
break;
case 0:
/* printf("Select returned 0\n"); */
gtp_retrans(gsn); /* Only retransmit if nothing else */
break;
default:
break;
}
if (tun_fd != -1 && FD_ISSET(tun_fd, &fds) &&
tun_decaps(tun, encaps_gtp, gsn) < 0) {
syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd);
if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
tun_decaps(tun) < 0) {
syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun->fd);
}
if (gtpfd != -1 && FD_ISSET(gtpfd, &fds) &&
gtp_decaps(gsn) < 0) {
syslog(LOG_ERR, "GTP read failed (gtpfd)=(%d)", gtpfd);
}
if (FD_ISSET(gsn->fd, &fds))
gtp_decaps(gsn);
}
gtp_free(gsn);
tun_free(tun);
return 1;

416
ggsn/ippool.c Normal file
View File

@ -0,0 +1,416 @@
/*
* IP address pool functions.
* Copyright (C) 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
*
*/
#include <netinet/in.h> /* in_addr */
#include <stdlib.h> /* calloc */
#include <stdio.h> /* sscanf */
#include "ippool.h"
/*
--------------------------------------------------------------------
Public domain by From Bob Jenkins, December 1996.
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/*
--------------------------------------------------------------------
lookup() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
level : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 6len+35 instructions.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (ub1 **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial.
See http://burtleburtle.net/bob/hash/evahash.html
Use for hash table lookup, or anything where one collision in 2^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
unsigned long int lookup( k, length, level)
register unsigned char *k; /* the key */
register unsigned long int length; /* the length of the key */
register unsigned long int level; /* the previous hash, or an arbitrary value */
{
register unsigned long int a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
/*
End of public domain code by From Bob Jenkins, December 1996.
--------------------------------------------------------------------
*/
int ippool_printaddr(struct ippool_t *this) {
int n;
printf("ippool_printaddr\n");
printf("First %d\n", this->first - this->member);
printf("Last %d\n", this->last - this->member);
printf("Listsize %d\n", this->listsize);
for (n=0; n<this->listsize; n++) {
printf("Unit %d inuse %d prev %d next %d addr %x\n",
n,
this->member[n].inuse,
this->member[n].prev - this->member,
this->member[n].next - this->member,
this->member[n].addr.s_addr
);
}
return 0;
}
unsigned long int ippool_hash4(struct in_addr *addr) {
return lookup(&addr->s_addr, sizeof(addr->s_addr), 0);
}
#ifndef IPPOOL_NOIP6
unsigned long int ippool_hash6(struct in6_addr *addr) {
return lookup(addr->u6_addr8, sizeof(addr->u6_addr8), 0);
}
#endif
/* Get IP address and mask */
int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number) {
/* Parse only first instance of network for now */
/* Eventually "number" will indicate the token which we want to parse */
unsigned int a1, a2, a3, a4;
unsigned int m1, m2, m3, m4;
int c;
unsigned int m;
int masklog;
c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u",
&a1, &a2, &a3, &a4,
&m1, &m2, &m3, &m4);
switch (c) {
case 4:
if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0) /* Full Internet */
mask->s_addr = 0x00000000;
else if (a2 == 0 && a3 == 0 && a4 == 0) /* class A */
mask->s_addr = htonl(0xff000000);
else if (a3 == 0 && a4 == 0) /* class B */
mask->s_addr = htonl(0xffff0000);
else if (a4 == 0) /* class C */
mask->s_addr = htonl(0xffffff00);
else
mask->s_addr = 0xffffffff;
break;
case 5:
if (m1 < 0 || m1 > 32) {
return -1; /* Invalid mask */
}
mask->s_addr = htonl(0xffffffff << (32 - m1));
break;
case 8:
if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256)
return -1; /* Wrong mask format */
m = m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4;
for (masklog = 0; ((1 << masklog) < ((~m)+1)); masklog++);
if (((~m)+1) != (1 << masklog))
return -1; /* Wrong mask format (not all ones followed by all zeros)*/
mask->s_addr = htonl(m);
break;
default:
return -1; /* Invalid mask */
}
if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256)
return -1; /* Wrong IP address format */
else
addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
return 0;
}
/* Create new address pool */
int ippool_new(struct ippool_t **this, char *pool, int flags) {
/* Parse only first instance of network for now */
int i;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
uint32_t hash;
struct in_addr addr;
struct in_addr mask;
unsigned int m;
unsigned int listsize;
if (ippool_aton(&addr, &mask, pool, 0))
return 0; /* Failed to parse pool */
m = ntohl(mask.s_addr);
listsize = ((~m)+1);
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
listsize--;
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
listsize--;
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
/* Failed to allocate memory for ippool */
return -1;
}
(*this)->listsize += listsize;
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), (*this)->listsize))){
/* Failed to allocate memory for members in ippool */
return -1;
}
for ((*this)->hashlog = 0;
((1 << (*this)->hashlog) < listsize);
(*this)->hashlog++);
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
/* Determine hashsize */
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
(*this)->hashmask = (*this)->hashsize -1;
/* Allocate hash table */
if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
/* Failed to allocate memory for hash members in ippool */
return -1;
}
(*this)->first = NULL;
(*this)->last = NULL;
for (i = 0; i<(*this)->listsize; i++) {
if (flags & IPPOOL_NONETWORK)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 1);
else
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i);
(*this)->member[i].inuse = 0;
(*this)->member[i].parent = *this;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->last;
if ((*this)->last) {
(*this)->last->next = &((*this)->member[i]);
}
else {
(*this)->first = &((*this)->member[i]);
}
(*this)->last = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
/* Insert into hash table */
hash = ippool_hash4(&(*this)->member[i].addr) & (*this)->hashmask;
for (p = (*this)->hash[hash]; p; p = p->nexthash)
p_prev = p;
if (!p_prev)
(*this)->hash[hash] = &((*this)->member[i]);
else
p_prev->nexthash = &((*this)->member[i]);
}
/*ippool_printaddr(*this);*/
return 0;
}
/* Delete existing address pool */
int ippool_free(struct ippool_t *this) {
free(this->hash);
free(this->member);
free(this);
return 0; /* Always OK */
}
/* Find an IP address in the pool */
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
uint32_t hash;
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
*member = p;
return 0;
}
}
*member = NULL;
return -1; /* Address could not be found */
}
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
struct ippoolm_t *p2 = NULL;
uint32_t hash;
/*ippool_printaddr(this);*/
if ((addr) && (addr->s_addr)) { /* IP address given */
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr)) {
p2 = p;
break;
}
}
}
else { /* No ip address given */
p2 = this -> first;
}
if (!p2) return -1; /* Not found */
if (p2->inuse) return -1; /* Allready in use / Should not happen */
/* Found new address. Remove from queue */
if (p2->prev)
p2->prev->next = p2->next;
else
this->first = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->last = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 1;
*member = p2;
/*ippool_printaddr(this);*/
return 0; /* Success */
}
int ippool_freeip(struct ippoolm_t *member) {
struct ippool_t *this = member->parent;
/*ippool_printaddr(this);*/
if (!member->inuse) return -1; /* Not in use: Should not happen */
/* Insert into list of unused */
member->prev = this->last;
if (this->last) {
this->last->next = member;
}
else {
this->first = member;
}
this->last = member;
member->inuse = 0;
/*ippool_printaddr(this);*/
return 0; /* Success */
}
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif

105
ggsn/ippool.h Normal file
View File

@ -0,0 +1,105 @@
/*
* IP address pool functions.
* Copyright (C) 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
*
*/
#ifndef _IPPOOL_H
#define _IPPOOL_H
/* Assuming that the address space is fragmented we need a hash table
in order to return the addresses.
The list pool should provide for both IPv4 and IPv6 addresses.
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
*/
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1;
#define IPPOOL_NOIP6
#define IPPOOL_NONETWORK 0x01
#define IPPOOL_NOBROADCAST 0x02
struct ippoolm_t; /* Forward declaration */
struct ippool_t {
int listsize; /* Total number of addresses */
struct ippoolm_t *member; /* Listsize array of members */
int hashsize; /* Size of hash table */
int hashlog; /* Log2 size of hash table */
int hashmask; /* Bitmask for calculating hash */
struct ippoolm_t **hash; /* Hashsize array of pointer to member */
struct ippoolm_t *first; /* Pointer to first available member */
struct ippoolm_t *last; /* Pointer to last available member */
};
struct ippoolm_t {
#ifndef IPPOOL_NOIP6
struct in6_addr addr; /* IP address of this member */
#else
struct in_addr addr; /* IP address of this member */
#endif
int inuse; /* 0=available; 1= inuse */
struct ippoolm_t *nexthash; /* Linked list part of hash table */
struct ippoolm_t *prev, *next; /* Double linked list of available members */
struct ippool_t *parent; /* Pointer to parent */
void *peer; /* Pointer to peer protocol handler */
};
/* The above structures requires approximately 20+4 = 24 bytes for
each address (IPv4). For IPv6 the corresponding value is 32+4 = 36
bytes for each address. */
/* Hash an IP address using code based on Bob Jenkins lookupa */
extern unsigned long int ippool_hash4(struct in_addr *addr);
/* Create new address pool */
extern int ippool_new(struct ippool_t **this, char *pool, int flags);
/* Delete existing address pool */
extern int ippool_free(struct ippool_t *this);
/* Find an IP address in the pool */
extern int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
extern int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Return a previously allocated IP address */
extern int ippool_freeip(struct ippoolm_t *member);
/* Get net and mask based on ascii string */
extern int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number);
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif
#endif /* !_IPPOOL_H */

View File

@ -1,32 +1,24 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
* Contributor(s):
*
*/
/*
* tun.c: Contains all TUN functionality. Should be able to handle multiple
* tunnels in the same program. Each tunnel is identified by the socket.
* I suppose that no other state information than the socket is needed.
* tun.c: Contains all TUN functionality. Is able to handle multiple
* tunnels in the same program. Each tunnel is identified by the struct,
* which is passed to functions.
*
* - tun_newtun: Initialise TUN tunnel.
* - tun_freetun: Free a device previously created with tun_newtun.
* - tun_encaps: Encapsulate packet in TUN tunnel and send off
* - tun_decaps: Extract packet from TUN tunnel and call function to
* ship it off as GTP encapsulated packet.
*
* TODO:
* - Do we need to handle fragmentation?
*/
@ -54,75 +46,471 @@
#include <linux/if.h>
#include <errno.h>
#include <linux/if_tun.h>
#include <net/route.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "tun.h"
#include "syserr.h"
int tun_newtun(struct tun_t **tun)
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
{
int len = RTA_LENGTH(dlen);
int alen = NLMSG_ALIGN(n->nlmsg_len);
struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
if (alen + len > nsize)
return -1;
rta->rta_len = len;
rta->rta_type = type;
memcpy(RTA_DATA(rta), d, dlen);
n->nlmsg_len = alen + len;
return 0;
}
int tun_gifindex(struct tun_t *this, int *index) {
struct ifreq ifr;
int fd;
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
syslog(LOG_ERR, "%s %d. calloc(nmemb=%d, size=%d) failed: Error = %s(%d)",
__FILE__, __LINE__, 1, sizeof(struct tun_t),
strerror(errno), errno);
return EOF;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl() failed");
close(fd);
return -1;
}
close(fd);
*index = ifr.ifr_ifindex;
return 0;
}
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
syslog(LOG_ERR, "TUN: open() failed");
int tun_sifflags(struct tun_t *this, int flags) {
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_flags = flags;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFFLAGS) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
/* Currently unused */
int tun_addroute2(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask) {
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
int status;
struct sockaddr_nl nladdr;
struct iovec iov;
struct msghdr msg;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = 0;
if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address family %d", local.nl_family);
close(fd);
return -1;
}
iov.iov_base = (void*)&req.n;
iov.iov_len = req.n.nlmsg_len;
msg.msg_name = (void*)&nladdr;
msg.msg_namelen = sizeof(nladdr),
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
req.n.nlmsg_seq = 0;
req.n.nlmsg_flags |= NLM_F_ACK;
status = sendmsg(fd, &msg, 0); /* TODO: Error check */
close(fd);
return 0;
}
int tun_addaddr(struct tun_t *this,
struct in_addr *addr,
struct in_addr *dstaddr,
struct in_addr *netmask) {
struct {
struct nlmsghdr n;
struct ifaddrmsg i;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
int status;
struct sockaddr_nl nladdr;
struct iovec iov;
struct msghdr msg;
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask);
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWADDR;
req.i.ifa_family = AF_INET;
req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
req.i.ifa_flags = 0;
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
if (tun_gifindex(this, &req.i.ifa_index)) {
return -1;
}
tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = 0;
if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address family %d", local.nl_family);
close(fd);
return -1;
}
iov.iov_base = (void*)&req.n;
iov.iov_len = req.n.nlmsg_len;
msg.msg_name = (void*)&nladdr;
msg.msg_namelen = sizeof(nladdr),
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
req.n.nlmsg_seq = 0;
req.n.nlmsg_flags |= NLM_F_ACK;
status = sendmsg(fd, &msg, 0); /* TODO Error check */
tun_sifflags(this, IFF_UP | IFF_RUNNING);
close(fd);
this->addrs++;
return 0;
}
int tun_setaddr(struct tun_t *this,
struct in_addr *addr,
struct in_addr *dstaddr,
struct in_addr *netmask)
{
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
/* Create a channel to the NET kernel. */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (addr) { /* Set the interface address */
this->addr.s_addr = addr->s_addr;
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
if (errno != EEXIST) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR) failed");
}
else {
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR): Address already exists");
}
close(fd);
return -1;
}
}
if (dstaddr) { /* Set the destination address */
this->dstaddr.s_addr = dstaddr->s_addr;
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
dstaddr->s_addr;
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFDSTADDR) failed");
close(fd);
return -1;
}
}
if (netmask) { /* Set the netmask */
this->netmask.s_addr = netmask->s_addr;
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
netmask->s_addr;
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFNETMASK) failed");
close(fd);
return -1;
}
}
close(fd);
this->addrs++;
return tun_sifflags(this, IFF_UP | IFF_RUNNING);
}
int tun_addroute(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask)
{
struct rtentry r;
int fd;
memset (&r, '\0', sizeof (r));
r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
/* Create a channel to the NET kernel. */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
r.rt_dst.sa_family = AF_INET;
r.rt_gateway.sa_family = AF_INET;
r.rt_genmask.sa_family = AF_INET;
((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCADDRT) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
int tun_new(struct tun_t **tun)
{
struct ifreq ifr;
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
return EOF;
}
(*tun)->cb_ind = NULL;
(*tun)->addrs = 0;
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
syslog(LOG_ERR, "TUN: ioctl() failed");
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
close((*tun)->fd);
return -1;
}
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
return (*tun)->fd;
(*tun)->devname[IFNAMSIZ] = 0;
return 0;
}
int tun_freetun(struct tun_t *tun)
int tun_free(struct tun_t *tun)
{
if (close(tun->fd)) {
syslog(LOG_ERR, "%s %d. close(fd=%d) failed: Error = %s",
__FILE__, __LINE__, tun->fd, strerror(errno));
return EOF;
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
}
free(tun);
return 0;
}
int tun_decaps(struct tun_t *tun,
int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
void *cl)
int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
this->cb_ind = cb_ind;
return 0;
}
int tun_decaps(struct tun_t *this)
{
unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ];
int status;
unsigned char buffer[PACKET_MAX];
int status;
if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, status);
if ((status = read(tun->fd, buffer, sizeof(buffer))) <= 0) {
syslog(LOG_ERR, "TUN: read(fd=%d,buffer=%lx,len=%d) from network failed: status = %d error = %s",
tun->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
return -1;
}
/* Need to include code to verify packet src and dest addresses */
return cb(cl, tun, buffer, status);
return 0;
}
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
return write(tun->fd, pack, len);
return write(tun->fd, pack, len);
}
int tun_runscript(struct tun_t *tun, char* script) {
char buf[TUN_SCRIPTSIZE];
char snet[TUN_ADDRSIZE];
char smask[TUN_ADDRSIZE];
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
/* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
script, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
system(buf);
return 0;
}

View File

@ -1,48 +1,78 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
* Contributor(s):
*
*/
#ifndef _TUN_H
#define _TUN_H
#define hton8(x) (x)
#define ntoh8(x) (x)
#define hton16(x) htons(x)
#define ntoh16(x) ntohs(x)
#define hton32(x) htonl(x)
#define ntoh32(x) ntohl(x)
#define PACKET_MAX 8196 /* Maximum packet size we receive */
#define TUN_SCRIPTSIZE 256
#define TUN_ADDRSIZE 128
#define TUN_NLBUFSIZE 1024
struct tun_packet_t {
unsigned int ver:4;
unsigned int ihl:4;
unsigned int dscp:6;
unsigned int ecn:2;
unsigned int length:16;
unsigned int id:16;
unsigned int flags:3;
unsigned int fragment:13;
unsigned int ttl:8;
unsigned int protocol:8;
unsigned int check:16;
unsigned int src:32;
unsigned int dst:32;
};
#define PACKET_MAX 8196 /* TODO */
/* ***********************************************************
* Information storage for each tun instance
*************************************************************/
struct tun_t {
int fd; /* File descriptor to network interface */
struct in_addr addr; /* IP address of tun interface */
int fd; /* File descriptor to tun interface */
struct in_addr addr;
struct in_addr dstaddr;
struct in_addr netmask;
int addrs; /* Number of allocated IP addresses */
char devname[IFNAMSIZ];/* Name of the tun device */
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len);
};
extern int tun_newtun(struct tun_t **tun);
extern int tun_freetun(struct tun_t *tun);
extern int tun_decaps(struct tun_t *tun,
int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
void *cl);
extern int tun_new(struct tun_t **tun);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
extern int tun_setaddr(struct tun_t *this, struct in_addr *our_adr,
struct in_addr *his_adr, struct in_addr *net_mask);
int tun_addroute(struct tun_t *this, struct in_addr *dst,
struct in_addr *gateway, struct in_addr *mask);
extern int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len));
extern int tun_runscript(struct tun_t *tun, char* script);
#endif /* !_TUN_H */

View File

@ -1,6 +1,6 @@
lib_LTLIBRARIES = libgtp.la
CFLAGS = -O2 -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"'
CFLAGS = -O2 -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb
libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h

View File

@ -87,7 +87,7 @@ am__quote = @am__quote@
install_sh = @install_sh@
lib_LTLIBRARIES = libgtp.la
CFLAGS = -O2 -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"'
CFLAGS = -O2 -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb
libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
subdir = gtp

233
gtp/gtp.c
View File

@ -54,10 +54,6 @@
#include "gtpie.h"
#include "queue.h"
struct gtp0_header gtp0_default;
struct gtp1_header_long gtp1_default;
/* API Functions */
const char* gtp_version()
@ -162,18 +158,29 @@ extern int gtp_set_cb_gpdu(struct gsn_t *gsn,
}
void get_default_gtp(int version, void *packet) {
struct gtp0_header *gtp0_default = (struct gtp0_header*) packet;
struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet;
switch (version) {
case 0:
memcpy(packet, &gtp0_default, sizeof(gtp0_default));
/* Initialise "standard" GTP0 header */
memset(gtp0_default, 0, sizeof(gtp0_default));
gtp0_default->flags=0x1e;
gtp0_default->spare1=0xff;
gtp0_default->spare2=0xff;
gtp0_default->spare3=0xff;
gtp0_default->number=0xff;
break;
case 1:
memcpy(packet, &gtp1_default, sizeof(gtp1_default));
/* Initialise "standard" GTP1 header */
memset(gtp1_default, 0, sizeof(gtp1_default));
gtp0_default->flags=0x1e;
break;
}
}
int print_packet(void *packet, unsigned len)
{
int i;
@ -448,6 +455,11 @@ int gtp_resp(int version, struct gsn_t *gsn, union gtp_packet *packet,
ntohs(peer->sin_port));
print_packet(packet, len);
*/
if (fcntl(gsn->fd, F_SETFL, 0)) {
gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
return -1;
}
if (sendto(gsn->fd, packet, len, 0,
(struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
@ -487,6 +499,12 @@ int gtp_dublicate(struct gsn_t *gsn, int version,
ntohs(peer->sin_port));
print_packet(&qmsg->p, qmsg->l);
*/
if (fcntl(gsn->fd, F_SETFL, 0)) {
gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
return -1;
}
if (sendto(gsn->fd, &qmsg->p, qmsg->l, 0,
(struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
gsn->err_sendto++;
@ -553,6 +571,9 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen)
(*gsn)->statedir = statedir;
log_restart(*gsn);
/* Initialise sequence number */
(*gsn)->seq_next = (*gsn)->restart_counter * 1024;
/* Initialise request retransmit queue */
queue_new(&(*gsn)->queue_req);
@ -573,8 +594,6 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen)
return -1;
}
(*gsn)->fd = gtp_fd;
/* syslog(LOG_ERR, "GTP: gtp_init() after socket");*/
(*gsn)->gsnc = *listen;
(*gsn)->gsnu = *listen;
@ -592,18 +611,6 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen)
return -1;
}
/* Initialise "standard" GTP0 header */
memset(&gtp0_default, 0, sizeof(gtp0_default));
gtp0_default.flags=0x1e;
gtp0_default.spare1=0xff;
gtp0_default.spare2=0xff;
gtp0_default.spare3=0xff;
gtp0_default.number=0xff;
/* Initialise "standard" GTP1 header */
memset(&gtp1_default, 0, sizeof(gtp1_default));
gtp0_default.flags=0x1e;
return 0;
}
@ -1736,90 +1743,111 @@ int gtp_decaps(struct gsn_t *gsn)
struct gtp0_header *pheader;
int version = 0; /* GTP version should be determined from header!*/
peerlen = sizeof(peer);
if ((status =
recvfrom(gsn->fd, buffer, sizeof(buffer), 0,
(struct sockaddr *) &peer, &peerlen)) < 0 ) {
gsn->err_readfrom++;
gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
return -1;
}
/* Strip off IP header, if present: TODO Is this nessesary? */
if ((buffer[0] & 0xF0) == 0x40) {
ip_len = (buffer[0] & 0xF) * 4;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"IP header found in return from read");
return -1;
}
/* Need at least 1 byte in order to check version */
if (status < (1)) {
gsn->empty++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Discarding packet - too small");
return -1;
}
/* TODO: Remove these ERROR MESSAGES
gtp_err(LOG_ERR, __FILE__, __LINE__, "Discarding packet - too small");
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Discarding packet - too small"); */
/* TODO: Need strategy of userspace buffering and blocking */
/* Currently read is non-blocking and send is blocking. */
/* This means that the program have to wait for busy send calls...*/
pheader = (struct gtp0_header *) (buffer + ip_len);
/* Version should be gtp0 (or earlier in theory) */
if (((pheader->flags & 0xe0) > 0x00)) {
gsn->unsup++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Unsupported GTP version");
return gtp_unsup_resp(gsn, &peer, buffer, status); /* 29.60: 11.1.1 */
}
while (1) { /* Loop until no more to read */
if (fcntl(gsn->fd, F_SETFL, O_NONBLOCK)) {
gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
return -1;
}
peerlen = sizeof(peer);
if ((status =
recvfrom(gsn->fd, buffer, sizeof(buffer), 0,
(struct sockaddr *) &peer, &peerlen)) < 0 ) {
if (errno == EAGAIN) return -1;
gsn->err_readfrom++;
gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
return -1;
}
/* Check length of gtp0 packet */
if (((pheader->flags & 0xe0) == 0x00) && (status < GTP0_HEADER_SIZE)) {
gsn->tooshort++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"GTP0 packet too short");
return -1; /* Silently discard 29.60: 11.1.2 */
}
switch (pheader->type) {
case GTP_ECHO_REQ:
return gtp_echo_ind(gsn, &peer, buffer+ip_len, status - ip_len);
case GTP_ECHO_RSP:
return gtp_echo_conf(gsn, &peer, buffer+ip_len, status - ip_len);
case GTP_NOT_SUPPORTED:
return gtp_unsup_conf(gsn, &peer, buffer+ip_len, status - ip_len);
case GTP_CREATE_PDP_REQ:
return gtp_create_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_CREATE_PDP_RSP:
return gtp_create_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_UPDATE_PDP_REQ:
return gtp_update_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_UPDATE_PDP_RSP:
return gtp_update_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_DELETE_PDP_REQ:
return gtp_delete_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_DELETE_PDP_RSP:
return gtp_delete_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_ERROR:
return gtp_error_ind_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
case GTP_GPDU:
return gtp_gpdu_ind(gsn, version, &peer, buffer+ip_len, status - ip_len);
default:
{
/* Strip off IP header, if present: TODO Is this nessesary? */
if ((buffer[0] & 0xF0) == 0x40) {
ip_len = (buffer[0] & 0xF) * 4;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"IP header found in return from read");
continue;
}
/* Need at least 1 byte in order to check version */
if (status < (1)) {
gsn->empty++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Discarding packet - too small");
continue;
}
/* TODO: Remove these ERROR MESSAGES
gtp_err(LOG_ERR, __FILE__, __LINE__, "Discarding packet - too small");
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Discarding packet - too small"); */
pheader = (struct gtp0_header *) (buffer + ip_len);
/* Version should be gtp0 (or earlier in theory) */
if (((pheader->flags & 0xe0) > 0x00)) {
gsn->unsup++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Unsupported GTP version");
gtp_unsup_resp(gsn, &peer, buffer, status); /* 29.60: 11.1.1 */
continue;
}
/* Check length of gtp0 packet */
if (((pheader->flags & 0xe0) == 0x00) && (status < GTP0_HEADER_SIZE)) {
gsn->tooshort++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"GTP0 packet too short");
continue; /* Silently discard 29.60: 11.1.2 */
}
switch (pheader->type) {
case GTP_ECHO_REQ:
gtp_echo_ind(gsn, &peer, buffer+ip_len, status - ip_len);
break;
case GTP_ECHO_RSP:
gtp_echo_conf(gsn, &peer, buffer+ip_len, status - ip_len);
break;
case GTP_NOT_SUPPORTED:
gtp_unsup_conf(gsn, &peer, buffer+ip_len, status - ip_len);
break;
case GTP_CREATE_PDP_REQ:
gtp_create_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_CREATE_PDP_RSP:
gtp_create_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_UPDATE_PDP_REQ:
gtp_update_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_UPDATE_PDP_RSP:
gtp_update_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_DELETE_PDP_REQ:
gtp_delete_pdp_ind(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_DELETE_PDP_RSP:
gtp_delete_pdp_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_ERROR:
gtp_error_ind_conf(gsn, version, &peer, buffer+ip_len,
status - ip_len);
break;
case GTP_GPDU:
gtp_gpdu_ind(gsn, version, &peer, buffer+ip_len, status - ip_len);
break;
default:
gsn->unknown++;
gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
"Unknown GTP message type received");
return -1;
break;
}
}
}
@ -1853,6 +1881,11 @@ int gtp_gpdu(struct gsn_t *gsn, struct pdp_t* pdp,
return EOF;
}
if (fcntl(gsn->fd, F_SETFL, 0)) {
gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
return -1;
}
memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
if (sendto(gsn->fd, &packet, GTP0_HEADER_SIZE+len, 0,

View File

@ -1,6 +1,6 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
@ -32,7 +32,7 @@
struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */
struct pdp_t* haship[PDP_MAX]; /* Hash table for IP and network interface */
/* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */
/* ***********************************************************
* Functions related to PDP storage
@ -109,7 +109,7 @@ struct pdp_t* haship[PDP_MAX]; /* Hash table for IP and network interface */
int pdp_init() {
memset(&pdpa, 0, sizeof(pdpa));
memset(&hashtid, 0, sizeof(hashtid));
memset(&haship, 0, sizeof(haship));
/* memset(&haship, 0, sizeof(haship)); */
return 0;
}
@ -227,8 +227,9 @@ int pdp_tidget(struct pdp_t **pdp, uint64_t tid) {
return EOF; /* End of linked list and not found */
}
/*
int pdp_iphash(void* ipif, struct ul66_t *eua) {
/*printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);*/
/#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
}
@ -276,27 +277,27 @@ int pdp_ipdel(struct pdp_t *pdp) {
pdp_prev = pdp2;
}
if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
return EOF; /* End of linked list and not found */
return EOF; /# End of linked list and not found #/
}
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
int hash = pdp_iphash(ipif, eua);
struct pdp_t *pdp2;
/*printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
eua->v[2],eua->v[3],eua->v[4],eua->v[5]);*/
/#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
(memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
*pdp = pdp2;
/*printf("End pdp_ipget. Found\n");*/
/#printf("End pdp_ipget. Found\n");#/
return 0;
}
}
if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
(unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
return EOF; /* End of linked list and not found */
return EOF; /# End of linked list and not found #/
}
*/
/* Various conversion functions */
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) {
@ -307,6 +308,14 @@ int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) {
return 0;
}
int pdp_euaton(struct ul66_t *eua, struct in_addr *dst) {
if((eua->l!=6) || (eua->v[0]!=0xf1) || (eua->v[1]!=0x21)) {
return EOF;
}
memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */
return 0;
}
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) {
return (imsi & 0x0fffffffffffffff) + ((uint64_t)nsapi << 60);
}

View File

@ -1,6 +1,6 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
@ -98,6 +98,7 @@ struct pdp_t {
/* Parameters shared by all PDP context belonging to the same MS */
void *ipif; /* IP network interface */
void *peer; /* Pointer to peer protocol */
void *asap; /* Application specific service access point */
uint64_t imsi; /* International Mobile Subscriber Identity.*/
@ -191,12 +192,15 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid);
int pdp_tiddel(struct pdp_t *pdp);
int pdp_tidget(struct pdp_t **pdp, uint64_t tid);
/*
int pdp_iphash(void* ipif, struct ul66_t *eua);
int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua);
int pdp_ipdel(struct pdp_t *pdp);
int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua);
*/
int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua);
int pdp_euaton(struct ul66_t *eua, struct in_addr *dst);
uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi);
int ulcpy(void* dst, void* src, size_t size);

View File

@ -133,7 +133,8 @@ int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
(*qmsg)->this = queue->next;
(*qmsg)->next=-1; /* End of the queue */
(*qmsg)->prev=queue->last; /* Link to the previous */
queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
if (queue->last != -1)
queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
queue->last = queue->next; /* End of queue */
if (queue->first == -1) queue->first = queue->next;
queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */

View File

@ -2,9 +2,9 @@ bin_PROGRAMS = sgsnemu
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -lgtp -L../gtp
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb -lgtp -L../gtp
sgsnemu_SOURCES = sgsnemu.c tun.c tun.h cmdline.c cmdline.h
sgsnemu_SOURCES = sgsnemu.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c

View File

@ -89,9 +89,9 @@ bin_PROGRAMS = sgsnemu
LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -lgtp -L../gtp
CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -ansi -DSBINDIR='"$(sbindir)"' -ggdb -lgtp -L../gtp
sgsnemu_SOURCES = sgsnemu.c tun.c tun.h cmdline.c cmdline.h
sgsnemu_SOURCES = sgsnemu.c tun.c tun.h cmdline.c cmdline.h ippool.h ippool.c syserr.h syserr.c
subdir = sgsnemu
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
@ -99,7 +99,8 @@ CONFIG_CLEAN_FILES =
bin_PROGRAMS = sgsnemu$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
am_sgsnemu_OBJECTS = sgsnemu.$(OBJEXT) tun.$(OBJEXT) cmdline.$(OBJEXT)
am_sgsnemu_OBJECTS = sgsnemu.$(OBJEXT) tun.$(OBJEXT) cmdline.$(OBJEXT) \
ippool.$(OBJEXT) syserr.$(OBJEXT)
sgsnemu_OBJECTS = $(am_sgsnemu_OBJECTS)
sgsnemu_LDADD = $(LDADD)
sgsnemu_DEPENDENCIES =
@ -111,7 +112,8 @@ CPPFLAGS = @CPPFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/cmdline.Po ./$(DEPDIR)/sgsnemu.Po \
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/cmdline.Po ./$(DEPDIR)/ippool.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sgsnemu.Po ./$(DEPDIR)/syserr.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/tun.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -173,7 +175,9 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmdline.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ippool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgsnemu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syserr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Po@am__quote@
distclean-depend:

View File

@ -1,7 +1,7 @@
/*
File autogenerated by gengetopt version 2.8rc
File autogenerated by gengetopt version 2.8
generated with the following command:
../../gengetopt-2.8rc/src/gengetopt --conf-parser
gengetopt --conf-parser
The developers of gengetopt consider the fixed text that goes in all
gengetopt output files to be in the public domain:
@ -61,10 +61,9 @@ cmdline_parser_print_help (void)
printf(" -uSTRING --uid=STRING Login user ID (default='mig')\n");
printf(" -pSTRING --pwd=STRING Login password (default='hemmelig')\n");
printf(" --createif Create local network interface (default=off)\n");
printf(" --defaultroute Create default route (default=off)\n");
printf(" --ipup=STRING Script to run after link-up\n");
printf(" --ipdown=STRING Script to run after link-down\n");
printf(" --net=STRING Network (default='0.0.0.0')\n");
printf(" --mask=STRING Network mask (default='0.0.0.0')\n");
printf(" --pinghost=STRING Ping remote host\n");
printf(" --pingrate=INT Number of ping req per second (default='1')\n");
printf(" --pingsize=INT Number of ping data bytes (default='56')\n");
@ -112,10 +111,9 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->uid_given = 0 ;
args_info->pwd_given = 0 ;
args_info->createif_given = 0 ;
args_info->defaultroute_given = 0 ;
args_info->ipup_given = 0 ;
args_info->ipdown_given = 0 ;
args_info->net_given = 0 ;
args_info->mask_given = 0 ;
args_info->pinghost_given = 0 ;
args_info->pingrate_given = 0 ;
args_info->pingsize_given = 0 ;
@ -139,10 +137,9 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->uid_arg = strdup("mig") ;\
args_info->pwd_arg = strdup("hemmelig") ;\
args_info->createif_flag = 0;\
args_info->defaultroute_flag = 0;\
args_info->ipup_arg = NULL; \
args_info->ipdown_arg = NULL; \
args_info->net_arg = strdup("0.0.0.0") ;\
args_info->mask_arg = strdup("0.0.0.0") ;\
args_info->pinghost_arg = NULL; \
args_info->pingrate_arg = 1 ;\
args_info->pingsize_arg = 56 ;\
@ -181,10 +178,9 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
{ "uid", 1, NULL, 'u' },
{ "pwd", 1, NULL, 'p' },
{ "createif", 0, NULL, 0 },
{ "defaultroute", 0, NULL, 0 },
{ "ipup", 1, NULL, 0 },
{ "ipdown", 1, NULL, 0 },
{ "net", 1, NULL, 0 },
{ "mask", 1, NULL, 0 },
{ "pinghost", 1, NULL, 0 },
{ "pingrate", 1, NULL, 0 },
{ "pingsize", 1, NULL, 0 },
@ -410,6 +406,19 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->createif_flag = !(args_info->createif_flag);
break;
}
/* Create default route. */
else if (strcmp (long_options[option_index].name, "defaultroute") == 0)
{
if (args_info->defaultroute_given)
{
fprintf (stderr, "%s: `--defaultroute' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->defaultroute_given = 1;
args_info->defaultroute_flag = !(args_info->defaultroute_flag);
break;
}
/* Script to run after link-up. */
else if (strcmp (long_options[option_index].name, "ipup") == 0)
{
@ -436,32 +445,6 @@ cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_i
args_info->ipdown_arg = strdup (optarg);
break;
}
/* Network. */
else if (strcmp (long_options[option_index].name, "net") == 0)
{
if (args_info->net_given)
{
fprintf (stderr, "%s: `--net' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->net_given = 1;
args_info->net_arg = strdup (optarg);
break;
}
/* Network mask. */
else if (strcmp (long_options[option_index].name, "mask") == 0)
{
if (args_info->mask_given)
{
fprintf (stderr, "%s: `--mask' option given more than once\n", PACKAGE);
clear_args ();
exit (EXIT_FAILURE);
}
args_info->mask_given = 1;
args_info->mask_arg = strdup (optarg);
break;
}
/* Ping remote host. */
else if (strcmp (long_options[option_index].name, "pinghost") == 0)
{
@ -851,6 +834,15 @@ cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *ar
}
continue;
}
if (!strcmp(fopt, "defaultroute"))
{
if (override || !args_info->defaultroute_given)
{
args_info->defaultroute_given = 1;
args_info->defaultroute_flag = !(args_info->defaultroute_flag);
}
continue;
}
if (!strcmp(fopt, "ipup"))
{
if (override || !args_info->ipup_given)
@ -883,38 +875,6 @@ cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *ar
}
continue;
}
if (!strcmp(fopt, "net"))
{
if (override || !args_info->net_given)
{
args_info->net_given = 1;
if (fnum == 2)
args_info->net_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "mask"))
{
if (override || !args_info->mask_given)
{
args_info->mask_given = 1;
if (fnum == 2)
args_info->mask_arg = strdup (farg);
else
{
fprintf (stderr, "%s:%d: required <option_name> <option_val>\n",
filename, line_num);
exit (EXIT_FAILURE);
}
}
continue;
}
if (!strcmp(fopt, "pinghost"))
{
if (override || !args_info->pinghost_given)

View File

@ -1,46 +1,49 @@
# OpenGGSN - Gateway GPRS Support Node
# Copyright (C) 2002 Mondru AB.
# OpenGGSN - Gateway GPRS Support Node
# Copyright (C) 2002, 2003 Mondru AB.
#
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
#
# The initial developer of the original code is
# Jens Jakobsen <jj@openggsn.org>
# The initial developer of the original code is
# Jens Jakobsen <jj@openggsn.org>
#
# Contributor(s):
# Contributor(s):
#
#
# Use "gengetopt --conf-parser < cmdline.ggo"
# to generate cmdline.c and cmdline.h
option "fg" f "Run in foreground" flag off
option "debug" d "Run in debug mode" flag off
option "fg" f "Run in foreground" flag off
option "debug" d "Run in debug mode" flag off
option "conf" c "Read configuration file" string no
option "pidfile" - "Filename of process id file" string default="./sgsnemu.pid" no
option "statedir" - "Directory of nonvolatile data" string default="./" no
option "conf" c "Read configuration file" string no
option "pidfile" - "Filename of process id file" string default="./sgsnemu.pid" no
option "statedir" - "Directory of nonvolatile data" string default="./" no
option "dns" - "DNS Server to use" string no
option "listen" l "Local interface" string no
option "remote" r "Remote host" string no
option "dns" - "DNS Server to use" string no
option "listen" l "Local interface" string no
option "remote" r "Remote host" string no
option "contexts" - "Number of contexts" int default="1" no
option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "contexts" - "Number of contexts" int default="1" no
option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "apn" a "Access point name" string default="internet" no
option "imsi" i "IMSI" string default="240010123456789" no
option "msisdn" m "Mobile Station ISDN number" string default="46702123456" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "uid" u "Login user ID" string default="mig" no
option "pwd" p "Login password" string default="hemmelig" no
option "apn" a "Access point name" string default="internet" no
option "imsi" i "IMSI" string default="240010123456789" no
option "msisdn" m "Mobile Station ISDN number" string default="46702123456" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "uid" u "Login user ID" string default="mig" no
option "pwd" p "Login password" string default="hemmelig" no
option "createif" - "Create local network interface" flag off
option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no
option "net" - "Network" string default="0.0.0.0" no
option "mask" - "Network mask" string default="0.0.0.0" no
option "createif" - "Create local network interface" flag off
option "defaultroute" - "Create default route" flag off
option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no
option "pinghost" - "Ping remote host" string no
option "pingrate" - "Number of ping req per second" int default="1" no
option "pingsize" - "Number of ping data bytes" int default="56" no
option "pingcount" - "Number of ping req to send" int default="0" no
option "pingquiet" - "Do not print ping packet info" flag off
option "pinghost" - "Ping remote host" string no
option "pingrate" - "Number of ping req per second" int default="1" no
option "pingsize" - "Number of ping data bytes" int default="56" no
option "pingcount" - "Number of ping req to send" int default="0" no
option "pingquiet" - "Do not print ping packet info" flag off

View File

@ -1,6 +1,6 @@
/* cmdline.h */
/* File autogenerated by gengetopt version 2.8rc */
/* File autogenerated by gengetopt version 2.8 */
#ifndef _cmdline_h
#define _cmdline_h
@ -37,10 +37,9 @@ struct gengetopt_args_info
char * uid_arg; /* Login user ID (default='mig'). */
char * pwd_arg; /* Login password (default='hemmelig'). */
int createif_flag; /* Create local network interface (default=off). */
int defaultroute_flag; /* Create default route (default=off). */
char * ipup_arg; /* Script to run after link-up. */
char * ipdown_arg; /* Script to run after link-down. */
char * net_arg; /* Network (default='0.0.0.0'). */
char * mask_arg; /* Network mask (default='0.0.0.0'). */
char * pinghost_arg; /* Ping remote host. */
int pingrate_arg; /* Number of ping req per second (default='1'). */
int pingsize_arg; /* Number of ping data bytes (default='56'). */
@ -66,10 +65,9 @@ struct gengetopt_args_info
int uid_given ; /* Whether uid was given. */
int pwd_given ; /* Whether pwd was given. */
int createif_given ; /* Whether createif was given. */
int defaultroute_given ; /* Whether defaultroute was given. */
int ipup_given ; /* Whether ipup was given. */
int ipdown_given ; /* Whether ipdown was given. */
int net_given ; /* Whether net was given. */
int mask_given ; /* Whether mask was given. */
int pinghost_given ; /* Whether pinghost was given. */
int pingrate_given ; /* Whether pingrate was given. */
int pingsize_given ; /* Whether pingsize was given. */

416
sgsnemu/ippool.c Normal file
View File

@ -0,0 +1,416 @@
/*
* IP address pool functions.
* Copyright (C) 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
*
*/
#include <netinet/in.h> /* in_addr */
#include <stdlib.h> /* calloc */
#include <stdio.h> /* sscanf */
#include "ippool.h"
/*
--------------------------------------------------------------------
Public domain by From Bob Jenkins, December 1996.
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/*
--------------------------------------------------------------------
lookup() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
level : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 6len+35 instructions.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (ub1 **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial.
See http://burtleburtle.net/bob/hash/evahash.html
Use for hash table lookup, or anything where one collision in 2^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
unsigned long int lookup( k, length, level)
register unsigned char *k; /* the key */
register unsigned long int length; /* the length of the key */
register unsigned long int level; /* the previous hash, or an arbitrary value */
{
register unsigned long int a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
/*
End of public domain code by From Bob Jenkins, December 1996.
--------------------------------------------------------------------
*/
int ippool_printaddr(struct ippool_t *this) {
int n;
printf("ippool_printaddr\n");
printf("First %d\n", this->first - this->member);
printf("Last %d\n", this->last - this->member);
printf("Listsize %d\n", this->listsize);
for (n=0; n<this->listsize; n++) {
printf("Unit %d inuse %d prev %d next %d addr %x\n",
n,
this->member[n].inuse,
this->member[n].prev - this->member,
this->member[n].next - this->member,
this->member[n].addr.s_addr
);
}
return 0;
}
unsigned long int ippool_hash4(struct in_addr *addr) {
return lookup(&addr->s_addr, sizeof(addr->s_addr), 0);
}
#ifndef IPPOOL_NOIP6
unsigned long int ippool_hash6(struct in6_addr *addr) {
return lookup(addr->u6_addr8, sizeof(addr->u6_addr8), 0);
}
#endif
/* Get IP address and mask */
int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number) {
/* Parse only first instance of network for now */
/* Eventually "number" will indicate the token which we want to parse */
unsigned int a1, a2, a3, a4;
unsigned int m1, m2, m3, m4;
int c;
unsigned int m;
int masklog;
c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u",
&a1, &a2, &a3, &a4,
&m1, &m2, &m3, &m4);
switch (c) {
case 4:
if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0) /* Full Internet */
mask->s_addr = 0x00000000;
else if (a2 == 0 && a3 == 0 && a4 == 0) /* class A */
mask->s_addr = htonl(0xff000000);
else if (a3 == 0 && a4 == 0) /* class B */
mask->s_addr = htonl(0xffff0000);
else if (a4 == 0) /* class C */
mask->s_addr = htonl(0xffffff00);
else
mask->s_addr = 0xffffffff;
break;
case 5:
if (m1 < 0 || m1 > 32) {
return -1; /* Invalid mask */
}
mask->s_addr = htonl(0xffffffff << (32 - m1));
break;
case 8:
if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256)
return -1; /* Wrong mask format */
m = m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4;
for (masklog = 0; ((1 << masklog) < ((~m)+1)); masklog++);
if (((~m)+1) != (1 << masklog))
return -1; /* Wrong mask format (not all ones followed by all zeros)*/
mask->s_addr = htonl(m);
break;
default:
return -1; /* Invalid mask */
}
if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256)
return -1; /* Wrong IP address format */
else
addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
return 0;
}
/* Create new address pool */
int ippool_new(struct ippool_t **this, char *pool, int flags) {
/* Parse only first instance of network for now */
int i;
struct ippoolm_t *p;
struct ippoolm_t *p_prev = NULL;
uint32_t hash;
struct in_addr addr;
struct in_addr mask;
unsigned int m;
unsigned int listsize;
if (ippool_aton(&addr, &mask, pool, 0))
return 0; /* Failed to parse pool */
m = ntohl(mask.s_addr);
listsize = ((~m)+1);
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
listsize--;
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
listsize--;
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
/* Failed to allocate memory for ippool */
return -1;
}
(*this)->listsize += listsize;
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), (*this)->listsize))){
/* Failed to allocate memory for members in ippool */
return -1;
}
for ((*this)->hashlog = 0;
((1 << (*this)->hashlog) < listsize);
(*this)->hashlog++);
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
/* Determine hashsize */
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
(*this)->hashmask = (*this)->hashsize -1;
/* Allocate hash table */
if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
/* Failed to allocate memory for hash members in ippool */
return -1;
}
(*this)->first = NULL;
(*this)->last = NULL;
for (i = 0; i<(*this)->listsize; i++) {
if (flags & IPPOOL_NONETWORK)
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 1);
else
(*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i);
(*this)->member[i].inuse = 0;
(*this)->member[i].parent = *this;
/* Insert into list of unused */
(*this)->member[i].prev = (*this)->last;
if ((*this)->last) {
(*this)->last->next = &((*this)->member[i]);
}
else {
(*this)->first = &((*this)->member[i]);
}
(*this)->last = &((*this)->member[i]);
(*this)->member[i].next = NULL; /* Redundant */
/* Insert into hash table */
hash = ippool_hash4(&(*this)->member[i].addr) & (*this)->hashmask;
for (p = (*this)->hash[hash]; p; p = p->nexthash)
p_prev = p;
if (!p_prev)
(*this)->hash[hash] = &((*this)->member[i]);
else
p_prev->nexthash = &((*this)->member[i]);
}
/*ippool_printaddr(*this);*/
return 0;
}
/* Delete existing address pool */
int ippool_free(struct ippool_t *this) {
free(this->hash);
free(this->member);
free(this);
return 0; /* Always OK */
}
/* Find an IP address in the pool */
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
uint32_t hash;
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
*member = p;
return 0;
}
}
*member = NULL;
return -1; /* Address could not be found */
}
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr) {
struct ippoolm_t *p;
struct ippoolm_t *p2 = NULL;
uint32_t hash;
/*ippool_printaddr(this);*/
if ((addr) && (addr->s_addr)) { /* IP address given */
/* Find in hash table */
hash = ippool_hash4(addr) & this->hashmask;
for (p = this->hash[hash]; p; p = p->nexthash) {
if ((p->addr.s_addr == addr->s_addr)) {
p2 = p;
break;
}
}
}
else { /* No ip address given */
p2 = this -> first;
}
if (!p2) return -1; /* Not found */
if (p2->inuse) return -1; /* Allready in use / Should not happen */
/* Found new address. Remove from queue */
if (p2->prev)
p2->prev->next = p2->next;
else
this->first = p2->next;
if (p2->next)
p2->next->prev = p2->prev;
else
this->last = p2->prev;
p2->next = NULL;
p2->prev = NULL;
p2->inuse = 1;
*member = p2;
/*ippool_printaddr(this);*/
return 0; /* Success */
}
int ippool_freeip(struct ippoolm_t *member) {
struct ippool_t *this = member->parent;
/*ippool_printaddr(this);*/
if (!member->inuse) return -1; /* Not in use: Should not happen */
/* Insert into list of unused */
member->prev = this->last;
if (this->last) {
this->last->next = member;
}
else {
this->first = member;
}
this->last = member;
member->inuse = 0;
/*ippool_printaddr(this);*/
return 0; /* Success */
}
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif

105
sgsnemu/ippool.h Normal file
View File

@ -0,0 +1,105 @@
/*
* IP address pool functions.
* Copyright (C) 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
*
*/
#ifndef _IPPOOL_H
#define _IPPOOL_H
/* Assuming that the address space is fragmented we need a hash table
in order to return the addresses.
The list pool should provide for both IPv4 and IPv6 addresses.
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
*/
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1;
#define IPPOOL_NOIP6
#define IPPOOL_NONETWORK 0x01
#define IPPOOL_NOBROADCAST 0x02
struct ippoolm_t; /* Forward declaration */
struct ippool_t {
int listsize; /* Total number of addresses */
struct ippoolm_t *member; /* Listsize array of members */
int hashsize; /* Size of hash table */
int hashlog; /* Log2 size of hash table */
int hashmask; /* Bitmask for calculating hash */
struct ippoolm_t **hash; /* Hashsize array of pointer to member */
struct ippoolm_t *first; /* Pointer to first available member */
struct ippoolm_t *last; /* Pointer to last available member */
};
struct ippoolm_t {
#ifndef IPPOOL_NOIP6
struct in6_addr addr; /* IP address of this member */
#else
struct in_addr addr; /* IP address of this member */
#endif
int inuse; /* 0=available; 1= inuse */
struct ippoolm_t *nexthash; /* Linked list part of hash table */
struct ippoolm_t *prev, *next; /* Double linked list of available members */
struct ippool_t *parent; /* Pointer to parent */
void *peer; /* Pointer to peer protocol handler */
};
/* The above structures requires approximately 20+4 = 24 bytes for
each address (IPv4). For IPv6 the corresponding value is 32+4 = 36
bytes for each address. */
/* Hash an IP address using code based on Bob Jenkins lookupa */
extern unsigned long int ippool_hash4(struct in_addr *addr);
/* Create new address pool */
extern int ippool_new(struct ippool_t **this, char *pool, int flags);
/* Delete existing address pool */
extern int ippool_free(struct ippool_t *this);
/* Find an IP address in the pool */
extern int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
check to see if the given address is available */
extern int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
struct in_addr *addr);
/* Return a previously allocated IP address */
extern int ippool_freeip(struct ippoolm_t *member);
/* Get net and mask based on ascii string */
extern int ippool_aton(struct in_addr *addr, struct in_addr *mask,
char *pool, int number);
#ifndef IPPOOL_NOIP6
extern unsigned long int ippool_hash6(struct in6_addr *addr);
extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
#endif
#endif /* !_IPPOOL_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,24 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
* Contributor(s):
*
*/
/*
* tun.c: Contains all TUN functionality. Should be able to handle multiple
* tunnels in the same program. Each tunnel is identified by the socket.
* I suppose that no other state information than the socket is needed.
* tun.c: Contains all TUN functionality. Is able to handle multiple
* tunnels in the same program. Each tunnel is identified by the struct,
* which is passed to functions.
*
* - tun_newtun: Initialise TUN tunnel.
* - tun_freetun: Free a device previously created with tun_newtun.
* - tun_encaps: Encapsulate packet in TUN tunnel and send off
* - tun_decaps: Extract packet from TUN tunnel and call function to
* ship it off as GTP encapsulated packet.
*
* TODO:
* - Do we need to handle fragmentation?
*/
@ -54,75 +46,471 @@
#include <linux/if.h>
#include <errno.h>
#include <linux/if_tun.h>
#include <net/route.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "tun.h"
#include "syserr.h"
int tun_newtun(struct tun_t **tun)
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
{
int len = RTA_LENGTH(dlen);
int alen = NLMSG_ALIGN(n->nlmsg_len);
struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
if (alen + len > nsize)
return -1;
rta->rta_len = len;
rta->rta_type = type;
memcpy(RTA_DATA(rta), d, dlen);
n->nlmsg_len = alen + len;
return 0;
}
int tun_gifindex(struct tun_t *this, int *index) {
struct ifreq ifr;
int fd;
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
syslog(LOG_ERR, "%s %d. calloc(nmemb=%d, size=%d) failed: Error = %s(%d)",
__FILE__, __LINE__, 1, sizeof(struct tun_t),
strerror(errno), errno);
return EOF;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl() failed");
close(fd);
return -1;
}
close(fd);
*index = ifr.ifr_ifindex;
return 0;
}
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
syslog(LOG_ERR, "TUN: open() failed");
int tun_sifflags(struct tun_t *this, int flags) {
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_flags = flags;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
}
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFFLAGS) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
/* Currently unused */
int tun_addroute2(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask) {
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
int status;
struct sockaddr_nl nladdr;
struct iovec iov;
struct msghdr msg;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = 0;
if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address family %d", local.nl_family);
close(fd);
return -1;
}
iov.iov_base = (void*)&req.n;
iov.iov_len = req.n.nlmsg_len;
msg.msg_name = (void*)&nladdr;
msg.msg_namelen = sizeof(nladdr),
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
req.n.nlmsg_seq = 0;
req.n.nlmsg_flags |= NLM_F_ACK;
status = sendmsg(fd, &msg, 0); /* TODO: Error check */
close(fd);
return 0;
}
int tun_addaddr(struct tun_t *this,
struct in_addr *addr,
struct in_addr *dstaddr,
struct in_addr *netmask) {
struct {
struct nlmsghdr n;
struct ifaddrmsg i;
char buf[TUN_NLBUFSIZE];
} req;
struct sockaddr_nl local;
int addr_len;
int fd;
int status;
struct sockaddr_nl nladdr;
struct iovec iov;
struct msghdr msg;
if (!this->addrs) /* Use ioctl for first addr to make ping work */
return tun_setaddr(this, addr, dstaddr, netmask);
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWADDR;
req.i.ifa_family = AF_INET;
req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
req.i.ifa_flags = 0;
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
if (tun_gifindex(this, &req.i.ifa_index)) {
return -1;
}
tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = 0;
if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"bind() failed");
close(fd);
return -1;
}
addr_len = sizeof(local);
if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"getsockname() failed");
close(fd);
return -1;
}
if (addr_len != sizeof(local)) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address length %d", addr_len);
close(fd);
return -1;
}
if (local.nl_family != AF_NETLINK) {
sys_err(LOG_ERR, __FILE__, __LINE__, 0,
"Wrong address family %d", local.nl_family);
close(fd);
return -1;
}
iov.iov_base = (void*)&req.n;
iov.iov_len = req.n.nlmsg_len;
msg.msg_name = (void*)&nladdr;
msg.msg_namelen = sizeof(nladdr),
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
req.n.nlmsg_seq = 0;
req.n.nlmsg_flags |= NLM_F_ACK;
status = sendmsg(fd, &msg, 0); /* TODO Error check */
tun_sifflags(this, IFF_UP | IFF_RUNNING);
close(fd);
this->addrs++;
return 0;
}
int tun_setaddr(struct tun_t *this,
struct in_addr *addr,
struct in_addr *dstaddr,
struct in_addr *netmask)
{
struct ifreq ifr;
int fd;
memset (&ifr, '\0', sizeof (ifr));
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_dstaddr.sa_family = AF_INET;
ifr.ifr_netmask.sa_family = AF_INET;
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
/* Create a channel to the NET kernel. */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
if (addr) { /* Set the interface address */
this->addr.s_addr = addr->s_addr;
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
if (errno != EEXIST) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR) failed");
}
else {
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFADDR): Address already exists");
}
close(fd);
return -1;
}
}
if (dstaddr) { /* Set the destination address */
this->dstaddr.s_addr = dstaddr->s_addr;
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
dstaddr->s_addr;
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFDSTADDR) failed");
close(fd);
return -1;
}
}
if (netmask) { /* Set the netmask */
this->netmask.s_addr = netmask->s_addr;
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
netmask->s_addr;
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCSIFNETMASK) failed");
close(fd);
return -1;
}
}
close(fd);
this->addrs++;
return tun_sifflags(this, IFF_UP | IFF_RUNNING);
}
int tun_addroute(struct tun_t *this,
struct in_addr *dst,
struct in_addr *gateway,
struct in_addr *mask)
{
struct rtentry r;
int fd;
memset (&r, '\0', sizeof (r));
r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
/* Create a channel to the NET kernel. */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"socket() failed");
return -1;
}
r.rt_dst.sa_family = AF_INET;
r.rt_gateway.sa_family = AF_INET;
r.rt_genmask.sa_family = AF_INET;
((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
"ioctl(SIOCADDRT) failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
int tun_new(struct tun_t **tun)
{
struct ifreq ifr;
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
return EOF;
}
(*tun)->cb_ind = NULL;
(*tun)->addrs = 0;
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
syslog(LOG_ERR, "TUN: ioctl() failed");
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
close((*tun)->fd);
return -1;
}
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
return (*tun)->fd;
(*tun)->devname[IFNAMSIZ] = 0;
return 0;
}
int tun_freetun(struct tun_t *tun)
int tun_free(struct tun_t *tun)
{
if (close(tun->fd)) {
syslog(LOG_ERR, "%s %d. close(fd=%d) failed: Error = %s",
__FILE__, __LINE__, tun->fd, strerror(errno));
return EOF;
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
}
free(tun);
return 0;
}
int tun_decaps(struct tun_t *tun,
int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
void *cl)
int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
this->cb_ind = cb_ind;
return 0;
}
int tun_decaps(struct tun_t *this)
{
unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ];
int status;
unsigned char buffer[PACKET_MAX];
int status;
if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
return -1;
}
if (this->cb_ind)
return this->cb_ind(this, buffer, status);
if ((status = read(tun->fd, buffer, sizeof(buffer))) <= 0) {
syslog(LOG_ERR, "TUN: read(fd=%d,buffer=%lx,len=%d) from network failed: status = %d error = %s",
tun->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
return -1;
}
/* Need to include code to verify packet src and dest addresses */
return cb(cl, tun, buffer, status);
return 0;
}
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
return write(tun->fd, pack, len);
return write(tun->fd, pack, len);
}
int tun_runscript(struct tun_t *tun, char* script) {
char buf[TUN_SCRIPTSIZE];
char snet[TUN_ADDRSIZE];
char smask[TUN_ADDRSIZE];
strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
snet[sizeof(snet)-1] = 0;
strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
smask[sizeof(smask)-1] = 0;
/* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
snprintf(buf, sizeof(buf), "%s %s %s %s",
script, tun->devname, snet, smask);
buf[sizeof(buf)-1] = 0;
system(buf);
return 0;
}

View File

@ -1,48 +1,78 @@
/*
* OpenGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
* The initial developer of the original code is
* Jens Jakobsen <jj@openggsn.org>
*
* Contributor(s):
* Contributor(s):
*
*/
#ifndef _TUN_H
#define _TUN_H
#define hton8(x) (x)
#define ntoh8(x) (x)
#define hton16(x) htons(x)
#define ntoh16(x) ntohs(x)
#define hton32(x) htonl(x)
#define ntoh32(x) ntohl(x)
#define PACKET_MAX 8196 /* Maximum packet size we receive */
#define TUN_SCRIPTSIZE 256
#define TUN_ADDRSIZE 128
#define TUN_NLBUFSIZE 1024
struct tun_packet_t {
unsigned int ver:4;
unsigned int ihl:4;
unsigned int dscp:6;
unsigned int ecn:2;
unsigned int length:16;
unsigned int id:16;
unsigned int flags:3;
unsigned int fragment:13;
unsigned int ttl:8;
unsigned int protocol:8;
unsigned int check:16;
unsigned int src:32;
unsigned int dst:32;
};
#define PACKET_MAX 8196 /* TODO */
/* ***********************************************************
* Information storage for each tun instance
*************************************************************/
struct tun_t {
int fd; /* File descriptor to network interface */
struct in_addr addr; /* IP address of tun interface */
int fd; /* File descriptor to tun interface */
struct in_addr addr;
struct in_addr dstaddr;
struct in_addr netmask;
int addrs; /* Number of allocated IP addresses */
char devname[IFNAMSIZ];/* Name of the tun device */
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len);
};
extern int tun_newtun(struct tun_t **tun);
extern int tun_freetun(struct tun_t *tun);
extern int tun_decaps(struct tun_t *tun,
int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
void *cl);
extern int tun_new(struct tun_t **tun);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
extern int tun_addaddr(struct tun_t *this, struct in_addr *addr,
struct in_addr *dstaddr, struct in_addr *netmask);
extern int tun_setaddr(struct tun_t *this, struct in_addr *our_adr,
struct in_addr *his_adr, struct in_addr *net_mask);
int tun_addroute(struct tun_t *this, struct in_addr *dst,
struct in_addr *gateway, struct in_addr *mask);
extern int tun_set_cb_ind(struct tun_t *this,
int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len));
extern int tun_runscript(struct tun_t *tun, char* script);
#endif /* !_TUN_H */