diff --git a/ggsn/cmdline.c b/ggsn/cmdline.c index d83376f..c5da6b4 100644 --- a/ggsn/cmdline.c +++ b/ggsn/cmdline.c @@ -23,878 +23,939 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; +const char *gengetopt_args_info_usage = + "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; const char *gengetopt_args_info_help[] = { - " -h, --help Print help and exit", - " -V, --version Print version and exit", - " -f, --fg Run in foreground (default=off)", - " -d, --debug Run in debug mode (default=off)", - " -c, --conf=STRING Read configuration file (default=`/etc/ggsn.conf')", - " --pidfile=STRING Filename of process id file \n (default=`/var/run/ggsn.pid')", - " --statedir=STRING Directory of nonvolatile data \n (default=`/var/lib/ggsn/')", - " -l, --listen=STRING Local interface", - " -n, --net=STRING Network (default=`192.168.0.0/24')", - " --ipup=STRING Script to run after link-up", - " --ipdown=STRING Script to run after link-down", - " --dynip=STRING Dynamic IP address pool", - " --statip=STRING Static IP address pool", - " --pcodns1=STRING PCO DNS Server 1 (default=`0.0.0.0')", - " --pcodns2=STRING PCO DNS Server 2 (default=`0.0.0.0')", - " --timelimit=INT Exit after timelimit seconds (default=`0')", - " -a, --apn=STRING Access point name (default=`internet')", - " -q, --qos=INT Requested quality of service (default=`0x0b921f')", - 0 + " -h, --help Print help and exit", + " -V, --version Print version and exit", + " -f, --fg Run in foreground (default=off)", + " -d, --debug Run in debug mode (default=off)", + " -c, --conf=STRING Read configuration file (default=`/etc/ggsn.conf')", + " --pidfile=STRING Filename of process id file \n (default=`/var/run/ggsn.pid')", + " --statedir=STRING Directory of nonvolatile data \n (default=`/var/lib/ggsn/')", + " -l, --listen=STRING Local interface", + " -n, --net=STRING Network (default=`192.168.0.0/24')", + " --ipup=STRING Script to run after link-up", + " --ipdown=STRING Script to run after link-down", + " --dynip=STRING Dynamic IP address pool", + " --statip=STRING Static IP address pool", + " --pcodns1=STRING PCO DNS Server 1 (default=`0.0.0.0')", + " --pcodns2=STRING PCO DNS Server 2 (default=`0.0.0.0')", + " --timelimit=INT Exit after timelimit seconds (default=`0')", + " -a, --apn=STRING Access point name (default=`internet')", + " -q, --qos=INT Requested quality of service (default=`0x0b921f')", + 0 }; static -void clear_given (struct gengetopt_args_info *args_info); +void clear_given(struct gengetopt_args_info *args_info); static -void clear_args (struct gengetopt_args_info *args_info); +void clear_args(struct gengetopt_args_info *args_info); static int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error); +cmdline_parser_internal(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required, + const char *additional_error); -struct line_list -{ - char * string_arg; - struct line_list * next; +struct line_list { + char *string_arg; + struct line_list *next; }; static struct line_list *cmd_line_list = 0; static struct line_list *cmd_line_list_tmp = 0; -static void -free_cmd_list(void) +static void free_cmd_list(void) { - /* free the list of a previous call */ - if (cmd_line_list) - { - while (cmd_line_list) { - cmd_line_list_tmp = cmd_line_list; - cmd_line_list = cmd_line_list->next; - free (cmd_line_list_tmp->string_arg); - free (cmd_line_list_tmp); - } - } + /* free the list of a previous call */ + if (cmd_line_list) { + while (cmd_line_list) { + cmd_line_list_tmp = cmd_line_list; + cmd_line_list = cmd_line_list->next; + free(cmd_line_list_tmp->string_arg); + free(cmd_line_list_tmp); + } + } } - -static char * -gengetopt_strdup (const char *s); +static char *gengetopt_strdup(const char *s); static -void clear_given (struct gengetopt_args_info *args_info) +void clear_given(struct gengetopt_args_info *args_info) { - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->fg_given = 0 ; - args_info->debug_given = 0 ; - args_info->conf_given = 0 ; - args_info->pidfile_given = 0 ; - args_info->statedir_given = 0 ; - args_info->listen_given = 0 ; - args_info->net_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->help_given = 0; + args_info->version_given = 0; + args_info->fg_given = 0; + args_info->debug_given = 0; + args_info->conf_given = 0; + args_info->pidfile_given = 0; + args_info->statedir_given = 0; + args_info->listen_given = 0; + args_info->net_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; } static -void clear_args (struct gengetopt_args_info *args_info) +void clear_args(struct gengetopt_args_info *args_info) { - args_info->fg_flag = 0; - args_info->debug_flag = 0; - args_info->conf_arg = gengetopt_strdup ("/etc/ggsn.conf"); - args_info->conf_orig = NULL; - args_info->pidfile_arg = gengetopt_strdup ("/var/run/ggsn.pid"); - args_info->pidfile_orig = NULL; - args_info->statedir_arg = gengetopt_strdup ("/var/lib/ggsn/"); - args_info->statedir_orig = NULL; - args_info->listen_arg = NULL; - args_info->listen_orig = NULL; - args_info->net_arg = gengetopt_strdup ("192.168.0.0/24"); - args_info->net_orig = NULL; - args_info->ipup_arg = NULL; - args_info->ipup_orig = NULL; - args_info->ipdown_arg = NULL; - args_info->ipdown_orig = NULL; - args_info->dynip_arg = NULL; - args_info->dynip_orig = NULL; - args_info->statip_arg = NULL; - args_info->statip_orig = NULL; - args_info->pcodns1_arg = gengetopt_strdup ("0.0.0.0"); - args_info->pcodns1_orig = NULL; - args_info->pcodns2_arg = gengetopt_strdup ("0.0.0.0"); - args_info->pcodns2_orig = NULL; - args_info->timelimit_arg = 0; - args_info->timelimit_orig = NULL; - args_info->apn_arg = gengetopt_strdup ("internet"); - args_info->apn_orig = NULL; - args_info->qos_arg = 0x0b921f; - args_info->qos_orig = NULL; - + args_info->fg_flag = 0; + args_info->debug_flag = 0; + args_info->conf_arg = gengetopt_strdup("/etc/ggsn.conf"); + args_info->conf_orig = NULL; + args_info->pidfile_arg = gengetopt_strdup("/var/run/ggsn.pid"); + args_info->pidfile_orig = NULL; + args_info->statedir_arg = gengetopt_strdup("/var/lib/ggsn/"); + args_info->statedir_orig = NULL; + args_info->listen_arg = NULL; + args_info->listen_orig = NULL; + args_info->net_arg = gengetopt_strdup("192.168.0.0/24"); + args_info->net_orig = NULL; + args_info->ipup_arg = NULL; + args_info->ipup_orig = NULL; + args_info->ipdown_arg = NULL; + args_info->ipdown_orig = NULL; + args_info->dynip_arg = NULL; + args_info->dynip_orig = NULL; + args_info->statip_arg = NULL; + args_info->statip_orig = NULL; + args_info->pcodns1_arg = gengetopt_strdup("0.0.0.0"); + args_info->pcodns1_orig = NULL; + args_info->pcodns2_arg = gengetopt_strdup("0.0.0.0"); + args_info->pcodns2_orig = NULL; + args_info->timelimit_arg = 0; + args_info->timelimit_orig = NULL; + args_info->apn_arg = gengetopt_strdup("internet"); + args_info->apn_orig = NULL; + args_info->qos_arg = 0x0b921f; + args_info->qos_orig = NULL; + } static void init_args_info(struct gengetopt_args_info *args_info) { - args_info->help_help = gengetopt_args_info_help[0] ; - args_info->version_help = gengetopt_args_info_help[1] ; - args_info->fg_help = gengetopt_args_info_help[2] ; - args_info->debug_help = gengetopt_args_info_help[3] ; - args_info->conf_help = gengetopt_args_info_help[4] ; - args_info->pidfile_help = gengetopt_args_info_help[5] ; - args_info->statedir_help = gengetopt_args_info_help[6] ; - args_info->listen_help = gengetopt_args_info_help[7] ; - args_info->net_help = gengetopt_args_info_help[8] ; - args_info->ipup_help = gengetopt_args_info_help[9] ; - args_info->ipdown_help = gengetopt_args_info_help[10] ; - args_info->dynip_help = gengetopt_args_info_help[11] ; - args_info->statip_help = gengetopt_args_info_help[12] ; - args_info->pcodns1_help = gengetopt_args_info_help[13] ; - args_info->pcodns2_help = gengetopt_args_info_help[14] ; - args_info->timelimit_help = gengetopt_args_info_help[15] ; - args_info->apn_help = gengetopt_args_info_help[16] ; - args_info->qos_help = gengetopt_args_info_help[17] ; - + args_info->help_help = gengetopt_args_info_help[0]; + args_info->version_help = gengetopt_args_info_help[1]; + args_info->fg_help = gengetopt_args_info_help[2]; + args_info->debug_help = gengetopt_args_info_help[3]; + args_info->conf_help = gengetopt_args_info_help[4]; + args_info->pidfile_help = gengetopt_args_info_help[5]; + args_info->statedir_help = gengetopt_args_info_help[6]; + args_info->listen_help = gengetopt_args_info_help[7]; + args_info->net_help = gengetopt_args_info_help[8]; + args_info->ipup_help = gengetopt_args_info_help[9]; + args_info->ipdown_help = gengetopt_args_info_help[10]; + args_info->dynip_help = gengetopt_args_info_help[11]; + args_info->statip_help = gengetopt_args_info_help[12]; + args_info->pcodns1_help = gengetopt_args_info_help[13]; + args_info->pcodns2_help = gengetopt_args_info_help[14]; + args_info->timelimit_help = gengetopt_args_info_help[15]; + args_info->apn_help = gengetopt_args_info_help[16]; + args_info->qos_help = gengetopt_args_info_help[17]; + } -void -cmdline_parser_print_version (void) +void cmdline_parser_print_version(void) { - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); + printf("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); } -void -cmdline_parser_print_help (void) +void cmdline_parser_print_help(void) { - int i = 0; - cmdline_parser_print_version (); + int i = 0; + cmdline_parser_print_version(); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); - printf("\n%s\n\n", gengetopt_args_info_usage); - while (gengetopt_args_info_help[i]) - printf("%s\n", gengetopt_args_info_help[i++]); + printf("\n%s\n\n", gengetopt_args_info_usage); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); } -void -cmdline_parser_init (struct gengetopt_args_info *args_info) +void cmdline_parser_init(struct gengetopt_args_info *args_info) { - clear_given (args_info); - clear_args (args_info); - init_args_info (args_info); + clear_given(args_info); + clear_args(args_info); + init_args_info(args_info); } -static void -cmdline_parser_release (struct gengetopt_args_info *args_info) +static void cmdline_parser_release(struct gengetopt_args_info *args_info) { - - if (args_info->conf_arg) - { - free (args_info->conf_arg); /* free previous argument */ - args_info->conf_arg = 0; - } - if (args_info->conf_orig) - { - free (args_info->conf_orig); /* free previous argument */ - args_info->conf_orig = 0; - } - if (args_info->pidfile_arg) - { - free (args_info->pidfile_arg); /* free previous argument */ - args_info->pidfile_arg = 0; - } - if (args_info->pidfile_orig) - { - free (args_info->pidfile_orig); /* free previous argument */ - args_info->pidfile_orig = 0; - } - if (args_info->statedir_arg) - { - free (args_info->statedir_arg); /* free previous argument */ - args_info->statedir_arg = 0; - } - if (args_info->statedir_orig) - { - free (args_info->statedir_orig); /* free previous argument */ - args_info->statedir_orig = 0; - } - if (args_info->listen_arg) - { - free (args_info->listen_arg); /* free previous argument */ - args_info->listen_arg = 0; - } - if (args_info->listen_orig) - { - free (args_info->listen_orig); /* free previous argument */ - args_info->listen_orig = 0; - } - if (args_info->net_arg) - { - free (args_info->net_arg); /* free previous argument */ - args_info->net_arg = 0; - } - if (args_info->net_orig) - { - free (args_info->net_orig); /* free previous argument */ - args_info->net_orig = 0; - } - if (args_info->ipup_arg) - { - free (args_info->ipup_arg); /* free previous argument */ - args_info->ipup_arg = 0; - } - if (args_info->ipup_orig) - { - free (args_info->ipup_orig); /* free previous argument */ - args_info->ipup_orig = 0; - } - if (args_info->ipdown_arg) - { - free (args_info->ipdown_arg); /* free previous argument */ - args_info->ipdown_arg = 0; - } - if (args_info->ipdown_orig) - { - free (args_info->ipdown_orig); /* free previous argument */ - args_info->ipdown_orig = 0; - } - if (args_info->dynip_arg) - { - free (args_info->dynip_arg); /* free previous argument */ - args_info->dynip_arg = 0; - } - if (args_info->dynip_orig) - { - free (args_info->dynip_orig); /* free previous argument */ - args_info->dynip_orig = 0; - } - if (args_info->statip_arg) - { - free (args_info->statip_arg); /* free previous argument */ - args_info->statip_arg = 0; - } - if (args_info->statip_orig) - { - free (args_info->statip_orig); /* free previous argument */ - args_info->statip_orig = 0; - } - if (args_info->pcodns1_arg) - { - free (args_info->pcodns1_arg); /* free previous argument */ - args_info->pcodns1_arg = 0; - } - if (args_info->pcodns1_orig) - { - free (args_info->pcodns1_orig); /* free previous argument */ - args_info->pcodns1_orig = 0; - } - if (args_info->pcodns2_arg) - { - free (args_info->pcodns2_arg); /* free previous argument */ - args_info->pcodns2_arg = 0; - } - if (args_info->pcodns2_orig) - { - free (args_info->pcodns2_orig); /* free previous argument */ - args_info->pcodns2_orig = 0; - } - if (args_info->timelimit_orig) - { - free (args_info->timelimit_orig); /* free previous argument */ - args_info->timelimit_orig = 0; - } - if (args_info->apn_arg) - { - free (args_info->apn_arg); /* free previous argument */ - args_info->apn_arg = 0; - } - if (args_info->apn_orig) - { - free (args_info->apn_orig); /* free previous argument */ - args_info->apn_orig = 0; - } - if (args_info->qos_orig) - { - free (args_info->qos_orig); /* free previous argument */ - args_info->qos_orig = 0; - } - - clear_given (args_info); + + if (args_info->conf_arg) { + free(args_info->conf_arg); /* free previous argument */ + args_info->conf_arg = 0; + } + if (args_info->conf_orig) { + free(args_info->conf_orig); /* free previous argument */ + args_info->conf_orig = 0; + } + if (args_info->pidfile_arg) { + free(args_info->pidfile_arg); /* free previous argument */ + args_info->pidfile_arg = 0; + } + if (args_info->pidfile_orig) { + free(args_info->pidfile_orig); /* free previous argument */ + args_info->pidfile_orig = 0; + } + if (args_info->statedir_arg) { + free(args_info->statedir_arg); /* free previous argument */ + args_info->statedir_arg = 0; + } + if (args_info->statedir_orig) { + free(args_info->statedir_orig); /* free previous argument */ + args_info->statedir_orig = 0; + } + if (args_info->listen_arg) { + free(args_info->listen_arg); /* free previous argument */ + args_info->listen_arg = 0; + } + if (args_info->listen_orig) { + free(args_info->listen_orig); /* free previous argument */ + args_info->listen_orig = 0; + } + if (args_info->net_arg) { + free(args_info->net_arg); /* free previous argument */ + args_info->net_arg = 0; + } + if (args_info->net_orig) { + free(args_info->net_orig); /* free previous argument */ + args_info->net_orig = 0; + } + if (args_info->ipup_arg) { + free(args_info->ipup_arg); /* free previous argument */ + args_info->ipup_arg = 0; + } + if (args_info->ipup_orig) { + free(args_info->ipup_orig); /* free previous argument */ + args_info->ipup_orig = 0; + } + if (args_info->ipdown_arg) { + free(args_info->ipdown_arg); /* free previous argument */ + args_info->ipdown_arg = 0; + } + if (args_info->ipdown_orig) { + free(args_info->ipdown_orig); /* free previous argument */ + args_info->ipdown_orig = 0; + } + if (args_info->dynip_arg) { + free(args_info->dynip_arg); /* free previous argument */ + args_info->dynip_arg = 0; + } + if (args_info->dynip_orig) { + free(args_info->dynip_orig); /* free previous argument */ + args_info->dynip_orig = 0; + } + if (args_info->statip_arg) { + free(args_info->statip_arg); /* free previous argument */ + args_info->statip_arg = 0; + } + if (args_info->statip_orig) { + free(args_info->statip_orig); /* free previous argument */ + args_info->statip_orig = 0; + } + if (args_info->pcodns1_arg) { + free(args_info->pcodns1_arg); /* free previous argument */ + args_info->pcodns1_arg = 0; + } + if (args_info->pcodns1_orig) { + free(args_info->pcodns1_orig); /* free previous argument */ + args_info->pcodns1_orig = 0; + } + if (args_info->pcodns2_arg) { + free(args_info->pcodns2_arg); /* free previous argument */ + args_info->pcodns2_arg = 0; + } + if (args_info->pcodns2_orig) { + free(args_info->pcodns2_orig); /* free previous argument */ + args_info->pcodns2_orig = 0; + } + if (args_info->timelimit_orig) { + free(args_info->timelimit_orig); /* free previous argument */ + args_info->timelimit_orig = 0; + } + if (args_info->apn_arg) { + free(args_info->apn_arg); /* free previous argument */ + args_info->apn_arg = 0; + } + if (args_info->apn_orig) { + free(args_info->apn_orig); /* free previous argument */ + args_info->apn_orig = 0; + } + if (args_info->qos_orig) { + free(args_info->qos_orig); /* free previous argument */ + args_info->qos_orig = 0; + } + + clear_given(args_info); } int -cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info) { - FILE *outfile; - int i = 0; + FILE *outfile; + int i = 0; - outfile = fopen(filename, "w"); + outfile = fopen(filename, "w"); - if (!outfile) - { - fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); - return EXIT_FAILURE; - } + if (!outfile) { + fprintf(stderr, "%s: cannot open file for writing: %s\n", + CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } - if (args_info->help_given) { - fprintf(outfile, "%s\n", "help"); - } - if (args_info->version_given) { - fprintf(outfile, "%s\n", "version"); - } - if (args_info->fg_given) { - fprintf(outfile, "%s\n", "fg"); - } - if (args_info->debug_given) { - fprintf(outfile, "%s\n", "debug"); - } - if (args_info->conf_given) { - if (args_info->conf_orig) { - fprintf(outfile, "%s=\"%s\"\n", "conf", args_info->conf_orig); - } else { - fprintf(outfile, "%s\n", "conf"); - } - } - if (args_info->pidfile_given) { - if (args_info->pidfile_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pidfile", args_info->pidfile_orig); - } else { - fprintf(outfile, "%s\n", "pidfile"); - } - } - if (args_info->statedir_given) { - if (args_info->statedir_orig) { - fprintf(outfile, "%s=\"%s\"\n", "statedir", args_info->statedir_orig); - } else { - fprintf(outfile, "%s\n", "statedir"); - } - } - if (args_info->listen_given) { - if (args_info->listen_orig) { - fprintf(outfile, "%s=\"%s\"\n", "listen", args_info->listen_orig); - } else { - fprintf(outfile, "%s\n", "listen"); - } - } - if (args_info->net_given) { - if (args_info->net_orig) { - fprintf(outfile, "%s=\"%s\"\n", "net", args_info->net_orig); - } else { - fprintf(outfile, "%s\n", "net"); - } - } - if (args_info->ipup_given) { - if (args_info->ipup_orig) { - fprintf(outfile, "%s=\"%s\"\n", "ipup", args_info->ipup_orig); - } else { - fprintf(outfile, "%s\n", "ipup"); - } - } - if (args_info->ipdown_given) { - if (args_info->ipdown_orig) { - fprintf(outfile, "%s=\"%s\"\n", "ipdown", args_info->ipdown_orig); - } else { - fprintf(outfile, "%s\n", "ipdown"); - } - } - if (args_info->dynip_given) { - if (args_info->dynip_orig) { - fprintf(outfile, "%s=\"%s\"\n", "dynip", args_info->dynip_orig); - } else { - fprintf(outfile, "%s\n", "dynip"); - } - } - if (args_info->statip_given) { - if (args_info->statip_orig) { - fprintf(outfile, "%s=\"%s\"\n", "statip", args_info->statip_orig); - } else { - fprintf(outfile, "%s\n", "statip"); - } - } - if (args_info->pcodns1_given) { - if (args_info->pcodns1_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pcodns1", args_info->pcodns1_orig); - } else { - fprintf(outfile, "%s\n", "pcodns1"); - } - } - if (args_info->pcodns2_given) { - if (args_info->pcodns2_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pcodns2", args_info->pcodns2_orig); - } else { - fprintf(outfile, "%s\n", "pcodns2"); - } - } - if (args_info->timelimit_given) { - if (args_info->timelimit_orig) { - fprintf(outfile, "%s=\"%s\"\n", "timelimit", args_info->timelimit_orig); - } else { - fprintf(outfile, "%s\n", "timelimit"); - } - } - if (args_info->apn_given) { - if (args_info->apn_orig) { - fprintf(outfile, "%s=\"%s\"\n", "apn", args_info->apn_orig); - } else { - fprintf(outfile, "%s\n", "apn"); - } - } - if (args_info->qos_given) { - if (args_info->qos_orig) { - fprintf(outfile, "%s=\"%s\"\n", "qos", args_info->qos_orig); - } else { - fprintf(outfile, "%s\n", "qos"); - } - } - - fclose (outfile); + if (args_info->help_given) { + fprintf(outfile, "%s\n", "help"); + } + if (args_info->version_given) { + fprintf(outfile, "%s\n", "version"); + } + if (args_info->fg_given) { + fprintf(outfile, "%s\n", "fg"); + } + if (args_info->debug_given) { + fprintf(outfile, "%s\n", "debug"); + } + if (args_info->conf_given) { + if (args_info->conf_orig) { + fprintf(outfile, "%s=\"%s\"\n", "conf", + args_info->conf_orig); + } else { + fprintf(outfile, "%s\n", "conf"); + } + } + if (args_info->pidfile_given) { + if (args_info->pidfile_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pidfile", + args_info->pidfile_orig); + } else { + fprintf(outfile, "%s\n", "pidfile"); + } + } + if (args_info->statedir_given) { + if (args_info->statedir_orig) { + fprintf(outfile, "%s=\"%s\"\n", "statedir", + args_info->statedir_orig); + } else { + fprintf(outfile, "%s\n", "statedir"); + } + } + if (args_info->listen_given) { + if (args_info->listen_orig) { + fprintf(outfile, "%s=\"%s\"\n", "listen", + args_info->listen_orig); + } else { + fprintf(outfile, "%s\n", "listen"); + } + } + if (args_info->net_given) { + if (args_info->net_orig) { + fprintf(outfile, "%s=\"%s\"\n", "net", + args_info->net_orig); + } else { + fprintf(outfile, "%s\n", "net"); + } + } + if (args_info->ipup_given) { + if (args_info->ipup_orig) { + fprintf(outfile, "%s=\"%s\"\n", "ipup", + args_info->ipup_orig); + } else { + fprintf(outfile, "%s\n", "ipup"); + } + } + if (args_info->ipdown_given) { + if (args_info->ipdown_orig) { + fprintf(outfile, "%s=\"%s\"\n", "ipdown", + args_info->ipdown_orig); + } else { + fprintf(outfile, "%s\n", "ipdown"); + } + } + if (args_info->dynip_given) { + if (args_info->dynip_orig) { + fprintf(outfile, "%s=\"%s\"\n", "dynip", + args_info->dynip_orig); + } else { + fprintf(outfile, "%s\n", "dynip"); + } + } + if (args_info->statip_given) { + if (args_info->statip_orig) { + fprintf(outfile, "%s=\"%s\"\n", "statip", + args_info->statip_orig); + } else { + fprintf(outfile, "%s\n", "statip"); + } + } + if (args_info->pcodns1_given) { + if (args_info->pcodns1_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pcodns1", + args_info->pcodns1_orig); + } else { + fprintf(outfile, "%s\n", "pcodns1"); + } + } + if (args_info->pcodns2_given) { + if (args_info->pcodns2_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pcodns2", + args_info->pcodns2_orig); + } else { + fprintf(outfile, "%s\n", "pcodns2"); + } + } + if (args_info->timelimit_given) { + if (args_info->timelimit_orig) { + fprintf(outfile, "%s=\"%s\"\n", "timelimit", + args_info->timelimit_orig); + } else { + fprintf(outfile, "%s\n", "timelimit"); + } + } + if (args_info->apn_given) { + if (args_info->apn_orig) { + fprintf(outfile, "%s=\"%s\"\n", "apn", + args_info->apn_orig); + } else { + fprintf(outfile, "%s\n", "apn"); + } + } + if (args_info->qos_given) { + if (args_info->qos_orig) { + fprintf(outfile, "%s=\"%s\"\n", "qos", + args_info->qos_orig); + } else { + fprintf(outfile, "%s\n", "qos"); + } + } - i = EXIT_SUCCESS; - return i; + fclose(outfile); + + i = EXIT_SUCCESS; + return i; } -void -cmdline_parser_free (struct gengetopt_args_info *args_info) +void cmdline_parser_free(struct gengetopt_args_info *args_info) { - cmdline_parser_release (args_info); + cmdline_parser_release(args_info); } - /* gengetopt_strdup() */ /* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) +char *gengetopt_strdup(const char *s) { - char *result = NULL; - if (!s) - return result; + char *result = NULL; + if (!s) + return result; - result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; + result = (char *)malloc(strlen(s) + 1); + if (result == (char *)0) + return (char *)0; + strcpy(result, s); + return result; } int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +cmdline_parser(int argc, char *const *argv, + struct gengetopt_args_info *args_info) { - return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); + return cmdline_parser2(argc, argv, args_info, 0, 1, 1); } int -cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +cmdline_parser2(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required) { - int result; + int result; - result = cmdline_parser_internal (argc, argv, args_info, override, initialize, check_required, NULL); + result = + cmdline_parser_internal(argc, argv, args_info, override, initialize, + check_required, NULL); - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; + if (result == EXIT_FAILURE) { + cmdline_parser_free(args_info); + exit(EXIT_FAILURE); + } + + return result; } int -cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +cmdline_parser_required(struct gengetopt_args_info *args_info, + const char *prog_name) { - return EXIT_SUCCESS; + return EXIT_SUCCESS; } int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error) +cmdline_parser_internal(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required, + const char *additional_error) { - int c; /* Character of the parsed option. */ + int c; /* Character of the parsed option. */ - int error = 0; - struct gengetopt_args_info local_args_info; + int error = 0; + struct gengetopt_args_info local_args_info; - if (initialize) - cmdline_parser_init (args_info); + if (initialize) + cmdline_parser_init(args_info); - cmdline_parser_init (&local_args_info); + cmdline_parser_init(&local_args_info); - optarg = 0; - optind = 0; - opterr = 1; - optopt = '?'; + optarg = 0; + optind = 0; + opterr = 1; + optopt = '?'; - while (1) - { - int option_index = 0; - char *stop_char; + while (1) { + int option_index = 0; + char *stop_char; - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "fg", 0, NULL, 'f' }, - { "debug", 0, NULL, 'd' }, - { "conf", 1, NULL, 'c' }, - { "pidfile", 1, NULL, 0 }, - { "statedir", 1, NULL, 0 }, - { "listen", 1, NULL, 'l' }, - { "net", 1, NULL, 'n' }, - { "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' }, - { NULL, 0, NULL, 0 } - }; + static struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'V'}, + {"fg", 0, NULL, 'f'}, + {"debug", 0, NULL, 'd'}, + {"conf", 1, NULL, 'c'}, + {"pidfile", 1, NULL, 0}, + {"statedir", 1, NULL, 0}, + {"listen", 1, NULL, 'l'}, + {"net", 1, NULL, 'n'}, + {"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'}, + {NULL, 0, NULL, 0} + }; - stop_char = 0; - c = getopt_long (argc, argv, "hVfdc:l:n:a:q:", long_options, &option_index); + stop_char = 0; + c = getopt_long(argc, argv, "hVfdc:l:n:a:q:", long_options, + &option_index); - if (c == -1) break; /* Exit from `while (1)' loop. */ + if (c == -1) + break; /* Exit from `while (1)' loop. */ - switch (c) - { - case 'h': /* Print help and exit. */ - cmdline_parser_print_help (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); + switch (c) { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help(); + cmdline_parser_free(&local_args_info); + exit(EXIT_SUCCESS); - case 'V': /* Print version and exit. */ - cmdline_parser_print_version (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); + case 'V': /* Print version and exit. */ + cmdline_parser_print_version(); + cmdline_parser_free(&local_args_info); + exit(EXIT_SUCCESS); - case 'f': /* Run in foreground. */ - if (local_args_info.fg_given) - { - fprintf (stderr, "%s: `--fg' (`-f') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->fg_given && ! override) - continue; - local_args_info.fg_given = 1; - args_info->fg_given = 1; - args_info->fg_flag = !(args_info->fg_flag); - break; + case 'f': /* Run in foreground. */ + if (local_args_info.fg_given) { + fprintf(stderr, + "%s: `--fg' (`-f') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->fg_given && !override) + continue; + local_args_info.fg_given = 1; + args_info->fg_given = 1; + args_info->fg_flag = !(args_info->fg_flag); + break; - case 'd': /* Run in debug mode. */ - if (local_args_info.debug_given) - { - fprintf (stderr, "%s: `--debug' (`-d') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->debug_given && ! override) - continue; - local_args_info.debug_given = 1; - args_info->debug_given = 1; - args_info->debug_flag = !(args_info->debug_flag); - break; + case 'd': /* Run in debug mode. */ + if (local_args_info.debug_given) { + fprintf(stderr, + "%s: `--debug' (`-d') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->debug_given && !override) + continue; + local_args_info.debug_given = 1; + args_info->debug_given = 1; + args_info->debug_flag = !(args_info->debug_flag); + break; - case 'c': /* Read configuration file. */ - if (local_args_info.conf_given) - { - fprintf (stderr, "%s: `--conf' (`-c') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->conf_given && ! override) - continue; - local_args_info.conf_given = 1; - args_info->conf_given = 1; - if (args_info->conf_arg) - free (args_info->conf_arg); /* free previous string */ - args_info->conf_arg = gengetopt_strdup (optarg); - if (args_info->conf_orig) - free (args_info->conf_orig); /* free previous string */ - args_info->conf_orig = gengetopt_strdup (optarg); - break; + case 'c': /* Read configuration file. */ + if (local_args_info.conf_given) { + fprintf(stderr, + "%s: `--conf' (`-c') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->conf_given && !override) + continue; + local_args_info.conf_given = 1; + args_info->conf_given = 1; + if (args_info->conf_arg) + free(args_info->conf_arg); /* free previous string */ + args_info->conf_arg = gengetopt_strdup(optarg); + if (args_info->conf_orig) + free(args_info->conf_orig); /* free previous string */ + args_info->conf_orig = gengetopt_strdup(optarg); + break; - case 'l': /* Local interface. */ - if (local_args_info.listen_given) - { - fprintf (stderr, "%s: `--listen' (`-l') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->listen_given && ! override) - continue; - local_args_info.listen_given = 1; - args_info->listen_given = 1; - if (args_info->listen_arg) - free (args_info->listen_arg); /* free previous string */ - args_info->listen_arg = gengetopt_strdup (optarg); - if (args_info->listen_orig) - free (args_info->listen_orig); /* free previous string */ - args_info->listen_orig = gengetopt_strdup (optarg); - break; + case 'l': /* Local interface. */ + if (local_args_info.listen_given) { + fprintf(stderr, + "%s: `--listen' (`-l') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->listen_given && !override) + continue; + local_args_info.listen_given = 1; + args_info->listen_given = 1; + if (args_info->listen_arg) + free(args_info->listen_arg); /* free previous string */ + args_info->listen_arg = gengetopt_strdup(optarg); + if (args_info->listen_orig) + free(args_info->listen_orig); /* free previous string */ + args_info->listen_orig = gengetopt_strdup(optarg); + break; - case 'n': /* Network. */ - if (local_args_info.net_given) - { - fprintf (stderr, "%s: `--net' (`-n') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->net_given && ! override) - continue; - local_args_info.net_given = 1; - args_info->net_given = 1; - if (args_info->net_arg) - free (args_info->net_arg); /* free previous string */ - args_info->net_arg = gengetopt_strdup (optarg); - if (args_info->net_orig) - free (args_info->net_orig); /* free previous string */ - args_info->net_orig = gengetopt_strdup (optarg); - break; + case 'n': /* Network. */ + if (local_args_info.net_given) { + fprintf(stderr, + "%s: `--net' (`-n') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->net_given && !override) + continue; + local_args_info.net_given = 1; + args_info->net_given = 1; + if (args_info->net_arg) + free(args_info->net_arg); /* free previous string */ + args_info->net_arg = gengetopt_strdup(optarg); + if (args_info->net_orig) + free(args_info->net_orig); /* free previous string */ + args_info->net_orig = gengetopt_strdup(optarg); + break; - case 'a': /* Access point name. */ - if (local_args_info.apn_given) - { - fprintf (stderr, "%s: `--apn' (`-a') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->apn_given && ! override) - continue; - local_args_info.apn_given = 1; - args_info->apn_given = 1; - if (args_info->apn_arg) - free (args_info->apn_arg); /* free previous string */ - args_info->apn_arg = gengetopt_strdup (optarg); - if (args_info->apn_orig) - free (args_info->apn_orig); /* free previous string */ - args_info->apn_orig = gengetopt_strdup (optarg); - break; + case 'a': /* Access point name. */ + if (local_args_info.apn_given) { + fprintf(stderr, + "%s: `--apn' (`-a') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->apn_given && !override) + continue; + local_args_info.apn_given = 1; + args_info->apn_given = 1; + if (args_info->apn_arg) + free(args_info->apn_arg); /* free previous string */ + args_info->apn_arg = gengetopt_strdup(optarg); + if (args_info->apn_orig) + free(args_info->apn_orig); /* free previous string */ + args_info->apn_orig = gengetopt_strdup(optarg); + break; - case 'q': /* Requested quality of service. */ - if (local_args_info.qos_given) - { - fprintf (stderr, "%s: `--qos' (`-q') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->qos_given && ! override) - continue; - local_args_info.qos_given = 1; - args_info->qos_given = 1; - args_info->qos_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qos_orig) - free (args_info->qos_orig); /* free previous string */ - args_info->qos_orig = gengetopt_strdup (optarg); - break; + case 'q': /* Requested quality of service. */ + if (local_args_info.qos_given) { + fprintf(stderr, + "%s: `--qos' (`-q') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->qos_given && !override) + continue; + local_args_info.qos_given = 1; + args_info->qos_given = 1; + args_info->qos_arg = strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qos_orig) + free(args_info->qos_orig); /* free previous string */ + args_info->qos_orig = gengetopt_strdup(optarg); + break; + case 0: /* Long option with no short option */ + /* Filename of process id file. */ + if (strcmp(long_options[option_index].name, "pidfile") + == 0) { + if (local_args_info.pidfile_given) { + fprintf(stderr, + "%s: `--pidfile' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pidfile_given && !override) + continue; + local_args_info.pidfile_given = 1; + args_info->pidfile_given = 1; + if (args_info->pidfile_arg) + free(args_info->pidfile_arg); /* free previous string */ + args_info->pidfile_arg = + gengetopt_strdup(optarg); + if (args_info->pidfile_orig) + free(args_info->pidfile_orig); /* free previous string */ + args_info->pidfile_orig = + gengetopt_strdup(optarg); + } + /* Directory of nonvolatile data. */ + else if (strcmp + (long_options[option_index].name, + "statedir") == 0) { + if (local_args_info.statedir_given) { + fprintf(stderr, + "%s: `--statedir' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->statedir_given && !override) + continue; + local_args_info.statedir_given = 1; + args_info->statedir_given = 1; + if (args_info->statedir_arg) + free(args_info->statedir_arg); /* free previous string */ + args_info->statedir_arg = + gengetopt_strdup(optarg); + if (args_info->statedir_orig) + free(args_info->statedir_orig); /* free previous string */ + args_info->statedir_orig = + gengetopt_strdup(optarg); + } + /* Script to run after link-up. */ + else if (strcmp(long_options[option_index].name, "ipup") + == 0) { + if (local_args_info.ipup_given) { + fprintf(stderr, + "%s: `--ipup' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->ipup_given && !override) + continue; + local_args_info.ipup_given = 1; + args_info->ipup_given = 1; + if (args_info->ipup_arg) + free(args_info->ipup_arg); /* free previous string */ + args_info->ipup_arg = gengetopt_strdup(optarg); + if (args_info->ipup_orig) + free(args_info->ipup_orig); /* free previous string */ + args_info->ipup_orig = gengetopt_strdup(optarg); + } + /* Script to run after link-down. */ + else if (strcmp + (long_options[option_index].name, + "ipdown") == 0) { + if (local_args_info.ipdown_given) { + fprintf(stderr, + "%s: `--ipdown' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->ipdown_given && !override) + continue; + local_args_info.ipdown_given = 1; + args_info->ipdown_given = 1; + if (args_info->ipdown_arg) + free(args_info->ipdown_arg); /* free previous string */ + args_info->ipdown_arg = + gengetopt_strdup(optarg); + if (args_info->ipdown_orig) + free(args_info->ipdown_orig); /* free previous string */ + args_info->ipdown_orig = + gengetopt_strdup(optarg); + } + /* Dynamic IP address pool. */ + else if (strcmp + (long_options[option_index].name, + "dynip") == 0) { + if (local_args_info.dynip_given) { + fprintf(stderr, + "%s: `--dynip' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->dynip_given && !override) + continue; + local_args_info.dynip_given = 1; + args_info->dynip_given = 1; + if (args_info->dynip_arg) + free(args_info->dynip_arg); /* free previous string */ + args_info->dynip_arg = gengetopt_strdup(optarg); + if (args_info->dynip_orig) + free(args_info->dynip_orig); /* free previous string */ + args_info->dynip_orig = + gengetopt_strdup(optarg); + } + /* Static IP address pool. */ + else if (strcmp + (long_options[option_index].name, + "statip") == 0) { + if (local_args_info.statip_given) { + fprintf(stderr, + "%s: `--statip' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->statip_given && !override) + continue; + local_args_info.statip_given = 1; + args_info->statip_given = 1; + if (args_info->statip_arg) + free(args_info->statip_arg); /* free previous string */ + args_info->statip_arg = + gengetopt_strdup(optarg); + if (args_info->statip_orig) + free(args_info->statip_orig); /* free previous string */ + args_info->statip_orig = + gengetopt_strdup(optarg); + } + /* PCO DNS Server 1. */ + else if (strcmp + (long_options[option_index].name, + "pcodns1") == 0) { + if (local_args_info.pcodns1_given) { + fprintf(stderr, + "%s: `--pcodns1' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pcodns1_given && !override) + continue; + local_args_info.pcodns1_given = 1; + args_info->pcodns1_given = 1; + if (args_info->pcodns1_arg) + free(args_info->pcodns1_arg); /* free previous string */ + args_info->pcodns1_arg = + gengetopt_strdup(optarg); + if (args_info->pcodns1_orig) + free(args_info->pcodns1_orig); /* free previous string */ + args_info->pcodns1_orig = + gengetopt_strdup(optarg); + } + /* PCO DNS Server 2. */ + else if (strcmp + (long_options[option_index].name, + "pcodns2") == 0) { + if (local_args_info.pcodns2_given) { + fprintf(stderr, + "%s: `--pcodns2' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pcodns2_given && !override) + continue; + local_args_info.pcodns2_given = 1; + args_info->pcodns2_given = 1; + if (args_info->pcodns2_arg) + free(args_info->pcodns2_arg); /* free previous string */ + args_info->pcodns2_arg = + gengetopt_strdup(optarg); + if (args_info->pcodns2_orig) + free(args_info->pcodns2_orig); /* free previous string */ + args_info->pcodns2_orig = + gengetopt_strdup(optarg); + } + /* Exit after timelimit seconds. */ + else if (strcmp + (long_options[option_index].name, + "timelimit") == 0) { + if (local_args_info.timelimit_given) { + fprintf(stderr, + "%s: `--timelimit' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->timelimit_given && !override) + continue; + local_args_info.timelimit_given = 1; + args_info->timelimit_given = 1; + args_info->timelimit_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->timelimit_orig) + free(args_info->timelimit_orig); /* free previous string */ + args_info->timelimit_orig = + gengetopt_strdup(optarg); + } - case 0: /* Long option with no short option */ - /* Filename of process id file. */ - if (strcmp (long_options[option_index].name, "pidfile") == 0) - { - if (local_args_info.pidfile_given) - { - fprintf (stderr, "%s: `--pidfile' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pidfile_given && ! override) - continue; - local_args_info.pidfile_given = 1; - args_info->pidfile_given = 1; - if (args_info->pidfile_arg) - free (args_info->pidfile_arg); /* free previous string */ - args_info->pidfile_arg = gengetopt_strdup (optarg); - if (args_info->pidfile_orig) - free (args_info->pidfile_orig); /* free previous string */ - args_info->pidfile_orig = gengetopt_strdup (optarg); - } - /* Directory of nonvolatile data. */ - else if (strcmp (long_options[option_index].name, "statedir") == 0) - { - if (local_args_info.statedir_given) - { - fprintf (stderr, "%s: `--statedir' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->statedir_given && ! override) - continue; - local_args_info.statedir_given = 1; - args_info->statedir_given = 1; - if (args_info->statedir_arg) - free (args_info->statedir_arg); /* free previous string */ - args_info->statedir_arg = gengetopt_strdup (optarg); - if (args_info->statedir_orig) - free (args_info->statedir_orig); /* free previous string */ - args_info->statedir_orig = gengetopt_strdup (optarg); - } - /* Script to run after link-up. */ - else if (strcmp (long_options[option_index].name, "ipup") == 0) - { - if (local_args_info.ipup_given) - { - fprintf (stderr, "%s: `--ipup' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->ipup_given && ! override) - continue; - local_args_info.ipup_given = 1; - args_info->ipup_given = 1; - if (args_info->ipup_arg) - free (args_info->ipup_arg); /* free previous string */ - args_info->ipup_arg = gengetopt_strdup (optarg); - if (args_info->ipup_orig) - free (args_info->ipup_orig); /* free previous string */ - args_info->ipup_orig = gengetopt_strdup (optarg); - } - /* Script to run after link-down. */ - else if (strcmp (long_options[option_index].name, "ipdown") == 0) - { - if (local_args_info.ipdown_given) - { - fprintf (stderr, "%s: `--ipdown' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->ipdown_given && ! override) - continue; - local_args_info.ipdown_given = 1; - args_info->ipdown_given = 1; - if (args_info->ipdown_arg) - free (args_info->ipdown_arg); /* free previous string */ - args_info->ipdown_arg = gengetopt_strdup (optarg); - if (args_info->ipdown_orig) - free (args_info->ipdown_orig); /* free previous string */ - args_info->ipdown_orig = gengetopt_strdup (optarg); - } - /* Dynamic IP address pool. */ - else if (strcmp (long_options[option_index].name, "dynip") == 0) - { - if (local_args_info.dynip_given) - { - fprintf (stderr, "%s: `--dynip' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->dynip_given && ! override) - continue; - local_args_info.dynip_given = 1; - args_info->dynip_given = 1; - if (args_info->dynip_arg) - free (args_info->dynip_arg); /* free previous string */ - args_info->dynip_arg = gengetopt_strdup (optarg); - if (args_info->dynip_orig) - free (args_info->dynip_orig); /* free previous string */ - args_info->dynip_orig = gengetopt_strdup (optarg); - } - /* Static IP address pool. */ - else if (strcmp (long_options[option_index].name, "statip") == 0) - { - if (local_args_info.statip_given) - { - fprintf (stderr, "%s: `--statip' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->statip_given && ! override) - continue; - local_args_info.statip_given = 1; - args_info->statip_given = 1; - if (args_info->statip_arg) - free (args_info->statip_arg); /* free previous string */ - args_info->statip_arg = gengetopt_strdup (optarg); - if (args_info->statip_orig) - free (args_info->statip_orig); /* free previous string */ - args_info->statip_orig = gengetopt_strdup (optarg); - } - /* PCO DNS Server 1. */ - else if (strcmp (long_options[option_index].name, "pcodns1") == 0) - { - if (local_args_info.pcodns1_given) - { - fprintf (stderr, "%s: `--pcodns1' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pcodns1_given && ! override) - continue; - local_args_info.pcodns1_given = 1; - args_info->pcodns1_given = 1; - if (args_info->pcodns1_arg) - free (args_info->pcodns1_arg); /* free previous string */ - args_info->pcodns1_arg = gengetopt_strdup (optarg); - if (args_info->pcodns1_orig) - free (args_info->pcodns1_orig); /* free previous string */ - args_info->pcodns1_orig = gengetopt_strdup (optarg); - } - /* PCO DNS Server 2. */ - else if (strcmp (long_options[option_index].name, "pcodns2") == 0) - { - if (local_args_info.pcodns2_given) - { - fprintf (stderr, "%s: `--pcodns2' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pcodns2_given && ! override) - continue; - local_args_info.pcodns2_given = 1; - args_info->pcodns2_given = 1; - if (args_info->pcodns2_arg) - free (args_info->pcodns2_arg); /* free previous string */ - args_info->pcodns2_arg = gengetopt_strdup (optarg); - if (args_info->pcodns2_orig) - free (args_info->pcodns2_orig); /* free previous string */ - args_info->pcodns2_orig = gengetopt_strdup (optarg); - } - /* Exit after timelimit seconds. */ - else if (strcmp (long_options[option_index].name, "timelimit") == 0) - { - if (local_args_info.timelimit_given) - { - fprintf (stderr, "%s: `--timelimit' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->timelimit_given && ! override) - continue; - local_args_info.timelimit_given = 1; - args_info->timelimit_given = 1; - args_info->timelimit_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->timelimit_orig) - free (args_info->timelimit_orig); /* free previous string */ - args_info->timelimit_orig = gengetopt_strdup (optarg); - } - - break; - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - goto failure; + break; + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); - abort (); - } /* switch */ - } /* while */ + default: /* bug: option not considered. */ + fprintf(stderr, "%s: option unknown: %c%s\n", + CMDLINE_PARSER_PACKAGE, c, + (additional_error ? additional_error : "")); + abort(); + } /* switch */ + } /* while */ + cmdline_parser_release(&local_args_info); + if (error) + return (EXIT_FAILURE); - - cmdline_parser_release (&local_args_info); - - if ( error ) - return (EXIT_FAILURE); - - return 0; + return 0; failure: - - cmdline_parser_release (&local_args_info); - return (EXIT_FAILURE); + + cmdline_parser_release(&local_args_info); + return (EXIT_FAILURE); } #ifndef CONFIG_FILE_LINE_SIZE @@ -905,168 +966,167 @@ failure: #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) /* 3 is for "--" and "=" */ -char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; +char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE + 1]; int -cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +cmdline_parser_configfile(char *const filename, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required) { - FILE* file; - char linebuf[CONFIG_FILE_LINE_SIZE]; - int line_num = 0; - int i, result, equal; - char *fopt, *farg; - char *str_index; - size_t len, next_token; - char delimiter; - int my_argc = 0; - char **my_argv_arg; - char *additional_error; + FILE *file; + char linebuf[CONFIG_FILE_LINE_SIZE]; + int line_num = 0; + int i, result, equal; + char *fopt, *farg; + char *str_index; + size_t len, next_token; + char delimiter; + int my_argc = 0; + char **my_argv_arg; + char *additional_error; - /* store the program name */ - cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); - cmd_line_list_tmp->next = cmd_line_list; - cmd_line_list = cmd_line_list_tmp; - cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); + /* store the program name */ + cmd_line_list_tmp = + (struct line_list *)malloc(sizeof(struct line_list)); + cmd_line_list_tmp->next = cmd_line_list; + cmd_line_list = cmd_line_list_tmp; + cmd_line_list->string_arg = gengetopt_strdup(CMDLINE_PARSER_PACKAGE); - if ((file = fopen(filename, "r")) == NULL) - { - fprintf (stderr, "%s: Error opening configuration file '%s'\n", - CMDLINE_PARSER_PACKAGE, filename); - result = EXIT_FAILURE; - goto conf_failure; - } + if ((file = fopen(filename, "r")) == NULL) { + fprintf(stderr, "%s: Error opening configuration file '%s'\n", + CMDLINE_PARSER_PACKAGE, filename); + result = EXIT_FAILURE; + goto conf_failure; + } - while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) - { - ++line_num; - my_argv[0] = '\0'; - len = strlen(linebuf); - if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) - { - fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } + while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) { + ++line_num; + my_argv[0] = '\0'; + len = strlen(linebuf); + if (len > (CONFIG_FILE_LINE_BUFFER_SIZE - 1)) { + fprintf(stderr, + "%s:%s:%d: Line too long in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, line_num); + result = EXIT_FAILURE; + goto conf_failure; + } - /* find first non-whitespace character in the line */ - next_token = strspn ( linebuf, " \t\r\n"); - str_index = linebuf + next_token; + /* find first non-whitespace character in the line */ + next_token = strspn(linebuf, " \t\r\n"); + str_index = linebuf + next_token; - if ( str_index[0] == '\0' || str_index[0] == '#') - continue; /* empty line or comment line is skipped */ + if (str_index[0] == '\0' || str_index[0] == '#') + continue; /* empty line or comment line is skipped */ - fopt = str_index; + fopt = str_index; - /* truncate fopt at the end of the first non-valid character */ - next_token = strcspn (fopt, " \t\r\n="); + /* truncate fopt at the end of the first non-valid character */ + next_token = strcspn(fopt, " \t\r\n="); - if (fopt[next_token] == '\0') /* the line is over */ - { - farg = NULL; - equal = 0; - goto noarg; - } + if (fopt[next_token] == '\0') { /* the line is over */ + farg = NULL; + equal = 0; + goto noarg; + } - /* remember if equal sign is present */ - equal = (fopt[next_token] == '='); - fopt[next_token++] = '\0'; + /* remember if equal sign is present */ + equal = (fopt[next_token] == '='); + fopt[next_token++] = '\0'; - /* advance pointers to the next token after the end of fopt */ - next_token += strspn (fopt + next_token, " \t\r\n"); - /* check for the presence of equal sign, and if so, skip it */ - if ( !equal ) - if ((equal = (fopt[next_token] == '='))) - { - next_token++; - next_token += strspn (fopt + next_token, " \t\r\n"); - } - str_index += next_token; + /* advance pointers to the next token after the end of fopt */ + next_token += strspn(fopt + next_token, " \t\r\n"); + /* check for the presence of equal sign, and if so, skip it */ + if (!equal) + if ((equal = (fopt[next_token] == '='))) { + next_token++; + next_token += + strspn(fopt + next_token, " \t\r\n"); + } + str_index += next_token; - /* find argument */ - farg = str_index; - if ( farg[0] == '\"' || farg[0] == '\'' ) - { /* quoted argument */ - str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ - if (! str_index) - { - fprintf - (stderr, - "%s:%s:%d: unterminated string in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } - } - else - { /* read up the remaining part up to a delimiter */ - next_token = strcspn (farg, " \t\r\n#\'\""); - str_index += next_token; - } + /* find argument */ + farg = str_index; + if (farg[0] == '\"' || farg[0] == '\'') { /* quoted argument */ + str_index = strchr(++farg, str_index[0]); /* skip opening quote */ + if (!str_index) { + fprintf + (stderr, + "%s:%s:%d: unterminated string in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, + line_num); + result = EXIT_FAILURE; + goto conf_failure; + } + } else { /* read up the remaining part up to a delimiter */ + next_token = strcspn(farg, " \t\r\n#\'\""); + str_index += next_token; + } - /* truncate farg at the delimiter and store it for further check */ - delimiter = *str_index, *str_index++ = '\0'; + /* truncate farg at the delimiter and store it for further check */ + delimiter = *str_index, *str_index++ = '\0'; - /* everything but comment is illegal at the end of line */ - if (delimiter != '\0' && delimiter != '#') - { - str_index += strspn(str_index, " \t\r\n"); - if (*str_index != '\0' && *str_index != '#') - { - fprintf - (stderr, - "%s:%s:%d: malformed string in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } - } + /* everything but comment is illegal at the end of line */ + if (delimiter != '\0' && delimiter != '#') { + str_index += strspn(str_index, " \t\r\n"); + if (*str_index != '\0' && *str_index != '#') { + fprintf + (stderr, + "%s:%s:%d: malformed string in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, + line_num); + result = EXIT_FAILURE; + goto conf_failure; + } + } - noarg: - ++my_argc; - len = strlen(fopt); +noarg: + ++my_argc; + len = strlen(fopt); - strcat (my_argv, len > 1 ? "--" : "-"); - strcat (my_argv, fopt); - if (len > 1 && ((farg &&*farg) || equal)) - strcat (my_argv, "="); - if (farg && *farg) - strcat (my_argv, farg); + strcat(my_argv, len > 1 ? "--" : "-"); + strcat(my_argv, fopt); + if (len > 1 && ((farg && *farg) || equal)) + strcat(my_argv, "="); + if (farg && *farg) + strcat(my_argv, farg); - cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); - cmd_line_list_tmp->next = cmd_line_list; - cmd_line_list = cmd_line_list_tmp; - cmd_line_list->string_arg = gengetopt_strdup(my_argv); - } /* while */ + cmd_line_list_tmp = + (struct line_list *)malloc(sizeof(struct line_list)); + cmd_line_list_tmp->next = cmd_line_list; + cmd_line_list = cmd_line_list_tmp; + cmd_line_list->string_arg = gengetopt_strdup(my_argv); + } /* while */ - ++my_argc; /* for program name */ - my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); - cmd_line_list_tmp = cmd_line_list; - for (i = my_argc - 1; i >= 0; --i) { - my_argv_arg[i] = cmd_line_list_tmp->string_arg; - cmd_line_list_tmp = cmd_line_list_tmp->next; - } - my_argv_arg[my_argc] = 0; + ++my_argc; /* for program name */ + my_argv_arg = (char **)malloc((my_argc + 1) * sizeof(char *)); + cmd_line_list_tmp = cmd_line_list; + for (i = my_argc - 1; i >= 0; --i) { + my_argv_arg[i] = cmd_line_list_tmp->string_arg; + cmd_line_list_tmp = cmd_line_list_tmp->next; + } + my_argv_arg[my_argc] = 0; - additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); - strcpy (additional_error, ADDITIONAL_ERROR); - strcat (additional_error, filename); - result = - cmdline_parser_internal (my_argc, my_argv_arg, args_info, override, initialize, check_required, additional_error); + additional_error = + (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); + strcpy(additional_error, ADDITIONAL_ERROR); + strcat(additional_error, filename); + result = + cmdline_parser_internal(my_argc, my_argv_arg, args_info, override, + initialize, check_required, + additional_error); - free (additional_error); - free (my_argv_arg); + free(additional_error); + free(my_argv_arg); conf_failure: - if (file) - fclose(file); + if (file) + fclose(file); - free_cmd_list(); - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; + free_cmd_list(); + if (result == EXIT_FAILURE) { + cmdline_parser_free(args_info); + exit(EXIT_FAILURE); + } + + return result; } diff --git a/ggsn/cmdline.h b/ggsn/cmdline.h index d9e3086..23a6eee 100644 --- a/ggsn/cmdline.h +++ b/ggsn/cmdline.h @@ -12,7 +12,7 @@ #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE #define CMDLINE_PARSER_PACKAGE PACKAGE @@ -22,105 +22,104 @@ extern "C" { #define CMDLINE_PARSER_VERSION VERSION #endif -struct gengetopt_args_info -{ - const char *help_help; /* Print help and exit help description. */ - const char *version_help; /* Print version and exit help description. */ - int fg_flag; /* Run in foreground (default=off). */ - const char *fg_help; /* Run in foreground help description. */ - int debug_flag; /* Run in debug mode (default=off). */ - const char *debug_help; /* Run in debug mode help description. */ - char * conf_arg; /* Read configuration file (default='/etc/ggsn.conf'). */ - char * conf_orig; /* Read configuration file original value given at command line. */ - const char *conf_help; /* Read configuration file help description. */ - char * pidfile_arg; /* Filename of process id file (default='/var/run/ggsn.pid'). */ - char * pidfile_orig; /* Filename of process id file original value given at command line. */ - const char *pidfile_help; /* Filename of process id file help description. */ - char * statedir_arg; /* Directory of nonvolatile data (default='/var/lib/ggsn/'). */ - char * statedir_orig; /* Directory of nonvolatile data original value given at command line. */ - const char *statedir_help; /* Directory of nonvolatile data help description. */ - char * listen_arg; /* Local interface. */ - char * listen_orig; /* Local interface original value given at command line. */ - const char *listen_help; /* Local interface help description. */ - char * net_arg; /* Network (default='192.168.0.0/24'). */ - char * net_orig; /* Network original value given at command line. */ - const char *net_help; /* Network help description. */ - char * ipup_arg; /* Script to run after link-up. */ - char * ipup_orig; /* Script to run after link-up original value given at command line. */ - const char *ipup_help; /* Script to run after link-up help description. */ - char * ipdown_arg; /* Script to run after link-down. */ - char * ipdown_orig; /* Script to run after link-down original value given at command line. */ - const char *ipdown_help; /* Script to run after link-down help description. */ - char * dynip_arg; /* Dynamic IP address pool. */ - char * dynip_orig; /* Dynamic IP address pool original value given at command line. */ - const char *dynip_help; /* Dynamic IP address pool help description. */ - char * statip_arg; /* Static IP address pool. */ - char * statip_orig; /* Static IP address pool original value given at command line. */ - const char *statip_help; /* Static IP address pool help description. */ - char * pcodns1_arg; /* PCO DNS Server 1 (default='0.0.0.0'). */ - char * pcodns1_orig; /* PCO DNS Server 1 original value given at command line. */ - const char *pcodns1_help; /* PCO DNS Server 1 help description. */ - char * pcodns2_arg; /* PCO DNS Server 2 (default='0.0.0.0'). */ - char * pcodns2_orig; /* PCO DNS Server 2 original value given at command line. */ - const char *pcodns2_help; /* PCO DNS Server 2 help description. */ - int timelimit_arg; /* Exit after timelimit seconds (default='0'). */ - char * timelimit_orig; /* Exit after timelimit seconds original value given at command line. */ - const char *timelimit_help; /* Exit after timelimit seconds help description. */ - char * apn_arg; /* Access point name (default='internet'). */ - char * apn_orig; /* Access point name original value given at command line. */ - const char *apn_help; /* Access point name help description. */ - int qos_arg; /* Requested quality of service (default='0x0b921f'). */ - char * qos_orig; /* Requested quality of service original value given at command line. */ - const char *qos_help; /* Requested quality of service help description. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int fg_given ; /* Whether fg was given. */ - int debug_given ; /* Whether debug was given. */ - int conf_given ; /* Whether conf was given. */ - int pidfile_given ; /* Whether pidfile was given. */ - int statedir_given ; /* Whether statedir was given. */ - int listen_given ; /* Whether listen was given. */ - int net_given ; /* Whether net 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. */ + struct gengetopt_args_info { + const char *help_help; /* Print help and exit help description. */ + const char *version_help; /* Print version and exit help description. */ + int fg_flag; /* Run in foreground (default=off). */ + const char *fg_help; /* Run in foreground help description. */ + int debug_flag; /* Run in debug mode (default=off). */ + const char *debug_help; /* Run in debug mode help description. */ + char *conf_arg; /* Read configuration file (default='/etc/ggsn.conf'). */ + char *conf_orig; /* Read configuration file original value given at command line. */ + const char *conf_help; /* Read configuration file help description. */ + char *pidfile_arg; /* Filename of process id file (default='/var/run/ggsn.pid'). */ + char *pidfile_orig; /* Filename of process id file original value given at command line. */ + const char *pidfile_help; /* Filename of process id file help description. */ + char *statedir_arg; /* Directory of nonvolatile data (default='/var/lib/ggsn/'). */ + char *statedir_orig; /* Directory of nonvolatile data original value given at command line. */ + const char *statedir_help; /* Directory of nonvolatile data help description. */ + char *listen_arg; /* Local interface. */ + char *listen_orig; /* Local interface original value given at command line. */ + const char *listen_help; /* Local interface help description. */ + char *net_arg; /* Network (default='192.168.0.0/24'). */ + char *net_orig; /* Network original value given at command line. */ + const char *net_help; /* Network help description. */ + char *ipup_arg; /* Script to run after link-up. */ + char *ipup_orig; /* Script to run after link-up original value given at command line. */ + const char *ipup_help; /* Script to run after link-up help description. */ + char *ipdown_arg; /* Script to run after link-down. */ + char *ipdown_orig; /* Script to run after link-down original value given at command line. */ + const char *ipdown_help; /* Script to run after link-down help description. */ + char *dynip_arg; /* Dynamic IP address pool. */ + char *dynip_orig; /* Dynamic IP address pool original value given at command line. */ + const char *dynip_help; /* Dynamic IP address pool help description. */ + char *statip_arg; /* Static IP address pool. */ + char *statip_orig; /* Static IP address pool original value given at command line. */ + const char *statip_help; /* Static IP address pool help description. */ + char *pcodns1_arg; /* PCO DNS Server 1 (default='0.0.0.0'). */ + char *pcodns1_orig; /* PCO DNS Server 1 original value given at command line. */ + const char *pcodns1_help; /* PCO DNS Server 1 help description. */ + char *pcodns2_arg; /* PCO DNS Server 2 (default='0.0.0.0'). */ + char *pcodns2_orig; /* PCO DNS Server 2 original value given at command line. */ + const char *pcodns2_help; /* PCO DNS Server 2 help description. */ + int timelimit_arg; /* Exit after timelimit seconds (default='0'). */ + char *timelimit_orig; /* Exit after timelimit seconds original value given at command line. */ + const char *timelimit_help; /* Exit after timelimit seconds help description. */ + char *apn_arg; /* Access point name (default='internet'). */ + char *apn_orig; /* Access point name original value given at command line. */ + const char *apn_help; /* Access point name help description. */ + int qos_arg; /* Requested quality of service (default='0x0b921f'). */ + char *qos_orig; /* Requested quality of service original value given at command line. */ + const char *qos_help; /* Requested quality of service help description. */ -} ; + int help_given; /* Whether help was given. */ + int version_given; /* Whether version was given. */ + int fg_given; /* Whether fg was given. */ + int debug_given; /* Whether debug was given. */ + int conf_given; /* Whether conf was given. */ + int pidfile_given; /* Whether pidfile was given. */ + int statedir_given; /* Whether statedir was given. */ + int listen_given; /* Whether listen was given. */ + int net_given; /* Whether net 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. */ -extern const char *gengetopt_args_info_purpose; -extern const char *gengetopt_args_info_usage; -extern const char *gengetopt_args_info_help[]; + }; -int cmdline_parser (int argc, char * const *argv, - struct gengetopt_args_info *args_info); -int cmdline_parser2 (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); -int cmdline_parser_file_save(const char *filename, - struct gengetopt_args_info *args_info); + extern const char *gengetopt_args_info_purpose; + extern const char *gengetopt_args_info_usage; + extern const char *gengetopt_args_info_help[]; -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); + int cmdline_parser(int argc, char *const *argv, + struct gengetopt_args_info *args_info); + int cmdline_parser2(int argc, char *const *argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); -void cmdline_parser_init (struct gengetopt_args_info *args_info); -void cmdline_parser_free (struct gengetopt_args_info *args_info); + void cmdline_parser_print_help(void); + void cmdline_parser_print_version(void); -int cmdline_parser_configfile (char * const filename, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); + void cmdline_parser_init(struct gengetopt_args_info *args_info); + void cmdline_parser_free(struct gengetopt_args_info *args_info); -int cmdline_parser_required (struct gengetopt_args_info *args_info, - const char *prog_name); + int cmdline_parser_configfile(char *const filename, + struct gengetopt_args_info *args_info, + int override, int initialize, + int check_required); + int cmdline_parser_required(struct gengetopt_args_info *args_info, + const char *prog_name); #ifdef __cplusplus } -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 9e0b597..1152519 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include @@ -55,507 +55,539 @@ #include "cmdline.h" int end = 0; -int maxfd = 0; /* For select() */ +int maxfd = 0; /* For select() */ struct in_addr listen_; -struct in_addr netaddr, destaddr, net, mask; /* Network interface */ -struct in_addr dns1, dns2; /* PCO DNS address */ -char *ipup, *ipdown; /* Filename of scripts */ -int debug; /* Print debug output */ +struct in_addr netaddr, destaddr, net, mask; /* Network interface */ +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 gsn_t *gsn; /* GSN instance */ -struct tun_t *tun; /* TUN instance */ -struct ippool_t *ippool; /* Pool of IP addresses */ +struct gsn_t *gsn; /* GSN instance */ +struct tun_t *tun; /* TUN instance */ +struct ippool_t *ippool; /* Pool of IP addresses */ /* To exit gracefully. Used with GCC compilation flag -pg and gprof */ -void signal_handler(int s) { - if (debug) printf("Received signal %d, exiting.\n", s); - end = 1; +void signal_handler(int s) +{ + if (debug) + printf("Received signal %d, exiting.\n", s); + end = 1; } /* Used to write process ID to file. Assume someone else will delete */ -void log_pid(char *pidfile) { - FILE *file; - mode_t oldmask; - - oldmask = umask(022); - file = fopen(pidfile, "w"); - umask(oldmask); - if(!file) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to create process ID file: %s!", pidfile); - return; - } - fprintf(file, "%d\n", (int) getpid()); - fclose(file); +void log_pid(char *pidfile) +{ + FILE *file; + mode_t oldmask; + + oldmask = umask(022); + file = fopen(pidfile, "w"); + umask(oldmask); + if (!file) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to create process ID file: %s!", pidfile); + return; + } + fprintf(file, "%d\n", (int)getpid()); + fclose(file); } #if defined(__sun__) -int daemon(int nochdir, int noclose) { - int fd; +int daemon(int nochdir, int noclose) +{ + int fd; - switch (fork()) { - case -1: - return (-1); - case 0: - break; - default: - _exit(0); - } + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } - if (setsid() == -1) - return (-1); - - if (!nochdir) chdir("/"); + if (setsid() == -1) + return (-1); - if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > 2) close (fd); - } - return (0); + if (!nochdir) + chdir("/"); + + if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + return (0); } #endif - int encaps_printf(void *p, void *packet, unsigned len) { - unsigned int i; - if (debug) { - printf("The packet looks like this:\n"); - for( i=0; ipeer) - ippool_freeip(ippool, (struct ippoolm_t *) pdp->peer); - else - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Peer not defined!"); - return 0; +int delete_context(struct pdp_t *pdp) +{ + if (debug) + printf("Deleting PDP context\n"); + if (pdp->peer) + ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer); + else + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Peer not defined!"); + return 0; } +int create_context_ind(struct pdp_t *pdp) +{ + struct in_addr addr; + struct ippoolm_t *member; -int create_context_ind(struct pdp_t *pdp) { - struct in_addr addr; - struct ippoolm_t *member; + if (debug) + printf("Received create PDP context request\n"); - if (debug) printf("Received create PDP context request\n"); + pdp->eua.l = 0; /* TODO: Indicates dynamic IP */ - pdp->eua.l=0; /* TODO: Indicates dynamic IP */ + /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */ + memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0)); + memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg)); - /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */ - memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0)); - memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg)); + memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */ + pdp->qos_neg.l = pdp->qos_req.l; - memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */ - pdp->qos_neg.l = pdp->qos_req.l; - - if (pdp_euaton(&pdp->eua, &addr)) { - addr.s_addr = 0; /* Request dynamic */ - } + if (pdp_euaton(&pdp->eua, &addr)) { + addr.s_addr = 0; /* Request dynamic */ + } - if (ippool_newip(ippool, &member, &addr, 0)) { - gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES); - return 0; /* Allready in use, or no more available */ - } + if (ippool_newip(ippool, &member, &addr, 0)) { + gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES); + return 0; /* Allready in use, or no more available */ + } - pdp_ntoeua(&member->addr, &pdp->eua); - pdp->peer = member; - pdp->ipif = tun; /* TODO */ - member->peer = pdp; + pdp_ntoeua(&member->addr, &pdp->eua); + pdp->peer = member; + pdp->ipif = tun; /* TODO */ + member->peer = pdp; - gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ); - return 0; /* Success */ + gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ); + return 0; /* Success */ } - /* 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; +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; - if (debug) printf("Received packet from tun!\n"); + 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_data_req(gsn, (struct pdp_t*) ipm->peer, pack, len); - return 0; + if (debug) + printf("Received packet from tun!\n"); + + 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_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len); + return 0; } -int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) { - if (debug) printf("encaps_tun. Packet received: forwarding to tun\n"); - return tun_encaps((struct tun_t*) pdp->ipif, pack, len); +int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) +{ + if (debug) + printf("encaps_tun. Packet received: forwarding to tun\n"); + return tun_encaps((struct tun_t *)pdp->ipif, pack, len); } - int main(int argc, char **argv) { - /* gengeopt declarations */ - struct gengetopt_args_info args_info; + /* gengeopt declarations */ + struct gengetopt_args_info args_info; - struct hostent *host; + struct hostent *host; - /* Handle keyboard interrupt SIGINT */ - struct sigaction s; - s.sa_handler = (void *) signal_handler; - if ((0 != sigemptyset( &s.sa_mask )) && debug) - printf("sigemptyset failed.\n"); - s.sa_flags = SA_RESETHAND; - if ((sigaction(SIGINT, &s, NULL) != 0) && debug) - printf("Could not register SIGINT signal handler.\n"); - - fd_set fds; /* For select() */ - struct timeval idleTime; /* How long to select() */ + /* Handle keyboard interrupt SIGINT */ + struct sigaction s; + s.sa_handler = (void *)signal_handler; + if ((0 != sigemptyset(&s.sa_mask)) && debug) + printf("sigemptyset failed.\n"); + s.sa_flags = SA_RESETHAND; + if ((sigaction(SIGINT, &s, NULL) != 0) && debug) + printf("Could not register SIGINT signal handler.\n"); + fd_set fds; /* For select() */ + struct timeval idleTime; /* How long to select() */ - int timelimit; /* Number of seconds to be connected */ - int starttime; /* Time program was started */ + int timelimit; /* Number of seconds to be connected */ + int starttime; /* Time program was started */ - /* open a connection to the syslog daemon */ - /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/ + /* open a connection to the syslog daemon */ + /*openlog(PACKAGE, LOG_PID, LOG_DAEMON); */ - /* TODO: Only use LOG__PERROR for linux */ + /* TODO: Only use LOG__PERROR for linux */ #ifdef __linux__ - openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON); + openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON); #else - openlog(PACKAGE, (LOG_PID), LOG_DAEMON); + openlog(PACKAGE, (LOG_PID), LOG_DAEMON); #endif + if (cmdline_parser(argc, argv, &args_info) != 0) + exit(1); + if (args_info.debug_flag) { + printf("listen: %s\n", args_info.listen_arg); + if (args_info.conf_arg) + printf("conf: %s\n", args_info.conf_arg); + printf("fg: %d\n", args_info.fg_flag); + printf("debug: %d\n", args_info.debug_flag); + printf("qos: %#08x\n", args_info.qos_arg); + if (args_info.apn_arg) + printf("apn: %s\n", args_info.apn_arg); + if (args_info.net_arg) + printf("net: %s\n", args_info.net_arg); + if (args_info.dynip_arg) + printf("dynip: %s\n", args_info.dynip_arg); + if (args_info.statip_arg) + printf("statip: %s\n", args_info.statip_arg); + if (args_info.ipup_arg) + printf("ipup: %s\n", args_info.ipup_arg); + if (args_info.ipdown_arg) + printf("ipdown: %s\n", args_info.ipdown_arg); + if (args_info.pidfile_arg) + printf("pidfile: %s\n", args_info.pidfile_arg); + if (args_info.statedir_arg) + printf("statedir: %s\n", args_info.statedir_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + } - if (cmdline_parser (argc, argv, &args_info) != 0) - exit(1); - if (args_info.debug_flag) { - printf("listen: %s\n", args_info.listen_arg); - if (args_info.conf_arg) printf("conf: %s\n", args_info.conf_arg); - printf("fg: %d\n", args_info.fg_flag); - printf("debug: %d\n", args_info.debug_flag); - printf("qos: %#08x\n", args_info.qos_arg); - if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg); - if (args_info.net_arg) printf("net: %s\n", args_info.net_arg); - if (args_info.dynip_arg) printf("dynip: %s\n", args_info.dynip_arg); - if (args_info.statip_arg) printf("statip: %s\n", args_info.statip_arg); - if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg); - if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg); - if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg); - if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - } + /* Try out our new parser */ - /* Try out our new parser */ - - if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0, 0, 0) != 0) - exit(1); - if (args_info.debug_flag) { - printf("cmdline_parser_configfile\n"); - printf("listen: %s\n", args_info.listen_arg); - printf("conf: %s\n", args_info.conf_arg); - printf("fg: %d\n", args_info.fg_flag); - printf("debug: %d\n", args_info.debug_flag); - printf("qos: %#08x\n", args_info.qos_arg); - if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg); - if (args_info.net_arg) printf("net: %s\n", args_info.net_arg); - if (args_info.dynip_arg) printf("dynip: %s\n", args_info.dynip_arg); - if (args_info.statip_arg) printf("statip: %s\n", args_info.statip_arg); - if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg); - if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg); - if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg); - if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - } + if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0) + != 0) + exit(1); + if (args_info.debug_flag) { + printf("cmdline_parser_configfile\n"); + printf("listen: %s\n", args_info.listen_arg); + printf("conf: %s\n", args_info.conf_arg); + printf("fg: %d\n", args_info.fg_flag); + printf("debug: %d\n", args_info.debug_flag); + printf("qos: %#08x\n", args_info.qos_arg); + if (args_info.apn_arg) + printf("apn: %s\n", args_info.apn_arg); + if (args_info.net_arg) + printf("net: %s\n", args_info.net_arg); + if (args_info.dynip_arg) + printf("dynip: %s\n", args_info.dynip_arg); + if (args_info.statip_arg) + printf("statip: %s\n", args_info.statip_arg); + if (args_info.ipup_arg) + printf("ipup: %s\n", args_info.ipup_arg); + if (args_info.ipdown_arg) + printf("ipdown: %s\n", args_info.ipdown_arg); + if (args_info.pidfile_arg) + printf("pidfile: %s\n", args_info.pidfile_arg); + if (args_info.statedir_arg) + printf("statedir: %s\n", args_info.statedir_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + } - /* Handle each option */ + /* Handle each option */ - /* debug */ - debug = args_info.debug_flag; + /* debug */ + debug = args_info.debug_flag; - /* listen */ - /* Do hostname lookup to translate hostname to IP address */ - /* Any port listening is not possible as a valid address is */ - /* required for create_pdp_context_response messages */ - if (args_info.listen_arg) { - if (!(host = gethostbyname(args_info.listen_arg))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid listening address: %s!", args_info.listen_arg); - exit(1); - } - else { - memcpy(&listen_.s_addr, host->h_addr, host->h_length); - } - } - else { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Listening address must be specified! " - "Please use command line option --listen or " - "edit %s configuration file\n", args_info.conf_arg); - exit(1); - } - + /* listen */ + /* Do hostname lookup to translate hostname to IP address */ + /* Any port listening is not possible as a valid address is */ + /* required for create_pdp_context_response messages */ + if (args_info.listen_arg) { + if (!(host = gethostbyname(args_info.listen_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid listening address: %s!", + args_info.listen_arg); + exit(1); + } else { + memcpy(&listen_.s_addr, host->h_addr, host->h_length); + } + } else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Listening address must be specified! " + "Please use command line option --listen or " + "edit %s configuration file\n", args_info.conf_arg); + exit(1); + } - /* net */ - /* Store net as in_addr net and mask */ - if (args_info.net_arg) { - 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); - exit(1); - } - netaddr.s_addr = htonl(ntohl(net.s_addr) + 1); - destaddr.s_addr = htonl(ntohl(net.s_addr) + 1); - } - else { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Network address must be specified: %s!", args_info.net_arg); - exit(1); - } + /* net */ + /* Store net as in_addr net and mask */ + if (args_info.net_arg) { + 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); + exit(1); + } + netaddr.s_addr = htonl(ntohl(net.s_addr) + 1); + destaddr.s_addr = htonl(ntohl(net.s_addr) + 1); + } else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Network address must be specified: %s!", + args_info.net_arg); + exit(1); + } - /* dynip */ - if (!args_info.dynip_arg) { - if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0, - IPPOOL_NONETWORK | IPPOOL_NOGATEWAY | IPPOOL_NOBROADCAST)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to allocate IP pool!"); - exit(1); - } - } - else { - if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1 ,0, - IPPOOL_NONETWORK | IPPOOL_NOGATEWAY | IPPOOL_NOBROADCAST)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to allocate IP pool!"); - exit(1); - } - } + /* dynip */ + if (!args_info.dynip_arg) { + if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0, + IPPOOL_NONETWORK | IPPOOL_NOGATEWAY | + IPPOOL_NOBROADCAST)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to allocate IP pool!"); + exit(1); + } + } else { + if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0, + IPPOOL_NONETWORK | IPPOOL_NOGATEWAY | + IPPOOL_NOBROADCAST)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to allocate IP pool!"); + exit(1); + } + } - /* DNS1 and DNS2 */ + /* DNS1 and DNS2 */ #ifdef HAVE_INET_ATON - dns1.s_addr = 0; - if (args_info.pcodns1_arg) { - if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to convert pcodns1!"); - exit(1); - } - } - dns2.s_addr = 0; - if (args_info.pcodns2_arg) { - if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to convert pcodns2!"); - exit(1); - } - } + dns1.s_addr = 0; + if (args_info.pcodns1_arg) { + if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to convert pcodns1!"); + exit(1); + } + } + dns2.s_addr = 0; + if (args_info.pcodns2_arg) { + if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to convert pcodns2!"); + exit(1); + } + } #else - dns1.s_addr = 0; - if (args_info.pcodns1_arg) { - dns1.s_addr = inet_addr(args_info.pcodns1_arg); - if (dns1.s_addr == -1) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to convert pcodns1!"); - exit(1); - } - } - dns2.s_addr = 0; - if (args_info.pcodns2_arg) { - dns2.s_addr = inet_addr(args_info.pcodns2_arg); - if (dns2.s_addr == -1) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to convert pcodns2!"); - exit(1); - } - } + dns1.s_addr = 0; + if (args_info.pcodns1_arg) { + dns1.s_addr = inet_addr(args_info.pcodns1_arg); + if (dns1.s_addr == -1) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to convert pcodns1!"); + exit(1); + } + } + dns2.s_addr = 0; + if (args_info.pcodns2_arg) { + dns2.s_addr = inet_addr(args_info.pcodns2_arg); + if (dns2.s_addr == -1) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to convert pcodns2!"); + exit(1); + } + } #endif + 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)); - 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; - /* ipup */ - ipup = args_info.ipup_arg; + /* ipdown */ + ipdown = args_info.ipdown_arg; - /* ipdown */ - ipdown = args_info.ipdown_arg; + /* Timelimit */ + timelimit = args_info.timelimit_arg; + starttime = time(NULL); - /* Timelimit */ - timelimit = args_info.timelimit_arg; - starttime = time(NULL); - - /* qos */ - qos.l = 3; - 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; + /* qos */ + qos.l = 3; + 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(apn.v)-1)) { - printf("Invalid APN\n"); - return -1; - } - apn.l = strlen(args_info.apn_arg) + 1; - apn.v[0] = (char) strlen(args_info.apn_arg); - strncpy((char *) &apn.v[1], args_info.apn_arg, sizeof(apn.v)-1); + /* apn */ + 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[0] = (char)strlen(args_info.apn_arg); + strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1); + /* foreground */ + /* If flag not given run as a daemon */ + if (!args_info.fg_flag) { + FILE *f; + int rc; + closelog(); + /* Close the standard file descriptors. */ + /* Is this really needed ? */ + f = freopen("/dev/null", "w", stdout); + if (f == NULL) { + sys_err(LOG_WARNING, __FILE__, __LINE__, 0, + "Could not redirect stdout to /dev/null"); + } + f = freopen("/dev/null", "w", stderr); + if (f == NULL) { + sys_err(LOG_WARNING, __FILE__, __LINE__, 0, + "Could not redirect stderr to /dev/null"); + } + f = freopen("/dev/null", "r", stdin); + if (f == NULL) { + sys_err(LOG_WARNING, __FILE__, __LINE__, 0, + "Could not redirect stdin to /dev/null"); + } + rc = daemon(0, 0); + if (rc != 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, rc, + "Could not daemonize"); + exit(1); + } + /* Open log again. This time with new pid */ + openlog(PACKAGE, LOG_PID, LOG_DAEMON); + } - /* foreground */ - /* If flag not given run as a daemon */ - if (!args_info.fg_flag) - { - FILE *f; - int rc; - closelog(); - /* Close the standard file descriptors. */ - /* Is this really needed ? */ - f = freopen("/dev/null", "w", stdout); - if (f == NULL) { - sys_err(LOG_WARNING, __FILE__, __LINE__, 0, - "Could not redirect stdout to /dev/null"); - } - f = freopen("/dev/null", "w", stderr); - if (f == NULL) { - sys_err(LOG_WARNING, __FILE__, __LINE__, 0, - "Could not redirect stderr to /dev/null"); - } - f = freopen("/dev/null", "r", stdin); - if (f == NULL) { - sys_err(LOG_WARNING, __FILE__, __LINE__, 0, - "Could not redirect stdin to /dev/null"); - } - rc = daemon(0, 0); - if (rc != 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, rc, "Could not daemonize"); - exit(1); - } - /* Open log again. This time with new pid */ - openlog(PACKAGE, LOG_PID, LOG_DAEMON); - } + /* pidfile */ + /* This has to be done after we have our final pid */ + if (args_info.pidfile_arg) { + log_pid(args_info.pidfile_arg); + } - /* pidfile */ - /* This has to be done after we have our final pid */ - if (args_info.pidfile_arg) { - log_pid(args_info.pidfile_arg); - } - + if (debug) + printf("gtpclient: Initialising GTP tunnel\n"); - if (debug) printf("gtpclient: Initialising GTP tunnel\n"); - - if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to create gtp"); - exit(1); - } - if (gsn->fd0 > maxfd) maxfd = gsn->fd0; - if (gsn->fd1c > maxfd) maxfd = gsn->fd1c; - if (gsn->fd1u > maxfd) maxfd = gsn->fd1u; + if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Failed to create gtp"); + exit(1); + } + if (gsn->fd0 > maxfd) + maxfd = gsn->fd0; + if (gsn->fd1c > maxfd) + maxfd = gsn->fd1c; + if (gsn->fd1u > maxfd) + maxfd = gsn->fd1u; - gtp_set_cb_data_ind(gsn, encaps_tun); - gtp_set_cb_delete_context(gsn, delete_context); - gtp_set_cb_create_context_ind(gsn, create_context_ind); + gtp_set_cb_data_ind(gsn, encaps_tun); + gtp_set_cb_delete_context(gsn, delete_context); + gtp_set_cb_create_context_ind(gsn, create_context_ind); + /* Create a tunnel interface */ + if (debug) + printf("Creating tun interface\n"); + if (tun_new((struct tun_t **)&tun)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Failed to create tun"); + if (debug) + printf("Failed to create tun\n"); + exit(1); + } - /* Create a tunnel interface */ - if (debug) printf("Creating tun interface\n"); - if (tun_new((struct tun_t**) &tun)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to create tun"); - if (debug) printf("Failed to create tun\n"); - exit(1); - } + if (debug) + printf("Setting tun IP address\n"); + if (tun_setaddr(tun, &netaddr, &destaddr, &mask)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to set tun IP address"); + if (debug) + printf("Failed to set tun IP address\n"); + exit(1); + } - if (debug) printf("Setting tun IP address\n"); - if (tun_setaddr(tun, &netaddr, &destaddr, &mask)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to set tun IP address"); - if (debug) printf("Failed to set tun IP address\n"); - exit(1); - } + tun_set_cb_ind(tun, cb_tun_ind); + if (tun->fd > maxfd) + maxfd = tun->fd; - - tun_set_cb_ind(tun, cb_tun_ind); - if (tun->fd > maxfd) maxfd = tun->fd; - - if (ipup) tun_runscript(tun, ipup); + if (ipup) + tun_runscript(tun, ipup); /******************************************************************/ - /* Main select loop */ + /* Main select loop */ /******************************************************************/ - while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit)) && (!end)) { + while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit)) + && (!end)) { - FD_ZERO(&fds); - if (tun) FD_SET(tun->fd, &fds); - FD_SET(gsn->fd0, &fds); - FD_SET(gsn->fd1c, &fds); - FD_SET(gsn->fd1u, &fds); - - gtp_retranstimeout(gsn, &idleTime); - switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { - case -1: /* errno == EINTR : unblocked signal */ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "select() returned -1"); - /* On error, select returns without modifying fds */ - FD_ZERO(&fds); - break; - case 0: - /* printf("Select returned 0\n"); */ - gtp_retrans(gsn); /* Only retransmit if nothing else */ - break; - default: - break; - } + FD_ZERO(&fds); + if (tun) + FD_SET(tun->fd, &fds); + FD_SET(gsn->fd0, &fds); + FD_SET(gsn->fd1c, &fds); + FD_SET(gsn->fd1u, &fds); - if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) && - tun_decaps(tun) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "TUN read failed (fd)=(%d)", tun->fd); - } - - if (FD_ISSET(gsn->fd0, &fds)) - gtp_decaps0(gsn); - - if (FD_ISSET(gsn->fd1c, &fds)) - gtp_decaps1c(gsn); - - if (FD_ISSET(gsn->fd1u, &fds)) - gtp_decaps1u(gsn); - - } + gtp_retranstimeout(gsn, &idleTime); + switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { + case -1: /* errno == EINTR : unblocked signal */ + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "select() returned -1"); + /* On error, select returns without modifying fds */ + FD_ZERO(&fds); + 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) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "TUN read failed (fd)=(%d)", tun->fd); + } + + if (FD_ISSET(gsn->fd0, &fds)) + gtp_decaps0(gsn); + + if (FD_ISSET(gsn->fd1c, &fds)) + gtp_decaps1c(gsn); + + if (FD_ISSET(gsn->fd1u, &fds)) + gtp_decaps1u(gsn); + + } + + cmdline_parser_free(&args_info); + ippool_free(ippool); + gtp_free(gsn); + tun_free(tun); + + return 1; - cmdline_parser_free(&args_info); - ippool_free(ippool); - gtp_free(gsn); - tun_free(tun); - - return 1; - } - diff --git a/gtp/gtp.c b/gtp/gtp.c index 4f75fd5..768d8c7 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -17,7 +17,6 @@ * - Do we need to handle fragmentation? */ - #ifdef __linux__ #define _GNU_SOURCE 1 #endif @@ -52,128 +51,127 @@ #include "gtpie.h" #include "queue.h" - /* Error reporting functions */ -void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) { - va_list args; - char buf[ERRMSG_SIZE]; +void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) +{ + va_list args; + char buf[ERRMSG_SIZE]; - va_start(args, fmt); - vsnprintf(buf, ERRMSG_SIZE, fmt, args); - va_end(args); - buf[ERRMSG_SIZE-1] = 0; - syslog(priority, "%s: %d: %s", filename, linenum, buf); + va_start(args, fmt); + vsnprintf(buf, ERRMSG_SIZE, fmt, args); + va_end(args); + buf[ERRMSG_SIZE - 1] = 0; + syslog(priority, "%s: %d: %s", filename, linenum, buf); } void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer, - void *pack, unsigned len, char *fmt, ...) { - - va_list args; - char buf[ERRMSG_SIZE]; - char buf2[ERRMSG_SIZE]; - unsigned int n; - int pos; - - va_start(args, fmt); - vsnprintf(buf, ERRMSG_SIZE, fmt, args); - va_end(args); - buf[ERRMSG_SIZE-1] = 0; + void *pack, unsigned len, char *fmt, ...) +{ - snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port), - len); - buf2[ERRMSG_SIZE-1] = 0; - pos = strlen(buf2); - for(n=0; nsin_addr), ntohs(peer->sin_port), len); + buf2[ERRMSG_SIZE - 1] = 0; + pos = strlen(buf2); + for (n = 0; n < len; n++) { + if ((pos + 4) < ERRMSG_SIZE) { + sprintf((buf2 + pos), " %02hhx", + ((unsigned char *)pack)[n]); + pos += 3; + } + } + buf2[pos] = 0; + + syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2); } - - - /* API Functions */ -const char* gtp_version() +const char *gtp_version() { - return VERSION; + return VERSION; } /* gtp_new */ /* gtp_free */ -int gtp_newpdp(struct gsn_t* gsn, struct pdp_t **pdp, - uint64_t imsi, uint8_t nsapi) { - return pdp_newpdp(pdp, imsi, nsapi, NULL); +int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, + uint64_t imsi, uint8_t nsapi) +{ + return pdp_newpdp(pdp, imsi, nsapi, NULL); } -int gtp_freepdp(struct gsn_t* gsn, struct pdp_t *pdp) { - return pdp_freepdp(pdp); +int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp) +{ + return pdp_freepdp(pdp); } /* gtp_gpdu */ -extern int gtp_fd(struct gsn_t *gsn) { - return gsn->fd0; +extern int gtp_fd(struct gsn_t *gsn) +{ + return gsn->fd0; } /* gtp_decaps */ /* gtp_retrans */ /* gtp_retranstimeout */ - int gtp_set_cb_unsup_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)) { - gsn->cb_unsup_ind = cb; - return 0; + int (*cb) (struct sockaddr_in * peer)) +{ + gsn->cb_unsup_ind = cb; + return 0; } int gtp_set_cb_extheader_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)) { - gsn->cb_extheader_ind = cb; - return 0; + int (*cb) (struct sockaddr_in * peer)) +{ + gsn->cb_extheader_ind = cb; + return 0; } - /* API: Initialise delete context callback */ /* Called whenever a pdp context is deleted for any reason */ -int gtp_set_cb_delete_context(struct gsn_t *gsn, - int (*cb) (struct pdp_t* pdp)) +int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp)) { - gsn->cb_delete_context = cb; - return 0; + gsn->cb_delete_context = cb; + return 0; } int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, - struct pdp_t* pdp, void *cbp)) { - gsn->cb_conf = cb; - return 0; + int (*cb) (int type, int cause, + struct pdp_t * pdp, void *cbp)) +{ + gsn->cb_conf = cb; + return 0; } int gtp_set_cb_recovery(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer, - uint8_t recovery)) { - gsn->cb_recovery = cb; - return 0; + int (*cb) (struct sockaddr_in * peer, uint8_t recovery)) +{ + gsn->cb_recovery = cb; + return 0; } extern int gtp_set_cb_data_ind(struct gsn_t *gsn, - int (*cb_data_ind) (struct pdp_t* pdp, - void* pack, - unsigned len)) + int (*cb_data_ind) (struct pdp_t * pdp, + void *pack, unsigned len)) { - gsn->cb_data_ind = cb_data_ind; - return 0; + gsn->cb_data_ind = cb_data_ind; + return 0; } /** @@ -184,35 +182,38 @@ extern int gtp_set_cb_data_ind(struct gsn_t *gsn, * to hold the packet header. * returns the length of the header. 0 on error. **/ -static unsigned int get_default_gtp(int version, uint8_t type, 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: - /* Initialise "standard" GTP0 header */ - memset(gtp0_default, 0, sizeof(struct gtp0_header)); - gtp0_default->flags=0x1e; - gtp0_default->type=hton8(type); - gtp0_default->spare1=0xff; - gtp0_default->spare2=0xff; - gtp0_default->spare3=0xff; - gtp0_default->number=0xff; - return GTP0_HEADER_SIZE; - case 1: - /* Initialise "standard" GTP1 header */ - /* 29.060: 8.2: S=1 and PN=0 */ - /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */ - /* and Supported Extension Headers Notification, the S field shall be */ - /* set to 1 */ - /* Currently extension headers are not supported */ - memset(gtp1_default, 0, sizeof(struct gtp1_header_long)); - gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */ - gtp1_default->type=hton8(type); - return GTP1_HEADER_SIZE_LONG; - default: - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version"); - return 0; - } +static unsigned int get_default_gtp(int version, uint8_t type, 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: + /* Initialise "standard" GTP0 header */ + memset(gtp0_default, 0, sizeof(struct gtp0_header)); + gtp0_default->flags = 0x1e; + gtp0_default->type = hton8(type); + gtp0_default->spare1 = 0xff; + gtp0_default->spare2 = 0xff; + gtp0_default->spare3 = 0xff; + gtp0_default->number = 0xff; + return GTP0_HEADER_SIZE; + case 1: + /* Initialise "standard" GTP1 header */ + /* 29.060: 8.2: S=1 and PN=0 */ + /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */ + /* and Supported Extension Headers Notification, the S field shall be */ + /* set to 1 */ + /* Currently extension headers are not supported */ + memset(gtp1_default, 0, sizeof(struct gtp1_header_long)); + gtp1_default->flags = 0x32; /* No extension, enable sequence, no N-PDU */ + gtp1_default->type = hton8(type); + return GTP1_HEADER_SIZE_LONG; + default: + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Unknown GTP packet version"); + return 0; + } } /** @@ -220,18 +221,18 @@ static unsigned int get_default_gtp(int version, uint8_t type, void *packet) { * Get sequence number of a packet. * Returns 0 on error **/ -static uint16_t get_seq(void *pack) { - union gtp_packet *packet = (union gtp_packet *) pack; +static uint16_t get_seq(void *pack) +{ + union gtp_packet *packet = (union gtp_packet *)pack; - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - return ntoh16(packet->gtp0.h.seq); - } - else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ - return ntoh16(packet->gtp1l.h.seq); - } else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return 0; - } + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return ntoh16(packet->gtp0.h.seq); + } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + return ntoh16(packet->gtp1l.h.seq); + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0; + } } /** @@ -239,13 +240,14 @@ static uint16_t get_seq(void *pack) { * Get tunnel identifier of a packet. * Returns 0 on error **/ -static uint64_t get_tid(void *pack) { - union gtp_packet *packet = (union gtp_packet *) pack; - - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - return packet->gtp0.h.tid; - } - return 0; +static uint64_t get_tid(void *pack) +{ + union gtp_packet *packet = (union gtp_packet *)pack; + + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return packet->gtp0.h.tid; + } + return 0; } /** @@ -253,21 +255,20 @@ static uint64_t get_tid(void *pack) { * Get the header length of a packet. * Returns 0 on error **/ -static uint16_t get_hlen(void *pack) { - union gtp_packet *packet = (union gtp_packet *) pack; +static uint16_t get_hlen(void *pack) +{ + union gtp_packet *packet = (union gtp_packet *)pack; - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - return GTP0_HEADER_SIZE; - } - else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ - return GTP1_HEADER_SIZE_LONG; - } - else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */ - return GTP1_HEADER_SIZE_SHORT; - } else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return 0; - } + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return GTP0_HEADER_SIZE; + } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + return GTP1_HEADER_SIZE_LONG; + } else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */ + return GTP1_HEADER_SIZE_SHORT; + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0; + } } /** @@ -275,55 +276,53 @@ static uint16_t get_hlen(void *pack) { * Get the tunnel endpoint identifier (flow label) of a packet. * Returns 0xffffffff on error. **/ -static uint32_t get_tei(void *pack) { - union gtp_packet *packet = (union gtp_packet *) pack; +static uint32_t get_tei(void *pack) +{ + union gtp_packet *packet = (union gtp_packet *)pack; - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - return ntoh16(packet->gtp0.h.flow); - } - else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */ - return ntoh32(packet->gtp1l.h.tei); - } - else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return 0xffffffff; - } + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return ntoh16(packet->gtp0.h.flow); + } else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */ + return ntoh32(packet->gtp1l.h.tei); + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0xffffffff; + } } - int print_packet(void *packet, unsigned len) { - unsigned int i; - printf("The packet looks like this (%d bytes):\n", len); - for( i=0; isin_addr), - ntohs(peer->sin_port), - len); - buf[size-1] = 0; - pos = strlen(buf); - for(n=0; nsin_addr), ntohs(peer->sin_port), len); + buf[size - 1] = 0; + pos = strlen(buf); + for (n = 0; n < len; n++) { + if ((pos + 4) < size) { + sprintf((buf + pos), " %02hhx", + ((unsigned char *)pack)[n]); + pos += 3; + } + } + buf[pos] = 0; + return buf; } - /* *********************************************************** * Reliable delivery of signalling messages * @@ -403,71 +402,74 @@ char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer, *************************************************************/ int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp, - union gtp_packet *packet, int len, - struct in_addr *inetaddr, void *cbp) { - struct sockaddr_in addr; - struct qmsg_t *qmsg; - int fd; + union gtp_packet *packet, int len, + struct in_addr *inetaddr, void *cbp) +{ + struct sockaddr_in addr; + struct qmsg_t *qmsg; + int fd; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = *inetaddr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *inetaddr; #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr.sin_len = sizeof(addr); #endif - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - addr.sin_port = htons(GTP0_PORT); - packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); - packet->gtp0.h.seq = hton16(gsn->seq_next); - if (pdp) - packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + - ((uint64_t)pdp->nsapi << 60); - if (pdp && ((packet->gtp0.h.type == GTP_GPDU) || - (packet->gtp0.h.type == GTP_ERROR))) - packet->gtp0.h.flow=hton16(pdp->flru); - else if (pdp) - packet->gtp0.h.flow=hton16(pdp->flrc); - fd = gsn->fd0; - } - else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ - addr.sin_port = htons(GTP1C_PORT); - packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); - packet->gtp1l.h.seq = hton16(gsn->seq_next); - if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) || - (packet->gtp1l.h.type == GTP_ERROR))) - packet->gtp1l.h.tei=hton32(pdp->teid_gn); - else if (pdp) - packet->gtp1l.h.tei=hton32(pdp->teic_gn); - fd = gsn->fd1c; - } else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return -1; - } - - if (sendto(fd, packet, len, 0, - (struct sockaddr *) &addr, sizeof(addr)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno)); - return -1; - } + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + addr.sin_port = htons(GTP0_PORT); + packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); + packet->gtp0.h.seq = hton16(gsn->seq_next); + if (pdp) + packet->gtp0.h.tid = + (pdp->imsi & 0x0fffffffffffffffull) + + ((uint64_t) pdp->nsapi << 60); + if (pdp && ((packet->gtp0.h.type == GTP_GPDU) + || (packet->gtp0.h.type == GTP_ERROR))) + packet->gtp0.h.flow = hton16(pdp->flru); + else if (pdp) + packet->gtp0.h.flow = hton16(pdp->flrc); + fd = gsn->fd0; + } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + addr.sin_port = htons(GTP1C_PORT); + packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); + packet->gtp1l.h.seq = hton16(gsn->seq_next); + if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) || + (packet->gtp1l.h.type == GTP_ERROR))) + packet->gtp1l.h.tei = hton32(pdp->teid_gn); + else if (pdp) + packet->gtp1l.h.tei = hton32(pdp->teic_gn); + fd = gsn->fd1c; + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return -1; + } - /* Use new queue structure */ - if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) { - gsn->err_queuefull++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full"); - } - else { - memcpy(&qmsg->p, packet, sizeof(union gtp_packet)); - qmsg->l = len; - qmsg->timeout = time(NULL) + 3; /* When to timeout */ - qmsg->retrans = 0; /* No retransmissions so far */ - qmsg->cbp = cbp; - qmsg->type = ntoh8(packet->gtp0.h.type); - qmsg->fd = fd; - } - gsn->seq_next++; /* Count up this time */ - return 0; + if (sendto(fd, packet, len, 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, + (unsigned long)&packet, len, strerror(errno)); + return -1; + } + + /* Use new queue structure */ + if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) { + gsn->err_queuefull++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Retransmit queue is full"); + } else { + memcpy(&qmsg->p, packet, sizeof(union gtp_packet)); + qmsg->l = len; + qmsg->timeout = time(NULL) + 3; /* When to timeout */ + qmsg->retrans = 0; /* No retransmissions so far */ + qmsg->cbp = cbp; + qmsg->type = ntoh8(packet->gtp0.h.type); + qmsg->fd = fd; + } + gsn->seq_next++; /* Count up this time */ + return 0; } /* gtp_conf @@ -475,373 +477,402 @@ int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp, * return 0 on success, EOF if packet was not found */ int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, - union gtp_packet *packet, int len, uint8_t *type, void **cbp) { + union gtp_packet *packet, int len, uint8_t * type, void **cbp) +{ - uint16_t seq; + uint16_t seq; - if ((packet->gtp0.h.flags & 0xe0) == 0x00) - seq = ntoh16(packet->gtp0.h.seq); - else if ((packet->gtp1l.h.flags & 0xe2) == 0x22) - seq = ntoh16(packet->gtp1l.h.seq); - else { - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, - "Unknown GTP packet version"); - return EOF; - } + if ((packet->gtp0.h.flags & 0xe0) == 0x00) + seq = ntoh16(packet->gtp0.h.seq); + else if ((packet->gtp1l.h.flags & 0xe2) == 0x22) + seq = ntoh16(packet->gtp1l.h.seq); + else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, + "Unknown GTP packet version"); + return EOF; + } - if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) { - gsn->err_seq++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, - "Confirmation packet not found in queue"); - return EOF; - } + if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) { + gsn->err_seq++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, + "Confirmation packet not found in queue"); + return EOF; + } - return 0; + return 0; } -int gtp_retrans(struct gsn_t *gsn) { - /* Retransmit any outstanding packets */ - /* Remove from queue if maxretrans exceeded */ - time_t now; - struct qmsg_t *qmsg; - now = time(NULL); - /*printf("Retrans: New beginning %d\n", (int) now);*/ +int gtp_retrans(struct gsn_t *gsn) +{ + /* Retransmit any outstanding packets */ + /* Remove from queue if maxretrans exceeded */ + time_t now; + struct qmsg_t *qmsg; + now = time(NULL); + /*printf("Retrans: New beginning %d\n", (int) now); */ - while ((!queue_getfirst(gsn->queue_req, &qmsg)) && - (qmsg->timeout <= now)) { - /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/ - if (qmsg->retrans > 3) { /* To many retrans */ - if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp); - queue_freemsg(gsn->queue_req, qmsg); - } - else { - if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, - (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd0, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); - } - queue_back(gsn->queue_req, qmsg); - qmsg->timeout = now + 3; - qmsg->retrans++; - } - } + while ((!queue_getfirst(gsn->queue_req, &qmsg)) && + (qmsg->timeout <= now)) { + /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */ + if (qmsg->retrans > 3) { /* To many retrans */ + if (gsn->cb_conf) + gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp); + queue_freemsg(gsn->queue_req, qmsg); + } else { + if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, + (struct sockaddr *)&qmsg->peer, + sizeof(struct sockaddr_in)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s", + gsn->fd0, (unsigned long)&qmsg->p, + qmsg->l, strerror(errno)); + } + queue_back(gsn->queue_req, qmsg); + qmsg->timeout = now + 3; + qmsg->retrans++; + } + } - /* Also clean up reply timeouts */ - while ((!queue_getfirst(gsn->queue_resp, &qmsg)) && - (qmsg->timeout < now)) { - /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/ - queue_freemsg(gsn->queue_resp, qmsg); - } + /* Also clean up reply timeouts */ + while ((!queue_getfirst(gsn->queue_resp, &qmsg)) && + (qmsg->timeout < now)) { + /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */ + queue_freemsg(gsn->queue_resp, qmsg); + } - return 0; + return 0; } -int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) { - time_t now, later; - struct qmsg_t *qmsg; +int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) +{ + time_t now, later; + struct qmsg_t *qmsg; - if (queue_getfirst(gsn->queue_req, &qmsg)) { - timeout->tv_sec = 10; - timeout->tv_usec = 0; - } - else { - now = time(NULL); - later = qmsg->timeout; - timeout->tv_sec = later - now; - timeout->tv_usec = 0; - if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */ - if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/ - } - return 0; + if (queue_getfirst(gsn->queue_req, &qmsg)) { + timeout->tv_sec = 10; + timeout->tv_usec = 0; + } else { + now = time(NULL); + later = qmsg->timeout; + timeout->tv_sec = later - now; + timeout->tv_usec = 0; + if (timeout->tv_sec < 0) + timeout->tv_sec = 0; /* No negative allowed */ + if (timeout->tv_sec > 10) + timeout->tv_sec = 10; /* Max sleep for 10 sec */ + } + return 0; } -int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp, +int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp, union gtp_packet *packet, int len, - struct sockaddr_in *peer, int fd, - uint16_t seq, uint64_t tid) { - struct qmsg_t *qmsg; + struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid) +{ + struct qmsg_t *qmsg; - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); - packet->gtp0.h.seq = hton16(seq); - packet->gtp0.h.tid = tid; - if (pdp && ((packet->gtp0.h.type == GTP_GPDU) || - (packet->gtp0.h.type == GTP_ERROR))) - packet->gtp0.h.flow=hton16(pdp->flru); - else if (pdp) - packet->gtp0.h.flow=hton16(pdp->flrc); - } - else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ - packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); - packet->gtp1l.h.seq = hton16(seq); - if (pdp && (fd == gsn->fd1u)) - packet->gtp1l.h.tei=hton32(pdp->teid_gn); - else if (pdp) - packet->gtp1l.h.tei=hton32(pdp->teic_gn); - } - else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return -1; - } - - if (fcntl(fd, F_SETFL, 0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); + packet->gtp0.h.seq = hton16(seq); + packet->gtp0.h.tid = tid; + if (pdp && ((packet->gtp0.h.type == GTP_GPDU) || + (packet->gtp0.h.type == GTP_ERROR))) + packet->gtp0.h.flow = hton16(pdp->flru); + else if (pdp) + packet->gtp0.h.flow = hton16(pdp->flrc); + } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); + packet->gtp1l.h.seq = hton16(seq); + if (pdp && (fd == gsn->fd1u)) + packet->gtp1l.h.tei = hton32(pdp->teid_gn); + else if (pdp) + packet->gtp1l.h.tei = hton32(pdp->teic_gn); + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return -1; + } - if (sendto(fd, packet, len, 0, - (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno)); - return -1; - } + if (fcntl(fd, F_SETFL, 0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } - /* Use new queue structure */ - if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) { - gsn->err_queuefull++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full"); - } - else { - memcpy(&qmsg->p, packet, sizeof(union gtp_packet)); - qmsg->l = len; - qmsg->timeout = time(NULL) + 60; /* When to timeout */ - qmsg->retrans = 0; /* No retransmissions so far */ - qmsg->cbp = NULL; - qmsg->type = 0; - qmsg->fd = fd; - } - return 0; + if (sendto(fd, packet, len, 0, + (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, + (unsigned long)&packet, len, strerror(errno)); + return -1; + } + + /* Use new queue structure */ + if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) { + gsn->err_queuefull++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Retransmit queue is full"); + } else { + memcpy(&qmsg->p, packet, sizeof(union gtp_packet)); + qmsg->l = len; + qmsg->timeout = time(NULL) + 60; /* When to timeout */ + qmsg->retrans = 0; /* No retransmissions so far */ + qmsg->cbp = NULL; + qmsg->type = 0; + qmsg->fd = fd; + } + return 0; } int gtp_notification(struct gsn_t *gsn, int version, union gtp_packet *packet, int len, - struct sockaddr_in *peer, int fd, - uint16_t seq) { + struct sockaddr_in *peer, int fd, uint16_t seq) +{ - struct sockaddr_in addr; - - memcpy(&addr, peer, sizeof(addr)); + struct sockaddr_in addr; - /* In GTP0 notifications are treated as replies. In GTP1 they - are requests for which there is no reply */ + memcpy(&addr, peer, sizeof(addr)); - if (fd == gsn->fd1c) - addr.sin_port = htons(GTP1C_PORT); - else if (fd == gsn->fd1u) - addr.sin_port = htons(GTP1C_PORT); + /* In GTP0 notifications are treated as replies. In GTP1 they + are requests for which there is no reply */ - if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ - packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); - packet->gtp0.h.seq = hton16(seq); - } - else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ - packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); - packet->gtp1l.h.seq = hton16(seq); - } - else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); - return -1; - } - - if (fcntl(fd, F_SETFL, 0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } + if (fd == gsn->fd1c) + addr.sin_port = htons(GTP1C_PORT); + else if (fd == gsn->fd1u) + addr.sin_port = htons(GTP1C_PORT); - if (sendto(fd, packet, len, 0, - (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno)); - return -1; - } - return 0; + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); + packet->gtp0.h.seq = hton16(seq); + } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); + packet->gtp1l.h.seq = hton16(seq); + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return -1; + } + + if (fcntl(fd, F_SETFL, 0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + + if (sendto(fd, packet, len, 0, + (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, + (unsigned long)&packet, len, strerror(errno)); + return -1; + } + return 0; } -int gtp_dublicate(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, uint16_t seq) { - struct qmsg_t *qmsg; +int gtp_dublicate(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, uint16_t seq) +{ + struct qmsg_t *qmsg; - if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) { - return EOF; /* Notfound */ - } + if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) { + return EOF; /* Notfound */ + } - if (fcntl(qmsg->fd, F_SETFL, 0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } - - if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, - (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", qmsg->fd, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); - } - return 0; + if (fcntl(qmsg->fd, F_SETFL, 0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + + if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, + (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", + qmsg->fd, (unsigned long)&qmsg->p, qmsg->l, + strerror(errno)); + } + return 0; } - - /* Perform restoration and recovery error handling as described in 29.060 */ -static void log_restart(struct gsn_t *gsn) { +static void log_restart(struct gsn_t *gsn) +{ FILE *f; int i, rc; int counter = 0; char filename[NAMESIZE]; - filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */ - strncpy(filename, gsn->statedir, NAMESIZE-1); - strncat(filename, RESTART_FILE, - NAMESIZE-1-sizeof(RESTART_FILE)); + filename[NAMESIZE - 1] = 0; /* No null term. guarantee by strncpy */ + strncpy(filename, gsn->statedir, NAMESIZE - 1); + strncat(filename, RESTART_FILE, NAMESIZE - 1 - sizeof(RESTART_FILE)); i = umask(022); /* We try to open file. On failure we will later try to create file */ if (!(f = fopen(filename, "r"))) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename); + gtp_err(LOG_ERR, __FILE__, __LINE__, + "State information file (%s) not found. Creating new file.", + filename); + } else { + umask(i); + rc = fscanf(f, "%d", &counter); + if (rc != 1) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "fscanf failed to read counter value"); + return; + } + if (fclose(f)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "fclose failed: Error = %s", strerror(errno)); + } } - else { - umask(i); - rc = fscanf(f, "%d", &counter); - if (rc != 1) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fscanf failed to read counter value"); - return; - } - if (fclose(f)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno)); - } - } - - gsn->restart_counter = (unsigned char) counter; + + gsn->restart_counter = (unsigned char)counter; gsn->restart_counter++; - + if (!(f = fopen(filename, "w"))) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno)); - return; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "fopen(path=%s, mode=%s) failed: Error = %s", filename, + "w", strerror(errno)); + return; } umask(i); fprintf(f, "%d\n", gsn->restart_counter); if (fclose(f)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno)); - return; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "fclose failed: Error = %s", strerror(errno)); + return; } } - - int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, - int mode) + int mode) { - struct sockaddr_in addr; - - syslog(LOG_ERR, "GTP: gtp_newgsn() started"); + struct sockaddr_in addr; - *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */ + syslog(LOG_ERR, "GTP: gtp_newgsn() started"); - (*gsn)->statedir = statedir; - log_restart(*gsn); + *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */ - /* Initialise sequence number */ - (*gsn)->seq_next = (*gsn)->restart_counter * 1024; - - /* Initialise request retransmit queue */ - queue_new(&(*gsn)->queue_req); - queue_new(&(*gsn)->queue_resp); - - /* Initialise pdp table */ - pdp_init(); + (*gsn)->statedir = statedir; + log_restart(*gsn); - /* Initialise call back functions */ - (*gsn)->cb_create_context_ind = 0; - (*gsn)->cb_delete_context = 0; - (*gsn)->cb_unsup_ind = 0; - (*gsn)->cb_conf = 0; - (*gsn)->cb_data_ind = 0; + /* Initialise sequence number */ + (*gsn)->seq_next = (*gsn)->restart_counter * 1024; - /* Store function parameters */ - (*gsn)->gsnc = *listen; - (*gsn)->gsnu = *listen; - (*gsn)->mode = mode; + /* Initialise request retransmit queue */ + queue_new(&(*gsn)->queue_req); + queue_new(&(*gsn)->queue_resp); + /* Initialise pdp table */ + pdp_init(); - /* Create GTP version 0 socket */ - if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ - addr.sin_port = htons(GTP0_PORT); + /* Initialise call back functions */ + (*gsn)->cb_create_context_ind = 0; + (*gsn)->cb_delete_context = 0; + (*gsn)->cb_unsup_ind = 0; + (*gsn)->cb_conf = 0; + (*gsn)->cb_data_ind = 0; + + /* Store function parameters */ + (*gsn)->gsnc = *listen; + (*gsn)->gsnu = *listen; + (*gsn)->mode = mode; + + /* Create GTP version 0 socket */ + if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", + AF_INET, SOCK_DGRAM, 0, strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *listen; /* Same IP for user traffic and signalling */ + addr.sin_port = htons(GTP0_PORT); #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr.sin_len = sizeof(addr); #endif - - if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd0, (unsigned long) &addr, sizeof(addr), strerror(errno)); - return -1; - } - /* Create GTP version 1 control plane socket */ - if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); - return -1; - } + if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s", + (*gsn)->fd0, (unsigned long)&addr, sizeof(addr), + strerror(errno)); + return -1; + } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ - addr.sin_port = htons(GTP1C_PORT); + /* Create GTP version 1 control plane socket */ + if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", + AF_INET, SOCK_DGRAM, 0, strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *listen; /* Same IP for user traffic and signalling */ + addr.sin_port = htons(GTP1C_PORT); #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr.sin_len = sizeof(addr); #endif - - if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno)); - return -1; - } - /* Create GTP version 1 user plane socket */ - if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); - return -1; - } + if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", + (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr), + strerror(errno)); + return -1; + } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ - addr.sin_port = htons(GTP1U_PORT); + /* Create GTP version 1 user plane socket */ + if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", + AF_INET, SOCK_DGRAM, 0, strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *listen; /* Same IP for user traffic and signalling */ + addr.sin_port = htons(GTP1U_PORT); #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr.sin_len = sizeof(addr); #endif - - if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno)); - return -1; - } - return 0; + if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", + (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr), + strerror(errno)); + return -1; + } + + return 0; } -int gtp_free(struct gsn_t *gsn) { +int gtp_free(struct gsn_t *gsn) +{ - /* Clean up retransmit queues */ - queue_free(gsn->queue_req); - queue_free(gsn->queue_resp); - - close(gsn->fd0); - close(gsn->fd1c); - close(gsn->fd1u); + /* Clean up retransmit queues */ + queue_free(gsn->queue_req); + queue_free(gsn->queue_resp); - free(gsn); - return 0; + close(gsn->fd0); + close(gsn->fd1c); + close(gsn->fd1u); + + free(gsn); + return 0; } /* *********************************************************** @@ -877,71 +908,78 @@ int gtp_free(struct gsn_t *gsn) { int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, struct in_addr *inetaddr) { - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet); - return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp); + union gtp_packet packet; + unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet); + return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp); } /* Send off an echo reply */ int gtp_echo_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, - void *pack, unsigned len) + struct sockaddr_in *peer, int fd, void *pack, unsigned len) { - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet); - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter); - return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, - get_seq(pack), get_tid(pack)); + union gtp_packet packet; + unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); + return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, + get_seq(pack), get_tid(pack)); } - /* Handle a received echo request */ -int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer, - int fd, void *pack, unsigned len) { +int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer, + int fd, void *pack, unsigned len) +{ - /* Check if it was a dublicate request */ - if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0; + /* Check if it was a dublicate request */ + if (!gtp_dublicate(gsn, 0, peer, get_seq(pack))) + return 0; - /* Send off reply to request */ - return gtp_echo_resp(gsn, version, peer, fd, pack, len); + /* Send off reply to request */ + return gtp_echo_resp(gsn, version, peer, fd, pack, len); } /* Handle a received echo reply */ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, - void *pack, unsigned len) { - union gtpie_member *ie[GTPIE_SIZE]; - unsigned char recovery; - void *cbp = NULL; - uint8_t type = 0; - int hlen = get_hlen(pack); + void *pack, unsigned len) +{ + union gtpie_member *ie[GTPIE_SIZE]; + unsigned char recovery; + void *cbp = NULL; + uint8_t type = 0; + int hlen = get_hlen(pack); - /* Remove packet from queue */ - if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; + /* Remove packet from queue */ + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) + return EOF; - /* Extract information elements into a pointer array */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; - } - - if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; - } + /* Extract information elements into a pointer array */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } - /* Echo reply packages does not have a cause information element */ - /* Instead we return the recovery number in the callback function */ - if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp); + if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } - if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery); + /* Echo reply packages does not have a cause information element */ + /* Instead we return the recovery number in the callback function */ + if (gsn->cb_conf) + gsn->cb_conf(type, recovery, NULL, cbp); - return 0; + if (gsn->cb_recovery) + gsn->cb_recovery(peer, recovery); + + return 0; } /* Send off a Version Not Supported message */ @@ -958,53 +996,56 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len) { - union gtp_packet packet; + union gtp_packet packet; - /* GTP 1 is the highest supported protocol */ - unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet); - return gtp_notification(gsn, version, &packet, length, - peer, fd, 0); + /* GTP 1 is the highest supported protocol */ + unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet); + return gtp_notification(gsn, version, &packet, length, peer, fd, 0); } /* Handle a Version Not Supported message */ -int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len) { +int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, + void *pack, unsigned len) +{ - if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer); - - return 0; + if (gsn->cb_unsup_ind) + gsn->cb_unsup_ind(peer); + + return 0; } /* Send off an Supported Extension Headers Notification */ int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len) { - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet); + union gtp_packet packet; + unsigned int length = + get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet); - uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU; + uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU; - if (version < 1) - return 0; + if (version < 1) + return 0; - /* We report back that we support only PDCP PDU headers */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu), - &pdcp_pdu); + /* We report back that we support only PDCP PDU headers */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, + sizeof(pdcp_pdu), &pdcp_pdu); - return gtp_notification(gsn, version, &packet, length, - peer, fd, get_seq(pack)); + return gtp_notification(gsn, version, &packet, length, + peer, fd, get_seq(pack)); } /* Handle a Supported Extension Headers Notification */ -int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len) { +int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer, + void *pack, unsigned len) +{ - if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer); - - return 0; + if (gsn->cb_extheader_ind) + gsn->cb_extheader_ind(peer); + + return 0; } - /* *********************************************************** * Session management messages * Messages: create, update and delete PDP context @@ -1018,1466 +1059,1564 @@ int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer, *************************************************************/ /* API: Send Create PDP Context Request (7.3.1) */ -extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, - void *cbp) { - union gtp_packet packet; - unsigned int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet); - struct pdp_t *linked_pdp = NULL; +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp) +{ + union gtp_packet packet; + unsigned int length = + get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet); + struct pdp_t *linked_pdp = NULL; - /* TODO: Secondary PDP Context Activation Procedure */ - /* In secondary activation procedure the PDP context is identified - by tei in the header. The following fields are omitted: Selection - mode, IMSI, MSISDN, End User Address, Access Point Name and - Protocol Configuration Options */ + /* TODO: Secondary PDP Context Activation Procedure */ + /* In secondary activation procedure the PDP context is identified + by tei in the header. The following fields are omitted: Selection + mode, IMSI, MSISDN, End User Address, Access Point Name and + Protocol Configuration Options */ - if (pdp->secondary) { - if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context"); - return EOF; - } - } + if (pdp->secondary) { + if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Unknown linked PDP context"); + return EOF; + } + } - if (pdp->version == 0) { - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_req0), pdp->qos_req0); - } + if (pdp->version == 0) { + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_req0), pdp->qos_req0); + } - /* Section 7.7.2 */ - if (pdp->version == 1) { - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, - sizeof(pdp->imsi), (uint8_t*) &pdp->imsi); - } + /* Section 7.7.2 */ + if (pdp->version == 1) { + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, + sizeof(pdp->imsi), (uint8_t *) & pdp->imsi); + } - /* Section 7.7.3 Routing Area Information */ - if (pdp->rai_given == 1) - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI, - pdp->rai.l, (uint8_t*) &pdp->rai.v); + /* Section 7.7.3 Routing Area Information */ + if (pdp->rai_given == 1) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI, + pdp->rai.l, (uint8_t *) & pdp->rai.v); + /* Section 7.7.11 */ + if (pdp->norecovery_given == 0) + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); - /* Section 7.7.11 */ - if (pdp->norecovery_given == 0) - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); + /* Section 7.7.12 */ + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE, + pdp->selmode); - /* Section 7.7.12 */ - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE, - pdp->selmode); + if (pdp->version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc); + } - if (pdp->version == 0) { - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - } + /* Section 7.7.13 */ + if (pdp->version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); - /* Section 7.7.13 */ - if (pdp->version == 1) { - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, - pdp->teid_own); + /* Section 7.7.14 */ + if (!pdp->teic_confirmed) + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); - /* Section 7.7.14 */ - if (!pdp->teic_confirmed) - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, - pdp->teic_own); + /* Section 7.7.17 */ + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi); - /* Section 7.7.17 */ - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, - pdp->nsapi); + /* Section 7.7.17 */ + if (pdp->secondary) /* Secondary PDP Context Activation Procedure */ + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, + linked_pdp->nsapi); - /* Section 7.7.17 */ - if (pdp->secondary) /* Secondary PDP Context Activation Procedure */ - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, - linked_pdp->nsapi); + /* Section 7.7.23 */ + if (pdp->cch_pdp) /* Only include charging if flags are set */ + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C, + pdp->cch_pdp); + } - /* Section 7.7.23 */ - if (pdp->cch_pdp) /* Only include charging if flags are set */ - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C, - pdp->cch_pdp); - } + /* TODO + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, + pdp->traceref); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, + pdp->tracetype); */ - /* TODO - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, - pdp->traceref); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, - pdp->tracetype); */ + /* Section 7.7.27 */ + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); - /* Section 7.7.27 */ - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); - + /* Section 7.7.30 */ + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN, + pdp->apn_use.l, pdp->apn_use.v); - /* Section 7.7.30 */ - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN, - pdp->apn_use.l, pdp->apn_use.v); + /* Section 7.7.31 */ + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + if (pdp->pco_req.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, + pdp->pco_req.l, pdp->pco_req.v); - /* Section 7.7.31 */ - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - if (pdp->pco_req.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, - pdp->pco_req.l, pdp->pco_req.v); - - /* Section 7.7.32 */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - /* Section 7.7.32 */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); + /* Section 7.7.32 */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlc.l, pdp->gsnlc.v); + /* Section 7.7.32 */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlu.l, pdp->gsnlu.v); - /* Section 7.7.33 */ - if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN, - pdp->msisdn.l, pdp->msisdn.v); + /* Section 7.7.33 */ + if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN, + pdp->msisdn.l, pdp->msisdn.v); - /* Section 7.7.34 */ - if (pdp->version == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, - pdp->qos_req.l, pdp->qos_req.v); + /* Section 7.7.34 */ + if (pdp->version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_req.l, pdp->qos_req.v); - /* Section 7.7.36 */ - if ((pdp->version == 1) && pdp->tft.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, - pdp->tft.l, pdp->tft.v); - - /* Section 7.7.41 */ - if ((pdp->version == 1) && pdp->triggerid.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, - pdp->triggerid.l, pdp->triggerid.v); - - /* Section 7.7.42 */ - if ((pdp->version == 1) && pdp->omcid.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, - pdp->omcid.l, pdp->omcid.v); - - /* new R7 fields */ - if (pdp->rattype_given == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE, - pdp->rattype.l, pdp->rattype.v); + /* Section 7.7.36 */ + if ((pdp->version == 1) && pdp->tft.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, + pdp->tft.l, pdp->tft.v); - if (pdp->userloc_given == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC, - pdp->userloc.l, pdp->userloc.v); + /* Section 7.7.41 */ + if ((pdp->version == 1) && pdp->triggerid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, + pdp->triggerid.l, pdp->triggerid.v); - if (pdp->mstz_given == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ, - pdp->mstz.l, pdp->mstz.v); + /* Section 7.7.42 */ + if ((pdp->version == 1) && pdp->omcid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, + pdp->omcid.l, pdp->omcid.v); - if (pdp->imeisv_given == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV, - pdp->imeisv.l, pdp->imeisv.v); + /* new R7 fields */ + if (pdp->rattype_given == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE, + pdp->rattype.l, pdp->rattype.v); - /* TODO hisaddr0 */ - gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp); + if (pdp->userloc_given == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC, + pdp->userloc.l, pdp->userloc.v); - return 0; + if (pdp->mstz_given == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ, + pdp->mstz.l, pdp->mstz.v); + + if (pdp->imeisv_given == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV, + pdp->imeisv.l, pdp->imeisv.v); + + /* TODO hisaddr0 */ + gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp); + + return 0; } /* API: Application response to context indication */ -int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) { +int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) +{ - /* Now send off a reply to the peer */ - gtp_create_pdp_resp(gsn, pdp->version, pdp, cause); - - if (cause != GTPCAUSE_ACC_REQ) { - pdp_freepdp(pdp); - } - - return 0; + /* Now send off a reply to the peer */ + gtp_create_pdp_resp(gsn, pdp->version, pdp, cause); + + if (cause != GTPCAUSE_ACC_REQ) { + pdp_freepdp(pdp); + } + + return 0; } /* API: Register create context indication callback */ int gtp_set_cb_create_context_ind(struct gsn_t *gsn, - int (*cb_create_context_ind) (struct pdp_t* pdp)) + int (*cb_create_context_ind) (struct pdp_t * + pdp)) { - gsn->cb_create_context_ind = cb_create_context_ind; - return 0; + gsn->cb_create_context_ind = cb_create_context_ind; + return 0; } - /* Send Create PDP Context Response */ -int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, - uint8_t cause) { - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet); +int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, + uint8_t cause) +{ + union gtp_packet packet; + unsigned int length = + get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet); - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); - if (cause == GTPCAUSE_ACC_REQ) { + if (cause == GTPCAUSE_ACC_REQ) { - if (version == 0) - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_neg0), pdp->qos_neg0); + if (version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_neg0), pdp->qos_neg0); - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER, - pdp->reorder); - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER, + pdp->reorder); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); - if (version == 0) { - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - } + if (version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } - if (version == 1) { - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, - pdp->teid_own); - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, - pdp->teic_own); - } + if (version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); + } - /* TODO: We use teic_own as charging ID */ - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, - pdp->teic_own); + /* TODO: We use teic_own as charging ID */ + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, + pdp->teic_own); - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); - if (pdp->pco_neg.l) { /* Optional PCO */ - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, - pdp->pco_neg.l, pdp->pco_neg.v); - } + if (pdp->pco_neg.l) { /* Optional PCO */ + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, + pdp->pco_neg.l, pdp->pco_neg.v); + } - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlc.l, pdp->gsnlc.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlu.l, pdp->gsnlu.v); - if (version == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, - pdp->qos_neg.l, pdp->qos_neg.v); + if (version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_neg.l, pdp->qos_neg.v); - /* TODO: Charging gateway address */ - } + /* TODO: Charging gateway address */ + } - return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer, - pdp->fd, pdp->seq, pdp->tid); + return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer, + pdp->fd, pdp->seq, pdp->tid); } /* Handle Create PDP Context Request */ int gtp_create_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, - void *pack, unsigned len) { - struct pdp_t *pdp, *pdp_old; - struct pdp_t pdp_buf; - union gtpie_member* ie[GTPIE_SIZE]; - uint8_t recovery; + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) +{ + struct pdp_t *pdp, *pdp_old; + struct pdp_t pdp_buf; + union gtpie_member *ie[GTPIE_SIZE]; + uint8_t recovery; - uint16_t seq = get_seq(pack); - int hlen = get_hlen(pack); - uint8_t linked_nsapi = 0; - struct pdp_t *linked_pdp = NULL; + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); + uint8_t linked_nsapi = 0; + struct pdp_t *linked_pdp = NULL; - if(!gtp_dublicate(gsn, version, peer, seq)) return 0; + if (!gtp_dublicate(gsn, version, peer, seq)) + return 0; - pdp = &pdp_buf; - memset(pdp, 0, sizeof(struct pdp_t)); + pdp = &pdp_buf; + memset(pdp, 0, sizeof(struct pdp_t)); - if (version == 0) { - pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull; - pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60; - } + if (version == 0) { + pdp->imsi = + ((union gtp_packet *)pack)->gtp0. + h.tid & 0x0fffffffffffffffull; + pdp->nsapi = + (((union gtp_packet *)pack)->gtp0. + h.tid & 0xf000000000000000ull) >> 60; + } - pdp->seq = seq; - pdp->sa_peer = *peer; - pdp->fd = fd; - pdp->version = version; + pdp->seq = seq; + pdp->sa_peer = *peer; + pdp->fd = fd; + pdp->version = version; - /* Decode information elements */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (0 == version) - return EOF; - else - return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE); - } + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (0 == version) + return EOF; + else + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_INVALID_MESSAGE); + } - if (version == 1) { - /* Linked NSAPI (conditional) */ - /* If included this is the Secondary PDP Context Activation Procedure */ - /* In secondary activation IMSI is not included, so the context must be */ - /* identified by the tei */ - if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) { - - /* Find the primary PDP context */ - if (pdp_getgtp1(&linked_pdp, get_tei(pack))) { - gsn->incorrect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Incorrect optional information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_OPT_IE_INCORRECT); - } + if (version == 1) { + /* Linked NSAPI (conditional) */ + /* If included this is the Secondary PDP Context Activation Procedure */ + /* In secondary activation IMSI is not included, so the context must be */ + /* identified by the tei */ + if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) { - /* Check that the primary PDP context matches linked nsapi */ - if (linked_pdp->nsapi != linked_nsapi) { - gsn->incorrect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Incorrect optional information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_OPT_IE_INCORRECT); - } - - /* Copy parameters from primary context */ - pdp->selmode = linked_pdp->selmode; - pdp->imsi = linked_pdp->imsi; - pdp->msisdn = linked_pdp->msisdn; - pdp->eua = linked_pdp->eua; - pdp->pco_req = linked_pdp->pco_req; - pdp->apn_req = linked_pdp->apn_req; - pdp->teic_gn = linked_pdp->teic_gn; - pdp->secondary = 1; - } - } /* if (version == 1) */ + /* Find the primary PDP context */ + if (pdp_getgtp1(&linked_pdp, get_tei(pack))) { + gsn->incorrect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Incorrect optional information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_OPT_IE_INCORRECT); + } - if (version == 0) { - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_req0, sizeof(pdp->qos_req0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); - } - } - - if ((version == 1) && (!linked_pdp)) { - /* Not Secondary PDP Context Activation Procedure */ - /* IMSI (conditional) */ - if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } - - /* Recovery (optional) */ - if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { - if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery); - } - - /* Selection mode (conditional) */ - if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ - if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0, - &pdp->selmode, sizeof(pdp->selmode))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } + /* Check that the primary PDP context matches linked nsapi */ + if (linked_pdp->nsapi != linked_nsapi) { + gsn->incorrect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Incorrect optional information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_OPT_IE_INCORRECT); + } - if (version == 0) { - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } - - - if (version == 1) { - /* TEID (mandatory) */ - if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } + /* Copy parameters from primary context */ + pdp->selmode = linked_pdp->selmode; + pdp->imsi = linked_pdp->imsi; + pdp->msisdn = linked_pdp->msisdn; + pdp->eua = linked_pdp->eua; + pdp->pco_req = linked_pdp->pco_req; + pdp->apn_req = linked_pdp->apn_req; + pdp->teic_gn = linked_pdp->teic_gn; + pdp->secondary = 1; + } + } + /* if (version == 1) */ + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + pdp->qos_req0, sizeof(pdp->qos_req0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* TEIC (conditional) */ - if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ - if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } + if ((version == 1) && (!linked_pdp)) { + /* Not Secondary PDP Context Activation Procedure */ + /* IMSI (conditional) */ + if (gtpie_gettv0 + (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* NSAPI (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } - - - /* Charging Characteriatics (optional) */ - /* Trace reference (optional) */ - /* Trace type (optional) */ - /* Charging Characteriatics (optional) */ - - if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ - /* End User Address (conditional) */ - if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - /* APN */ - if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l, - &pdp->apn_req.v, sizeof(pdp->apn_req.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - /* Extract protocol configuration options (optional) */ - if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, - &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { - } - } + /* Recovery (optional) */ + if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { + if (gsn->cb_recovery) + gsn->cb_recovery(peer, recovery); + } - /* SGSN address for signalling (mandatory) */ - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } + /* Selection mode (conditional) */ + if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ + if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0, + &pdp->selmode, sizeof(pdp->selmode))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* SGSN address for user traffic (mandatory) */ - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ - /* MSISDN (conditional) */ - if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l, - &pdp->msisdn.v, sizeof(pdp->msisdn.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - if (version == 1) { - /* QoS (mandatory) */ - if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, - &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* TFT (conditional) */ - if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, - &pdp->tft.v, sizeof(pdp->tft.v))) { - } + if (version == 1) { + /* TEID (mandatory) */ + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* Trigger ID */ - /* OMC identity */ - } + /* TEIC (conditional) */ + if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* Initialize our own IP addresses */ - in_addr2gsna(&pdp->gsnlc, &gsn->gsnc); - in_addr2gsna(&pdp->gsnlu, &gsn->gsnu); - - if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n"); - - if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) { - /* Found old pdp with same tid. Now the voodoo begins! */ - /* 09.60 / 29.060 allows create on existing context to "steal" */ - /* the context which was allready established */ - /* We check that the APN, selection mode and MSISDN is the same */ - if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n"); - if ((pdp->apn_req.l == pdp_old->apn_req.l) - && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l)) - && (pdp->selmode == pdp_old->selmode) - && (pdp->msisdn.l == pdp_old->msisdn.l) - && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) { - /* OK! We are dealing with the same APN. We will copy new - * parameters to the old pdp and send off confirmation - * We ignore the following information elements: - * QoS: MS will get originally negotiated QoS. - * End user address (EUA). MS will get old EUA anyway. - * Protocol configuration option (PCO): Only application can verify */ + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n"); - - /* Copy remote flow label */ - pdp_old->flru = pdp->flru; - pdp_old->flrc = pdp->flrc; + /* Charging Characteriatics (optional) */ + /* Trace reference (optional) */ + /* Trace type (optional) */ + /* Charging Characteriatics (optional) */ - /* Copy remote tei */ - pdp_old->teid_gn = pdp->teid_gn; - pdp_old->teic_gn = pdp->teic_gn; + if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ + /* End User Address (conditional) */ + if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, + &pdp->eua.v, sizeof(pdp->eua.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* Copy peer GSN address */ - pdp_old->gsnrc.l = pdp->gsnrc.l; - memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l); - pdp_old->gsnru.l = pdp->gsnru.l; - memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l); + /* APN */ + if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l, + &pdp->apn_req.v, sizeof(pdp->apn_req.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* Copy request parameters */ - pdp_old->seq = pdp->seq; - pdp_old->sa_peer = pdp->sa_peer; - pdp_old->fd = pdp->fd = fd; - pdp_old->version = pdp->version = version; + /* Extract protocol configuration options (optional) */ + if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, + &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { + } + } - /* Switch to using the old pdp context */ - pdp = pdp_old; - - /* Confirm to peer that things were "successful" */ - return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ); - } - else { /* This is not the same PDP context. Delete the old one. */ + /* SGSN address for signalling (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n"); - - if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old); - pdp_freepdp(pdp_old); - - if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n"); - } - } + /* SGSN address for user traffic (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp); + if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */ + /* MSISDN (conditional) */ + if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l, + &pdp->msisdn.v, sizeof(pdp->msisdn.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* Callback function to validata login */ - if (gsn->cb_create_context_ind !=0) - return gsn->cb_create_context_ind(pdp); - else { - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "No create_context_ind callback defined"); - return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED); - } + if (version == 1) { + /* QoS (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, + &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* TFT (conditional) */ + if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, + &pdp->tft.v, sizeof(pdp->tft.v))) { + } + + /* Trigger ID */ + /* OMC identity */ + } + + /* Initialize our own IP addresses */ + in_addr2gsna(&pdp->gsnlc, &gsn->gsnc); + in_addr2gsna(&pdp->gsnlu, &gsn->gsnu); + + if (GTP_DEBUG) + printf("gtp_create_pdp_ind: Before pdp_tidget\n"); + + if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) { + /* Found old pdp with same tid. Now the voodoo begins! */ + /* 09.60 / 29.060 allows create on existing context to "steal" */ + /* the context which was allready established */ + /* We check that the APN, selection mode and MSISDN is the same */ + if (GTP_DEBUG) + printf("gtp_create_pdp_ind: Old context found\n"); + if ((pdp->apn_req.l == pdp_old->apn_req.l) + && + (!memcmp + (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l)) + && (pdp->selmode == pdp_old->selmode) + && (pdp->msisdn.l == pdp_old->msisdn.l) + && + (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) + { + /* OK! We are dealing with the same APN. We will copy new + * parameters to the old pdp and send off confirmation + * We ignore the following information elements: + * QoS: MS will get originally negotiated QoS. + * End user address (EUA). MS will get old EUA anyway. + * Protocol configuration option (PCO): Only application can verify */ + + if (GTP_DEBUG) + printf + ("gtp_create_pdp_ind: Old context found\n"); + + /* Copy remote flow label */ + pdp_old->flru = pdp->flru; + pdp_old->flrc = pdp->flrc; + + /* Copy remote tei */ + pdp_old->teid_gn = pdp->teid_gn; + pdp_old->teic_gn = pdp->teic_gn; + + /* Copy peer GSN address */ + pdp_old->gsnrc.l = pdp->gsnrc.l; + memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l); + pdp_old->gsnru.l = pdp->gsnru.l; + memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l); + + /* Copy request parameters */ + pdp_old->seq = pdp->seq; + pdp_old->sa_peer = pdp->sa_peer; + pdp_old->fd = pdp->fd = fd; + pdp_old->version = pdp->version = version; + + /* Switch to using the old pdp context */ + pdp = pdp_old; + + /* Confirm to peer that things were "successful" */ + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_ACC_REQ); + } else { /* This is not the same PDP context. Delete the old one. */ + + if (GTP_DEBUG) + printf + ("gtp_create_pdp_ind: Deleting old context\n"); + + if (gsn->cb_delete_context) + gsn->cb_delete_context(pdp_old); + pdp_freepdp(pdp_old); + + if (GTP_DEBUG) + printf("gtp_create_pdp_ind: Deleted...\n"); + } + } + + pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp); + + /* Callback function to validata login */ + if (gsn->cb_create_context_ind != 0) + return gsn->cb_create_context_ind(pdp); + else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "No create_context_ind callback defined"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_NOT_SUPPORTED); + } } - /* Handle Create PDP Context Response */ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len) { - struct pdp_t *pdp; - union gtpie_member *ie[GTPIE_SIZE]; - uint8_t cause, recovery; - void *cbp = NULL; - uint8_t type = 0; - int hlen = get_hlen(pack); + struct sockaddr_in *peer, void *pack, unsigned len) +{ + struct pdp_t *pdp; + union gtpie_member *ie[GTPIE_SIZE]; + uint8_t cause, recovery; + void *cbp = NULL; + uint8_t type = 0; + int hlen = get_hlen(pack); - /* Remove packet from queue */ - if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; - - /* Find the context in question */ - if (pdp_getgtp1(&pdp, get_tei(pack))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; - } + /* Remove packet from queue */ + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) + return EOF; - /* Register that we have received a valid teic from GGSN */ - pdp->teic_confirmed = 1; + /* Find the context in question */ + if (pdp_getgtp1(&pdp, get_tei(pack))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } - /* Decode information elements */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + /* Register that we have received a valid teic from GGSN */ + pdp->teic_confirmed = 1; - /* Extract cause value (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - /* Extract recovery (optional) */ - if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { - if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery); - } + /* Extract cause value (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - /* Extract protocol configuration options (optional) */ - if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, - &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { - } + /* Extract recovery (optional) */ + if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { + if (gsn->cb_recovery) + gsn->cb_recovery(peer, recovery); + } - /* Check all conditional information elements */ - if (GTPCAUSE_ACC_REQ == cause) { + /* Extract protocol configuration options (optional) */ + if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, + &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { + } - if (version == 0) { - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - &pdp->qos_neg0, sizeof(pdp->qos_neg0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - } - - if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + /* Check all conditional information elements */ + if (GTPCAUSE_ACC_REQ == cause) { - if (version == 0) { - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - } + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + &pdp->qos_neg0, + sizeof(pdp->qos_neg0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } - if (version == 1) { - if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - - if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - } - - if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - } - - if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - if (version == 1) { - if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l, - &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - } - - } - - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - return 0; + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } + + if (version == 1) { + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } + + if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + } + + if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, + &pdp->eua.v, sizeof(pdp->eua.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (version == 1) { + if (gtpie_gettlv + (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l, + &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } + + } + + if (gsn->cb_conf) + gsn->cb_conf(type, cause, pdp, cbp); + + return 0; } - /* API: Send Update PDP Context Request */ int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, - struct in_addr* inetaddr) { - union gtp_packet packet; - unsigned int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet); - - if (pdp->version == 0) - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_req0), pdp->qos_req0); - - /* Include IMSI if updating with unknown teic_gn */ - if ((pdp->version == 1) && (!pdp->teic_gn)) - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, - sizeof(pdp->imsi), (uint8_t*) &pdp->imsi); - - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); - - if (pdp->version == 0) { - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - } - - if (pdp->version == 1) { - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, - pdp->teid_own); + struct in_addr *inetaddr) +{ + union gtp_packet packet; + unsigned int length = + get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet); - if (!pdp->teic_confirmed) - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, - pdp->teic_own); - } - - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, - pdp->nsapi); - - /* TODO - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, - pdp->traceref); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, - pdp->tracetype); */ - - /* TODO if ggsn update message - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); - */ - - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); - - if (pdp->version == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, - pdp->qos_req.l, pdp->qos_req.v); - - - if ((pdp->version == 1) && pdp->tft.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, - pdp->tft.l, pdp->tft.v); - - if ((pdp->version == 1) && pdp->triggerid.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, - pdp->triggerid.l, pdp->triggerid.v); - - if ((pdp->version == 1) && pdp->omcid.l) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, - pdp->omcid.l, pdp->omcid.v); - - gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp); + if (pdp->version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_req0), pdp->qos_req0); - return 0; + /* Include IMSI if updating with unknown teic_gn */ + if ((pdp->version == 1) && (!pdp->teic_gn)) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, + sizeof(pdp->imsi), (uint8_t *) & pdp->imsi); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); + + if (pdp->version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc); + } + + if (pdp->version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + + if (!pdp->teic_confirmed) + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); + } + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi); + + /* TODO + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, + pdp->traceref); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, + pdp->tracetype); */ + + /* TODO if ggsn update message + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); + */ + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlc.l, pdp->gsnlc.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlu.l, pdp->gsnlu.v); + + if (pdp->version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_req.l, pdp->qos_req.v); + + if ((pdp->version == 1) && pdp->tft.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, + pdp->tft.l, pdp->tft.v); + + if ((pdp->version == 1) && pdp->triggerid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, + pdp->triggerid.l, pdp->triggerid.v); + + if ((pdp->version == 1) && pdp->omcid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, + pdp->omcid.l, pdp->omcid.v); + + gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp); + + return 0; } - /* Send Update PDP Context Response */ -int gtp_update_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, +int gtp_update_pdp_resp(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len, - struct pdp_t *pdp, uint8_t cause) { - - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet); - - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); - - if (cause == GTPCAUSE_ACC_REQ) { - - if (version == 0) - gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_neg0), pdp->qos_neg0); + struct pdp_t *pdp, uint8_t cause) +{ - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); + union gtp_packet packet; + unsigned int length = + get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet); - if (version == 0) { - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - } + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); - if (version == 1) { - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, - pdp->teid_own); - - if (!pdp->teic_confirmed) - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, - pdp->teic_own); - } - - /* TODO we use teid_own as charging ID address */ - gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, - pdp->teid_own); - - /* If ggsn - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); */ - - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); - - if (version == 1) - gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, - pdp->qos_neg.l, pdp->qos_neg.v); - - /* TODO: Charging gateway address */ - } - - return gtp_resp(version, gsn, pdp, &packet, length, peer, - fd, get_seq(pack), get_tid(pack)); + if (cause == GTPCAUSE_ACC_REQ) { + + if (version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_neg0), pdp->qos_neg0); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); + + if (version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } + + if (version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + + if (!pdp->teic_confirmed) + gtpie_tv4(&packet, &length, GTP_MAX, + GTPIE_TEI_C, pdp->teic_own); + } + + /* TODO we use teid_own as charging ID address */ + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, + pdp->teid_own); + + /* If ggsn + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); */ + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlc.l, pdp->gsnlc.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlu.l, pdp->gsnlu.v); + + if (version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_neg.l, pdp->qos_neg.v); + + /* TODO: Charging gateway address */ + } + + return gtp_resp(version, gsn, pdp, &packet, length, peer, + fd, get_seq(pack), get_tid(pack)); } - /* Handle Update PDP Context Request */ int gtp_update_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, - void *pack, unsigned len) { - struct pdp_t *pdp; - struct pdp_t pdp_backup; - union gtpie_member* ie[GTPIE_SIZE]; - uint8_t recovery; + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) +{ + struct pdp_t *pdp; + struct pdp_t pdp_backup; + union gtpie_member *ie[GTPIE_SIZE]; + uint8_t recovery; - uint16_t seq = get_seq(pack); - int hlen = get_hlen(pack); + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); - uint64_t imsi; - uint8_t nsapi; - - /* Is this a dublicate ? */ - if(!gtp_dublicate(gsn, version, peer, seq)) { - return 0; /* We allready send of response once */ - } - - - /* Decode information elements */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (0 == version) - return EOF; - else - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - NULL, GTPCAUSE_INVALID_MESSAGE); - } + uint64_t imsi; + uint8_t nsapi; - /* Finding PDP: */ - /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */ - /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */ - /* we have to use the tunnel endpoint identifier */ - if (version == 0) { - imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull; - nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60; - - /* Find the context in question */ - if (pdp_getimsi(&pdp, imsi, nsapi)) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - NULL, GTPCAUSE_NON_EXIST); - } - } - else if (version == 1) { - /* NSAPI (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - NULL, GTPCAUSE_MAN_IE_MISSING); - } - - /* IMSI (conditional) */ - if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) { - /* Find the context in question */ - if (pdp_getgtp1(&pdp, get_tei(pack))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - NULL, GTPCAUSE_NON_EXIST); - } - } - else { - /* Find the context in question */ - if (pdp_getimsi(&pdp, imsi, nsapi)) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - NULL, GTPCAUSE_NON_EXIST); - } - } - } - else { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version"); - return EOF; - } - - /* Make a backup copy in case anything is wrong */ - memcpy(&pdp_backup, pdp, sizeof(pdp_backup)); + /* Is this a dublicate ? */ + if (!gtp_dublicate(gsn, version, peer, seq)) { + return 0; /* We allready send of response once */ + } - if (version == 0) { - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_req0, sizeof(pdp->qos_req0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, - pdp, GTPCAUSE_MAN_IE_MISSING); - } - } + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (0 == version) + return EOF; + else + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, + GTPCAUSE_INVALID_MESSAGE); + } - /* Recovery (optional) */ - if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { - if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery); - } + /* Finding PDP: */ + /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */ + /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */ + /* we have to use the tunnel endpoint identifier */ + if (version == 0) { + imsi = + ((union gtp_packet *)pack)->gtp0. + h.tid & 0x0fffffffffffffffull; + nsapi = + (((union gtp_packet *)pack)->gtp0. + h.tid & 0xf000000000000000ull) >> 60; - if (version == 0) { - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } + /* Find the context in question */ + if (pdp_getimsi(&pdp, imsi, nsapi)) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, + GTPCAUSE_NON_EXIST); + } + } else if (version == 1) { + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, + GTPCAUSE_MAN_IE_MISSING); + } + /* IMSI (conditional) */ + if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) { + /* Find the context in question */ + if (pdp_getgtp1(&pdp, get_tei(pack))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, + fd, pack, len, NULL, + GTPCAUSE_NON_EXIST); + } + } else { + /* Find the context in question */ + if (pdp_getimsi(&pdp, imsi, nsapi)) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, + pack, len, "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, + fd, pack, len, NULL, + GTPCAUSE_NON_EXIST); + } + } + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version"); + return EOF; + } - if (version == 1) { - /* TEID (mandatory) */ - if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - /* TEIC (conditional) */ - /* If TEIC is not included it means that we have allready received it */ - /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */ - /* all updated contexts, or only for one of the linked contexts */ - gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn); - - /* NSAPI (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - } - - /* Trace reference (optional) */ - /* Trace type (optional) */ + /* Make a backup copy in case anything is wrong */ + memcpy(&pdp_backup, pdp, sizeof(pdp_backup)); - /* End User Address (conditional) TODO: GGSN Initiated - if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, pdp, - GTPCAUSE_MAN_IE_MISSING); - } */ + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + pdp->qos_req0, sizeof(pdp->qos_req0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } + /* Recovery (optional) */ + if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { + if (gsn->cb_recovery) + gsn->cb_recovery(peer, recovery); + } - /* SGSN address for signalling (mandatory) */ - /* It is weird that this is mandatory when TEIC is conditional */ - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* SGSN address for user traffic (mandatory) */ - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } - - if (version == 1) { - /* QoS (mandatory) */ - if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, - &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); - } + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } - /* TFT (conditional) */ - if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, - &pdp->tft.v, sizeof(pdp->tft.v))) { - } - - /* OMC identity */ - } + if (version == 1) { + /* TEID (mandatory) */ + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* Confirm to peer that things were "successful" */ - return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, - GTPCAUSE_ACC_REQ); + /* TEIC (conditional) */ + /* If TEIC is not included it means that we have allready received it */ + /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */ + /* all updated contexts, or only for one of the linked contexts */ + gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn); + + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } + + /* Trace reference (optional) */ + /* Trace type (optional) */ + + /* End User Address (conditional) TODO: GGSN Initiated + if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, + &pdp->eua.v, sizeof(pdp->eua.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } */ + + /* SGSN address for signalling (mandatory) */ + /* It is weird that this is mandatory when TEIC is conditional */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + pdp, GTPCAUSE_MAN_IE_MISSING); + } + + /* SGSN address for user traffic (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + pdp, GTPCAUSE_MAN_IE_MISSING); + } + + if (version == 1) { + /* QoS (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, + &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, + len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* TFT (conditional) */ + if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, + &pdp->tft.v, sizeof(pdp->tft.v))) { + } + + /* OMC identity */ + } + + /* Confirm to peer that things were "successful" */ + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_ACC_REQ); } - /* Handle Update PDP Context Response */ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len) { - struct pdp_t *pdp; - union gtpie_member *ie[GTPIE_SIZE]; - uint8_t cause, recovery; - void *cbp = NULL; - uint8_t type = 0; - - /* Remove packet from queue */ - if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF; + struct sockaddr_in *peer, void *pack, unsigned len) +{ + struct pdp_t *pdp; + union gtpie_member *ie[GTPIE_SIZE]; + uint8_t cause, recovery; + void *cbp = NULL; + uint8_t type = 0; - /* Find the context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp); - return EOF; - } + /* Remove packet from queue */ + if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) + return EOF; - /* Register that we have received a valid teic from GGSN */ - pdp->teic_confirmed = 1; + /* Find the context in question */ + if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + if (gsn->cb_conf) + gsn->cb_conf(type, cause, NULL, cbp); + return EOF; + } - /* Decode information elements */ - if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } - - /* Extract cause value (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + /* Register that we have received a valid teic from GGSN */ + pdp->teic_confirmed = 1; - /* Extract recovery (optional) */ - if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { - if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery); - } + /* Decode information elements */ + if (gtpie_decaps + (ie, 0, pack + GTP0_HEADER_SIZE, len - GTP0_HEADER_SIZE)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - /* Check all conditional information elements */ - if (GTPCAUSE_ACC_REQ != cause) { - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return 0; - } - else { - /* Check for missing conditionary information elements */ - if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) && - gtpie_exist(ie, GTPIE_REORDER, 0) && - gtpie_exist(ie, GTPIE_FL_DI, 0) && - gtpie_exist(ie, GTPIE_FL_C, 0) && - gtpie_exist(ie, GTPIE_CHARGING_ID, 0) && - gtpie_exist(ie, GTPIE_EUA, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; - } + /* Extract cause value (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - /* Update pdp with new values */ - gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_neg0, sizeof(pdp->qos_neg0)); - gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder); - gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru); - gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc); - gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid); - gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v)); - - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); - return 0; /* Succes */ - } + /* Extract recovery (optional) */ + if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { + if (gsn->cb_recovery) + gsn->cb_recovery(peer, recovery); + } + + /* Check all conditional information elements */ + if (GTPCAUSE_ACC_REQ != cause) { + if (gsn->cb_conf) + gsn->cb_conf(type, cause, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return 0; + } else { + /* Check for missing conditionary information elements */ + if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) && + gtpie_exist(ie, GTPIE_REORDER, 0) && + gtpie_exist(ie, GTPIE_FL_DI, 0) && + gtpie_exist(ie, GTPIE_FL_C, 0) && + gtpie_exist(ie, GTPIE_CHARGING_ID, 0) && + gtpie_exist(ie, GTPIE_EUA, 0) && + gtpie_exist(ie, GTPIE_GSN_ADDR, 0) && + gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, + "Missing conditional information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + /* Update pdp with new values */ + gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + pdp->qos_neg0, sizeof(pdp->qos_neg0)); + gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder); + gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru); + gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc); + gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid); + gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, + &pdp->eua.v, sizeof(pdp->eua.v)); + gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v)); + gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v)); + + if (gsn->cb_conf) + gsn->cb_conf(type, cause, pdp, cbp); + return 0; /* Succes */ + } } - /* API: Send Delete PDP Context Request */ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, - int teardown) { - union gtp_packet packet; - unsigned int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet); - struct in_addr addr; - struct pdp_t *linked_pdp; - struct pdp_t *secondary_pdp; - int n; - int count = 0; + int teardown) +{ + union gtp_packet packet; + unsigned int length = + get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet); + struct in_addr addr; + struct pdp_t *linked_pdp; + struct pdp_t *secondary_pdp; + int n; + int count = 0; - if (gsna2in_addr(&addr, &pdp->gsnrc)) { - gsn->err_address++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed"); - return EOF; - } - - if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context"); - return EOF; - } - - if (!teardown) { - for (n=0; n< PDP_MAXNSAPI; n++) - if (linked_pdp->secondary_tei[n]) count++; - if (count <= 1) { - gtp_err(LOG_ERR, __FILE__, __LINE__, - "Must use teardown for last context"); - return EOF; - } - } - - if (pdp->version == 1) { - if (teardown) - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN, - 0xff); - - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, - pdp->nsapi); - } - - gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp); - - if (teardown) { /* Remove all contexts */ - for (n=0; n< PDP_MAXNSAPI; n++) { - if (linked_pdp->secondary_tei[n]) { - if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context"); - return EOF; + if (gsna2in_addr(&addr, &pdp->gsnrc)) { + gsn->err_address++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "GSN address conversion failed"); + return EOF; } - if (linked_pdp != secondary_pdp) { - if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp); - pdp_freepdp(secondary_pdp); - } - } - } - if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp); - pdp_freepdp(linked_pdp); - } - else { - if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - if (pdp == linked_pdp) { - linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0; - linked_pdp->nodata = 1; - } - else - pdp_freepdp(pdp); - } - return 0; + if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Unknown linked PDP context"); + return EOF; + } + + if (!teardown) { + for (n = 0; n < PDP_MAXNSAPI; n++) + if (linked_pdp->secondary_tei[n]) + count++; + if (count <= 1) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Must use teardown for last context"); + return EOF; + } + } + + if (pdp->version == 1) { + if (teardown) + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN, + 0xff); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi); + } + + gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp); + + if (teardown) { /* Remove all contexts */ + for (n = 0; n < PDP_MAXNSAPI; n++) { + if (linked_pdp->secondary_tei[n]) { + if (pdp_getgtp1 + (&secondary_pdp, + linked_pdp->secondary_tei[n])) { + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Unknown secondary PDP context"); + return EOF; + } + if (linked_pdp != secondary_pdp) { + if (gsn->cb_delete_context) + gsn->cb_delete_context + (secondary_pdp); + pdp_freepdp(secondary_pdp); + } + } + } + if (gsn->cb_delete_context) + gsn->cb_delete_context(linked_pdp); + pdp_freepdp(linked_pdp); + } else { + if (gsn->cb_delete_context) + gsn->cb_delete_context(pdp); + if (pdp == linked_pdp) { + linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0; + linked_pdp->nodata = 1; + } else + pdp_freepdp(pdp); + } + + return 0; } /* Send Delete PDP Context Response */ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, - void *pack, unsigned len, - struct pdp_t *pdp, struct pdp_t *linked_pdp, + void *pack, unsigned len, + struct pdp_t *pdp, struct pdp_t *linked_pdp, uint8_t cause, int teardown) { - union gtp_packet packet; - struct pdp_t *secondary_pdp; - unsigned int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet); - int n; + union gtp_packet packet; + struct pdp_t *secondary_pdp; + unsigned int length = + get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet); + int n; - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); - gtp_resp(version, gsn, pdp, &packet, length, peer, fd, - get_seq(pack), get_tid(pack)); + gtp_resp(version, gsn, pdp, &packet, length, peer, fd, + get_seq(pack), get_tid(pack)); - if (cause == GTPCAUSE_ACC_REQ) { - if ((teardown) || (version == 0)) { /* Remove all contexts */ - for (n=0; n< PDP_MAXNSAPI; n++) { - if (linked_pdp->secondary_tei[n]) { - if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) { - gtp_err(LOG_ERR, __FILE__, __LINE__, - "Unknown secondary PDP context"); - return EOF; - } - if (linked_pdp != secondary_pdp) { - if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp); - pdp_freepdp(secondary_pdp); - } + if (cause == GTPCAUSE_ACC_REQ) { + if ((teardown) || (version == 0)) { /* Remove all contexts */ + for (n = 0; n < PDP_MAXNSAPI; n++) { + if (linked_pdp->secondary_tei[n]) { + if (pdp_getgtp1 + (&secondary_pdp, + linked_pdp->secondary_tei[n])) { + gtp_err(LOG_ERR, __FILE__, + __LINE__, + "Unknown secondary PDP context"); + return EOF; + } + if (linked_pdp != secondary_pdp) { + if (gsn->cb_delete_context) + gsn->cb_delete_context + (secondary_pdp); + pdp_freepdp(secondary_pdp); + } + } + } + if (gsn->cb_delete_context) + gsn->cb_delete_context(linked_pdp); + pdp_freepdp(linked_pdp); + } else { /* Remove only current context */ + if (gsn->cb_delete_context) + gsn->cb_delete_context(pdp); + if (pdp == linked_pdp) { + linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = + 0; + linked_pdp->nodata = 1; + } else + pdp_freepdp(pdp); + } } - } - if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp); - pdp_freepdp(linked_pdp); - } - else { /* Remove only current context */ - if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - if (pdp == linked_pdp) { - linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0; - linked_pdp->nodata = 1; - } - else - pdp_freepdp(pdp); - } - } /* if (cause == GTPCAUSE_ACC_REQ) */ - - return 0; + /* if (cause == GTPCAUSE_ACC_REQ) */ + return 0; } /* Handle Delete PDP Context Request */ int gtp_delete_pdp_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, - void *pack, unsigned len) { - struct pdp_t *pdp = NULL; - struct pdp_t *linked_pdp = NULL; - union gtpie_member* ie[GTPIE_SIZE]; - - uint16_t seq = get_seq(pack); - int hlen = get_hlen(pack); + void *pack, unsigned len) +{ + struct pdp_t *pdp = NULL; + struct pdp_t *linked_pdp = NULL; + union gtpie_member *ie[GTPIE_SIZE]; - uint8_t nsapi; - uint8_t teardown = 0; - int n; - int count = 0; + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); - /* Is this a dublicate ? */ - if(!gtp_dublicate(gsn, version, peer, seq)) { - return 0; /* We allready send off response once */ - } + uint8_t nsapi; + uint8_t teardown = 0; + int n; + int count = 0; - /* Find the linked context in question */ - if (pdp_getgtp1(&linked_pdp, get_tei(pack))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL, - GTPCAUSE_NON_EXIST, teardown); - } + /* Is this a dublicate ? */ + if (!gtp_dublicate(gsn, version, peer, seq)) { + return 0; /* We allready send off response once */ + } - /* If version 0 this is also the secondary context */ - if (version == 0) - pdp = linked_pdp; - - /* Decode information elements */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (0 == version) - return EOF; - else - return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL, - GTPCAUSE_INVALID_MESSAGE, teardown); - } - - if (version == 1) { - /* NSAPI (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL, - GTPCAUSE_MAN_IE_MISSING, teardown); - } - - /* Find the context in question */ - if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL, - GTPCAUSE_NON_EXIST, teardown); - } - - /* Teardown (conditional) */ - gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown); + /* Find the linked context in question */ + if (pdp_getgtp1(&linked_pdp, get_tei(pack))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, NULL, GTPCAUSE_NON_EXIST, + teardown); + } - if (!teardown) { - for (n=0; n< PDP_MAXNSAPI; n++) - if (linked_pdp->secondary_tei[n]) count++; - if (count <= 1) { - return 0; /* 29.060 7.3.5 Ignore message */ - } - } - } + /* If version 0 this is also the secondary context */ + if (version == 0) + pdp = linked_pdp; - return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, - pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown); + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (0 == version) + return EOF; + else + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, NULL, + GTPCAUSE_INVALID_MESSAGE, + teardown); + } + + if (version == 1) { + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Missing mandatory information field"); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, NULL, + GTPCAUSE_MAN_IE_MISSING, + teardown); + } + + /* Find the context in question */ + if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Unknown PDP context"); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, + len, NULL, NULL, + GTPCAUSE_NON_EXIST, + teardown); + } + + /* Teardown (conditional) */ + gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown); + + if (!teardown) { + for (n = 0; n < PDP_MAXNSAPI; n++) + if (linked_pdp->secondary_tei[n]) + count++; + if (count <= 1) { + return 0; /* 29.060 7.3.5 Ignore message */ + } + } + } + + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown); } - /* Handle Delete PDP Context Response */ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len) { - union gtpie_member *ie[GTPIE_SIZE]; - uint8_t cause; - void *cbp = NULL; - uint8_t type = 0; - int hlen = get_hlen(pack); - - /* Remove packet from queue */ - if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; - - /* Decode information elements */ - if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { - gsn->invalid++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; - } + struct sockaddr_in *peer, void *pack, unsigned len) +{ + union gtpie_member *ie[GTPIE_SIZE]; + uint8_t cause; + void *cbp = NULL; + uint8_t type = 0; + int hlen = get_hlen(pack); - /* Extract cause value (mandatory) */ - if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; - } + /* Remove packet from queue */ + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) + return EOF; - /* Check the cause value (again) */ - if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) { - gsn->err_cause++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unexpected cause value received: %d", cause); - if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp); - return EOF; - } - - /* Callback function to notify application */ - if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp); - - return 0; + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Invalid message format"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } + + /* Extract cause value (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } + + /* Check the cause value (again) */ + if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) { + gsn->err_cause++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unexpected cause value received: %d", cause); + if (gsn->cb_conf) + gsn->cb_conf(type, cause, NULL, cbp); + return EOF; + } + + /* Callback function to notify application */ + if (gsn->cb_conf) + gsn->cb_conf(type, cause, NULL, cbp); + + return 0; } /* Send Error Indication (response to a GPDU message */ @@ -2485,90 +2624,91 @@ int gtp_error_ind_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len) { - union gtp_packet packet; - unsigned int length = get_default_gtp(version, GTP_ERROR, &packet); - - return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, - get_seq(pack), get_tid(pack)); + union gtp_packet packet; + unsigned int length = get_default_gtp(version, GTP_ERROR, &packet); + + return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, + get_seq(pack), get_tid(pack)); } /* Handle Error Indication */ int gtp_error_ind_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len) { - struct pdp_t *pdp; - - /* Find the context in question */ - if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return EOF; - } + struct sockaddr_in *peer, void *pack, unsigned len) +{ + struct pdp_t *pdp; - gsn->err_unknownpdp++; /* TODO: Change counter */ - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Received Error Indication"); + /* Find the context in question */ + if (pdp_tidget(&pdp, ((union gtp_packet *)pack)->gtp0.h.tid)) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return EOF; + } - if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); - return 0; + gsn->err_unknownpdp++; /* TODO: Change counter */ + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Received Error Indication"); + + if (gsn->cb_delete_context) + gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); + return 0; } int gtp_gpdu_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, - void *pack, unsigned len) { + struct sockaddr_in *peer, int fd, void *pack, unsigned len) +{ - int hlen = GTP1_HEADER_SIZE_SHORT; + int hlen = GTP1_HEADER_SIZE_SHORT; - /* Need to include code to verify packet src and dest addresses */ - struct pdp_t *pdp; + /* Need to include code to verify packet src and dest addresses */ + struct pdp_t *pdp; - if (version == 0) { - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); - } - hlen = GTP0_HEADER_SIZE; - } - else if (version == 1) { - if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); - } + if (version == 0) { + if (pdp_getgtp0 + (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, + len); + } + hlen = GTP0_HEADER_SIZE; + } else if (version == 1) { + if (pdp_getgtp1 + (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, + len, "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, + len); + } - /* Is this a long or a short header ? */ - if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07) - hlen = GTP1_HEADER_SIZE_LONG; - else - hlen = GTP1_HEADER_SIZE_SHORT; - } - else { - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown version"); - } - - /* If the GPDU was not from the peer GSN tell him to delete context */ - if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */ - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); - } + /* Is this a long or a short header ? */ + if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07) + hlen = GTP1_HEADER_SIZE_LONG; + else + hlen = GTP1_HEADER_SIZE_SHORT; + } else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown version"); + } - /* Callback function */ - if (gsn->cb_data_ind !=0) - return gsn->cb_data_ind(pdp, pack+hlen, len-hlen); + /* If the GPDU was not from the peer GSN tell him to delete context */ + if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */ + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); + } - return 0; + /* Callback function */ + if (gsn->cb_data_ind != 0) + return gsn->cb_data_ind(pdp, pack + hlen, len - hlen); + + return 0; } - - /* Receives GTP packet and sends off for further processing * Function will check the validity of the header. If the header * is not valid the packet is either dropped or a version not @@ -2576,505 +2716,548 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version, * TODO: Need to decide on return values! */ int gtp_decaps0(struct gsn_t *gsn) { - unsigned char buffer[PACKET_MAX]; - struct sockaddr_in peer; - size_t peerlen; - int status; - struct gtp0_header *pheader; - int version = 0; /* GTP version should be determined from header!*/ - int fd = gsn->fd0; + unsigned char buffer[PACKET_MAX]; + struct sockaddr_in peer; + size_t peerlen; + int status; + struct gtp0_header *pheader; + int version = 0; /* GTP version should be determined from header! */ + int fd = gsn->fd0; - /* 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...*/ + /* 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... */ - while (1) { /* Loop until no more to read */ - if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } - peerlen = sizeof(peer); - if ((status = - recvfrom(gsn->fd0, buffer, sizeof(buffer), 0, - (struct sockaddr *) &peer, &peerlen)) < 0 ) { - if (errno == EAGAIN) return 0; - gsn->err_readfrom++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd0, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); - 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"); - continue; - } - - pheader = (struct gtp0_header *) (buffer); - - /* Version should be gtp0 (or earlier) */ - /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */ - /* GTP 0 messages. If other version message is received we reply that we */ - /* only support version 0, implying that this is the only version */ - /* supported on this port */ - if (((pheader->flags & 0xe0) > 0x00)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported GTP version"); - gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */ - continue; - } - - /* Check length of gtp0 packet */ - if (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 */ - } + while (1) { /* Loop until no more to read */ + if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + peerlen = sizeof(peer); + if ((status = + recvfrom(gsn->fd0, buffer, sizeof(buffer), 0, + (struct sockaddr *)&peer, &peerlen)) < 0) { + if (errno == EAGAIN) + return 0; + gsn->err_readfrom++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s", + gsn->fd0, (unsigned long)buffer, sizeof(buffer), + status, status ? strerror(errno) : "No error"); + return -1; + } - /* Check packet length field versus length of packet */ - if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { - gsn->tooshort++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "GTP packet length field does not match actual length"); - continue; /* Silently discard */ - } - - if ((gsn->mode == GTP_MODE_GGSN) && - ((pheader->type == GTP_CREATE_PDP_RSP) || - (pheader->type == GTP_UPDATE_PDP_RSP) || - (pheader->type == GTP_DELETE_PDP_RSP))) { - gsn->unexpect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unexpected GTP Signalling Message"); - continue; /* Silently discard 29.60: 11.1.4 */ - } + /* 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; + } - if ((gsn->mode == GTP_MODE_SGSN) && - ((pheader->type == GTP_CREATE_PDP_REQ) || - (pheader->type == GTP_UPDATE_PDP_REQ) || - (pheader->type == GTP_DELETE_PDP_REQ))) { - gsn->unexpect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unexpected GTP Signalling Message"); - continue; /* Silently discard 29.60: 11.1.4 */ - } + pheader = (struct gtp0_header *)(buffer); - switch (pheader->type) { - case GTP_ECHO_REQ: - gtp_echo_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_ECHO_RSP: - gtp_echo_conf(gsn, version, &peer, buffer, status); - break; - case GTP_NOT_SUPPORTED: - gtp_unsup_ind(gsn, &peer, buffer, status); - break; - case GTP_CREATE_PDP_REQ: - gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_CREATE_PDP_RSP: - gtp_create_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_UPDATE_PDP_REQ: - gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_UPDATE_PDP_RSP: - gtp_update_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_DELETE_PDP_REQ: - gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_DELETE_PDP_RSP: - gtp_delete_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_ERROR: - gtp_error_ind_conf(gsn, version, &peer, buffer, status); - break; - case GTP_GPDU: - gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); - break; - default: - gsn->unknown++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unknown GTP message type received"); - break; - } - } + /* Version should be gtp0 (or earlier) */ + /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */ + /* GTP 0 messages. If other version message is received we reply that we */ + /* only support version 0, implying that this is the only version */ + /* supported on this port */ + if (((pheader->flags & 0xe0) > 0x00)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported GTP version"); + gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */ + continue; + } + + /* Check length of gtp0 packet */ + if (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 */ + } + + /* Check packet length field versus length of packet */ + if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } + + if ((gsn->mode == GTP_MODE_GGSN) && + ((pheader->type == GTP_CREATE_PDP_RSP) || + (pheader->type == GTP_UPDATE_PDP_RSP) || + (pheader->type == GTP_DELETE_PDP_RSP))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + if ((gsn->mode == GTP_MODE_SGSN) && + ((pheader->type == GTP_CREATE_PDP_REQ) || + (pheader->type == GTP_UPDATE_PDP_REQ) || + (pheader->type == GTP_DELETE_PDP_REQ))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + switch (pheader->type) { + case GTP_ECHO_REQ: + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_ECHO_RSP: + gtp_echo_conf(gsn, version, &peer, buffer, status); + break; + case GTP_NOT_SUPPORTED: + gtp_unsup_ind(gsn, &peer, buffer, status); + break; + case GTP_CREATE_PDP_REQ: + gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_CREATE_PDP_RSP: + gtp_create_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_UPDATE_PDP_REQ: + gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_UPDATE_PDP_RSP: + gtp_update_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_DELETE_PDP_REQ: + gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_DELETE_PDP_RSP: + gtp_delete_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_ERROR: + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + case GTP_GPDU: + gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); + break; + default: + gsn->unknown++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unknown GTP message type received"); + break; + } + } } - int gtp_decaps1c(struct gsn_t *gsn) { - unsigned char buffer[PACKET_MAX]; - struct sockaddr_in peer; - size_t peerlen; - int status; - struct gtp1_header_short *pheader; - int version = 1; /* TODO GTP version should be determined from header!*/ - int fd = gsn->fd1c; + unsigned char buffer[PACKET_MAX]; + struct sockaddr_in peer; + size_t peerlen; + int status; + struct gtp1_header_short *pheader; + int version = 1; /* TODO GTP version should be determined from header! */ + int fd = gsn->fd1c; - /* 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...*/ + /* 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... */ - while (1) { /* Loop until no more to read */ - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } - peerlen = sizeof(peer); - if ((status = - recvfrom(fd, buffer, sizeof(buffer), 0, - (struct sockaddr *) &peer, &peerlen)) < 0 ) { - if (errno == EAGAIN) return 0; - gsn->err_readfrom++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); - 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"); - continue; - } - - pheader = (struct gtp1_header_short *) (buffer); - - /* Version must be no larger than GTP 1 */ - if (((pheader->flags & 0xe0) > 0x20)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported GTP version"); - gtp_unsup_req(gsn, version, &peer, fd, buffer, status); - /*29.60: 11.1.1*/ - continue; - } + while (1) { /* Loop until no more to read */ + if (fcntl(fd, F_SETFL, O_NONBLOCK)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + peerlen = sizeof(peer); + if ((status = + recvfrom(fd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&peer, &peerlen)) < 0) { + if (errno == EAGAIN) + return 0; + gsn->err_readfrom++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", + fd, (unsigned long)buffer, sizeof(buffer), + status, status ? strerror(errno) : "No error"); + return -1; + } - /* Version must be at least GTP 1 */ - /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ - /* GTP 1 messages. If GTP 0 message is received we silently discard */ - /* the message */ - if (((pheader->flags & 0xe0) < 0x20)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported GTP version"); - 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; + } - /* Check packet flag field */ - if (((pheader->flags & 0xf7) != 0x32)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported packet flag"); - continue; - } + pheader = (struct gtp1_header_short *)(buffer); - /* Check length of packet */ - if (status < GTP1_HEADER_SIZE_LONG) { - gsn->tooshort++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "GTP packet too short"); - continue; /* Silently discard 29.60: 11.1.2 */ - } + /* Version must be no larger than GTP 1 */ + if (((pheader->flags & 0xe0) > 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported GTP version"); + gtp_unsup_req(gsn, version, &peer, fd, buffer, status); + /*29.60: 11.1.1 */ + continue; + } - /* Check packet length field versus length of packet */ - if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { - gsn->tooshort++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "GTP packet length field does not match actual length"); - continue; /* Silently discard */ - } + /* Version must be at least GTP 1 */ + /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ + /* GTP 1 messages. If GTP 0 message is received we silently discard */ + /* the message */ + if (((pheader->flags & 0xe0) < 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported GTP version"); + continue; + } - /* Check for extension headers */ - /* TODO: We really should cycle through the headers and determine */ - /* if any have the comprehension required flag set */ - if (((pheader->flags & 0x04) != 0x00)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported extension header"); - gtp_extheader_req(gsn, version, &peer, fd, buffer, status); + /* Check packet flag field */ + if (((pheader->flags & 0xf7) != 0x32)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported packet flag"); + continue; + } - continue; - } + /* Check length of packet */ + if (status < GTP1_HEADER_SIZE_LONG) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "GTP packet too short"); + continue; /* Silently discard 29.60: 11.1.2 */ + } - if ((gsn->mode == GTP_MODE_GGSN) && - ((pheader->type == GTP_CREATE_PDP_RSP) || - (pheader->type == GTP_UPDATE_PDP_RSP) || - (pheader->type == GTP_DELETE_PDP_RSP))) { - gsn->unexpect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unexpected GTP Signalling Message"); - continue; /* Silently discard 29.60: 11.1.4 */ - } + /* Check packet length field versus length of packet */ + if (status != + (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } - if ((gsn->mode == GTP_MODE_SGSN) && - ((pheader->type == GTP_CREATE_PDP_REQ) || - (pheader->type == GTP_UPDATE_PDP_REQ) || - (pheader->type == GTP_DELETE_PDP_REQ))) { - gsn->unexpect++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unexpected GTP Signalling Message"); - continue; /* Silently discard 29.60: 11.1.4 */ - } + /* Check for extension headers */ + /* TODO: We really should cycle through the headers and determine */ + /* if any have the comprehension required flag set */ + if (((pheader->flags & 0x04) != 0x00)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported extension header"); + gtp_extheader_req(gsn, version, &peer, fd, buffer, + status); - switch (pheader->type) { - case GTP_ECHO_REQ: - gtp_echo_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_ECHO_RSP: - gtp_echo_conf(gsn, version, &peer, buffer, status); - break; - case GTP_NOT_SUPPORTED: - gtp_unsup_ind(gsn, &peer, buffer, status); - break; - case GTP_SUPP_EXT_HEADER: - gtp_extheader_ind(gsn, &peer, buffer, status); - break; - case GTP_CREATE_PDP_REQ: - gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_CREATE_PDP_RSP: - gtp_create_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_UPDATE_PDP_REQ: - gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_UPDATE_PDP_RSP: - gtp_update_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_DELETE_PDP_REQ: - gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_DELETE_PDP_RSP: - gtp_delete_pdp_conf(gsn, version, &peer, buffer, status); - break; - case GTP_ERROR: - gtp_error_ind_conf(gsn, version, &peer, buffer, status); - break; - default: - gsn->unknown++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unknown GTP message type received"); - break; - } - } + continue; + } + + if ((gsn->mode == GTP_MODE_GGSN) && + ((pheader->type == GTP_CREATE_PDP_RSP) || + (pheader->type == GTP_UPDATE_PDP_RSP) || + (pheader->type == GTP_DELETE_PDP_RSP))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + if ((gsn->mode == GTP_MODE_SGSN) && + ((pheader->type == GTP_CREATE_PDP_REQ) || + (pheader->type == GTP_UPDATE_PDP_REQ) || + (pheader->type == GTP_DELETE_PDP_REQ))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + switch (pheader->type) { + case GTP_ECHO_REQ: + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_ECHO_RSP: + gtp_echo_conf(gsn, version, &peer, buffer, status); + break; + case GTP_NOT_SUPPORTED: + gtp_unsup_ind(gsn, &peer, buffer, status); + break; + case GTP_SUPP_EXT_HEADER: + gtp_extheader_ind(gsn, &peer, buffer, status); + break; + case GTP_CREATE_PDP_REQ: + gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_CREATE_PDP_RSP: + gtp_create_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_UPDATE_PDP_REQ: + gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_UPDATE_PDP_RSP: + gtp_update_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_DELETE_PDP_REQ: + gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, + status); + break; + case GTP_DELETE_PDP_RSP: + gtp_delete_pdp_conf(gsn, version, &peer, buffer, + status); + break; + case GTP_ERROR: + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + default: + gsn->unknown++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unknown GTP message type received"); + break; + } + } } int gtp_decaps1u(struct gsn_t *gsn) { - unsigned char buffer[PACKET_MAX]; - struct sockaddr_in peer; - size_t peerlen; - int status; - struct gtp1_header_short *pheader; - int version = 1; /* GTP version should be determined from header!*/ - int fd = gsn->fd1u; + unsigned char buffer[PACKET_MAX]; + struct sockaddr_in peer; + size_t peerlen; + int status; + struct gtp1_header_short *pheader; + int version = 1; /* GTP version should be determined from header! */ + int fd = gsn->fd1u; - /* 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...*/ + /* 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... */ - while (1) { /* Loop until no more to read */ - if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } - peerlen = sizeof(peer); - if ((status = - recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0, - (struct sockaddr *) &peer, &peerlen)) < 0 ) { - if (errno == EAGAIN) return 0; - gsn->err_readfrom++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd1u, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); - 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"); - continue; - } - - pheader = (struct gtp1_header_short *) (buffer); - - /* Version must be no larger than GTP 1 */ - if (((pheader->flags & 0xe0) > 0x20)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported GTP version"); - gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/ - continue; - } + while (1) { /* Loop until no more to read */ + if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + peerlen = sizeof(peer); + if ((status = + recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0, + (struct sockaddr *)&peer, &peerlen)) < 0) { + if (errno == EAGAIN) + return 0; + gsn->err_readfrom++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s", + gsn->fd1u, (unsigned long)buffer, + sizeof(buffer), status, + status ? strerror(errno) : "No error"); + return -1; + } - /* Version must be at least GTP 1 */ - /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ - /* GTP 1 messages. If GTP 0 message is received we silently discard */ - /* the message */ - if (((pheader->flags & 0xe0) < 0x20)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported GTP version"); - 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; + } - /* Check packet flag field (allow both with and without sequence number)*/ - if (((pheader->flags & 0xf5) != 0x30)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported packet flag"); - continue; - } + pheader = (struct gtp1_header_short *)(buffer); - /* Check length of packet */ - if (status < GTP1_HEADER_SIZE_SHORT) { - gsn->tooshort++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "GTP packet too short"); - continue; /* Silently discard 29.60: 11.1.2 */ - } + /* Version must be no larger than GTP 1 */ + if (((pheader->flags & 0xe0) > 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported GTP version"); + gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */ + continue; + } - /* Check packet length field versus length of packet */ - if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { - gsn->tooshort++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "GTP packet length field does not match actual length"); - continue; /* Silently discard */ - } + /* Version must be at least GTP 1 */ + /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ + /* GTP 1 messages. If GTP 0 message is received we silently discard */ + /* the message */ + if (((pheader->flags & 0xe0) < 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported GTP version"); + continue; + } - /* Check for extension headers */ - /* TODO: We really should cycle through the headers and determine */ - /* if any have the comprehension required flag set */ - if (((pheader->flags & 0x04) != 0x00)) { - gsn->unsup++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unsupported extension header"); - gtp_extheader_req(gsn, version, &peer, fd, buffer, status); + /* Check packet flag field (allow both with and without sequence number) */ + if (((pheader->flags & 0xf5) != 0x30)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported packet flag"); + continue; + } - continue; - } - - switch (pheader->type) { - case GTP_ECHO_REQ: - gtp_echo_ind(gsn, version, &peer, fd, buffer, status); - break; - case GTP_ECHO_RSP: - gtp_echo_conf(gsn, version, &peer, buffer, status); - break; - case GTP_SUPP_EXT_HEADER: - gtp_extheader_ind(gsn, &peer, buffer, status); - break; - case GTP_ERROR: - gtp_error_ind_conf(gsn, version, &peer, buffer, status); - break; - /* Supported header extensions */ - case GTP_GPDU: - gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); - break; - default: - gsn->unknown++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Unknown GTP message type received"); - break; - } - } + /* Check length of packet */ + if (status < GTP1_HEADER_SIZE_SHORT) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "GTP packet too short"); + continue; /* Silently discard 29.60: 11.1.2 */ + } + + /* Check packet length field versus length of packet */ + if (status != + (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } + + /* Check for extension headers */ + /* TODO: We really should cycle through the headers and determine */ + /* if any have the comprehension required flag set */ + if (((pheader->flags & 0x04) != 0x00)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, "Unsupported extension header"); + gtp_extheader_req(gsn, version, &peer, fd, buffer, + status); + + continue; + } + + switch (pheader->type) { + case GTP_ECHO_REQ: + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_ECHO_RSP: + gtp_echo_conf(gsn, version, &peer, buffer, status); + break; + case GTP_SUPP_EXT_HEADER: + gtp_extheader_ind(gsn, &peer, buffer, status); + break; + case GTP_ERROR: + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + /* Supported header extensions */ + case GTP_GPDU: + gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); + break; + default: + gsn->unknown++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, + status, + "Unknown GTP message type received"); + break; + } + } } -int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp, - void *pack, unsigned len) +int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len) { - union gtp_packet packet; - struct sockaddr_in addr; - int fd; - int length; + union gtp_packet packet; + struct sockaddr_in addr; + int fd; + int length; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr.sin_len = sizeof(addr); #endif - memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */ + memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */ - if (pdp->version == 0) { - - length = GTP0_HEADER_SIZE+len; - addr.sin_port = htons(GTP0_PORT); - fd = gsn->fd0; - - get_default_gtp(0, GTP_GPDU, &packet); - packet.gtp0.h.length = hton16(len); - packet.gtp0.h.seq = hton16(pdp->gtpsntx++); - packet.gtp0.h.flow = hton16(pdp->flru); - packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + ((uint64_t)pdp->nsapi << 60); + if (pdp->version == 0) { - if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) { - gsn->err_memcpy++; - gtp_err(LOG_ERR, __FILE__, __LINE__, - "Memcpy failed: %d > %d", len, - sizeof (union gtp_packet) - sizeof(struct gtp0_header)); - return EOF; - } - memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */ - } - else if (pdp->version == 1) { - - length = GTP1_HEADER_SIZE_LONG+len; - addr.sin_port = htons(GTP1U_PORT); - fd = gsn->fd1u; + length = GTP0_HEADER_SIZE + len; + addr.sin_port = htons(GTP0_PORT); + fd = gsn->fd0; - get_default_gtp(1, GTP_GPDU, &packet); - packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+ - GTP1_HEADER_SIZE_LONG); - packet.gtp1l.h.seq = hton16(pdp->gtpsntx++); - packet.gtp1l.h.tei = hton32(pdp->teid_gn); + get_default_gtp(0, GTP_GPDU, &packet); + packet.gtp0.h.length = hton16(len); + packet.gtp0.h.seq = hton16(pdp->gtpsntx++); + packet.gtp0.h.flow = hton16(pdp->flru); + packet.gtp0.h.tid = + (pdp->imsi & 0x0fffffffffffffffull) + + ((uint64_t) pdp->nsapi << 60); - if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) { - gsn->err_memcpy++; - gtp_err(LOG_ERR, __FILE__, __LINE__, - "Memcpy failed: %d > %d", len, - sizeof (union gtp_packet) - sizeof(struct gtp0_header)); - return EOF; - } - memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */ - } - else { - gtp_err(LOG_ERR, __FILE__, __LINE__, - "Unknown version"); - return EOF; - } + if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) { + gsn->err_memcpy++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Memcpy failed: %d > %d", len, + sizeof(union gtp_packet) - + sizeof(struct gtp0_header)); + return EOF; + } + memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */ + } else if (pdp->version == 1) { - if (fcntl(fd, F_SETFL, 0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } + length = GTP1_HEADER_SIZE_LONG + len; + addr.sin_port = htons(GTP1U_PORT); + fd = gsn->fd1u; - if (sendto(fd, &packet, length, 0, - (struct sockaddr *) &addr, sizeof(addr)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, GTP0_HEADER_SIZE+len, strerror(errno)); - return EOF; - } - return 0; + get_default_gtp(1, GTP_GPDU, &packet); + packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT + + GTP1_HEADER_SIZE_LONG); + packet.gtp1l.h.seq = hton16(pdp->gtpsntx++); + packet.gtp1l.h.tei = hton32(pdp->teid_gn); + + if (len > + sizeof(union gtp_packet) - + sizeof(struct gtp1_header_long)) { + gsn->err_memcpy++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Memcpy failed: %d > %d", len, + sizeof(union gtp_packet) - + sizeof(struct gtp0_header)); + return EOF; + } + memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */ + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version"); + return EOF; + } + + if (fcntl(fd, F_SETFL, 0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + + if (sendto(fd, &packet, length, 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, + (unsigned long)&packet, GTP0_HEADER_SIZE + len, + strerror(errno)); + return EOF; + } + return 0; } - /* *********************************************************** * Conversion functions *************************************************************/ -int char2ul_t(char* src, struct ul_t dst) { - dst.l = strlen(src)+1; - dst.v = malloc(dst.l); - dst.v[0] = dst.l - 1; - memcpy(&dst.v[1], src, dst.v[0]); - return 0; +int char2ul_t(char *src, struct ul_t dst) +{ + dst.l = strlen(src) + 1; + dst.v = malloc(dst.l); + dst.v[0] = dst.l - 1; + memcpy(&dst.v[1], src, dst.v[0]); + return 0; } /* *********************************************************** @@ -3090,40 +3273,40 @@ int char2ul_t(char* src, struct ul_t dst) { * port number. *************************************************************/ -int ipv42eua(struct ul66_t *eua, struct in_addr *src) { - eua->v[0] = 0xf1; /* IETF */ - eua->v[1] = 0x21; /* IPv4 */ - if (src) { - eua->l = 6; - memcpy(&eua->v[2], src, 4); - } - else - { - eua->l = 2; - } - return 0; +int ipv42eua(struct ul66_t *eua, struct in_addr *src) +{ + eua->v[0] = 0xf1; /* IETF */ + eua->v[1] = 0x21; /* IPv4 */ + if (src) { + eua->l = 6; + memcpy(&eua->v[2], src, 4); + } else { + eua->l = 2; + } + return 0; } -int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) { - if ((eua->l != 6) || - (eua->v[0] != 0xf1) || - (eua->v[1] = 0x21)) - return -1; /* Not IPv4 address*/ - memcpy(dst, &eua->v[2], 4); - return 0; +int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) +{ + if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] = 0x21)) + return -1; /* Not IPv4 address */ + memcpy(dst, &eua->v[2], 4); + return 0; } -int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) { - memset(dst, 0, sizeof(struct in_addr)); - if (gsna->l != 4) return EOF; /* Return if not IPv4 */ - memcpy(dst, gsna->v, gsna->l); - return 0; +int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) +{ + memset(dst, 0, sizeof(struct in_addr)); + if (gsna->l != 4) + return EOF; /* Return if not IPv4 */ + memcpy(dst, gsna->v, gsna->l); + return 0; } -int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) { - memset(gsna, 0, sizeof(struct ul16_t)); - gsna->l = 4; - memcpy(gsna->v, src, gsna->l); - return 0; +int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) +{ + memset(gsna, 0, sizeof(struct ul16_t)); + gsna->l = 4; + memcpy(gsna->v, src, gsna->l); + return 0; } - diff --git a/gtp/gtp.h b/gtp/gtp.h index fb4cc3d..7417f08 100644 --- a/gtp/gtp.h +++ b/gtp/gtp.h @@ -12,7 +12,7 @@ #ifndef _GTP_H #define _GTP_H -#define GTP_DEBUG 0 /* Print debug information */ +#define GTP_DEBUG 0 /* Print debug information */ #define GTP_MODE_GGSN 1 #define GTP_MODE_SGSN 2 @@ -22,7 +22,7 @@ #define GTP1U_PORT 2152 #define PACKET_MAX 8196 -#define GTP_MAX 0xffff /* TODO: Choose right number */ +#define GTP_MAX 0xffff /* TODO: Choose right number */ #define GTP0_HEADER_SIZE 20 #define GTP1_HEADER_SIZE_SHORT 8 #define GTP1_HEADER_SIZE_LONG 12 @@ -34,107 +34,104 @@ #define NAMESIZE 1024 /* GTP version 1 extension header type definitions. */ -#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */ +#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */ /* GTP version 1 message type definitions. Also covers version 0 except * * for anonymous PDP context which was superceded in version 1 */ /* 0 For future use. */ -#define GTP_ECHO_REQ 1 /* Echo Request */ -#define GTP_ECHO_RSP 2 /* Echo Response */ -#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */ -#define GTP_ALIVE_REQ 4 /* Node Alive Request */ -#define GTP_ALIVE_RSP 5 /* Node Alive Response */ -#define GTP_REDIR_REQ 6 /* Redirection Request */ -#define GTP_REDIR_RSP 7 /* Redirection Response */ +#define GTP_ECHO_REQ 1 /* Echo Request */ +#define GTP_ECHO_RSP 2 /* Echo Response */ +#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */ +#define GTP_ALIVE_REQ 4 /* Node Alive Request */ +#define GTP_ALIVE_RSP 5 /* Node Alive Response */ +#define GTP_REDIR_REQ 6 /* Redirection Request */ +#define GTP_REDIR_RSP 7 /* Redirection Response */ /* 8-15 For future use. */ -#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */ -#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */ -#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */ -#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */ -#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */ -#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */ -/* 22-25 For future use. */ /* In version GTP 1 anonomous PDP context */ -#define GTP_ERROR 26 /* Error Indication */ -#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */ -#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */ -#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */ -#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */ -#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */ -#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */ -#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */ -#define GTP_FAILURE_REQ 34 /* Failure Report Request */ -#define GTP_FAILURE_RSP 35 /* Failure Report Response */ -#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */ -#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */ -/* 38-47 For future use. */ -#define GTP_IDEN_REQ 48 /* Identification Request */ -#define GTP_IDEN_RSP 49 /* Identification Response */ -#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */ -#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */ -#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */ -#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */ -#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */ -#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */ -#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */ -#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */ -#define GTP_FWD_SRNS 58 /* Forward SRNS Context */ -#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */ -#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */ +#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */ +#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */ +#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */ +#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */ +#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */ +#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */ + /* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */ +#define GTP_ERROR 26 /* Error Indication */ +#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */ +#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */ +#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */ +#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */ +#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */ +#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */ +#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */ +#define GTP_FAILURE_REQ 34 /* Failure Report Request */ +#define GTP_FAILURE_RSP 35 /* Failure Report Response */ +#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */ +#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */ +/* 38-47 For future use. */ +#define GTP_IDEN_REQ 48 /* Identification Request */ +#define GTP_IDEN_RSP 49 /* Identification Response */ +#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */ +#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */ +#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */ +#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */ +#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */ +#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */ +#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */ +#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */ +#define GTP_FWD_SRNS 58 /* Forward SRNS Context */ +#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */ +#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */ /* 61-239 For future use. */ -#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */ -#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */ +#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */ +#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */ /* 242-254 For future use. */ -#define GTP_GPDU 255 /* G-PDU */ - +#define GTP_GPDU 255 /* G-PDU */ /* GTP information element cause codes from 29.060 v3.9.0 7.7 */ /* */ -#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ -#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ -#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ -#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ -#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ -#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ -#define GTPCAUSE_006 6 /* For future use 6-48 */ -#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ -#define GTPCAUSE_064 64 /* For future use 64-127 */ -#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ -#define GTPCAUSE_129 129 /* For future use 129-176 */ -#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ -#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ -#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ -#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ -#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ -#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ -#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ -#define GTPCAUSE_198 198 /* For future use */ -#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ -#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ -#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ -#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ -#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ -#define GTPCAUSE_SYS_FAIL 204 /* System failure */ -#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ -#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ -#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ -#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ -#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ -#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ -#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ -#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ -#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ -#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ -#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ -#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ -#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ -#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ -#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN*/ -#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ -#define GTPCAUSE_221 221 /* For Future Use 221-240 */ -#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ - - +#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ +#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ +#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ +#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ +#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ +#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ +#define GTPCAUSE_006 6 /* For future use 6-48 */ +#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ +#define GTPCAUSE_064 64 /* For future use 64-127 */ +#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ +#define GTPCAUSE_129 129 /* For future use 129-176 */ +#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ +#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ +#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ +#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ +#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ +#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ +#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ +#define GTPCAUSE_198 198 /* For future use */ +#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ +#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ +#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ +#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ +#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ +#define GTPCAUSE_SYS_FAIL 204 /* System failure */ +#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ +#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ +#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ +#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ +#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ +#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ +#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ +#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ +#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ +#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ +#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ +#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ +#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ +#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ +#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN */ +#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ +#define GTPCAUSE_221 221 /* For Future Use 221-240 */ +#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ /* GTP 0 header. * Explanation to some of the fields: @@ -147,75 +144,72 @@ * Tunnel ID is IMSI+NSAPI. Unique identifier of PDP context. Is somewhat * redundant because the header also includes flow. */ -struct gtp0_header { /* Descriptions from 3GPP 09.60 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 000..... Version: 1 (0) */ - /* ...1111. Spare (7) */ - /* .......0 SNDCP N-PDU Number flag (0) */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of G-PDU excluding header) */ - uint16_t seq; /* 05 Sequence Number */ - uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */ - uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ - uint8_t spare1; /* 10 Spare */ - uint8_t spare2; /* 11 Spare */ - uint8_t spare3; /* 12 Spare */ - uint64_t tid; /* 13 Tunnel ID */ -}; /* 20 */ +struct gtp0_header { /* Descriptions from 3GPP 09.60 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 000..... Version: 1 (0) */ + /* ...1111. Spare (7) */ + /* .......0 SNDCP N-PDU Number flag (0) */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of G-PDU excluding header) */ + uint16_t seq; /* 05 Sequence Number */ + uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */ + uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ + uint8_t spare1; /* 10 Spare */ + uint8_t spare2; /* 11 Spare */ + uint8_t spare3; /* 12 Spare */ + uint64_t tid; /* 13 Tunnel ID */ +}; /* 20 */ -struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 001..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....0... Spare = 0 */ - /* .....0.. Extension header flag: 0 */ - /* ......0. Sequence number flag: 0 */ - /* .......0 PN: N-PDU Number flag */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of IP packet or signalling) */ - uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */ +struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......0. Sequence number flag: 0 */ + /* .......0 PN: N-PDU Number flag */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of IP packet or signalling) */ + uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */ }; -struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 001..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....0... Spare = 0 */ - /* .....0.. Extension header flag: 0 */ - /* ......1. Sequence number flag: 1 */ - /* .......0 PN: N-PDU Number flag */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of IP packet or signalling) */ - uint32_t tei; /* 05 Tunnel Endpoint ID */ - uint16_t seq; /* 10 Sequence Number */ - uint8_t npdu; /* 11 N-PDU Number */ - uint8_t next; /* 12 Next extension header type. Empty = 0 */ +struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......1. Sequence number flag: 1 */ + /* .......0 PN: N-PDU Number flag */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of IP packet or signalling) */ + uint32_t tei; /* 05 Tunnel Endpoint ID */ + uint16_t seq; /* 10 Sequence Number */ + uint8_t npdu; /* 11 N-PDU Number */ + uint8_t next; /* 12 Next extension header type. Empty = 0 */ }; struct gtp0_packet { - struct gtp0_header h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp0_header h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); struct gtp1_packet_short { - struct gtp1_header_short h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp1_header_short h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); struct gtp1_packet_long { - struct gtp1_header_long h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp1_header_long h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); union gtp_packet { - uint8_t flags; - struct gtp0_packet gtp0; - struct gtp1_packet_short gtp1s; - struct gtp1_packet_long gtp1l; -} __attribute__((packed)); - - - + uint8_t flags; + struct gtp0_packet gtp0; + struct gtp1_packet_short gtp1s; + struct gtp1_packet_long gtp1l; +} __attribute__ ((packed)); /* *********************************************************** * Information storage for each gsn instance @@ -233,64 +227,63 @@ union gtp_packet { *************************************************************/ struct gsn_t { - /* Parameters related to the network interface */ + /* Parameters related to the network interface */ - int fd0; /* GTP0 file descriptor */ - int fd1c; /* GTP1 control plane file descriptor */ - int fd1u; /* GTP0 user plane file descriptor */ - int mode; /* Mode of operation: GGSN or SGSN */ - struct in_addr gsnc; /* IP address of this gsn for signalling */ - struct in_addr gsnu; /* IP address of this gsn for user traffic */ + int fd0; /* GTP0 file descriptor */ + int fd1c; /* GTP1 control plane file descriptor */ + int fd1u; /* GTP0 user plane file descriptor */ + int mode; /* Mode of operation: GGSN or SGSN */ + struct in_addr gsnc; /* IP address of this gsn for signalling */ + struct in_addr gsnu; /* IP address of this gsn for user traffic */ - /* Parameters related to signalling messages */ - uint16_t seq_next; /* Next sequence number to use */ - int seq_first; /* First packet in queue (oldest timeout) */ - int seq_last; /* Last packet in queue (youngest timeout) */ + /* Parameters related to signalling messages */ + uint16_t seq_next; /* Next sequence number to use */ + int seq_first; /* First packet in queue (oldest timeout) */ + int seq_last; /* Last packet in queue (youngest timeout) */ - unsigned char restart_counter; /* Increment on restart. Stored on disk */ - char *statedir; /* Disk location for permanent storage */ + unsigned char restart_counter; /* Increment on restart. Stored on disk */ + char *statedir; /* Disk location for permanent storage */ - struct queue_t *queue_req; /* Request queue */ - struct queue_t *queue_resp; /* Response queue */ + struct queue_t *queue_req; /* Request queue */ + struct queue_t *queue_resp; /* Response queue */ - /* Call back functions */ - int (*cb_delete_context) (struct pdp_t*); - int (*cb_create_context_ind) (struct pdp_t*); - int (*cb_unsup_ind) (struct sockaddr_in *peer); - int (*cb_extheader_ind) (struct sockaddr_in *peer); - int (*cb_conf) (int type, int cause, struct pdp_t *pdp, void* cbp); - int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len); - int (*cb_recovery) (struct sockaddr_in *peer, uint8_t recovery); + /* Call back functions */ + int (*cb_delete_context) (struct pdp_t *); + int (*cb_create_context_ind) (struct pdp_t *); + int (*cb_unsup_ind) (struct sockaddr_in * peer); + int (*cb_extheader_ind) (struct sockaddr_in * peer); + int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp); + int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len); + int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery); - /* Counters */ - - uint64_t err_socket; /* Number of socket errors */ - uint64_t err_readfrom; /* Number of readfrom errors */ - uint64_t err_sendto; /* Number of sendto errors */ - uint64_t err_memcpy; /* Number of memcpy */ - uint64_t err_queuefull; /* Number of times queue was full */ - uint64_t err_seq; /* Number of seq out of range */ - uint64_t err_address; /* GSN address conversion failed */ - uint64_t err_unknownpdp; /* GSN address conversion failed */ - uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */ - uint64_t err_cause; /* Unexpected cause value received */ - uint64_t err_outofpdp; /* Out of storage for PDP contexts */ + /* Counters */ - uint64_t empty; /* Number of empty packets */ - uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */ - uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */ - uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */ - uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */ - uint64_t dublicate; /* Number of dublicate or unsolicited replies */ - uint64_t missing; /* Number of missing information field messages */ - uint64_t incorrect; /* Number of incorrect information field messages */ - uint64_t invalid; /* Number of invalid message format messages */ + uint64_t err_socket; /* Number of socket errors */ + uint64_t err_readfrom; /* Number of readfrom errors */ + uint64_t err_sendto; /* Number of sendto errors */ + uint64_t err_memcpy; /* Number of memcpy */ + uint64_t err_queuefull; /* Number of times queue was full */ + uint64_t err_seq; /* Number of seq out of range */ + uint64_t err_address; /* GSN address conversion failed */ + uint64_t err_unknownpdp; /* GSN address conversion failed */ + uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */ + uint64_t err_cause; /* Unexpected cause value received */ + uint64_t err_outofpdp; /* Out of storage for PDP contexts */ + + uint64_t empty; /* Number of empty packets */ + uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */ + uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */ + uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */ + uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */ + uint64_t dublicate; /* Number of dublicate or unsolicited replies */ + uint64_t missing; /* Number of missing information field messages */ + uint64_t incorrect; /* Number of incorrect information field messages */ + uint64_t invalid; /* Number of invalid message format messages */ }; - /* External API functions */ -extern const char* gtp_version(); +extern const char *gtp_version(); extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, int mode); @@ -300,27 +293,29 @@ extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp); -extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp); extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn, - int (*cb_create_context_ind) (struct pdp_t* pdp)); + int (*cb_create_context_ind) (struct + pdp_t * + pdp)); -extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause); -extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, - void *cbp, struct in_addr* inetaddr); +extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, struct in_addr *inetaddr); -extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, int teardown); extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len); extern int gtp_set_cb_data_ind(struct gsn_t *gsn, - int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len)); - + int (*cb_data_ind) (struct pdp_t * pdp, + void *pack, unsigned len)); extern int gtp_fd(struct gsn_t *gsn); extern int gtp_decaps0(struct gsn_t *gsn); @@ -329,45 +324,46 @@ extern int gtp_decaps1u(struct gsn_t *gsn); extern int gtp_retrans(struct gsn_t *gsn); extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout); -extern int gtp_set_cb_delete_context(struct gsn_t *gsn, - int (*cb_delete_context) (struct pdp_t* pdp)); +extern int gtp_set_cb_delete_context(struct gsn_t *gsn, + int (*cb_delete_context) (struct pdp_t * + pdp)); /*extern int gtp_set_cb_create_context(struct gsn_t *gsn, int (*cb_create_context) (struct pdp_t* pdp)); */ extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)); + int (*cb) (struct sockaddr_in * peer)); extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)); - + int (*cb) (struct sockaddr_in * peer)); extern int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, struct pdp_t* pdp, void *cbp)); + int (*cb) (int type, int cause, struct pdp_t * pdp, + void *cbp)); int gtp_set_cb_recovery(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer, uint8_t recovery)); + int (*cb) (struct sockaddr_in * peer, + uint8_t recovery)); /* Internal functions (not part of the API */ extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, struct in_addr *inetaddrs); -extern int gtp_echo_resp(struct gsn_t *gsn, int version, +extern int gtp_echo_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, +extern int gtp_echo_ind(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len); +extern int gtp_echo_conf(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_unsup_req(struct gsn_t *gsn, int version, +extern int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len); extern int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, +extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, uint8_t cause); extern int gtp_create_pdp_ind(struct gsn_t *gsn, int version, @@ -379,14 +375,14 @@ extern int gtp_create_pdp_conf(struct gsn_t *gsn, int version, void *pack, unsigned len); extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *cbp, - struct in_addr* inetaddr, struct pdp_t *pdp); + struct in_addr *inetaddr, struct pdp_t *pdp); extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *cbp, struct pdp_t *pdp); extern int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, - void *pack, unsigned len, + void *pack, unsigned len, struct pdp_t *pdp, struct pdp_t *linked_pdp, uint8_t cause, int teardown); @@ -398,10 +394,9 @@ extern int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len); - extern int ipv42eua(struct ul66_t *eua, struct in_addr *src); extern int eua2ipv4(struct in_addr *dst, struct ul66_t *eua); extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna); extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src); -#endif /* !_GTP_H */ +#endif /* !_GTP_H */ diff --git a/gtp/gtpie.c b/gtp/gtpie.c index 39561d2..232183e 100644 --- a/gtp/gtpie.c +++ b/gtp/gtpie.c @@ -39,523 +39,592 @@ #include "gtpie.h" -int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v) { - if ((*length + 3 + l) >= size) return 1; - ((union gtpie_member*) (p + *length))->tlv.t = hton8(t); - ((union gtpie_member*) (p + *length))->tlv.l = hton16(l); - memcpy((void*) (p + *length +3), v, l); - *length += 3 + l; - return 0; +int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, + int l, void *v) +{ + if ((*length + 3 + l) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tlv.t = hton8(t); + ((union gtpie_member *)(p + *length))->tlv.l = hton16(l); + memcpy((void *)(p + *length + 3), v, l); + *length += 3 + l; + return 0; } -int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, uint8_t *v) { - if ((*length + 1 + l) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv0.t = hton8(t); - memcpy((void*) (p + *length +1), v, l); - *length += 1 + l; - return 0; +int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, + int l, uint8_t * v) +{ + if ((*length + 1 + l) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv0.t = hton8(t); + memcpy((void *)(p + *length + 1), v, l); + *length += 1 + l; + return 0; } -int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v) { - if ((*length + 2) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv1.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv1.v = hton8(v); - *length += 2; - return 0; +int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint8_t v) +{ + if ((*length + 2) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv1.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv1.v = hton8(v); + *length += 2; + return 0; } -int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v) { - if ((*length + 3) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv2.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv2.v = hton16(v); - *length += 3; - return 0; +int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint16_t v) +{ + if ((*length + 3) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv2.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv2.v = hton16(v); + *length += 3; + return 0; } -int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v) { - if ((*length + 5) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv4.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv4.v = hton32(v); - *length += 5; - return 0; +int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint32_t v) +{ + if ((*length + 5) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv4.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv4.v = hton32(v); + *length += 5; + return 0; } -int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v) { - if ((*length + 9) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv8.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv8.v = hton64(v); - *length += 9; - return 0; +int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint64_t v) +{ + if ((*length + 9) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv8.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv8.v = hton64(v); + *length += 9; + return 0; } -int gtpie_getie(union gtpie_member* ie[], int type, int instance) { - int j; - for (j=0; j< GTPIE_SIZE; j++) { - if ((ie[j] != 0) && (ie[j]->t == type)) { - if (instance-- == 0) return j; - } - } - return -1; -} - -int gtpie_exist(union gtpie_member* ie[], int type, int instance) { - int j; - for (j=0; j< GTPIE_SIZE; j++) { - if ((ie[j] != 0) && (ie[j]->t == type)) { - if (instance-- == 0) return 1; - } - } - return 0; -} - -int gtpie_gettlv(union gtpie_member* ie[], int type, int instance, - unsigned int *length, void *dst, unsigned int size){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) { - *length = ntoh16(ie[ien]->tlv.l); - if (*length <= size) - memcpy(dst, ie[ien]->tlv.v, *length); - else - return EOF; - } - return 0; -} - -int gtpie_gettv0(union gtpie_member* ie[], int type, int instance, - void *dst, unsigned int size){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - memcpy(dst, ie[ien]->tv0.v, size); - else - return EOF; - return 0; -} - -int gtpie_gettv1(union gtpie_member* ie[], int type, int instance, - uint8_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh8(ie[ien]->tv1.v); - else - return EOF; - return 0; -} - -int gtpie_gettv2(union gtpie_member* ie[], int type, int instance, - uint16_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh16(ie[ien]->tv2.v); - else - return EOF; - return 0; -} - -int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, - uint32_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh32(ie[ien]->tv4.v); - else - return EOF; - return 0; -} - -int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, - uint64_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh64(ie[ien]->tv8.v); - else - return EOF; - return 0; -} - -int gtpie_decaps(union gtpie_member* ie[], int version, void *pack, unsigned len) { - int i; - int j = 0; - unsigned char *p; - unsigned char *end; - - end = (unsigned char*) pack + len; - p = pack; - - memset(ie, 0, sizeof(union gtpie_member *) * GTPIE_SIZE); - - while ((ptv1.t, ie[j]->tv1.v); - p+= 1 + 1; - j++; - } - break; - case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */ - case GTPIE_FL_C: - if (version != 0) { - if (jtv4.t, ie[j]->tv4.v); - p+= 1 + 4; - j++; +int gtpie_getie(union gtpie_member *ie[], int type, int instance) +{ + int j; + for (j = 0; j < GTPIE_SIZE; j++) { + if ((ie[j] != 0) && (ie[j]->t == type)) { + if (instance-- == 0) + return j; + } } - break; - } - case GTPIE_PFI: /* TV GTPIE types with value length 2 */ - case GTPIE_CHARGING_C: - case GTPIE_TRACE_REF: - case GTPIE_TRACE_TYPE: - if (jtv2.t, ie[j]->tv2.v); - p+= 1 + 2; - j++; - } - break; - case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ - case GTPIE_P_TMSI_S: - if (jtv0.t, ie[j]->tv0.v[0], - ie[j]->tv0.v[1], ie[j]->tv0.v[2]); - p+= 1 + 3; - j++; - } - break; - case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ - case GTPIE_P_TMSI: - case GTPIE_CHARGING_ID: - /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */ - /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */ - if (jtv4.t, ie[j]->tv4.v); - p+= 1 + 4; - j++; - } - break; - case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ - if (jtv0.t); - p+= 1 + 5; - j++; - } - break; - case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ - if (jtv0.t); - p+= 1 + 7; - j++; - } - break; - case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ - if (jtv0.t, ie[j]->tv8.v); - p+= 1 + 8; - j++; - } - break; - case GTPIE_RAI: /* TV GTPIE types with value length 6 */ - if (jtv0.t, ie[j]->tv8.v); - p+= 1 + 6; - j++; - } - break; - case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ - if (jtv0.t); - p+= 1 + 28; - j++; - } - break; - case GTPIE_EXT_HEADER_T: /* GTP extension header */ - if (jext.t); - p+= 2 + ntoh8(ie[j]->ext.l); - j++; - } - break; - case GTPIE_EUA: /* TLV GTPIE types with variable length */ - case GTPIE_MM_CONTEXT: - case GTPIE_PDP_CONTEXT: - case GTPIE_APN: - case GTPIE_PCO: - case GTPIE_GSN_ADDR: - case GTPIE_MSISDN: - case GTPIE_QOS_PROFILE: - case GTPIE_AUTH_QUINTUP: - case GTPIE_TFT: - case GTPIE_TARGET_INF: - case GTPIE_UTRAN_TRANS: - case GTPIE_RAB_SETUP: - case GTPIE_TRIGGER_ID: - case GTPIE_OMC_ID: - case GTPIE_CHARGING_ADDR: - case GTPIE_RAT_TYPE: - case GTPIE_USER_LOC: - case GTPIE_MS_TZ: - case GTPIE_IMEI_SV: - case GTPIE_PRIVATE: - if (jtlv.t); - p+= 3 + ntoh16(ie[j]->tlv.l); - j++; - } - break; - default: - if (GTPIE_DEBUG) printf("GTPIE something unknown. Type %d\n", *p); - return EOF; /* We received something unknown */ - } - } - if (p==end) { - if (GTPIE_DEBUG) printf("GTPIE normal return. %lx %lx\n", - (unsigned long) p, (unsigned long) end); - return 0; /* We landed at the end of the packet: OK */ - } - else if (!(jt == type)) { + if (instance-- == 0) + return 1; + } + } + return 0; +} - memset(pack, 0, GTPIE_MAX); - end = p + GTPIE_MAX; - for (i=1; iext.l); - break; - case GTPIE_EUA: /* TLV GTPIE types with length length 2 */ - case GTPIE_MM_CONTEXT: - case GTPIE_PDP_CONTEXT: - case GTPIE_APN: - case GTPIE_PCO: - case GTPIE_GSN_ADDR: - case GTPIE_MSISDN: - case GTPIE_QOS_PROFILE: - case GTPIE_AUTH_QUINTUP: - case GTPIE_TFT: - case GTPIE_TARGET_INF: - case GTPIE_UTRAN_TRANS: - case GTPIE_RAB_SETUP: - case GTPIE_TRIGGER_ID: - case GTPIE_OMC_ID: - case GTPIE_CHARGING_ADDR: - case GTPIE_PRIVATE: - iesize = 3 + hton16(ie[i]->tlv.l); - break; - default: - return 2; /* We received something unknown */ - } - if (p+iesize < end) { - memcpy(p, ie[i], iesize); - p += iesize; - *len += iesize; - } - else return 2; /* Out of space */ - } - return 0; +int gtpie_gettlv(union gtpie_member *ie[], int type, int instance, + unsigned int *length, void *dst, unsigned int size) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) { + *length = ntoh16(ie[ien]->tlv.l); + if (*length <= size) + memcpy(dst, ie[ien]->tlv.v, *length); + else + return EOF; + } + return 0; +} + +int gtpie_gettv0(union gtpie_member *ie[], int type, int instance, + void *dst, unsigned int size) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + memcpy(dst, ie[ien]->tv0.v, size); + else + return EOF; + return 0; +} + +int gtpie_gettv1(union gtpie_member *ie[], int type, int instance, + uint8_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh8(ie[ien]->tv1.v); + else + return EOF; + return 0; +} + +int gtpie_gettv2(union gtpie_member *ie[], int type, int instance, + uint16_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh16(ie[ien]->tv2.v); + else + return EOF; + return 0; +} + +int gtpie_gettv4(union gtpie_member *ie[], int type, int instance, + uint32_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh32(ie[ien]->tv4.v); + else + return EOF; + return 0; +} + +int gtpie_gettv8(union gtpie_member *ie[], int type, int instance, + uint64_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh64(ie[ien]->tv8.v); + else + return EOF; + return 0; +} + +int gtpie_decaps(union gtpie_member *ie[], int version, void *pack, + unsigned len) +{ + int i; + int j = 0; + unsigned char *p; + unsigned char *end; + + end = (unsigned char *)pack + len; + p = pack; + + memset(ie, 0, sizeof(union gtpie_member *) * GTPIE_SIZE); + + while ((p < end) && (j < GTPIE_SIZE)) { + if (GTPIE_DEBUG) { + printf("The packet looks like this:\n"); + for (i = 0; i < (end - p); i++) { + printf("%02x ", + (unsigned char)*(char *)(p + i)); + if (!((i + 1) % 16)) + printf("\n"); + }; + printf("\n"); + } + + switch (*p) { + case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ + case GTPIE_REORDER: + case GTPIE_MAP_CAUSE: + case GTPIE_MS_VALIDATED: + case GTPIE_RECOVERY: + case GTPIE_SELECTION_MODE: + case GTPIE_TEARDOWN: + case GTPIE_NSAPI: + case GTPIE_RANAP_CAUSE: + case GTPIE_RP_SMS: + case GTPIE_RP: + case GTPIE_MS_NOT_REACH: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV1 found. Type %d, value %d\n", + ie[j]->tv1.t, ie[j]->tv1.v); + p += 1 + 1; + j++; + } + break; + case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */ + case GTPIE_FL_C: + if (version != 0) { + if (j < GTPIE_SIZE) { /* GTPIE_TEI_DI & GTPIE_TEI_C with length 4 */ + /* case GTPIE_TEI_DI: gtp1 */ + /* case GTPIE_TEI_C: gtp1 */ + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 4 found. Type %d, value %d\n", + ie[j]->tv4.t, + ie[j]->tv4.v); + p += 1 + 4; + j++; + } + break; + } + case GTPIE_PFI: /* TV GTPIE types with value length 2 */ + case GTPIE_CHARGING_C: + case GTPIE_TRACE_REF: + case GTPIE_TRACE_TYPE: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV2 found. Type %d, value %d\n", + ie[j]->tv2.t, ie[j]->tv2.v); + p += 1 + 2; + j++; + } + break; + case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ + case GTPIE_P_TMSI_S: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 3 found. Type %d, value %d, %d, %d\n", + ie[j]->tv0.t, ie[j]->tv0.v[0], + ie[j]->tv0.v[1], ie[j]->tv0.v[2]); + p += 1 + 3; + j++; + } + break; + case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ + case GTPIE_P_TMSI: + case GTPIE_CHARGING_ID: + /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */ + /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 4 found. Type %d, value %d\n", + ie[j]->tv4.t, ie[j]->tv4.v); + p += 1 + 4; + j++; + } + break; + case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 5 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 5; + j++; + } + break; + case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 7 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 7; + j++; + } + break; + case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE_IMSI - GTPIE TV 8 found. Type %d, value 0x%llx\n", + ie[j]->tv0.t, ie[j]->tv8.v); + p += 1 + 8; + j++; + } + break; + case GTPIE_RAI: /* TV GTPIE types with value length 6 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE_RAI - GTPIE TV 6 found. Type %d, value 0x%llx\n", + ie[j]->tv0.t, ie[j]->tv8.v); + p += 1 + 6; + j++; + } + break; + case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 28 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 28; + j++; + } + break; + case GTPIE_EXT_HEADER_T: /* GTP extension header */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE GTP extension header found. Type %d\n", + ie[j]->ext.t); + p += 2 + ntoh8(ie[j]->ext.l); + j++; + } + break; + case GTPIE_EUA: /* TLV GTPIE types with variable length */ + case GTPIE_MM_CONTEXT: + case GTPIE_PDP_CONTEXT: + case GTPIE_APN: + case GTPIE_PCO: + case GTPIE_GSN_ADDR: + case GTPIE_MSISDN: + case GTPIE_QOS_PROFILE: + case GTPIE_AUTH_QUINTUP: + case GTPIE_TFT: + case GTPIE_TARGET_INF: + case GTPIE_UTRAN_TRANS: + case GTPIE_RAB_SETUP: + case GTPIE_TRIGGER_ID: + case GTPIE_OMC_ID: + case GTPIE_CHARGING_ADDR: + case GTPIE_RAT_TYPE: + case GTPIE_USER_LOC: + case GTPIE_MS_TZ: + case GTPIE_IMEI_SV: + case GTPIE_PRIVATE: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TLV found. Type %d\n", + ie[j]->tlv.t); + p += 3 + ntoh16(ie[j]->tlv.l); + j++; + } + break; + default: + if (GTPIE_DEBUG) + printf("GTPIE something unknown. Type %d\n", + *p); + return EOF; /* We received something unknown */ + } + } + if (p == end) { + if (GTPIE_DEBUG) + printf("GTPIE normal return. %lx %lx\n", + (unsigned long)p, (unsigned long)end); + return 0; /* We landed at the end of the packet: OK */ + } else if (!(j < GTPIE_SIZE)) { + if (GTPIE_DEBUG) + printf("GTPIE too many elements.\n"); + return EOF; /* We received too many information elements */ + } else { + if (GTPIE_DEBUG) + printf("GTPIE exceeded end of packet. %lx %lx\n", + (unsigned long)p, (unsigned long)end); + return EOF; /* We exceeded the end of the packet: Error */ + } +} + +int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len) +{ + int i; + unsigned char *p; + unsigned char *end; + union gtpie_member *m; + int iesize; + + p = pack; + + memset(pack, 0, GTPIE_MAX); + end = p + GTPIE_MAX; + for (i = 1; i < GTPIE_SIZE; i++) + if (ie[i] != 0) { + if (GTPIE_DEBUG) + printf("gtpie_encaps. Type %d\n", i); + m = (union gtpie_member *)p; + switch (i) { + case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ + case GTPIE_REORDER: + case GTPIE_MAP_CAUSE: + case GTPIE_MS_VALIDATED: + case GTPIE_RECOVERY: + case GTPIE_SELECTION_MODE: + case GTPIE_TEARDOWN: + case GTPIE_NSAPI: + case GTPIE_RANAP_CAUSE: + case GTPIE_RP_SMS: + case GTPIE_RP: + case GTPIE_MS_NOT_REACH: + iesize = 2; + break; + case GTPIE_FL_DI: /* TV GTPIE types with value length 2 */ + case GTPIE_FL_C: + case GTPIE_PFI: + case GTPIE_CHARGING_C: + case GTPIE_TRACE_REF: + case GTPIE_TRACE_TYPE: + iesize = 3; + break; + case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ + case GTPIE_P_TMSI_S: + iesize = 4; + break; + case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ + case GTPIE_P_TMSI: + /* case GTPIE_TEI_DI: only in gtp1 */ + /* case GTPIE_TEI_C: only in gtp1 */ + case GTPIE_CHARGING_ID: + iesize = 5; + break; + case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ + iesize = 6; + break; + case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ + iesize = 8; + break; + case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ + case GTPIE_RAI: + iesize = 9; + break; + case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ + iesize = 29; + break; + case GTPIE_EXT_HEADER_T: /* GTP extension header */ + iesize = 2 + hton8(ie[i]->ext.l); + break; + case GTPIE_EUA: /* TLV GTPIE types with length length 2 */ + case GTPIE_MM_CONTEXT: + case GTPIE_PDP_CONTEXT: + case GTPIE_APN: + case GTPIE_PCO: + case GTPIE_GSN_ADDR: + case GTPIE_MSISDN: + case GTPIE_QOS_PROFILE: + case GTPIE_AUTH_QUINTUP: + case GTPIE_TFT: + case GTPIE_TARGET_INF: + case GTPIE_UTRAN_TRANS: + case GTPIE_RAB_SETUP: + case GTPIE_TRIGGER_ID: + case GTPIE_OMC_ID: + case GTPIE_CHARGING_ADDR: + case GTPIE_PRIVATE: + iesize = 3 + hton16(ie[i]->tlv.l); + break; + default: + return 2; /* We received something unknown */ + } + if (p + iesize < end) { + memcpy(p, ie[i], iesize); + p += iesize; + *len += iesize; + } else + return 2; /* Out of space */ + } + return 0; } int gtpie_encaps2(union gtpie_member ie[], unsigned int size, - void *pack, unsigned *len) { - unsigned int i, j; - unsigned char *p; - unsigned char *end; - union gtpie_member *m; - int iesize; - - p = pack; + void *pack, unsigned *len) +{ + unsigned int i, j; + unsigned char *p; + unsigned char *end; + union gtpie_member *m; + int iesize; - memset(pack, 0, GTPIE_MAX); - end = p + GTPIE_MAX; - for (j=0; j> 32; - l = (uint32_t) q; + register uint32_t u, l; + u = q >> 32; + l = (uint32_t) q; - return htonl(u) | ((uint64_t)htonl(l) << 32); + return htonl(u) | ((uint64_t) htonl(l) << 32); } #define ntoh64(_x) hton64(_x) @@ -42,127 +41,124 @@ hton64(uint64_t q) #error "Please fix " #endif +#define GTPIE_SIZE 256 /* Max number of information elements */ +#define GTPIE_MAX 0xffff /* Max length of information elements */ +#define GTPIE_MAX_TV 28 /* Max length of type value pair */ +#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */ -#define GTPIE_SIZE 256 /* Max number of information elements */ -#define GTPIE_MAX 0xffff /* Max length of information elements */ -#define GTPIE_MAX_TV 28 /* Max length of type value pair */ -#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */ - -#define GTPIE_DEBUG 0 /* Print debug information */ +#define GTPIE_DEBUG 0 /* Print debug information */ /* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */ /* Also covers version 0. Note that version 0 6: QOS Profile was superceded * * by 135: QOS Profile in version 1 */ -#define GTPIE_CAUSE 1 /* Cause 1 */ -#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */ -#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */ -#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */ -#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */ -#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3*/ - /* 6-7 SPARE */ /* 6 is QoS Profile vers 0 */ -#define GTPIE_REORDER 8 /* Reordering Required 1 */ -#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */ - /* 10 SPARE */ -#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */ -#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */ -#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */ -#define GTPIE_RECOVERY 14 /* Recovery 1 */ -#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */ -#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */ -#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */ -#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */ -#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */ -#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */ -#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */ -#define GTPIE_NSAPI 20 /* NSAPI 1 */ -#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */ -#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */ -#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */ -#define GTPIE_RP 24 /* Radio Priority 1 */ -#define GTPIE_PFI 25 /* Packet Flow Id 2 */ -#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */ -#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */ -#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */ -#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */ - /* 30-116 UNUSED */ +#define GTPIE_CAUSE 1 /* Cause 1 */ +#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */ +#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */ +#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */ +#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */ +#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3 */ + /* 6-7 SPARE *//* 6 is QoS Profile vers 0 */ +#define GTPIE_REORDER 8 /* Reordering Required 1 */ +#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */ + /* 10 SPARE */ +#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */ +#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */ +#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */ +#define GTPIE_RECOVERY 14 /* Recovery 1 */ +#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */ +#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */ +#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */ +#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */ +#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */ +#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */ +#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */ +#define GTPIE_NSAPI 20 /* NSAPI 1 */ +#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */ +#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */ +#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */ +#define GTPIE_RP 24 /* Radio Priority 1 */ +#define GTPIE_PFI 25 /* Packet Flow Id 2 */ +#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */ +#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */ +#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */ +#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */ + /* 30-116 UNUSED */ /* 117-126 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */ -#define GTPIE_EUA 128 /* End User Address */ -#define GTPIE_MM_CONTEXT 129 /* MM Context */ -#define GTPIE_PDP_CONTEXT 130 /* PDP Context */ -#define GTPIE_APN 131 /* Access Point Name */ -#define GTPIE_PCO 132 /* Protocol Configuration Options */ -#define GTPIE_GSN_ADDR 133 /* GSN Address */ -#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */ -#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */ -#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */ -#define GTPIE_TFT 137 /* Traffic Flow Template */ -#define GTPIE_TARGET_INF 138 /* Target Identification */ -#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */ -#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */ -#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */ -#define GTPIE_TRIGGER_ID 142 /* Trigger Id */ -#define GTPIE_OMC_ID 143 /* OMC Identity */ -#define GTPIE_RAT_TYPE 151 /* Radio Access Technology Type */ -#define GTPIE_USER_LOC 152 /* User Location Information */ -#define GTPIE_MS_TZ 153 /* MS Time Zone */ -#define GTPIE_IMEI_SV 154 /* IMEI Software Version */ +#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */ +#define GTPIE_EUA 128 /* End User Address */ +#define GTPIE_MM_CONTEXT 129 /* MM Context */ +#define GTPIE_PDP_CONTEXT 130 /* PDP Context */ +#define GTPIE_APN 131 /* Access Point Name */ +#define GTPIE_PCO 132 /* Protocol Configuration Options */ +#define GTPIE_GSN_ADDR 133 /* GSN Address */ +#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */ +#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */ +#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */ +#define GTPIE_TFT 137 /* Traffic Flow Template */ +#define GTPIE_TARGET_INF 138 /* Target Identification */ +#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */ +#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */ +#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */ +#define GTPIE_TRIGGER_ID 142 /* Trigger Id */ +#define GTPIE_OMC_ID 143 /* OMC Identity */ +#define GTPIE_RAT_TYPE 151 /* Radio Access Technology Type */ +#define GTPIE_USER_LOC 152 /* User Location Information */ +#define GTPIE_MS_TZ 153 /* MS Time Zone */ +#define GTPIE_IMEI_SV 154 /* IMEI Software Version */ /* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */ +#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */ /* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_PRIVATE 255 /* Private Extension */ - +#define GTPIE_PRIVATE 255 /* Private Extension */ /* GTP information element structs in network order */ -struct gtpie_ext { /* Extension header */ - uint8_t t; /* Type */ - uint8_t l; /* Length */ - uint8_t *p; /* Value */ -} __attribute__((packed)); +struct gtpie_ext { /* Extension header */ + uint8_t t; /* Type */ + uint8_t l; /* Length */ + uint8_t *p; /* Value */ +} __attribute__ ((packed)); -struct gtpie_tlv { /* Type length value pair */ - uint8_t t; /* Type */ - uint16_t l; /* Length */ - uint8_t v[GTPIE_MAX_TLV]; /* Value */ -} __attribute__((packed)); +struct gtpie_tlv { /* Type length value pair */ + uint8_t t; /* Type */ + uint16_t l; /* Length */ + uint8_t v[GTPIE_MAX_TLV]; /* Value */ +} __attribute__ ((packed)); -struct gtpie_tv0 { /* 1 byte type value pair */ - uint8_t t; /* Type */ - uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */ -}__attribute__((packed)); +struct gtpie_tv0 { /* 1 byte type value pair */ + uint8_t t; /* Type */ + uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */ +} __attribute__ ((packed)); -struct gtpie_tv1 { /* 1 byte type value pair */ - uint8_t t; /* Type */ - uint8_t v; /* Value */ -}__attribute__((packed)); +struct gtpie_tv1 { /* 1 byte type value pair */ + uint8_t t; /* Type */ + uint8_t v; /* Value */ +} __attribute__ ((packed)); -struct gtpie_tv2 { /* 2 byte type value pair */ - uint8_t t; /* Type */ - uint16_t v; /* Value */ -}__attribute__((packed)); +struct gtpie_tv2 { /* 2 byte type value pair */ + uint8_t t; /* Type */ + uint16_t v; /* Value */ +} __attribute__ ((packed)); -struct gtpie_tv4 { /* 4 byte type value pair */ - uint8_t t; /* Type */ - uint32_t v; /* Value */ -}__attribute__((packed)); - -struct gtpie_tv8 { /* 8 byte type value pair */ - uint8_t t; /* Type */ - uint64_t v; /* Value */ -}__attribute__((packed)); +struct gtpie_tv4 { /* 4 byte type value pair */ + uint8_t t; /* Type */ + uint32_t v; /* Value */ +} __attribute__ ((packed)); +struct gtpie_tv8 { /* 8 byte type value pair */ + uint8_t t; /* Type */ + uint64_t v; /* Value */ +} __attribute__ ((packed)); union gtpie_member { - uint8_t t; - struct gtpie_ext ext; - struct gtpie_tlv tlv; - struct gtpie_tv0 tv0; - struct gtpie_tv1 tv1; - struct gtpie_tv2 tv2; - struct gtpie_tv4 tv4; - struct gtpie_tv8 tv8; -}__attribute__((packed)); + uint8_t t; + struct gtpie_ext ext; + struct gtpie_tlv tlv; + struct gtpie_tv0 tv0; + struct gtpie_tv1 tv1; + struct gtpie_tv2 tv2; + struct gtpie_tv4 tv4; + struct gtpie_tv8 tv8; +} __attribute__ ((packed)); /* cause @@ -214,45 +210,46 @@ private */ struct tlv1 { - uint8_t type; - uint8_t length; -}__attribute__((packed)); + uint8_t type; + uint8_t length; +} __attribute__ ((packed)); struct tlv2 { - uint8_t type; - uint16_t length; -}__attribute__((packed)); + uint8_t type; + uint16_t length; +} __attribute__ ((packed)); extern int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v); -extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size, - uint8_t t, int l, uint8_t *v); -extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v); -extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v); -extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v); -extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v); -extern int gtpie_getie(union gtpie_member* ie[], int type, int instance); -extern int gtpie_exist(union gtpie_member* ie[], int type, int instance); -extern int gtpie_gettlv(union gtpie_member* ie[], int type, int instance, +extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size, + uint8_t t, int l, uint8_t * v); +extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint8_t v); +extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint16_t v); +extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint32_t v); +extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint64_t v); +extern int gtpie_getie(union gtpie_member *ie[], int type, int instance); +extern int gtpie_exist(union gtpie_member *ie[], int type, int instance); +extern int gtpie_gettlv(union gtpie_member *ie[], int type, int instance, unsigned int *length, void *dst, unsigned int size); -extern int gtpie_gettv0(union gtpie_member* ie[], int type, int instance, +extern int gtpie_gettv0(union gtpie_member *ie[], int type, int instance, void *dst, unsigned int size); -extern int gtpie_gettv1(union gtpie_member* ie[], int type, int instance, - uint8_t *dst); -extern int gtpie_gettv2(union gtpie_member* ie[], int type, int instance, - uint16_t *dst); -extern int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, - uint32_t *dst); -extern int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, - uint64_t *dst); +extern int gtpie_gettv1(union gtpie_member *ie[], int type, int instance, + uint8_t * dst); +extern int gtpie_gettv2(union gtpie_member *ie[], int type, int instance, + uint16_t * dst); +extern int gtpie_gettv4(union gtpie_member *ie[], int type, int instance, + uint32_t * dst); +extern int gtpie_gettv8(union gtpie_member *ie[], int type, int instance, + uint64_t * dst); -extern int gtpie_decaps(union gtpie_member* ie[], int version, +extern int gtpie_decaps(union gtpie_member *ie[], int version, void *pack, unsigned len); -extern int gtpie_encaps(union gtpie_member* ie[], void *pack, unsigned *len); +extern int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len); extern int gtpie_encaps2(union gtpie_member ie[], unsigned int size, - void *pack, unsigned *len); - - -#endif /* !_GTPIE_H */ - + void *pack, unsigned *len); +#endif /* !_GTPIE_H */ diff --git a/gtp/lookupa.c b/gtp/lookupa.c index 8ff114b..1eff74a 100644 --- a/gtp/lookupa.c +++ b/gtp/lookupa.c @@ -81,52 +81,64 @@ acceptable. Do NOT use for cryptographic purposes. -------------------------------------------------------------------- */ -ub4 lookup( k, length, level) -register ub1 *k; /* the key */ -register ub4 length; /* the length of the key */ -register ub4 level; /* the previous hash, or an arbitrary value */ +ub4 lookup(k, length, level) +register ub1 *k; /* the key */ +register ub4 length; /* the length of the key */ +register ub4 level; /* the previous hash, or an arbitrary value */ { - register ub4 a,b,c,len; + register ub4 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 */ + /* 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; - } + 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); + 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; + return c; } - /* -------------------------------------------------------------------- mixc -- mixc 8 4-bit values as quickly and thoroughly as possible. @@ -169,78 +181,120 @@ Use to detect changes between revisions of documents, assuming nobody is trying to cause collisions. Do NOT use for cryptography. -------------------------------------------------------------------- */ -void checksum( k, len, state) +void checksum(k, len, state) register ub1 *k; -register ub4 len; +register ub4 len; register ub4 *state; { - register ub4 a,b,c,d,e,f,g,h,length; + register ub4 a, b, c, d, e, f, g, h, length; - /* Use the length and level; add in the golden ratio. */ - length = len; - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; + /* Use the length and level; add in the golden ratio. */ + length = len; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; /*---------------------------------------- handle most of the key */ - while (len >= 32) - { - a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24)); - b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24)); - c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24)); - d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24)); - e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24)); - f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24)); - g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24)); - h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24)); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - k += 32; len -= 32; - } + while (len >= 32) { + a += (k[0] + (k[1] << 8) + (k[2] << 16) + (k[3] << 24)); + b += (k[4] + (k[5] << 8) + (k[6] << 16) + (k[7] << 24)); + c += (k[8] + (k[9] << 8) + (k[10] << 16) + (k[11] << 24)); + d += (k[12] + (k[13] << 8) + (k[14] << 16) + (k[15] << 24)); + e += (k[16] + (k[17] << 8) + (k[18] << 16) + (k[19] << 24)); + f += (k[20] + (k[21] << 8) + (k[22] << 16) + (k[23] << 24)); + g += (k[24] + (k[25] << 8) + (k[26] << 16) + (k[27] << 24)); + h += (k[28] + (k[29] << 8) + (k[30] << 16) + (k[31] << 24)); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + k += 32; + len -= 32; + } /*------------------------------------- handle the last 31 bytes */ - h += length; - switch(len) - { - case 31: h+=(k[30]<<24); - case 30: h+=(k[29]<<16); - case 29: h+=(k[28]<<8); - case 28: g+=(k[27]<<24); - case 27: g+=(k[26]<<16); - case 26: g+=(k[25]<<8); - case 25: g+=k[24]; - case 24: f+=(k[23]<<24); - case 23: f+=(k[22]<<16); - case 22: f+=(k[21]<<8); - case 21: f+=k[20]; - case 20: e+=(k[19]<<24); - case 19: e+=(k[18]<<16); - case 18: e+=(k[17]<<8); - case 17: e+=k[16]; - case 16: d+=(k[15]<<24); - case 15: d+=(k[14]<<16); - case 14: d+=(k[13]<<8); - case 13: d+=k[12]; - case 12: c+=(k[11]<<24); - case 11: c+=(k[10]<<16); - case 10: c+=(k[9]<<8); - case 9 : c+=k[8]; - case 8 : b+=(k[7]<<24); - case 7 : b+=(k[6]<<16); - case 6 : b+=(k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=(k[3]<<24); - case 3 : a+=(k[2]<<16); - case 2 : a+=(k[1]<<8); - case 1 : a+=k[0]; - } - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); + h += length; + switch (len) { + case 31: + h += (k[30] << 24); + case 30: + h += (k[29] << 16); + case 29: + h += (k[28] << 8); + case 28: + g += (k[27] << 24); + case 27: + g += (k[26] << 16); + case 26: + g += (k[25] << 8); + case 25: + g += k[24]; + case 24: + f += (k[23] << 24); + case 23: + f += (k[22] << 16); + case 22: + f += (k[21] << 8); + case 21: + f += k[20]; + case 20: + e += (k[19] << 24); + case 19: + e += (k[18] << 16); + case 18: + e += (k[17] << 8); + case 17: + e += k[16]; + case 16: + d += (k[15] << 24); + case 15: + d += (k[14] << 16); + case 14: + d += (k[13] << 8); + case 13: + d += k[12]; + case 12: + c += (k[11] << 24); + case 11: + c += (k[10] << 16); + case 10: + c += (k[9] << 8); + case 9: + c += k[8]; + case 8: + b += (k[7] << 24); + case 7: + b += (k[6] << 16); + case 6: + b += (k[5] << 8); + case 5: + b += k[4]; + case 4: + a += (k[3] << 24); + case 3: + a += (k[2] << 16); + case 2: + a += (k[1] << 8); + case 1: + a += k[0]; + } + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); /*-------------------------------------------- report the result */ - state[0]=a; state[1]=b; state[2]=c; state[3]=d; - state[4]=e; state[5]=f; state[6]=g; state[7]=h; + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + state[5] = f; + state[6] = g; + state[7] = h; } diff --git a/gtp/lookupa.h b/gtp/lookupa.h index 16784a9..a733509 100644 --- a/gtp/lookupa.h +++ b/gtp/lookupa.h @@ -16,14 +16,14 @@ Source is http://burtleburtle.net/bob/c/lookupa.h #ifndef LOOKUPA #define LOOKUPA -typedef unsigned long int ub4; /* unsigned 4-byte quantities */ -typedef unsigned char ub1; +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +typedef unsigned char ub1; #define CHECKSTATE 8 #define hashsize(n) ((ub4)1<<(n)) #define hashmask(n) (hashsize(n)-1) -ub4 lookup(/*_ ub1 *k, ub4 length, ub4 level _*/); -void checksum(/*_ ub1 *k, ub4 length, ub4 *state _*/); +ub4 lookup( /*_ ub1 *k, ub4 length, ub4 level _*/ ); +void checksum( /*_ ub1 *k, ub4 length, ub4 *state _*/ ); #endif /* LOOKUPA */ diff --git a/gtp/pdp.c b/gtp/pdp.c index 648d70d..7ce9128 100644 --- a/gtp/pdp.c +++ b/gtp/pdp.c @@ -31,8 +31,8 @@ * Global variables TODO: most should be moved to gsn_t *************************************************************/ -struct pdp_t pdpa[PDP_MAX]; /* PDP storage */ -struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */ +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 */ /* *********************************************************** @@ -107,144 +107,171 @@ struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */ * *************************************************************/ -int pdp_init() { - memset(&pdpa, 0, sizeof(pdpa)); - memset(&hashtid, 0, sizeof(hashtid)); - /* memset(&haship, 0, sizeof(haship)); */ +int pdp_init() +{ + memset(&pdpa, 0, sizeof(pdpa)); + memset(&hashtid, 0, sizeof(hashtid)); + /* memset(&haship, 0, sizeof(haship)); */ - return 0; + return 0; } -int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, - struct pdp_t *pdp_old){ - int n; - for (n=0; ninuse = 1; - (*pdp)->imsi = imsi; - (*pdp)->nsapi = nsapi; - (*pdp)->fllc = (uint16_t) n + 1; - (*pdp)->fllu = (uint16_t) n + 1; - (*pdp)->teid_own = (uint32_t) n + 1; - if (!(*pdp)->secondary) (*pdp)->teic_own = (uint32_t) n + 1; - pdp_tidset(*pdp, pdp_gettid(imsi, nsapi)); - - /* Insert reference in primary context */ - if (((*pdp)->teic_own > 0 ) && ((*pdp)->teic_own <= PDP_MAX)) { - pdpa[(*pdp)->teic_own-1].secondary_tei[(*pdp)->nsapi & 0x0f] = - (*pdp)->teid_own; - } - - return 0; - } - } - return EOF; /* No more available */ +int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, + struct pdp_t *pdp_old) +{ + int n; + for (n = 0; n < PDP_MAX; n++) { /* TODO: Need to do better than linear search */ + if (pdpa[n].inuse == 0) { + *pdp = &pdpa[n]; + if (NULL != pdp_old) + memcpy(*pdp, pdp_old, sizeof(struct pdp_t)); + else + memset(*pdp, 0, sizeof(struct pdp_t)); + (*pdp)->inuse = 1; + (*pdp)->imsi = imsi; + (*pdp)->nsapi = nsapi; + (*pdp)->fllc = (uint16_t) n + 1; + (*pdp)->fllu = (uint16_t) n + 1; + (*pdp)->teid_own = (uint32_t) n + 1; + if (!(*pdp)->secondary) + (*pdp)->teic_own = (uint32_t) n + 1; + pdp_tidset(*pdp, pdp_gettid(imsi, nsapi)); + + /* Insert reference in primary context */ + if (((*pdp)->teic_own > 0) + && ((*pdp)->teic_own <= PDP_MAX)) { + pdpa[(*pdp)->teic_own - + 1].secondary_tei[(*pdp)->nsapi & 0x0f] = + (*pdp)->teid_own; + } + + return 0; + } + } + return EOF; /* No more available */ } -int pdp_freepdp(struct pdp_t *pdp){ - pdp_tiddel(pdp); +int pdp_freepdp(struct pdp_t *pdp) +{ + pdp_tiddel(pdp); - /* Remove any references in primary context */ - if ((pdp->secondary) && (pdp->teic_own > 0 ) && (pdp->teic_own <= PDP_MAX)) { - pdpa[pdp->teic_own-1].secondary_tei[pdp->nsapi & 0x0f] = 0; - } + /* Remove any references in primary context */ + if ((pdp->secondary) && (pdp->teic_own > 0) + && (pdp->teic_own <= PDP_MAX)) { + pdpa[pdp->teic_own - 1].secondary_tei[pdp->nsapi & 0x0f] = 0; + } - memset(pdp, 0, sizeof(struct pdp_t)); - return 0; + memset(pdp, 0, sizeof(struct pdp_t)); + return 0; } -int pdp_getpdp(struct pdp_t **pdp){ - *pdp = &pdpa[0]; - return 0; +int pdp_getpdp(struct pdp_t **pdp) +{ + *pdp = &pdpa[0]; + return 0; } -int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl){ - if ((fl>PDP_MAX) || (fl<1)) { - return EOF; /* Not found */ - } - else { - *pdp = &pdpa[fl-1]; - if ((*pdp)->inuse) return 0; - else return EOF; - /* Context exists. We do no further validity checking. */ - } +int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl) +{ + if ((fl > PDP_MAX) || (fl < 1)) { + return EOF; /* Not found */ + } else { + *pdp = &pdpa[fl - 1]; + if ((*pdp)->inuse) + return 0; + else + return EOF; + /* Context exists. We do no further validity checking. */ + } } -int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei){ - if ((tei>PDP_MAX) || (tei<1)) { - return EOF; /* Not found */ - } - else { - *pdp = &pdpa[tei-1]; - if ((*pdp)->inuse) return 0; - else return EOF; - /* Context exists. We do no further validity checking. */ - } +int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei) +{ + if ((tei > PDP_MAX) || (tei < 1)) { + return EOF; /* Not found */ + } else { + *pdp = &pdpa[tei - 1]; + if ((*pdp)->inuse) + return 0; + else + return EOF; + /* Context exists. We do no further validity checking. */ + } } - -int pdp_tidhash(uint64_t tid) { - return (lookup(&tid, sizeof(tid), 0) % PDP_MAX); +int pdp_tidhash(uint64_t tid) +{ + return (lookup(&tid, sizeof(tid), 0) % PDP_MAX); } -int pdp_tidset(struct pdp_t *pdp, uint64_t tid) { - int hash = pdp_tidhash(tid); - struct pdp_t *pdp2; - struct pdp_t *pdp_prev = NULL; - if (PDP_DEBUG) printf("Begin pdp_tidset tid = %llx\n", tid); - pdp->tidnext = NULL; - pdp->tid = tid; - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) - pdp_prev = pdp2; - if (!pdp_prev) - hashtid[hash] = pdp; - else - pdp_prev->tidnext = pdp; - if (PDP_DEBUG) printf("End pdp_tidset\n"); - return 0; +int pdp_tidset(struct pdp_t *pdp, uint64_t tid) +{ + int hash = pdp_tidhash(tid); + struct pdp_t *pdp2; + struct pdp_t *pdp_prev = NULL; + if (PDP_DEBUG) + printf("Begin pdp_tidset tid = %llx\n", tid); + pdp->tidnext = NULL; + pdp->tid = tid; + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) + pdp_prev = pdp2; + if (!pdp_prev) + hashtid[hash] = pdp; + else + pdp_prev->tidnext = pdp; + if (PDP_DEBUG) + printf("End pdp_tidset\n"); + return 0; } -int pdp_tiddel(struct pdp_t *pdp) { - int hash = pdp_tidhash(pdp->tid); - struct pdp_t *pdp2; - struct pdp_t *pdp_prev = NULL; - if (PDP_DEBUG) printf("Begin pdp_tiddel tid = %llx\n", pdp->tid); - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { - if (pdp2 == pdp) { - if (!pdp_prev) - hashtid[hash] = pdp2->tidnext; - else - pdp_prev->tidnext = pdp2->tidnext; - if (PDP_DEBUG) printf("End pdp_tiddel: PDP found\n"); - return 0; - } - pdp_prev = pdp2; - } - if (PDP_DEBUG) printf("End pdp_tiddel: PDP not found\n"); - return EOF; /* End of linked list and not found */ +int pdp_tiddel(struct pdp_t *pdp) +{ + int hash = pdp_tidhash(pdp->tid); + struct pdp_t *pdp2; + struct pdp_t *pdp_prev = NULL; + if (PDP_DEBUG) + printf("Begin pdp_tiddel tid = %llx\n", pdp->tid); + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { + if (pdp2 == pdp) { + if (!pdp_prev) + hashtid[hash] = pdp2->tidnext; + else + pdp_prev->tidnext = pdp2->tidnext; + if (PDP_DEBUG) + printf("End pdp_tiddel: PDP found\n"); + return 0; + } + pdp_prev = pdp2; + } + if (PDP_DEBUG) + printf("End pdp_tiddel: PDP not found\n"); + return EOF; /* End of linked list and not found */ } -int pdp_tidget(struct pdp_t **pdp, uint64_t tid) { - int hash = pdp_tidhash(tid); - struct pdp_t *pdp2; - if (PDP_DEBUG) printf("Begin pdp_tidget tid = %llx\n", tid); - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { - if (pdp2->tid == tid) { - *pdp = pdp2; - if (PDP_DEBUG) printf("Begin pdp_tidget. Found\n"); - return 0; - } - } - if (PDP_DEBUG) printf("Begin pdp_tidget. Not found\n"); - return EOF; /* End of linked list and not found */ +int pdp_tidget(struct pdp_t **pdp, uint64_t tid) +{ + int hash = pdp_tidhash(tid); + struct pdp_t *pdp2; + if (PDP_DEBUG) + printf("Begin pdp_tidget tid = %llx\n", tid); + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { + if (pdp2->tid == tid) { + *pdp = pdp2; + if (PDP_DEBUG) + printf("Begin pdp_tidget. Found\n"); + return 0; + } + } + if (PDP_DEBUG) + printf("Begin pdp_tidget. Not found\n"); + return EOF; /* End of linked list and not found */ } -int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) { - return pdp_tidget(pdp, - (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60)); +int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) +{ + return pdp_tidget(pdp, + (imsi & 0x0fffffffffffffffull) + + ((uint64_t) nsapi << 60)); } /* @@ -320,32 +347,36 @@ int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) { */ /* Various conversion functions */ -int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) { - eua->l=6; - eua->v[0]=0xf1; /* IETF */ - eua->v[1]=0x21; /* IPv4 */ - memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */ - return 0; +int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) +{ + eua->l = 6; + eua->v[0] = 0xf1; /* IETF */ + eua->v[1] = 0x21; /* IPv4 */ + memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */ + 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; +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 & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60); +uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) +{ + return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60); } -int ulcpy(void* dst, void* src, size_t size) { - if (((struct ul255_t*)src)->l <= size) { - ((struct ul255_t*)dst)->l = ((struct ul255_t*)src)->l; - memcpy(((struct ul255_t*)dst)->v, ((struct ul255_t*)src)->v, - ((struct ul255_t*)dst)->l); - return 0; - } - else return EOF; +int ulcpy(void *dst, void *src, size_t size) +{ + if (((struct ul255_t *)src)->l <= size) { + ((struct ul255_t *)dst)->l = ((struct ul255_t *)src)->l; + memcpy(((struct ul255_t *)dst)->v, ((struct ul255_t *)src)->v, + ((struct ul255_t *)dst)->l); + return 0; + } else + return EOF; } diff --git a/gtp/pdp.h b/gtp/pdp.h index e3bd06d..b069a6f 100644 --- a/gtp/pdp.h +++ b/gtp/pdp.h @@ -12,42 +12,40 @@ #ifndef _PDP_H #define _PDP_H -#define PDP_MAX 1024 /* Max number of PDP contexts */ -#define PDP_MAXNSAPI 16 /* Max number of NSAPI */ +#define PDP_MAX 1024 /* Max number of PDP contexts */ +#define PDP_MAXNSAPI 16 /* Max number of NSAPI */ -#define PDP_DEBUG 0 /* Print debug information */ +#define PDP_DEBUG 0 /* Print debug information */ /* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */ /* Also covers version 0. Note that version 0 6: QOS Profile was superceded * * by 135: QOS Profile in version 1 */ - struct sl_t { -unsigned int l; -char *v; + unsigned int l; + char *v; }; struct ul_t { -unsigned int l; -unsigned char *v; + unsigned int l; + unsigned char *v; }; struct ul16_t { -unsigned int l; -unsigned char v[16]; + unsigned int l; + unsigned char v[16]; }; struct ul66_t { -unsigned int l; -unsigned char v[66]; + unsigned int l; + unsigned char v[66]; }; struct ul255_t { -unsigned int l; -unsigned char v[255]; + unsigned int l; + unsigned char v[255]; }; - /* ***************************************************************** * Information storage for each PDP context * @@ -103,131 +101,130 @@ unsigned char v[255]; *****************************************************************/ struct pdp_t { - /* Parameter determining if this PDP is in use. */ - uint8_t inuse; /* 0=free. 1=used by somebody */ + /* Parameter determining if this PDP is in use. */ + uint8_t inuse; /* 0=free. 1=used by somebody */ - /* Pointers related to hash tables */ - struct pdp_t *tidnext; - struct pdp_t *ipnext; + /* Pointers related to hash tables */ + struct pdp_t *tidnext; + struct pdp_t *ipnext; - /* Parameters shared by all PDP context belonging to the same MS */ + /* 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 */ + 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.*/ - struct ul16_t msisdn; /* The basic MSISDN of the MS. */ - uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */ - uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */ - uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */ - uint16_t tracetype;/* Indicates the type of trace. */ - struct ul_t triggerid;/* Identifies the entity that initiated the trace. */ - struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */ - uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */ + uint64_t imsi; /* International Mobile Subscriber Identity. */ + struct ul16_t msisdn; /* The basic MSISDN of the MS. */ + uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */ + uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */ + uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */ + uint16_t tracetype; /* Indicates the type of trace. */ + struct ul_t triggerid; /* Identifies the entity that initiated the trace. */ + struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */ + uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */ - /* Parameters specific to each individual PDP context */ + /* Parameters specific to each individual PDP context */ - uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */ - uint8_t pdp_state;/* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */ - /* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */ - /* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */ - struct ul66_t eua; /* End user address. PDP type and address combined */ - uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */ - struct ul255_t apn_req;/* The APN requested. */ - struct ul255_t apn_sub;/* The APN received from the HLR. */ - struct ul255_t apn_use;/* The APN Network Identifier currently used. */ - uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */ - uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */ + uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */ + uint8_t pdp_state; /* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */ + /* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */ + /* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */ + struct ul66_t eua; /* End user address. PDP type and address combined */ + uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */ + struct ul255_t apn_req; /* The APN requested. */ + struct ul255_t apn_sub; /* The APN received from the HLR. */ + struct ul255_t apn_use; /* The APN Network Identifier currently used. */ + uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */ + uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */ - uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */ - uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */ - uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */ - uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */ - uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */ + uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */ + uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */ + uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */ + uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */ + uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */ - uint16_t fllc; /* (Local Flow Label Control, gtp0) */ - uint16_t fllu; /* (Local Flow Label Data I, gtp0) */ - uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */ - uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */ + uint16_t fllc; /* (Local Flow Label Control, gtp0) */ + uint16_t fllu; /* (Local Flow Label Data I, gtp0) */ + uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */ + uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */ - struct ul255_t tft; /* Traffic flow template. */ - /*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */ - /*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */ - /*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */ - /*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */ + struct ul255_t tft; /* Traffic flow template. */ + /*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */ + /*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */ + /*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */ + /*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */ - struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */ - struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */ - struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */ - struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */ + struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */ + struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */ + struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */ + struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */ - uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */ - uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */ - uint8_t qos_req0[3]; /* The quality of service profile requested. */ - uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */ - struct ul255_t qos_sub; /* The quality of service profile subscribed. */ - struct ul255_t qos_req; /* The quality of service profile requested. */ - struct ul255_t qos_neg; /* The quality of service profile negotiated. */ - uint8_t radio_pri;/* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */ - uint16_t flow_id; /* Packet flow identifier. */ - /* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP)*/ - uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */ - uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */ - uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */ + uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */ + uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */ + uint8_t qos_req0[3]; /* The quality of service profile requested. */ + uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */ + struct ul255_t qos_sub; /* The quality of service profile subscribed. */ + struct ul255_t qos_req; /* The quality of service profile requested. */ + struct ul255_t qos_neg; /* The quality of service profile negotiated. */ + uint8_t radio_pri; /* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */ + uint16_t flow_id; /* Packet flow identifier. */ + /* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP) */ + uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */ + uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */ + uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */ /* uint16_t gtpsnd; GTP-U sequence number of the next downlink N-PDU to be sent to the SGSN / received from the GGSN. */ /* uint16_t gtpsnu; GTP-U sequence number of the next uplink N-PDU to be received from the SGSN / sent to the GGSN */ - uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */ - uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */ - uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */ - uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */ - uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */ - uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */ - struct ul16_t rnc_addr;/* The IP address of the RNC currently used. */ - uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */ - struct ul255_t pco_req; /* Requested packet control options. */ - struct ul255_t pco_neg; /* Negotiated packet control options. */ - uint32_t selmode; /* Selection mode. */ - struct ul255_t rattype; /* Radio Access Technology Type */ - int rattype_given; /* Radio Access Technology Type given*/ - struct ul255_t userloc; /* User Location Information */ - int userloc_given; /* User Location Information given*/ - struct ul255_t rai; /* Routing Area Information */ - int rai_given; /* Routing Area Information given*/ - struct ul255_t mstz; /* MS Time Zone */ - int mstz_given; /* MS Time Zone given*/ - struct ul255_t imeisv; /* IMEI Software Version */ - int imeisv_given; /* IMEI Software Version given*/ - int norecovery_given; /* norecovery given*/ + uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */ + uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */ + uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */ + uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */ + uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */ + uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */ + struct ul16_t rnc_addr; /* The IP address of the RNC currently used. */ + uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */ + struct ul255_t pco_req; /* Requested packet control options. */ + struct ul255_t pco_neg; /* Negotiated packet control options. */ + uint32_t selmode; /* Selection mode. */ + struct ul255_t rattype; /* Radio Access Technology Type */ + int rattype_given; /* Radio Access Technology Type given */ + struct ul255_t userloc; /* User Location Information */ + int userloc_given; /* User Location Information given */ + struct ul255_t rai; /* Routing Area Information */ + int rai_given; /* Routing Area Information given */ + struct ul255_t mstz; /* MS Time Zone */ + int mstz_given; /* MS Time Zone given */ + struct ul255_t imeisv; /* IMEI Software Version */ + int imeisv_given; /* IMEI Software Version given */ + int norecovery_given; /* norecovery given */ - /* Additional parameters used by library */ + /* Additional parameters used by library */ - int version; /* Protocol version currently in use. 0 or 1 */ + int version; /* Protocol version currently in use. 0 or 1 */ - uint64_t tid; /* Combination of imsi and nsapi */ - uint16_t seq; /* Sequence number of last request */ - struct sockaddr_in sa_peer; /* Address of last request */ - int fd; /* File descriptor request was received on */ + uint64_t tid; /* Combination of imsi and nsapi */ + uint16_t seq; /* Sequence number of last request */ + struct sockaddr_in sa_peer; /* Address of last request */ + int fd; /* File descriptor request was received on */ - uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */ + uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */ - /* Parameters used for secondary activation procedure (tei data) */ - /* If (secondary == 1) then teic_own indicates linked PDP context */ - uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */ - uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */ + /* Parameters used for secondary activation procedure (tei data) */ + /* If (secondary == 1) then teic_own indicates linked PDP context */ + uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */ + uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */ - /* Secondary contexts of this primary context */ - uint32_t secondary_tei[PDP_MAXNSAPI]; + /* Secondary contexts of this primary context */ + uint32_t secondary_tei[PDP_MAXNSAPI]; - /* IP address used for Create and Update PDP Context Requests */ - struct in_addr hisaddr0; /* Server address */ - struct in_addr hisaddr1; /* Server address */ + /* IP address used for Create and Update PDP Context Requests */ + struct in_addr hisaddr0; /* Server address */ + struct in_addr hisaddr1; /* Server address */ - /* to be used by libgtp callers/users (to attach their own private state) */ - void *priv; + /* to be used by libgtp callers/users (to attach their own private state) */ + void *priv; }; - /* functions related to pdp_t management */ int pdp_init(); int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, @@ -245,7 +242,6 @@ 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); @@ -256,6 +252,6 @@ 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); +int ulcpy(void *dst, void *src, size_t size); -#endif /* !_PDP_H */ +#endif /* !_PDP_H */ diff --git a/gtp/queue.c b/gtp/queue.c index 7fdf9df..02c18ec 100644 --- a/gtp/queue.c +++ b/gtp/queue.c @@ -29,224 +29,260 @@ #include "gtp.h" #include "queue.h" -int queue_print(struct queue_t *queue) { - int n; - printf("Queue: %x Next: %d First: %d Last: %d\n", (int) queue, queue->next, queue->first, queue->last); - printf("# State seq next prev timeout retrans\n"); - for (n=0; nqmsga[n].state, - queue->qmsga[n].seq, - queue->qmsga[n].next, - queue->qmsga[n].prev, - (int) queue->qmsga[n].timeout, - queue->qmsga[n].retrans); - } - return 0; +int queue_print(struct queue_t *queue) +{ + int n; + printf("Queue: %x Next: %d First: %d Last: %d\n", (int)queue, + queue->next, queue->first, queue->last); + printf("# State seq next prev timeout retrans\n"); + for (n = 0; n < QUEUE_SIZE; n++) { + printf("%d %d %d %d %d %d %d\n", + n, + queue->qmsga[n].state, + queue->qmsga[n].seq, + queue->qmsga[n].next, + queue->qmsga[n].prev, + (int)queue->qmsga[n].timeout, queue->qmsga[n].retrans); + } + return 0; } -int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) { - /* With QUEUE_HASH_SIZE = 2^16 this describes all possible - seq values. Thus we have perfect hash for the request queue. - For the response queue we might have collisions, but not very - often. - For performance optimisation we should remove the modulus - operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */ - return seq % QUEUE_HASH_SIZE; +int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) +{ + /* With QUEUE_HASH_SIZE = 2^16 this describes all possible + seq values. Thus we have perfect hash for the request queue. + For the response queue we might have collisions, but not very + often. + For performance optimisation we should remove the modulus + operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */ + return seq % QUEUE_HASH_SIZE; } int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int hash = queue_seqhash(peer, seq); - struct qmsg_t *qmsg2; - struct qmsg_t *qmsg_prev = NULL; + struct sockaddr_in *peer, uint16_t seq) +{ + int hash = queue_seqhash(peer, seq); + struct qmsg_t *qmsg2; + struct qmsg_t *qmsg_prev = NULL; - if (QUEUE_DEBUG) printf("Begin queue_seqset seq = %d\n", (int) seq); - if (QUEUE_DEBUG) printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), sizeof(*peer)); + if (QUEUE_DEBUG) + printf("Begin queue_seqset seq = %d\n", (int)seq); + if (QUEUE_DEBUG) + printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), + sizeof(*peer)); - qmsg->seq = seq; - memcpy(&qmsg->peer, peer, sizeof(*peer)); + qmsg->seq = seq; + memcpy(&qmsg->peer, peer, sizeof(*peer)); - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) - qmsg_prev = qmsg2; - if (!qmsg_prev) - queue->hashseq[hash] = qmsg; - else - qmsg_prev->seqnext = qmsg; - if (QUEUE_DEBUG) printf("End queue_seqset\n"); - return 0; + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) + qmsg_prev = qmsg2; + if (!qmsg_prev) + queue->hashseq[hash] = qmsg; + else + qmsg_prev->seqnext = qmsg; + if (QUEUE_DEBUG) + printf("End queue_seqset\n"); + return 0; } +int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) +{ + int hash = queue_seqhash(&qmsg->peer, qmsg->seq); + struct qmsg_t *qmsg2; + struct qmsg_t *qmsg_prev = NULL; + if (QUEUE_DEBUG) + printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq); -int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) { - int hash = queue_seqhash(&qmsg->peer, qmsg->seq); - struct qmsg_t *qmsg2; - struct qmsg_t *qmsg_prev = NULL; - if (QUEUE_DEBUG) printf("Begin queue_seqdel seq = %d\n", (int) qmsg->seq); - - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { - if (qmsg == qmsg) { - if (!qmsg_prev) - queue->hashseq[hash] = qmsg2->seqnext; - else - qmsg_prev->seqnext = qmsg2->seqnext; - if (QUEUE_DEBUG) printf("End queue_seqset: SEQ found\n"); - return 0; - } - qmsg_prev = qmsg2; - } - printf("End queue_seqset: SEQ not found\n"); - return EOF; /* End of linked list and not found */ + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { + if (qmsg == qmsg) { + if (!qmsg_prev) + queue->hashseq[hash] = qmsg2->seqnext; + else + qmsg_prev->seqnext = qmsg2->seqnext; + if (QUEUE_DEBUG) + printf("End queue_seqset: SEQ found\n"); + return 0; + } + qmsg_prev = qmsg2; + } + printf("End queue_seqset: SEQ not found\n"); + return EOF; /* End of linked list and not found */ } - /* Allocates and initialises new queue structure */ -int queue_new(struct queue_t **queue) { - if (QUEUE_DEBUG) printf("queue_new\n"); - *queue = calloc(1, sizeof(struct queue_t)); - (*queue)->next = 0; - (*queue)->first = -1; - (*queue)->last = -1; +int queue_new(struct queue_t **queue) +{ + if (QUEUE_DEBUG) + printf("queue_new\n"); + *queue = calloc(1, sizeof(struct queue_t)); + (*queue)->next = 0; + (*queue)->first = -1; + (*queue)->last = -1; - if (QUEUE_DEBUG) queue_print(*queue); - if (*queue) return 0; - else return EOF; + if (QUEUE_DEBUG) + queue_print(*queue); + if (*queue) + return 0; + else + return EOF; } /* Deallocates queue structure */ -int queue_free(struct queue_t *queue) { - if (QUEUE_DEBUG) printf("queue_free\n"); - if (QUEUE_DEBUG) queue_print(queue); - free(queue); - return 0; +int queue_free(struct queue_t *queue) +{ + if (QUEUE_DEBUG) + printf("queue_free\n"); + if (QUEUE_DEBUG) + queue_print(queue); + free(queue); + return 0; } int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - if (QUEUE_DEBUG) printf("queue_newmsg %d\n", (int) seq); - if (queue->qmsga[queue->next].state == 1) { - return EOF; /* Queue is full */ - } - else { - *qmsg = &queue->qmsga[queue->next]; - queue_seqset(queue, *qmsg, peer, seq); - (*qmsg)->state = 1; /* Space taken */ - (*qmsg)->this = queue->next; - (*qmsg)->next=-1; /* End of the queue */ - (*qmsg)->prev=queue->last; /* Link to the previous */ - 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 */ - if (QUEUE_DEBUG) queue_print(queue); - return 0; - } + struct sockaddr_in *peer, uint16_t seq) +{ + if (QUEUE_DEBUG) + printf("queue_newmsg %d\n", (int)seq); + if (queue->qmsga[queue->next].state == 1) { + return EOF; /* Queue is full */ + } else { + *qmsg = &queue->qmsga[queue->next]; + queue_seqset(queue, *qmsg, peer, seq); + (*qmsg)->state = 1; /* Space taken */ + (*qmsg)->this = queue->next; + (*qmsg)->next = -1; /* End of the queue */ + (*qmsg)->prev = queue->last; /* Link to the previous */ + 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 */ + if (QUEUE_DEBUG) + queue_print(queue); + return 0; + } } -int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) { - if (QUEUE_DEBUG) printf("queue_freemsg\n"); - if (qmsg->state != 1) { - return EOF; /* Not in queue */ - } +int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) +{ + if (QUEUE_DEBUG) + printf("queue_freemsg\n"); + if (qmsg->state != 1) { + return EOF; /* Not in queue */ + } - queue_seqdel(queue, qmsg); + queue_seqdel(queue, qmsg); - if (qmsg->next == -1) /* Are we the last in queue? */ - queue->last = qmsg->prev; - else - queue->qmsga[qmsg->next].prev = qmsg->prev; - - if (qmsg->prev == -1) /* Are we the first in queue? */ - queue->first = qmsg->next; - else - queue->qmsga[qmsg->prev].next = qmsg->next; + if (qmsg->next == -1) /* Are we the last in queue? */ + queue->last = qmsg->prev; + else + queue->qmsga[qmsg->next].prev = qmsg->prev; - memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */ + if (qmsg->prev == -1) /* Are we the first in queue? */ + queue->first = qmsg->next; + else + queue->qmsga[qmsg->prev].next = qmsg->next; - if (QUEUE_DEBUG) queue_print(queue); + memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */ - return 0; + if (QUEUE_DEBUG) + queue_print(queue); + + return 0; } -int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) { - if (QUEUE_DEBUG) printf("queue_back\n"); - if (qmsg->state != 1) { - return EOF; /* Not in queue */ - } +int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) +{ + if (QUEUE_DEBUG) + printf("queue_back\n"); + if (qmsg->state != 1) { + return EOF; /* Not in queue */ + } - /* Insert stuff to maintain hash table */ + /* Insert stuff to maintain hash table */ - if (qmsg->next != -1) {/* Only swop if there are others */ - queue->qmsga[qmsg->next].prev = qmsg->prev; - queue->first = qmsg->next; - - qmsg->next = -1; - qmsg->prev = queue->last; - if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this; - queue->last = qmsg->this; - } - if (QUEUE_DEBUG) queue_print(queue); - return 0; + if (qmsg->next != -1) { /* Only swop if there are others */ + queue->qmsga[qmsg->next].prev = qmsg->prev; + queue->first = qmsg->next; + + qmsg->next = -1; + qmsg->prev = queue->last; + if (queue->last != -1) + queue->qmsga[queue->last].next = qmsg->this; + queue->last = qmsg->this; + } + if (QUEUE_DEBUG) + queue_print(queue); + return 0; } /* Get the element with a particular sequence number */ -int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) { - /*printf("queue_getfirst\n");*/ - if (queue->first == -1) { - *qmsg = NULL; - return EOF; /* End of queue = queue is empty. */ - } - *qmsg = &queue->qmsga[queue->first]; - if (QUEUE_DEBUG) queue_print(queue); - return 0; +int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) +{ + /*printf("queue_getfirst\n"); */ + if (queue->first == -1) { + *qmsg = NULL; + return EOF; /* End of queue = queue is empty. */ + } + *qmsg = &queue->qmsga[queue->first]; + if (QUEUE_DEBUG) + queue_print(queue); + return 0; } int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int n; - if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq); - if (QUEUE_DEBUG) queue_print(queue); - for (n=0; nqmsga[n].seq == seq) && - (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) { - *qmsg = &queue->qmsga[n]; - return 0; - } - } - return EOF; /* Not found */ + struct sockaddr_in *peer, uint16_t seq) +{ + int n; + if (QUEUE_DEBUG) + printf("queue_getseq, %d\n", (int)seq); + if (QUEUE_DEBUG) + queue_print(queue); + for (n = 0; n < QUEUE_SIZE; n++) { + if ((queue->qmsga[n].seq == seq) && + (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) { + *qmsg = &queue->qmsga[n]; + return 0; + } + } + return EOF; /* Not found */ } int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int hash = queue_seqhash(peer, seq); - struct qmsg_t *qmsg2; - if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq); - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { - if ((qmsg2->seq == seq) && - (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) { - *qmsg = qmsg2; - if (QUEUE_DEBUG) printf("End queue_seqget. Found\n"); - return 0; - } - } - if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n"); - return EOF; /* End of linked list and not found */ + struct sockaddr_in *peer, uint16_t seq) +{ + int hash = queue_seqhash(peer, seq); + struct qmsg_t *qmsg2; + if (QUEUE_DEBUG) + printf("Begin queue_seqget seq = %d\n", (int)seq); + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { + if ((qmsg2->seq == seq) && + (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) { + *qmsg = qmsg2; + if (QUEUE_DEBUG) + printf("End queue_seqget. Found\n"); + return 0; + } + } + if (QUEUE_DEBUG) + printf("End queue_seqget. Not found\n"); + return EOF; /* End of linked list and not found */ } -int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **cbp) { - struct qmsg_t *qmsg; - if (queue_seqget(queue, &qmsg, peer, seq)) { - *cbp = NULL; - *type = 0; - return EOF; - } - *cbp = qmsg->cbp; - *type = qmsg->type; - if (queue_freemsg(queue, qmsg)) { - return EOF; - } - return 0; +int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, + uint16_t seq, uint8_t * type, void **cbp) +{ + struct qmsg_t *qmsg; + if (queue_seqget(queue, &qmsg, peer, seq)) { + *cbp = NULL; + *type = 0; + return EOF; + } + *cbp = qmsg->cbp; + *type = qmsg->type; + if (queue_freemsg(queue, qmsg)) { + return EOF; + } + return 0; } diff --git a/gtp/queue.h b/gtp/queue.h index 46fa22d..556b6ef 100644 --- a/gtp/queue.h +++ b/gtp/queue.h @@ -17,37 +17,36 @@ #ifndef _QUEUE_H #define _QUEUE_H -#define QUEUE_DEBUG 0 /* Print debug information */ +#define QUEUE_DEBUG 0 /* Print debug information */ -#define QUEUE_SIZE 1024 /* Size of retransmission queue */ -#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */ +#define QUEUE_SIZE 1024 /* Size of retransmission queue */ +#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */ -struct qmsg_t { /* Holder for queued packets */ - int state; /* 0=empty, 1=full */ - uint16_t seq; /* The sequence number */ - uint8_t type; /* The type of packet */ - void *cbp; /* Application specific pointer */ - union gtp_packet p; /* The packet stored */ - int l; /* Length of the packet */ - int fd; /* Socket packet was sent to / received from */ - struct sockaddr_in peer;/* Address packet was sent to / received from */ - struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */ - int next; /* Pointer to the next in queue. -1: Last */ - int prev; /* Pointer to the previous in queue. -1: First */ - int this; /* Pointer to myself */ - time_t timeout; /* When do we retransmit this packet? */ - int retrans; /* How many times did we retransmit this? */ +struct qmsg_t { /* Holder for queued packets */ + int state; /* 0=empty, 1=full */ + uint16_t seq; /* The sequence number */ + uint8_t type; /* The type of packet */ + void *cbp; /* Application specific pointer */ + union gtp_packet p; /* The packet stored */ + int l; /* Length of the packet */ + int fd; /* Socket packet was sent to / received from */ + struct sockaddr_in peer; /* Address packet was sent to / received from */ + struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */ + int next; /* Pointer to the next in queue. -1: Last */ + int prev; /* Pointer to the previous in queue. -1: First */ + int this; /* Pointer to myself */ + time_t timeout; /* When do we retransmit this packet? */ + int retrans; /* How many times did we retransmit this? */ }; struct queue_t { - struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */ - void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */ - int next; /* Next location in queue to use */ - int first; /* First packet in queue (oldest timeout) */ - int last; /* Last packet in queue (youngest timeout) */ + struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */ + void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */ + int next; /* Next location in queue to use */ + int first; /* First packet in queue (oldest timeout) */ + int last; /* Last packet in queue (youngest timeout) */ }; - /* Allocates and initialises new queue structure */ int queue_new(struct queue_t **queue); /* Deallocates queue structure */ @@ -63,11 +62,9 @@ int queue_back(struct queue_t *queue, struct qmsg_t *qmsg); int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg); /* Get the element with a particular sequence number */ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq); + struct sockaddr_in *peer, uint16_t seq); /* Free message based on sequence number */ int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **cbp); - - -#endif /* !_QUEUE_H */ + uint16_t seq, uint8_t * type, void **cbp); +#endif /* !_QUEUE_H */ diff --git a/lib/getopt.c b/lib/getopt.c index 9bafa45..f6e2a8e 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -24,19 +24,19 @@ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO -# define _NO_PROTO +#define _NO_PROTO #endif #ifdef HAVE_CONFIG_H -# include +#include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ -# ifndef const -# define const -# endif +#ifndef const +#define const +#endif #endif #include @@ -51,41 +51,40 @@ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif #endif #ifndef ELIDE_CODE - /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ +#include +#include +#endif /* GNU C library. */ #ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif +#include +#if HAVE_STRING_H - 0 +#include +#endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ -# if defined HAVE_LIBINTL_H || defined _LIBC -# include -# ifndef _ -# define _(msgid) gettext (msgid) -# endif -# else -# define _(msgid) (msgid) -# endif +#if defined HAVE_LIBINTL_H || defined _LIBC +#include +#ifndef _ +#define _(msgid) gettext (msgid) +#endif +#else +#define _(msgid) (msgid) +#endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' @@ -182,9 +181,8 @@ int optopt = '?'; of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +static enum { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ @@ -195,35 +193,33 @@ static char *posixly_correct; because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ -# include -# define my_index strchr +#include +#define my_index strchr #else -# if HAVE_STRING_H -# include -# else -# include -# endif +#if HAVE_STRING_H +#include +#else +#include +#endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv -extern char *getenv (); +extern char *getenv(); #endif -static char * -my_index (str, chr) - const char *str; - int chr; +static char *my_index(str, chr) +const char *str; +int chr; { - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; + while (*str) { + if (*str == chr) + return (char *)str; + str++; + } + return 0; } /* If using GCC, we can safely declare strlen this way. @@ -231,11 +227,11 @@ my_index (str, chr) #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen +#if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ +extern int strlen(const char *); +#endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ @@ -259,28 +255,28 @@ extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ -# ifdef USE_NONOPTION_FLAGS +#ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; -# endif +#endif -# ifdef USE_NONOPTION_FLAGS -# define SWAP_FLAGS(ch1, ch2) \ +#ifdef USE_NONOPTION_FLAGS +#define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } -# else -# define SWAP_FLAGS(ch1, ch2) -# endif -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ +#else +#define SWAP_FLAGS(ch1, ch2) +#endif +#else /* !_LIBC */ +#define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) @@ -292,158 +288,145 @@ static int nonoption_flags_len; the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ -static void exchange (char **); +static void exchange(char **); #endif -static void -exchange (argv) - char **argv; +static void exchange(argv) +char **argv; { - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc(top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else { + memset(__mempcpy(new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } } - } #endif - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = + argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, + top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } + /* Update records for the slots the non-options now occupy. */ - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); +static const char *_getopt_initialize(int, char *const *, const char *); #endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +static const char *_getopt_initialize(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; { - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ - first_nonopt = last_nonopt = optind; + first_nonopt = last_nonopt = optind; - nextchar = NULL; + nextchar = NULL; - posixly_correct = getenv ("POSIXLY_CORRECT"); + posixly_correct = getenv("POSIXLY_CORRECT"); - /* Determine how to handle the ordering of options and nonoptions. */ + /* Determine how to handle the ordering of options and nonoptions. */ - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; + if (optstring[0] == '-') { + ordering = RETURN_IN_ORDER; + ++optstring; + } else if (optstring[0] == '+') { + ordering = REQUIRE_ORDER; + ++optstring; + } else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS - if (posixly_correct == NULL - && argc == __libc_argc && argv == __libc_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) { + if (nonoption_flags_max_len == 0) { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = + strlen(orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset(__mempcpy + (__getopt_nonoption_flags, + orig_str, len), '\0', + nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } else + nonoption_flags_len = 0; #endif - return optstring; + return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters @@ -502,554 +485,527 @@ _getopt_initialize (argc, argv, optstring) If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; +int _getopt_internal(argc, argv, optstring, longopts, longind, long_only) +int argc; +char *const *argv; +const char *optstring; +const struct option *longopts; +int *longind; +int long_only; { - int print_errors = opterr; - if (optstring[0] == ':') - print_errors = 0; + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; - if (argc < 1) - return -1; + if (argc < 1) + return -1; - optarg = NULL; + optarg = NULL; - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } + if (optind == 0 || !__getopt_initialized) { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize(argc, argv, optstring); + __getopt_initialized = 1; + } - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ + if (nextchar == NULL || *nextchar == '\0') { + /* Advance to the next ARGV-element. */ - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ + if (ordering == PERMUTE) { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; + if (first_nonopt != last_nonopt + && last_nonopt != optind) + exchange((char **)argv); + else if (last_nonopt != optind) + first_nonopt = optind; - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (print_errors) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - } - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp(argv[optind], "--")) { + optind++; + + if (first_nonopt != last_nonopt + && last_nonopt != optind) + exchange((char **)argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); } - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only + && (argv[optind][2] + || !my_index(optstring, argv[optind][1]))))) { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) { + if ((unsigned int)(nameend - nextchar) + == (unsigned int)strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) { + if (print_errors) + fprintf(stderr, + _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) { + option_index = indfound; + optind++; + if (*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else { + if (print_errors) { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf(stderr, + _ + ("%s: option `--%s' doesn't allow an argument\n"), + argv[0], + pfound->name); + else + /* +option or -option */ + fprintf(stderr, + _ + ("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], + argv[optind - + 1][0], + pfound->name); + } + + nextchar += strlen(nextchar); + + optopt = pfound->val; + return '?'; + } + } else if (pfound->has_arg == 1) { + if (optind < argc) + optarg = argv[optind++]; + else { + if (print_errors) + fprintf(stderr, + _ + ("%s: option `%s' requires an argument\n"), + argv[0], + argv[optind - 1]); + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index(optstring, *nextchar) == NULL) { + if (print_errors) { + if (argv[optind][1] == '-') + /* --option */ + fprintf(stderr, + _ + ("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf(stderr, + _ + ("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], + nextchar); + } + nextchar = (char *)""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + { - if (print_errors) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; + char c = *nextchar++; + char *temp = my_index(optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') { + if (print_errors) { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, + _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf(stderr, + _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if (optind == argc) { + if (print_errors) { + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, + _ + ("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; + *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp + (p->name, nextchar, nameend - nextchar)) { + if ((unsigned int)(nameend - + nextchar) == + strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) + fprintf(stderr, + _ + ("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen(nextchar); + optind++; + return '?'; + } + if (pfound != NULL) { + option_index = indfound; + if (*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else { + if (print_errors) + fprintf(stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); + + nextchar += strlen(nextchar); + return '?'; + } + } else if (pfound->has_arg == 1) { + if (optind < argc) + optarg = argv[optind++]; + else { + if (print_errors) + fprintf(stderr, + _ + ("%s: option `%s' requires an argument\n"), + argv[0], + argv[optind - + 1]); + nextchar += strlen(nextchar); + return optstring[0] == + ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') { + optarg = nextchar; + optind++; + } else + optarg = NULL; + nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if (optind == argc) { + if (print_errors) { + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, + _ + ("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (print_errors) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (print_errors) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } } -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +int getopt(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; { - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); + return _getopt_internal(argc, argv, optstring, + (const struct option *)0, (int *)0, 0); } -#endif /* Not ELIDE_CODE. */ +#endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ -int -main (argc, argv) - int argc; - char **argv; +int main(argc, argv) +int argc; +char **argv; { - int c; - int digit_optind = 0; + int c; + int digit_optind = 0; - while (1) - { - int this_option_optind = optind ? optind : 1; + while (1) { + int this_option_optind = optind ? optind : 1; - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; + c = getopt(argc, argv, "abc:d:0123456789"); + if (c == -1) + break; - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 + && digit_optind != this_option_optind) + printf + ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; - case 'a': - printf ("option a\n"); - break; + case 'a': + printf("option a\n"); + break; - case 'b': - printf ("option b\n"); - break; + case 'b': + printf("option b\n"); + break; - case 'c': - printf ("option c with value `%s'\n", optarg); - break; + case 'c': + printf("option c with value `%s'\n", optarg); + break; - case '?': - break; + case '?': + break; - default: - printf ("?? getopt returned character code 0%o ??\n", c); + default: + printf("?? getopt returned character code 0%o ??\n", c); + } } - } - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } - exit (0); + exit(0); } #endif /* TEST */ diff --git a/lib/getopt1.c b/lib/getopt1.c index 22a7efb..c4e4190 100644 --- a/lib/getopt1.c +++ b/lib/getopt1.c @@ -52,7 +52,6 @@ #ifndef ELIDE_CODE - /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ @@ -63,15 +62,15 @@ #define NULL 0 #endif -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +int getopt_long(argc, argv, options, long_options, opt_index) +int argc; +char *const *argv; +const char *options; +const struct option *long_options; +int *opt_index; { - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); + return _getopt_internal(argc, argv, options, long_options, opt_index, + 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. @@ -79,110 +78,106 @@ getopt_long (argc, argv, options, long_options, opt_index) but does match a short option, it is parsed as a short option instead. */ -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +int getopt_long_only(argc, argv, options, long_options, opt_index) +int argc; +char *const *argv; +const char *options; +const struct option *long_options; +int *opt_index; { - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); + return _getopt_internal(argc, argv, options, long_options, opt_index, + 1); } - -#endif /* Not ELIDE_CODE. */ +#endif /* Not ELIDE_CODE. */ #ifdef TEST #include -int -main (argc, argv) - int argc; - char **argv; +int main(argc, argv) +int argc; +char **argv; { - int c; - int digit_optind = 0; + int c; + int digit_optind = 0; - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; + while (1) { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; + c = getopt_long(argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; + switch (c) { + case 0: + printf("option %s", long_options[option_index].name); + if (optarg) + printf(" with arg %s", optarg); + printf("\n"); + break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 + && digit_optind != this_option_optind) + printf + ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; - case 'a': - printf ("option a\n"); - break; + case 'a': + printf("option a\n"); + break; - case 'b': - printf ("option b\n"); - break; + case 'b': + printf("option b\n"); + break; - case 'c': - printf ("option c with value `%s'\n", optarg); - break; + case 'c': + printf("option c with value `%s'\n", optarg); + break; - case 'd': - printf ("option d with value `%s'\n", optarg); - break; + case 'd': + printf("option d with value `%s'\n", optarg); + break; - case '?': - break; + case '?': + break; - default: - printf ("?? getopt returned character code 0%o ??\n", c); + default: + printf("?? getopt returned character code 0%o ??\n", c); + } } - } - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } - exit (0); + exit(0); } #endif /* TEST */ diff --git a/lib/gnugetopt.h b/lib/gnugetopt.h index a1b8dd6..31a693e 100644 --- a/lib/gnugetopt.h +++ b/lib/gnugetopt.h @@ -20,7 +20,7 @@ #ifndef _GETOPT_H #ifndef __need_getopt -# define _GETOPT_H 1 +#define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used @@ -31,7 +31,7 @@ if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ -# include +#include #endif #ifdef __cplusplus @@ -44,7 +44,7 @@ extern "C" { Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -extern char *optarg; + extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -58,16 +58,16 @@ extern char *optarg; Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ -extern int optind; + extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ -extern int opterr; + extern int opterr; /* Set to an option character which was unrecognized. */ -extern int optopt; + extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. @@ -91,27 +91,25 @@ extern int optopt; one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ -struct option -{ -# if (defined __STDC__ && __STDC__) || defined __cplusplus - const char *name; -# else - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; + struct option { +#if (defined __STDC__ && __STDC__) || defined __cplusplus + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; + }; /* Names for the values of the `has_arg' field of `struct option'. */ -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 +#endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for @@ -138,43 +136,44 @@ struct option `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus -# ifdef __GNU_LIBRARY__ +#ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ -extern int getopt (int __argc, char *const *__argv, const char *__shortopts); -# else /* not __GNU_LIBRARY__ */ -extern int getopt (); -# endif /* __GNU_LIBRARY__ */ + extern int getopt(int __argc, char *const *__argv, + const char *__shortopts); +#else /* not __GNU_LIBRARY__ */ + extern int getopt(); +#endif /* __GNU_LIBRARY__ */ -# ifndef __need_getopt -extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); +#ifndef __need_getopt + extern int getopt_long(int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + extern int getopt_long_only(int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, + int *__longind); /* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ -extern int getopt (); -# ifndef __need_getopt -extern int getopt_long (); -extern int getopt_long_only (); + extern int _getopt_internal(int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, + int *__longind, int __long_only); +#endif +#else /* not __STDC__ */ + extern int getopt(); +#ifndef __need_getopt + extern int getopt_long(); + extern int getopt_long_only(); -extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ + extern int _getopt_internal(); +#endif +#endif /* __STDC__ */ #ifdef __cplusplus } #endif - /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt - -#endif /* getopt.h */ +#endif /* getopt.h */ diff --git a/lib/ippool.c b/lib/ippool.c index fa3d8af..7ece1e8 100644 --- a/lib/ippool.c +++ b/lib/ippool.c @@ -10,9 +10,9 @@ */ #include -#include /* in_addr */ -#include /* calloc */ -#include /* sscanf */ +#include /* in_addr */ +#include /* calloc */ +#include /* sscanf */ #include #include #include @@ -21,312 +21,320 @@ #include "ippool.h" #include "lookup.h" +int ippool_printaddr(struct ippool_t *this) +{ + unsigned int n; + printf("ippool_printaddr\n"); + printf("Firstdyn %d\n", this->firstdyn - this->member); + printf("Lastdyn %d\n", this->lastdyn - this->member); + printf("Firststat %d\n", this->firststat - this->member); + printf("Laststat %d\n", this->laststat - this->member); + printf("Listsize %d\n", this->listsize); -int ippool_printaddr(struct ippool_t *this) { - unsigned int n; - printf("ippool_printaddr\n"); - printf("Firstdyn %d\n", this->firstdyn - this->member); - printf("Lastdyn %d\n", this->lastdyn - this->member); - printf("Firststat %d\n", this->firststat - this->member); - printf("Laststat %d\n", this->laststat - this->member); - printf("Listsize %d\n", this->listsize); - - for (n=0; nlistsize; n++) { - printf("Unit %d inuse %d prev %d next %d addr %s %x\n", - n, - this->member[n].inuse, - this->member[n].prev - this->member, - this->member[n].next - this->member, - inet_ntoa(this->member[n].addr), - this->member[n].addr.s_addr - ); - } - return 0; + for (n = 0; n < this->listsize; n++) { + printf("Unit %d inuse %d prev %d next %d addr %s %x\n", + n, + this->member[n].inuse, + this->member[n].prev - this->member, + this->member[n].next - this->member, + inet_ntoa(this->member[n].addr), + this->member[n].addr.s_addr); + } + return 0; } -int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member) { - uint32_t hash; - struct ippoolm_t *p; - struct ippoolm_t *p_prev = NULL; +int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member) +{ + uint32_t hash; + struct ippoolm_t *p; + struct ippoolm_t *p_prev = NULL; - /* Insert into hash table */ - hash = ippool_hash4(&member->addr) & this->hashmask; - for (p = this->hash[hash]; p; p = p->nexthash) - p_prev = p; - if (!p_prev) - this->hash[hash] = member; - else - p_prev->nexthash = member; - return 0; /* Always OK to insert */ + /* Insert into hash table */ + hash = ippool_hash4(&member->addr) & this->hashmask; + for (p = this->hash[hash]; p; p = p->nexthash) + p_prev = p; + if (!p_prev) + this->hash[hash] = member; + else + p_prev->nexthash = member; + return 0; /* Always OK to insert */ } -int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member) { - uint32_t hash; - struct ippoolm_t *p; - struct ippoolm_t *p_prev = NULL; +int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member) +{ + uint32_t hash; + struct ippoolm_t *p; + struct ippoolm_t *p_prev = NULL; - /* Find in hash table */ - hash = ippool_hash4(&member->addr) & this->hashmask; - for (p = this->hash[hash]; p; p = p->nexthash) { - if (p == member) { - break; - } - p_prev = p; - } + /* Find in hash table */ + hash = ippool_hash4(&member->addr) & this->hashmask; + for (p = this->hash[hash]; p; p = p->nexthash) { + if (p == member) { + break; + } + p_prev = p; + } - if (p!= member) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "ippool_hashdel: Tried to delete member not in hash table"); - return -1; - } + if (p != member) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "ippool_hashdel: Tried to delete member not in hash table"); + return -1; + } - if (!p_prev) - this->hash[hash] = p->nexthash; - else - p_prev->nexthash = p->nexthash; + if (!p_prev) + this->hash[hash] = p->nexthash; + else + p_prev->nexthash = p->nexthash; - return 0; + return 0; } - -unsigned long int ippool_hash4(struct in_addr *addr) { - return lookup((unsigned char*) &addr->s_addr, sizeof(addr->s_addr), 0); +unsigned long int ippool_hash4(struct in_addr *addr) +{ + return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0); } #ifndef IPPOOL_NOIP6 -unsigned long int ippool_hash6(struct in6_addr *addr) { - return lookup((unsigned char*) addr->u6_addr8, sizeof(addr->u6_addr8), 0); +unsigned long int ippool_hash6(struct in6_addr *addr) +{ + return lookup((unsigned char *)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) { + char *pool, int number) +{ - /* Parse only first instance of network for now */ - /* Eventually "number" will indicate the token which we want to parse */ + /* 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; - int m; - int masklog; + unsigned int a1, a2, a3, a4; + unsigned int m1, m2, m3, m4; + int c; + 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: - mask->s_addr = 0xffffffff; - break; - case 5: - if (m1 > 32) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); - return -1; /* Invalid mask */ - } - mask->s_addr = htonl(0xffffffff << (32 - m1)); - break; - case 8: - if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); - 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)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); - return -1; /* Wrong mask format (not all ones followed by all zeros)*/ - } - mask->s_addr = htonl(m); - break; - default: - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); - return -1; /* Invalid mask */ - } + c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u", + &a1, &a2, &a3, &a4, &m1, &m2, &m3, &m4); + switch (c) { + case 4: + mask->s_addr = 0xffffffff; + break; + case 5: + if (m1 > 32) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); + return -1; /* Invalid mask */ + } + mask->s_addr = htonl(0xffffffff << (32 - m1)); + break; + case 8: + if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); + 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)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); + return -1; /* Wrong mask format (not all ones followed by all zeros) */ + } + mask->s_addr = htonl(m); + break; + default: + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Invalid mask"); + return -1; /* Invalid mask */ + } - if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Wrong IP address format"); - return -1; - } - else - addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4); + if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Wrong IP address format"); + return -1; + } else + addr->s_addr = + htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4); - return 0; + return 0; } /* Create new address pool */ -int ippool_new(struct ippool_t **this, char *dyn, char *stat, - int allowdyn, int allowstat, int flags) { +int ippool_new(struct ippool_t **this, char *dyn, char *stat, + int allowdyn, int allowstat, int flags) +{ - /* Parse only first instance of pool for now */ + /* Parse only first instance of pool for now */ - int i; - struct in_addr addr; - struct in_addr mask; - struct in_addr stataddr; - struct in_addr statmask; - unsigned int m; - int listsize; - int dynsize; - unsigned int statsize; + int i; + struct in_addr addr; + struct in_addr mask; + struct in_addr stataddr; + struct in_addr statmask; + unsigned int m; + int listsize; + int dynsize; + unsigned int statsize; - if (!allowdyn) { - dynsize = 0; - } - else { - if (ippool_aton(&addr, &mask, dyn, 0)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to parse dynamic pool"); - return -1; - } + if (!allowdyn) { + dynsize = 0; + } else { + if (ippool_aton(&addr, &mask, dyn, 0)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to parse dynamic pool"); + return -1; + } - /* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */ - if (flags & IPPOOL_NOGATEWAY) { - flags |= IPPOOL_NONETWORK; - } - - m = ntohl(mask.s_addr); - dynsize = ((~m)+1); - if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */ - dynsize--; - if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */ - dynsize--; - if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */ - dynsize--; - } + /* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */ + if (flags & IPPOOL_NOGATEWAY) { + flags |= IPPOOL_NONETWORK; + } - if (!allowstat) { - statsize = 0; - stataddr.s_addr = 0; - statmask.s_addr = 0; - } - else { - if (ippool_aton(&stataddr, &statmask, stat, 0)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to parse static range"); - return -1; - } + m = ntohl(mask.s_addr); + dynsize = ((~m) + 1); + if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */ + dynsize--; + if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */ + dynsize--; + if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */ + dynsize--; + } - m = ntohl(statmask.s_addr); - statsize = ((~m)+1); - if (statsize > IPPOOL_STATSIZE) statsize = IPPOOL_STATSIZE; - } + if (!allowstat) { + statsize = 0; + stataddr.s_addr = 0; + statmask.s_addr = 0; + } else { + if (ippool_aton(&stataddr, &statmask, stat, 0)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to parse static range"); + return -1; + } - listsize = dynsize + statsize; /* Allocate space for static IP addresses */ + m = ntohl(statmask.s_addr); + statsize = ((~m) + 1); + if (statsize > IPPOOL_STATSIZE) + statsize = IPPOOL_STATSIZE; + } - if (!(*this = calloc(sizeof(struct ippool_t), 1))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to allocate memory for ippool"); - return -1; - } - - (*this)->allowdyn = allowdyn; - (*this)->allowstat = allowstat; - (*this)->stataddr = stataddr; - (*this)->statmask = statmask; + listsize = dynsize + statsize; /* Allocate space for static IP addresses */ - (*this)->listsize += listsize; - if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))){ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to allocate memory for members in ippool"); - return -1; - } - - for ((*this)->hashlog = 0; - ((1 << (*this)->hashlog) < listsize); - (*this)->hashlog++); + if (!(*this = calloc(sizeof(struct ippool_t), 1))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to allocate memory for ippool"); + return -1; + } - /* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */ + (*this)->allowdyn = allowdyn; + (*this)->allowstat = allowstat; + (*this)->stataddr = stataddr; + (*this)->statmask = statmask; - /* 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))){ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to allocate memory for hash members in ippool"); - return -1; - } - - (*this)->firstdyn = NULL; - (*this)->lastdyn = NULL; - for (i = 0; ilistsize += listsize; + if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to allocate memory for members in ippool"); + return -1; + } - if (flags & IPPOOL_NOGATEWAY) - (*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 2); - else 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; + for ((*this)->hashlog = 0; + ((1 << (*this)->hashlog) < listsize); (*this)->hashlog++) ; - /* Insert into list of unused */ - (*this)->member[i].prev = (*this)->lastdyn; - if ((*this)->lastdyn) { - (*this)->lastdyn->next = &((*this)->member[i]); - } - else { - (*this)->firstdyn = &((*this)->member[i]); - } - (*this)->lastdyn = &((*this)->member[i]); - (*this)->member[i].next = NULL; /* Redundant */ + /* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */ - ( void)ippool_hashadd(*this, &(*this)->member[i]); - } + /* Determine hashsize */ + (*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet */ + (*this)->hashmask = (*this)->hashsize - 1; - (*this)->firststat = NULL; - (*this)->laststat = NULL; - for (i = dynsize; ihash = + calloc(sizeof(struct ippoolm_t), (*this)->hashsize))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to allocate memory for hash members in ippool"); + return -1; + } - (*this)->member[i].addr.s_addr = 0; - (*this)->member[i].inuse = 0; + (*this)->firstdyn = NULL; + (*this)->lastdyn = NULL; + for (i = 0; i < dynsize; i++) { - /* Insert into list of unused */ - (*this)->member[i].prev = (*this)->laststat; - if ((*this)->laststat) { - (*this)->laststat->next = &((*this)->member[i]); - } - else { - (*this)->firststat = &((*this)->member[i]); - } - (*this)->laststat = &((*this)->member[i]); - (*this)->member[i].next = NULL; /* Redundant */ - } + if (flags & IPPOOL_NOGATEWAY) + (*this)->member[i].addr.s_addr = + htonl(ntohl(addr.s_addr) + i + 2); + else 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); - if (0) (void)ippool_printaddr(*this); - return 0; + (*this)->member[i].inuse = 0; + + /* Insert into list of unused */ + (*this)->member[i].prev = (*this)->lastdyn; + if ((*this)->lastdyn) { + (*this)->lastdyn->next = &((*this)->member[i]); + } else { + (*this)->firstdyn = &((*this)->member[i]); + } + (*this)->lastdyn = &((*this)->member[i]); + (*this)->member[i].next = NULL; /* Redundant */ + + (void)ippool_hashadd(*this, &(*this)->member[i]); + } + + (*this)->firststat = NULL; + (*this)->laststat = NULL; + for (i = dynsize; i < listsize; i++) { + + (*this)->member[i].addr.s_addr = 0; + (*this)->member[i].inuse = 0; + + /* Insert into list of unused */ + (*this)->member[i].prev = (*this)->laststat; + if ((*this)->laststat) { + (*this)->laststat->next = &((*this)->member[i]); + } else { + (*this)->firststat = &((*this)->member[i]); + } + (*this)->laststat = &((*this)->member[i]); + (*this)->member[i].next = NULL; /* Redundant */ + } + + if (0) + (void)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 */ +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; + 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)) { - if (member) *member = p; - return 0; - } - } - if (member) *member = NULL; - /*sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address could not be found");*/ - return -1; + /* 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)) { + if (member) + *member = p; + return 0; + } + } + if (member) + *member = NULL; + /*sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address could not be found"); */ + return -1; } /** @@ -337,188 +345,193 @@ int ippool_getip(struct ippool_t *this, struct ippoolm_t **member, * address space. **/ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member, - struct in_addr *addr, int statip) { - struct ippoolm_t *p; - struct ippoolm_t *p2 = NULL; - uint32_t hash; + struct in_addr *addr, int statip) +{ + struct ippoolm_t *p; + struct ippoolm_t *p2 = NULL; + uint32_t hash; - /* If static: - * Look in dynaddr. - * If found remove from firstdyn/lastdyn linked list. - * Else allocate from stataddr. - * Remove from firststat/laststat linked list. - * Insert into hash table. - * - * If dynamic - * Remove from firstdyn/lastdyn linked list. - * - */ + /* If static: + * Look in dynaddr. + * If found remove from firstdyn/lastdyn linked list. + * Else allocate from stataddr. + * Remove from firststat/laststat linked list. + * Insert into hash table. + * + * If dynamic + * Remove from firstdyn/lastdyn linked list. + * + */ - if (0) (void)ippool_printaddr(this); + if (0) + (void)ippool_printaddr(this); - /* First check to see if this type of address is allowed */ - if ((addr) && (addr->s_addr) && statip) { /* IP address given */ - if (!this->allowstat) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static IP address not allowed"); - return -1; - } - if ((addr->s_addr & this->statmask.s_addr) != this->stataddr.s_addr) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Static out of range"); - return -1; - } - } - else { - if (!this->allowdyn) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Dynamic IP address not allowed"); - return -1; - } - } + /* First check to see if this type of address is allowed */ + if ((addr) && (addr->s_addr) && statip) { /* IP address given */ + if (!this->allowstat) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Static IP address not allowed"); + return -1; + } + if ((addr->s_addr & this->statmask.s_addr) != + this->stataddr.s_addr) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Static out of range"); + return -1; + } + } else { + if (!this->allowdyn) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Dynamic IP address not allowed"); + return -1; + } + } - /* If IP address given try to find it in dynamic address pool */ - 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; - } - } - } + /* If IP address given try to find it in dynamic address pool */ + 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; + } + } + } - /* If IP was already allocated we can not use it */ - if ((!statip) && (p2) && (p2->inuse)) { - p2 = NULL; - } + /* If IP was already allocated we can not use it */ + if ((!statip) && (p2) && (p2->inuse)) { + p2 = NULL; + } - /* If not found yet and dynamic IP then allocate dynamic IP */ - if ((!p2) && (!statip)) { - if (!this ->firstdyn) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "No more IP addresses available"); - return -1; - } - else - p2 = this ->firstdyn; - } - - if (p2) { /* Was allocated from dynamic address pool */ - if (p2->inuse) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "IP address allready in use"); - return -1; /* Allready in use / Should not happen */ - } + /* If not found yet and dynamic IP then allocate dynamic IP */ + if ((!p2) && (!statip)) { + if (!this->firstdyn) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "No more IP addresses available"); + return -1; + } else + p2 = this->firstdyn; + } - /* Remove from linked list of free dynamic addresses */ - if (p2->prev) - p2->prev->next = p2->next; - else - this->firstdyn = p2->next; - if (p2->next) - p2->next->prev = p2->prev; - else - this->lastdyn = p2->prev; - p2->next = NULL; - p2->prev = NULL; - p2->inuse = 1; /* Dynamic address in use */ - - *member = p2; - if (0) (void)ippool_printaddr(this); - return 0; /* Success */ - } + if (p2) { /* Was allocated from dynamic address pool */ + if (p2->inuse) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "IP address allready in use"); + return -1; /* Allready in use / Should not happen */ + } - /* It was not possible to allocate from dynamic address pool */ - /* Try to allocate from static address space */ + /* Remove from linked list of free dynamic addresses */ + if (p2->prev) + p2->prev->next = p2->next; + else + this->firstdyn = p2->next; + if (p2->next) + p2->next->prev = p2->prev; + else + this->lastdyn = p2->prev; + p2->next = NULL; + p2->prev = NULL; + p2->inuse = 1; /* Dynamic address in use */ - if ((addr) && (addr->s_addr) && (statip)) { /* IP address given */ - if (!this->firststat) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "No more IP addresses available"); - return -1; /* No more available */ - } - else - p2 = this ->firststat; + *member = p2; + if (0) + (void)ippool_printaddr(this); + return 0; /* Success */ + } - /* Remove from linked list of free static addresses */ - if (p2->prev) - p2->prev->next = p2->next; - else - this->firststat = p2->next; - if (p2->next) - p2->next->prev = p2->prev; - else - this->laststat = p2->prev; - p2->next = NULL; - p2->prev = NULL; - p2->inuse = 2; /* Static address in use */ - memcpy(&p2->addr, addr, sizeof(addr)); - *member = p2; - (void)ippool_hashadd(this, *member); - if (0) (void)ippool_printaddr(this); - return 0; /* Success */ - } + /* It was not possible to allocate from dynamic address pool */ + /* Try to allocate from static address space */ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Could not allocate IP address"); - return -1; /* Should never get here. TODO: Bad code */ + if ((addr) && (addr->s_addr) && (statip)) { /* IP address given */ + if (!this->firststat) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "No more IP addresses available"); + return -1; /* No more available */ + } else + p2 = this->firststat; + + /* Remove from linked list of free static addresses */ + if (p2->prev) + p2->prev->next = p2->next; + else + this->firststat = p2->next; + if (p2->next) + p2->next->prev = p2->prev; + else + this->laststat = p2->prev; + p2->next = NULL; + p2->prev = NULL; + p2->inuse = 2; /* Static address in use */ + memcpy(&p2->addr, addr, sizeof(addr)); + *member = p2; + (void)ippool_hashadd(this, *member); + if (0) + (void)ippool_printaddr(this); + return 0; /* Success */ + } + + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Could not allocate IP address"); + return -1; /* Should never get here. TODO: Bad code */ } +int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member) +{ -int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member) { - - if (0) (void)ippool_printaddr(this); + if (0) + (void)ippool_printaddr(this); - if (!member->inuse) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use"); - return -1; /* Not in use: Should not happen */ - } + if (!member->inuse) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use"); + return -1; /* Not in use: Should not happen */ + } - switch (member->inuse) { - case 0: /* Not in use: Should not happen */ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use"); - return -1; - case 1: /* Allocated from dynamic address space */ - /* Insert into list of unused */ - member->prev = this->lastdyn; - if (this->lastdyn) { - this->lastdyn->next = member; - } - else { - this->firstdyn = member; - } - this->lastdyn = member; - - member->inuse = 0; - member->peer = NULL; - if (0) (void)ippool_printaddr(this); - return 0; - case 2: /* Allocated from static address space */ - if (ippool_hashdel(this, member)) - return -1; - /* Insert into list of unused */ - member->prev = this->laststat; - if (this->laststat) { - this->laststat->next = member; - } - else { - this->firststat = member; - } - this->laststat = member; - - member->inuse = 0; - member->addr.s_addr = 0; - member->peer = NULL; - member->nexthash = NULL; - if (0) (void)ippool_printaddr(this); - return 0; - default: /* Should not happen */ - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Could not free IP address"); - return -1; - } + switch (member->inuse) { + case 0: /* Not in use: Should not happen */ + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Address not in use"); + return -1; + case 1: /* Allocated from dynamic address space */ + /* Insert into list of unused */ + member->prev = this->lastdyn; + if (this->lastdyn) { + this->lastdyn->next = member; + } else { + this->firstdyn = member; + } + this->lastdyn = member; + + member->inuse = 0; + member->peer = NULL; + if (0) + (void)ippool_printaddr(this); + return 0; + case 2: /* Allocated from static address space */ + if (ippool_hashdel(this, member)) + return -1; + /* Insert into list of unused */ + member->prev = this->laststat; + if (this->laststat) { + this->laststat->next = member; + } else { + this->firststat = member; + } + this->laststat = member; + + member->inuse = 0; + member->addr.s_addr = 0; + member->peer = NULL; + member->nexthash = NULL; + if (0) + (void)ippool_printaddr(this); + return 0; + default: /* Should not happen */ + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Could not free IP address"); + return -1; + } } - #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); diff --git a/lib/ippool.h b/lib/ippool.h index 02691a6..534140d 100644 --- a/lib/ippool.h +++ b/lib/ippool.h @@ -34,35 +34,35 @@ #define IPPOOL_STATSIZE 0x10000 -struct ippoolm_t; /* Forward declaration */ +struct ippoolm_t; /* Forward declaration */ struct ippool_t { - unsigned int listsize; /* Total number of addresses */ - int allowdyn; /* Allow dynamic IP address allocation */ - int allowstat; /* Allow static IP address allocation */ - struct in_addr stataddr; /* Static address range network address */ - struct in_addr statmask; /* Static address range network mask */ - struct ippoolm_t *member; /* Listsize array of members */ - unsigned 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 *firstdyn; /* Pointer to first free dynamic member */ - struct ippoolm_t *lastdyn; /* Pointer to last free dynamic member */ - struct ippoolm_t *firststat; /* Pointer to first free static member */ - struct ippoolm_t *laststat; /* Pointer to last free static member */ + unsigned int listsize; /* Total number of addresses */ + int allowdyn; /* Allow dynamic IP address allocation */ + int allowstat; /* Allow static IP address allocation */ + struct in_addr stataddr; /* Static address range network address */ + struct in_addr statmask; /* Static address range network mask */ + struct ippoolm_t *member; /* Listsize array of members */ + unsigned 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 *firstdyn; /* Pointer to first free dynamic member */ + struct ippoolm_t *lastdyn; /* Pointer to last free dynamic member */ + struct ippoolm_t *firststat; /* Pointer to first free static member */ + struct ippoolm_t *laststat; /* Pointer to last free static member */ }; struct ippoolm_t { #ifndef IPPOOL_NOIP6 - struct in6_addr addr; /* IP address of this member */ + struct in6_addr addr; /* IP address of this member */ #else - struct in_addr addr; /* IP address of this member */ + struct in_addr addr; /* IP address of this member */ #endif - int inuse; /* 0=available; 1= dynamic; 2 = static */ - struct ippoolm_t *nexthash; /* Linked list part of hash table */ - struct ippoolm_t *prev, *next; /* Linked list of free dynamic or static */ - void *peer; /* Pointer to peer protocol handler */ + int inuse; /* 0=available; 1= dynamic; 2 = static */ + struct ippoolm_t *nexthash; /* Linked list part of hash table */ + struct ippoolm_t *prev, *next; /* Linked list of free dynamic or static */ + void *peer; /* Pointer to peer protocol handler */ }; /* The above structures require approximately 20+4 = 24 bytes for @@ -73,7 +73,7 @@ struct ippoolm_t { extern unsigned long int ippool_hash4(struct in_addr *addr); /* Create new address pool */ -extern int ippool_new(struct ippool_t **this, char *dyn, char *stat, +extern int ippool_new(struct ippool_t **this, char *dyn, char *stat, int allowdyn, int allowstat, int flags); /* Delete existing address pool */ @@ -81,7 +81,7 @@ 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); + 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 */ @@ -95,11 +95,10 @@ extern int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member); 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 */ +#endif /* !_IPPOOL_H */ diff --git a/lib/lookup.c b/lib/lookup.c index 02e2491..d2f13c4 100755 --- a/lib/lookup.c +++ b/lib/lookup.c @@ -17,10 +17,10 @@ * statistical properties and speed. It is NOT recommended 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*/ +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 */ { #define mix(a,b,c) \ @@ -36,45 +36,57 @@ register unsigned long int level; /* the previous hash, or an arbitrary value*/ c -= a; c -= b; c ^= (b>>15); \ } - typedef unsigned long int ub4; /* unsigned 4-byte quantities */ - typedef unsigned char ub1; /* unsigned 1-byte quantities */ - 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; -} + typedef unsigned long int ub4; /* unsigned 4-byte quantities */ + typedef unsigned char ub1; /* unsigned 1-byte quantities */ + 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; +} diff --git a/lib/lookup.h b/lib/lookup.h index 18b94c1..2df6c50 100755 --- a/lib/lookup.h +++ b/lib/lookup.h @@ -20,6 +20,7 @@ #ifndef _LOOKUP_H #define _LOOKUP_H -unsigned long int lookup( unsigned char *k, unsigned long int length, unsigned long int level); +unsigned long int lookup(unsigned char *k, unsigned long int length, + unsigned long int level); -#endif /* !_LOOKUP_H */ +#endif /* !_LOOKUP_H */ diff --git a/lib/syserr.c b/lib/syserr.c index 002d8c3..048cd45 100644 --- a/lib/syserr.c +++ b/lib/syserr.c @@ -20,52 +20,55 @@ #include "syserr.h" +void sys_err(int pri, char *fn, int ln, int en, char *fmt, ...) +{ + va_list args; + char buf[SYSERR_MSGSIZE]; -void sys_err(int pri, char *fn, int ln, int en, char *fmt, ...) { - va_list args; - char buf[SYSERR_MSGSIZE]; - - va_start(args, fmt); - vsnprintf(buf, SYSERR_MSGSIZE, fmt, args); - va_end(args); - buf[SYSERR_MSGSIZE-1] = 0; /* Make sure it is null terminated */ - if (en) - syslog(pri, "%s: %d: %d (%s) %s", fn, ln, en, strerror(en), buf); - else - syslog(pri, "%s: %d: %s", fn, ln, buf); + va_start(args, fmt); + vsnprintf(buf, SYSERR_MSGSIZE, fmt, args); + va_end(args); + buf[SYSERR_MSGSIZE - 1] = 0; /* Make sure it is null terminated */ + if (en) + syslog(pri, "%s: %d: %d (%s) %s", fn, ln, en, strerror(en), + buf); + else + syslog(pri, "%s: %d: %s", fn, ln, buf); } void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer, - void *pack, unsigned len, char *fmt, ...) { - - va_list args; - char buf[SYSERR_MSGSIZE]; - char buf2[SYSERR_MSGSIZE]; - unsigned int n; - int pos; - - va_start(args, fmt); - vsnprintf(buf, SYSERR_MSGSIZE, fmt, args); - va_end(args); - buf[SYSERR_MSGSIZE-1] = 0; + void *pack, unsigned len, char *fmt, ...) +{ - snprintf(buf2, SYSERR_MSGSIZE, "Packet from %s:%u, length: %d, content:", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port), - len); - buf2[SYSERR_MSGSIZE-1] = 0; - pos = strlen(buf2); - for(n=0; nsin_addr), ntohs(peer->sin_port), len); + buf2[SYSERR_MSGSIZE - 1] = 0; + pos = strlen(buf2); + for (n = 0; n < len; n++) { + if ((pos + 4) < SYSERR_MSGSIZE) { + sprintf((buf2 + pos), " %02hhx", + ((unsigned char *)pack)[n]); + pos += 3; + } + } + buf2[pos] = 0; + + if (en) + syslog(pri, "%s: %d: %d (%s) %s. %s", fn, ln, en, strerror(en), + buf, buf2); + else + syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2); } diff --git a/lib/syserr.h b/lib/syserr.h index a1ccb2d..e3ebdf0 100644 --- a/lib/syserr.h +++ b/lib/syserr.h @@ -18,4 +18,4 @@ void sys_err(int pri, char *filename, int en, int line, char *fmt, ...); void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer, void *pack, unsigned len, char *fmt, ...); -#endif /* !_SYSERR_H */ +#endif /* !_SYSERR_H */ diff --git a/lib/tun.c b/lib/tun.c index 03d057c..f2fb14a 100644 --- a/lib/tun.c +++ b/lib/tun.c @@ -16,7 +16,6 @@ * */ - #include #include #include @@ -64,76 +63,72 @@ #error "Unknown platform!" #endif - #include "tun.h" #include "syserr.h" - #if defined(__linux__) 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 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, __u32 *index) { - struct ifreq ifr; - int fd; +int tun_gifindex(struct tun_t *this, __u32 * index) +{ + 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 */ - 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; + 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; } #endif -int tun_sifflags(struct tun_t *this, int flags) { - struct ifreq ifr; - int fd; +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; + 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, @@ -232,390 +227,377 @@ int tun_addroute2(struct tun_t *this, int tun_addaddr(struct tun_t *this, struct in_addr *addr, - struct in_addr *dstaddr, - struct in_addr *netmask) { + struct in_addr *dstaddr, struct in_addr *netmask) +{ #if defined(__linux__) - struct { - struct nlmsghdr n; - struct ifaddrmsg i; - char buf[TUN_NLBUFSIZE]; - } req; - - struct sockaddr_nl local; - socklen_t addr_len; - int fd; - int status; - - struct sockaddr_nl nladdr; - struct iovec iov; - struct msghdr msg; + struct { + struct nlmsghdr n; + struct ifaddrmsg i; + char buf[TUN_NLBUFSIZE]; + } req; - if (!this->addrs) /* Use ioctl for first addr to make ping work */ - return tun_setaddr(this, addr, dstaddr, netmask); + struct sockaddr_nl local; + socklen_t addr_len; + int fd; + int status; - 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; - } + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg; - tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr)); - tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr)); + if (!this->addrs) /* Use ioctl for first addr to make ping work */ + return tun_setaddr(this, addr, dstaddr, netmask); - if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "socket() failed"); - return -1; - } + 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; + } - 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; - } + tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr)); + tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr)); - 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 ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "socket() failed"); + return -1; + } - if (addr_len != sizeof(local)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Wrong address length %d", addr_len); - close(fd); - return -1; - } + memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_groups = 0; - 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; + if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "bind() failed"); + close(fd); + return -1; + } - 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; + 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; + } - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; + if (addr_len != sizeof(local)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Wrong address length %d", addr_len); + close(fd); + return -1; + } - req.n.nlmsg_seq = 0; - req.n.nlmsg_flags |= NLM_F_ACK; + if (local.nl_family != AF_NETLINK) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Wrong address family %d", local.nl_family); + close(fd); + return -1; + } - status = sendmsg(fd, &msg, 0); /* TODO Error check */ + iov.iov_base = (void *)&req.n; + iov.iov_len = req.n.nlmsg_len; - tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */ - close(fd); - this->addrs++; - return 0; + 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); /* TODO */ + close(fd); + this->addrs++; + return 0; #elif defined (__FreeBSD__) || defined (__APPLE__) - int fd; - struct ifaliasreq areq; + int fd; + struct ifaliasreq areq; - /* TODO: Is this needed on FreeBSD? */ - if (!this->addrs) /* Use ioctl for first addr to make ping work */ - return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */ + /* TODO: Is this needed on FreeBSD? */ + if (!this->addrs) /* Use ioctl for first addr to make ping work */ + return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */ - memset(&areq, 0, sizeof(areq)); + memset(&areq, 0, sizeof(areq)); - /* Set up interface name */ - strncpy(areq.ifra_name, this->devname, IFNAMSIZ); - areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + /* Set up interface name */ + strncpy(areq.ifra_name, this->devname, IFNAMSIZ); + areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */ - ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET; - ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr); - ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr; + ((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET; + ((struct sockaddr_in *)&areq.ifra_addr)->sin_len = + sizeof(areq.ifra_addr); + ((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr; - ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET; - ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask); - ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr; + ((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET; + ((struct sockaddr_in *)&areq.ifra_mask)->sin_len = + sizeof(areq.ifra_mask); + ((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr = + netmask->s_addr; - /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */ - ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET; - ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len = - sizeof(areq.ifra_broadaddr); - ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr = - dstaddr->s_addr; + /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */ + ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len = + sizeof(areq.ifra_broadaddr); + ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr = + dstaddr->s_addr; - /* 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 (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "ioctl(SIOCAIFADDR) failed"); - close(fd); - return -1; - } + /* 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; + } - close(fd); - this->addrs++; - return 0; + if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "ioctl(SIOCAIFADDR) failed"); + close(fd); + return -1; + } + + close(fd); + this->addrs++; + return 0; #elif defined (__sun__) - - if (!this->addrs) /* Use ioctl for first addr to make ping work */ - return tun_setaddr(this, addr, dstaddr, netmask); - - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "Setting multiple addresses not possible on Solaris"); - return -1; + + if (!this->addrs) /* Use ioctl for first addr to make ping work */ + return tun_setaddr(this, addr, dstaddr, netmask); + + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Setting multiple addresses not possible on Solaris"); + return -1; #else #error "Unknown platform!" #endif - -} +} int tun_setaddr(struct tun_t *this, struct in_addr *addr, - struct in_addr *dstaddr, - struct in_addr *netmask) + struct in_addr *dstaddr, struct in_addr *netmask) { - struct ifreq ifr; - int fd; + struct ifreq ifr; + int fd; - memset (&ifr, '\0', sizeof (ifr)); - ifr.ifr_addr.sa_family = AF_INET; - ifr.ifr_dstaddr.sa_family = AF_INET; + memset(&ifr, '\0', sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_dstaddr.sa_family = AF_INET; #if defined(__linux__) - ifr.ifr_netmask.sa_family = AF_INET; + ifr.ifr_netmask.sa_family = AF_INET; #elif defined(__FreeBSD__) || defined (__APPLE__) - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_len = - sizeof (struct sockaddr_in); - ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len = - sizeof (struct sockaddr_in); + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_len = + sizeof(struct sockaddr_in); + ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len = + sizeof(struct sockaddr_in); #endif - strncpy(ifr.ifr_name, this->devname, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + 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; - } + /* 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; - memcpy(&((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr, addr, - sizeof(*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 (addr) { /* Set the interface address */ + this->addr.s_addr = addr->s_addr; + memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr, + sizeof(*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; - memcpy(&((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr, - dstaddr, sizeof(*dstaddr)); - if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "ioctl(SIOCSIFDSTADDR) failed"); - close(fd); - return -1; - } - } + if (dstaddr) { /* Set the destination address */ + this->dstaddr.s_addr = dstaddr->s_addr; + memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr, + dstaddr, sizeof(*dstaddr)); + 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; + if (netmask) { /* Set the netmask */ + this->netmask.s_addr = netmask->s_addr; #if defined(__linux__) - memcpy(&((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr, - netmask, sizeof(*netmask)); + memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr, + netmask, sizeof(*netmask)); #elif defined(__FreeBSD__) || defined (__APPLE__) - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = - netmask->s_addr; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = + netmask->s_addr; #elif defined(__sun__) - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = - netmask->s_addr; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = + netmask->s_addr; #else #error "Unknown platform!" #endif - 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++; - - /* On linux the route to the interface is set automatically - on FreeBSD we have to do this manually */ + if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "ioctl(SIOCSIFNETMASK) failed"); + close(fd); + return -1; + } + } - /* TODO: How does it work on Solaris? */ + close(fd); + this->addrs++; - tun_sifflags(this, IFF_UP | IFF_RUNNING); + /* On linux the route to the interface is set automatically + on FreeBSD we have to do this manually */ + + /* TODO: How does it work on Solaris? */ + + tun_sifflags(this, IFF_UP | IFF_RUNNING); #if defined(__FreeBSD__) || defined (__APPLE__) - tun_addroute(this, dstaddr, addr, netmask); - this->routes = 1; + tun_addroute(this, dstaddr, addr, netmask); + this->routes = 1; #endif - return 0; + return 0; } int tun_route(struct tun_t *this, struct in_addr *dst, - struct in_addr *gateway, - struct in_addr *mask, - int delete) + struct in_addr *gateway, struct in_addr *mask, int delete) { - - /* TODO: Learn how to set routing table on sun */ + /* TODO: Learn how to set routing table on sun */ #if defined(__linux__) - struct rtentry r; - int fd; + struct rtentry r; + int fd; - memset (&r, '\0', sizeof (r)); - r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */ + 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; - } + /* 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; + memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst)); + memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway, + sizeof(*gateway)); + memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask, + sizeof(*mask)); + + if (delete) { + if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "ioctl(SIOCDELRT) failed"); + close(fd); + return -1; + } + } else { + if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "ioctl(SIOCADDRT) failed"); + close(fd); + return -1; + } + } + close(fd); + return 0; - r.rt_dst.sa_family = AF_INET; - r.rt_gateway.sa_family = AF_INET; - r.rt_genmask.sa_family = AF_INET; - memcpy(&((struct sockaddr_in *) &r.rt_dst)->sin_addr, dst, sizeof(*dst)); - memcpy(&((struct sockaddr_in *) &r.rt_gateway)->sin_addr, gateway, - sizeof(*gateway)); - memcpy(&((struct sockaddr_in *) &r.rt_genmask)->sin_addr, mask, - sizeof(*mask)); - - if (delete) { - if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "ioctl(SIOCDELRT) failed"); - close(fd); - return -1; - } - } - else { - if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "ioctl(SIOCADDRT) failed"); - close(fd); - return -1; - } - } - close(fd); - return 0; - #elif defined(__FreeBSD__) || defined (__APPLE__) -struct { - struct rt_msghdr rt; - struct sockaddr_in dst; - struct sockaddr_in gate; - struct sockaddr_in mask; -} req; + struct { + struct rt_msghdr rt; + struct sockaddr_in dst; + struct sockaddr_in gate; + struct sockaddr_in mask; + } req; - int fd; - struct rt_msghdr *rtm; - - if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "socket() failed"); - return -1; - } - - memset(&req, 0x00, sizeof(req)); - - rtm = &req.rt; - - rtm->rtm_msglen = sizeof(req); - rtm->rtm_version = RTM_VERSION; - if (delete) { - rtm->rtm_type = RTM_DELETE; - } - else { - rtm->rtm_type = RTM_ADD; - } - rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */ - rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; - rtm->rtm_pid = getpid(); - rtm->rtm_seq = 0044; /* TODO */ - - req.dst.sin_family = AF_INET; - req.dst.sin_len = sizeof(req.dst); - req.mask.sin_family = AF_INET; - req.mask.sin_len = sizeof(req.mask); - req.gate.sin_family = AF_INET; - req.gate.sin_len = sizeof(req.gate); + int fd; + struct rt_msghdr *rtm; - req.dst.sin_addr.s_addr = dst->s_addr; - req.mask.sin_addr.s_addr = mask->s_addr; - req.gate.sin_addr.s_addr = gateway->s_addr; - - if(write(fd, rtm, rtm->rtm_msglen) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, - "write() failed"); - close(fd); - return -1; - } - close(fd); - return 0; + if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "socket() failed"); + return -1; + } + + memset(&req, 0x00, sizeof(req)); + + rtm = &req.rt; + + rtm->rtm_msglen = sizeof(req); + rtm->rtm_version = RTM_VERSION; + if (delete) { + rtm->rtm_type = RTM_DELETE; + } else { + rtm->rtm_type = RTM_ADD; + } + rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */ + rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + rtm->rtm_pid = getpid(); + rtm->rtm_seq = 0044; /* TODO */ + + req.dst.sin_family = AF_INET; + req.dst.sin_len = sizeof(req.dst); + req.mask.sin_family = AF_INET; + req.mask.sin_len = sizeof(req.mask); + req.gate.sin_family = AF_INET; + req.gate.sin_len = sizeof(req.gate); + + req.dst.sin_addr.s_addr = dst->s_addr; + req.mask.sin_addr.s_addr = mask->s_addr; + req.gate.sin_addr.s_addr = gateway->s_addr; + + if (write(fd, rtm, rtm->rtm_msglen) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "write() failed"); + close(fd); + return -1; + } + close(fd); + return 0; #elif defined(__sun__) - sys_err(LOG_WARNING, __FILE__, __LINE__, errno, - "Could not set up routing on Solaris. Please add route manually."); - return 0; - + sys_err(LOG_WARNING, __FILE__, __LINE__, errno, + "Could not set up routing on Solaris. Please add route manually."); + return 0; + #else #error "Unknown platform!" #endif @@ -624,172 +606,179 @@ struct { int tun_addroute(struct tun_t *this, struct in_addr *dst, - struct in_addr *gateway, - struct in_addr *mask) + struct in_addr *gateway, struct in_addr *mask) { - return tun_route(this, dst, gateway, mask, 0); + return tun_route(this, dst, gateway, mask, 0); } int tun_delroute(struct tun_t *this, struct in_addr *dst, - struct in_addr *gateway, - struct in_addr *mask) + struct in_addr *gateway, struct in_addr *mask) { - return tun_route(this, dst, gateway, mask, 1); + return tun_route(this, dst, gateway, mask, 1); } - int tun_new(struct tun_t **tun) { #if defined(__linux__) - struct ifreq ifr; + struct ifreq ifr; #elif defined(__FreeBSD__) || defined (__APPLE__) - char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */ - int devnum; - struct ifaliasreq areq; - int fd; + char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */ + int devnum; + struct ifaliasreq areq; + int fd; #elif defined(__sun__) - int if_fd, ppa = -1; - static int ip_fd = 0; - int muxid; - struct ifreq ifr; + int if_fd, ppa = -1; + static int ip_fd = 0; + int muxid; + struct ifreq ifr; #else #error "Unknown platform!" #endif - - 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; - (*tun)->routes = 0; - + + 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; + (*tun)->routes = 0; + #if defined(__linux__) - /* Open the actual tun device */ - if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed"); - return -1; - } - - /* Set device flags. For some weird reason this is also the method - used to obtain the network interface name */ - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */ - if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed"); - close((*tun)->fd); - return -1; - } - - strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ); - (*tun)->devname[IFNAMSIZ-1] = 0; - - ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */ - return 0; - + /* Open the actual tun device */ + if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed"); + return -1; + } + + /* Set device flags. For some weird reason this is also the method + used to obtain the network interface name */ + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */ + if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed"); + close((*tun)->fd); + return -1; + } + + strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ); + (*tun)->devname[IFNAMSIZ - 1] = 0; + + ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */ + return 0; + #elif defined(__FreeBSD__) || defined (__APPLE__) - /* Find suitable device */ - for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */ - snprintf(devname, sizeof(devname), "/dev/tun%d", devnum); - devname[sizeof(devname)] = 0; - if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break; - if (errno != EBUSY) break; - } - if ((*tun)->fd < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device"); - return -1; - } + /* Find suitable device */ + for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */ + snprintf(devname, sizeof(devname), "/dev/tun%d", devnum); + devname[sizeof(devname)] = 0; + if (((*tun)->fd = open(devname, O_RDWR)) >= 0) + break; + if (errno != EBUSY) + break; + } + if ((*tun)->fd < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't find tunnel device"); + return -1; + } - snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum); - (*tun)->devname[sizeof((*tun)->devname)] = 0; + snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum); + (*tun)->devname[sizeof((*tun)->devname)] = 0; - /* The tun device we found might have "old" IP addresses allocated */ - /* We need to delete those. This problem is not present on Linux */ + /* The tun device we found might have "old" IP addresses allocated */ + /* We need to delete those. This problem is not present on Linux */ - memset(&areq, 0, sizeof(areq)); + memset(&areq, 0, sizeof(areq)); - /* Set up interface name */ - strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ); - areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + /* Set up interface name */ + strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ); + areq.ifra_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; - } - - /* Delete any IP addresses until SIOCDIFADDR fails */ - while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1); + /* 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; + } - close(fd); - return 0; + /* Delete any IP addresses until SIOCDIFADDR fails */ + while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ; + + close(fd); + return 0; #elif defined(__sun__) - if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp"); - return -1; - } - - if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun"); - return -1; - } - - /* Assign a new PPA and get its unit number. */ - if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface"); - return -1; - } - - if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)"); - return -1; - } - if(ioctl(if_fd, I_PUSH, "ip") < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module"); - return -1; - } - - /* Assign ppa according to the unit number returned by tun device */ - if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){ - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa); - return -1; - } + if ((ip_fd = open("/dev/udp", O_RDWR, 0)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't open /dev/udp"); + return -1; + } - /* Link the two streams */ - if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP"); - return -1; - } + if (((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't open /dev/tun"); + return -1; + } - close (if_fd); - - snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa); - (*tun)->devname[sizeof((*tun)->devname)] = 0; + /* Assign a new PPA and get its unit number. */ + if ((ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't assign new interface"); + return -1; + } - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, (*tun)->devname); - ifr.ifr_ip_muxid = muxid; - - if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) { - ioctl(ip_fd, I_PUNLINK, muxid); - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id"); - return -1; - } - - /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) - msg (M_ERR, "Set file descriptor to non-blocking failed"); */ + if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't open /dev/tun (2)"); + return -1; + } + if (ioctl(if_fd, I_PUSH, "ip") < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't push IP module"); + return -1; + } - return 0; + /* Assign ppa according to the unit number returned by tun device */ + if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", + ppa); + return -1; + } + + /* Link the two streams */ + if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't link TUN device to IP"); + return -1; + } + + close(if_fd); + + snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa); + (*tun)->devname[sizeof((*tun)->devname)] = 0; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, (*tun)->devname); + ifr.ifr_ip_muxid = muxid; + + if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) { + ioctl(ip_fd, I_PUNLINK, muxid); + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Can't set multiplexor id"); + return -1; + } + + /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) + msg (M_ERR, "Set file descriptor to non-blocking failed"); */ + + return 0; #else #error "Unknown platform!" @@ -800,107 +789,106 @@ int tun_new(struct tun_t **tun) int tun_free(struct tun_t *tun) { - if (tun->routes) { - tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask); - } + if (tun->routes) { + tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask); + } - if (close(tun->fd)) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed"); - } + if (close(tun->fd)) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed"); + } - /* TODO: For solaris we need to unlink streams */ + /* TODO: For solaris we need to unlink streams */ - free(tun); - return 0; + free(tun); + return 0; } - -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_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) { #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) - 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); + unsigned char buffer[PACKET_MAX]; + int status; - return 0; + 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); + + return 0; #elif defined (__sun__) - unsigned char buffer[PACKET_MAX]; - struct strbuf sbuf; - int f = 0; - - sbuf.maxlen = PACKET_MAX; - sbuf.buf = buffer; - if (getmsg(this->fd, NULL, &sbuf, &f) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed"); - return -1; - } + unsigned char buffer[PACKET_MAX]; + struct strbuf sbuf; + int f = 0; - if (this->cb_ind) - return this->cb_ind(this, buffer, sbuf.len); + sbuf.maxlen = PACKET_MAX; + sbuf.buf = buffer; + if (getmsg(this->fd, NULL, &sbuf, &f) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed"); + return -1; + } + + if (this->cb_ind) + return this->cb_ind(this, buffer, sbuf.len); + + return 0; - return 0; - #endif } - int tun_encaps(struct tun_t *tun, void *pack, unsigned len) { #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) - return write(tun->fd, pack, len); + return write(tun->fd, pack, len); #elif defined (__sun__) - struct strbuf sbuf; - sbuf.len = len; - sbuf.buf = pack; - return putmsg(tun->fd, NULL, &sbuf, 0); + struct strbuf sbuf; + sbuf.len = len; + sbuf.buf = pack; + return putmsg(tun->fd, NULL, &sbuf, 0); #endif } -int tun_runscript(struct tun_t *tun, char* script) { - - char buf[TUN_SCRIPTSIZE]; - char snet[TUN_ADDRSIZE]; - char smask[TUN_ADDRSIZE]; - int rc; +int tun_runscript(struct tun_t *tun, char *script) +{ - 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; - rc = system(buf); - if (rc == -1) { - sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Error executing command %s", - buf); - return -1; - } - return 0; + char buf[TUN_SCRIPTSIZE]; + char snet[TUN_ADDRSIZE]; + char smask[TUN_ADDRSIZE]; + int rc; + + 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; + rc = system(buf); + if (rc == -1) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "Error executing command %s", buf); + return -1; + } + return 0; } diff --git a/lib/tun.h b/lib/tun.h index 7972c53..ce7b91c 100644 --- a/lib/tun.h +++ b/lib/tun.h @@ -12,44 +12,42 @@ #ifndef _TUN_H #define _TUN_H -#define PACKET_MAX 8196 /* Maximum packet size we receive */ +#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; + 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; }; - /* *********************************************************** * Information storage for each tun instance *************************************************************/ struct tun_t { - 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 */ - int routes; /* One if we allocated an automatic route */ - char devname[IFNAMSIZ];/* Name of the tun device */ - int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len); + 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 */ + int routes; /* One if we allocated an automatic route */ + char devname[IFNAMSIZ]; /* Name of the tun device */ + int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len); }; - extern int tun_new(struct tun_t **tun); extern int tun_free(struct tun_t *tun); extern int tun_decaps(struct tun_t *this); @@ -58,17 +56,16 @@ 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, +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, +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_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); -extern int tun_runscript(struct tun_t *tun, char* script); - -#endif /* !_TUN_H */ +#endif /* !_TUN_H */ diff --git a/sgsnemu/cmdline.c b/sgsnemu/cmdline.c index 1c4c041..1ff1a59 100644 --- a/sgsnemu/cmdline.c +++ b/sgsnemu/cmdline.c @@ -23,1560 +23,1732 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; +const char *gengetopt_args_info_usage = + "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; const char *gengetopt_args_info_help[] = { - " -h, --help Print help and exit", - " -V, --version Print version and exit", - " -d, --debug Run in debug mode (default=off)", - " -c, --conf=STRING Read configuration file", - " --pidfile=STRING Filename of process id file (default=`./sgsnemu.pid')", - " --statedir=STRING Directory of nonvolatile data (default=`./')", - " --dns=STRING DNS Server to use", - " -l, --listen=STRING Local interface", - " -r, --remote=STRING Remote host", - " --contexts=INT Number of contexts (default=`1')", - " --timelimit=INT Exit after timelimit seconds (default=`0')", - " --gtpversion=INT GTP version to use (default=`1')", - " -a, --apn=STRING Access point name (default=`internet')", - " --selmode=INT Selection mode (default=`0x01')", - " --rattype=INT Radio Access Technology Type (optional-1to5)", - " --userloc=STRING User Location Information (optional-type.MCC.MNC.LAC.CIorSACorRAC)", - " --rai=STRING Routing Area Information (optional-MCC.MNC.LAC.RAC)", - " --mstz=STRING MS Time Zone (optional- sign.NbQuartersOfAnHour.DSTAdjustment)", - " --imeisv=STRING IMEI(SV) International Mobile Equipment Identity (and Software Version) (optional,16 digits)", - " -i, --imsi=STRING IMSI (default=`240010123456789')", - " --nsapi=INT NSAPI (default=`0')", - " -m, --msisdn=STRING Mobile Station ISDN number (default=`46702123456')", - " -q, --qos=INT Requested quality of service (default=`0x000b921f')", - " --qose1=INT Requested quality of service Extension 1 (example=`0x9396404074f9ffff')", - " --qose2=INT Requested quality of service Extension 2 (example=`0x11')", - " --qose3=INT Requested quality of service Extension 3 (example=`0x0101')", - " --qose4=INT Requested quality of service Extension 4 (example=`0x4040')", - " --charging=INT Charging characteristics (default=`0x0800')", - " -u, --uid=STRING Login user ID (default=`mig')", - " -p, --pwd=STRING Login password (default=`hemmelig')", - " --createif Create local network interface (default=off)", - " -n, --net=STRING Network address for local interface", - " --defaultroute Create default route (default=off)", - " --ipup=STRING Script to run after link-up", - " --ipdown=STRING Script to run after link-down", - " --pinghost=STRING Ping remote host", - " --pingrate=INT Number of ping req per second (default=`1')", - " --pingsize=INT Number of ping data bytes (default=`56')", - " --pingcount=INT Number of ping req to send (default=`0')", - " --pingquiet Do not print ping packet info (default=off)", - " --norecovery Do not send recovery (default=off)", - 0 + " -h, --help Print help and exit", + " -V, --version Print version and exit", + " -d, --debug Run in debug mode (default=off)", + " -c, --conf=STRING Read configuration file", + " --pidfile=STRING Filename of process id file (default=`./sgsnemu.pid')", + " --statedir=STRING Directory of nonvolatile data (default=`./')", + " --dns=STRING DNS Server to use", + " -l, --listen=STRING Local interface", + " -r, --remote=STRING Remote host", + " --contexts=INT Number of contexts (default=`1')", + " --timelimit=INT Exit after timelimit seconds (default=`0')", + " --gtpversion=INT GTP version to use (default=`1')", + " -a, --apn=STRING Access point name (default=`internet')", + " --selmode=INT Selection mode (default=`0x01')", + " --rattype=INT Radio Access Technology Type (optional-1to5)", + " --userloc=STRING User Location Information (optional-type.MCC.MNC.LAC.CIorSACorRAC)", + " --rai=STRING Routing Area Information (optional-MCC.MNC.LAC.RAC)", + " --mstz=STRING MS Time Zone (optional- sign.NbQuartersOfAnHour.DSTAdjustment)", + " --imeisv=STRING IMEI(SV) International Mobile Equipment Identity (and Software Version) (optional,16 digits)", + " -i, --imsi=STRING IMSI (default=`240010123456789')", + " --nsapi=INT NSAPI (default=`0')", + " -m, --msisdn=STRING Mobile Station ISDN number (default=`46702123456')", + " -q, --qos=INT Requested quality of service (default=`0x000b921f')", + " --qose1=INT Requested quality of service Extension 1 (example=`0x9396404074f9ffff')", + " --qose2=INT Requested quality of service Extension 2 (example=`0x11')", + " --qose3=INT Requested quality of service Extension 3 (example=`0x0101')", + " --qose4=INT Requested quality of service Extension 4 (example=`0x4040')", + " --charging=INT Charging characteristics (default=`0x0800')", + " -u, --uid=STRING Login user ID (default=`mig')", + " -p, --pwd=STRING Login password (default=`hemmelig')", + " --createif Create local network interface (default=off)", + " -n, --net=STRING Network address for local interface", + " --defaultroute Create default route (default=off)", + " --ipup=STRING Script to run after link-up", + " --ipdown=STRING Script to run after link-down", + " --pinghost=STRING Ping remote host", + " --pingrate=INT Number of ping req per second (default=`1')", + " --pingsize=INT Number of ping data bytes (default=`56')", + " --pingcount=INT Number of ping req to send (default=`0')", + " --pingquiet Do not print ping packet info (default=off)", + " --norecovery Do not send recovery (default=off)", + 0 }; static -void clear_given (struct gengetopt_args_info *args_info); +void clear_given(struct gengetopt_args_info *args_info); static -void clear_args (struct gengetopt_args_info *args_info); +void clear_args(struct gengetopt_args_info *args_info); static int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error); +cmdline_parser_internal(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required, + const char *additional_error); -struct line_list -{ - char * string_arg; - struct line_list * next; +struct line_list { + char *string_arg; + struct line_list *next; }; static struct line_list *cmd_line_list = 0; static struct line_list *cmd_line_list_tmp = 0; -static void -free_cmd_list(void) +static void free_cmd_list(void) { - /* free the list of a previous call */ - if (cmd_line_list) - { - while (cmd_line_list) { - cmd_line_list_tmp = cmd_line_list; - cmd_line_list = cmd_line_list->next; - free (cmd_line_list_tmp->string_arg); - free (cmd_line_list_tmp); - } - } + /* free the list of a previous call */ + if (cmd_line_list) { + while (cmd_line_list) { + cmd_line_list_tmp = cmd_line_list; + cmd_line_list = cmd_line_list->next; + free(cmd_line_list_tmp->string_arg); + free(cmd_line_list_tmp); + } + } } - -static char * -gengetopt_strdup (const char *s); +static char *gengetopt_strdup(const char *s); static -void clear_given (struct gengetopt_args_info *args_info) +void clear_given(struct gengetopt_args_info *args_info) { - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->debug_given = 0 ; - args_info->conf_given = 0 ; - args_info->pidfile_given = 0 ; - args_info->statedir_given = 0 ; - args_info->dns_given = 0 ; - args_info->listen_given = 0 ; - args_info->remote_given = 0 ; - args_info->contexts_given = 0 ; - args_info->timelimit_given = 0 ; - args_info->gtpversion_given = 0 ; - args_info->apn_given = 0 ; - args_info->selmode_given = 0 ; - args_info->rattype_given = 0 ; - args_info->userloc_given = 0 ; - args_info->rai_given = 0 ; - args_info->mstz_given = 0 ; - args_info->imeisv_given = 0 ; - args_info->imsi_given = 0 ; - args_info->nsapi_given = 0 ; - args_info->msisdn_given = 0 ; - args_info->qos_given = 0 ; - args_info->qose1_given = 0 ; - args_info->qose2_given = 0 ; - args_info->qose3_given = 0 ; - args_info->qose4_given = 0 ; - args_info->charging_given = 0 ; - args_info->uid_given = 0 ; - args_info->pwd_given = 0 ; - args_info->createif_given = 0 ; - args_info->net_given = 0 ; - args_info->defaultroute_given = 0 ; - args_info->ipup_given = 0 ; - args_info->ipdown_given = 0 ; - args_info->pinghost_given = 0 ; - args_info->pingrate_given = 0 ; - args_info->pingsize_given = 0 ; - args_info->pingcount_given = 0 ; - args_info->pingquiet_given = 0 ; - args_info->norecovery_given = 0 ; + args_info->help_given = 0; + args_info->version_given = 0; + args_info->debug_given = 0; + args_info->conf_given = 0; + args_info->pidfile_given = 0; + args_info->statedir_given = 0; + args_info->dns_given = 0; + args_info->listen_given = 0; + args_info->remote_given = 0; + args_info->contexts_given = 0; + args_info->timelimit_given = 0; + args_info->gtpversion_given = 0; + args_info->apn_given = 0; + args_info->selmode_given = 0; + args_info->rattype_given = 0; + args_info->userloc_given = 0; + args_info->rai_given = 0; + args_info->mstz_given = 0; + args_info->imeisv_given = 0; + args_info->imsi_given = 0; + args_info->nsapi_given = 0; + args_info->msisdn_given = 0; + args_info->qos_given = 0; + args_info->qose1_given = 0; + args_info->qose2_given = 0; + args_info->qose3_given = 0; + args_info->qose4_given = 0; + args_info->charging_given = 0; + args_info->uid_given = 0; + args_info->pwd_given = 0; + args_info->createif_given = 0; + args_info->net_given = 0; + args_info->defaultroute_given = 0; + args_info->ipup_given = 0; + args_info->ipdown_given = 0; + args_info->pinghost_given = 0; + args_info->pingrate_given = 0; + args_info->pingsize_given = 0; + args_info->pingcount_given = 0; + args_info->pingquiet_given = 0; + args_info->norecovery_given = 0; } static -void clear_args (struct gengetopt_args_info *args_info) +void clear_args(struct gengetopt_args_info *args_info) { - args_info->debug_flag = 0; - args_info->conf_arg = NULL; - args_info->conf_orig = NULL; - args_info->pidfile_arg = gengetopt_strdup ("./sgsnemu.pid"); - args_info->pidfile_orig = NULL; - args_info->statedir_arg = gengetopt_strdup ("./"); - args_info->statedir_orig = NULL; - args_info->dns_arg = NULL; - args_info->dns_orig = NULL; - args_info->listen_arg = NULL; - args_info->listen_orig = NULL; - args_info->remote_arg = NULL; - args_info->remote_orig = NULL; - args_info->contexts_arg = 1; - args_info->contexts_orig = NULL; - args_info->timelimit_arg = 0; - args_info->timelimit_orig = NULL; - args_info->gtpversion_arg = 1; - args_info->gtpversion_orig = NULL; - args_info->apn_arg = gengetopt_strdup ("internet"); - args_info->apn_orig = NULL; - args_info->selmode_arg = 0x01; - args_info->selmode_orig = NULL; - args_info->rattype_arg = "1"; - args_info->rattype_orig = NULL; - args_info->userloc_arg = strdup("02509946241207"); - args_info->userloc_orig = NULL; - args_info->rai_arg = strdup("02509946241207"); - args_info->rai_orig = NULL; - args_info->mstz_arg = strdup("0"); - args_info->mstz_orig = NULL; - args_info->imeisv_arg = strdup("2143658709214365"); - args_info->imeisv_orig = NULL; - args_info->imsi_arg = gengetopt_strdup ("240010123456789"); - args_info->imsi_orig = NULL; - args_info->nsapi_arg = 0; - args_info->nsapi_orig = NULL; - args_info->msisdn_arg = gengetopt_strdup ("46702123456"); - args_info->msisdn_orig = NULL; - args_info->qos_arg = 0x000b921f; - args_info->qos_orig = NULL; - args_info->qose1_arg = 0x9396404074f9ffff; - args_info->qose1_orig = NULL; - args_info->qose2_arg = 0x11; - args_info->qose2_orig = NULL; - args_info->qose3_arg = 0x0101; - args_info->qose3_orig = NULL; - args_info->qose4_arg = 0x4040; - args_info->qose4_orig = NULL; - args_info->charging_arg = 0x0800; - args_info->charging_orig = NULL; - args_info->uid_arg = gengetopt_strdup ("mig"); - args_info->uid_orig = NULL; - args_info->pwd_arg = gengetopt_strdup ("hemmelig"); - args_info->pwd_orig = NULL; - args_info->createif_flag = 0; - args_info->net_arg = NULL; - args_info->net_orig = NULL; - args_info->defaultroute_flag = 0; - args_info->ipup_arg = NULL; - args_info->ipup_orig = NULL; - args_info->ipdown_arg = NULL; - args_info->ipdown_orig = NULL; - args_info->pinghost_arg = NULL; - args_info->pinghost_orig = NULL; - args_info->pingrate_arg = 1; - args_info->pingrate_orig = NULL; - args_info->pingsize_arg = 56; - args_info->pingsize_orig = NULL; - args_info->pingcount_arg = 0; - args_info->pingcount_orig = NULL; - args_info->pingquiet_flag = 0; - args_info->norecovery_flag = 0; - + args_info->debug_flag = 0; + args_info->conf_arg = NULL; + args_info->conf_orig = NULL; + args_info->pidfile_arg = gengetopt_strdup("./sgsnemu.pid"); + args_info->pidfile_orig = NULL; + args_info->statedir_arg = gengetopt_strdup("./"); + args_info->statedir_orig = NULL; + args_info->dns_arg = NULL; + args_info->dns_orig = NULL; + args_info->listen_arg = NULL; + args_info->listen_orig = NULL; + args_info->remote_arg = NULL; + args_info->remote_orig = NULL; + args_info->contexts_arg = 1; + args_info->contexts_orig = NULL; + args_info->timelimit_arg = 0; + args_info->timelimit_orig = NULL; + args_info->gtpversion_arg = 1; + args_info->gtpversion_orig = NULL; + args_info->apn_arg = gengetopt_strdup("internet"); + args_info->apn_orig = NULL; + args_info->selmode_arg = 0x01; + args_info->selmode_orig = NULL; + args_info->rattype_arg = "1"; + args_info->rattype_orig = NULL; + args_info->userloc_arg = strdup("02509946241207"); + args_info->userloc_orig = NULL; + args_info->rai_arg = strdup("02509946241207"); + args_info->rai_orig = NULL; + args_info->mstz_arg = strdup("0"); + args_info->mstz_orig = NULL; + args_info->imeisv_arg = strdup("2143658709214365"); + args_info->imeisv_orig = NULL; + args_info->imsi_arg = gengetopt_strdup("240010123456789"); + args_info->imsi_orig = NULL; + args_info->nsapi_arg = 0; + args_info->nsapi_orig = NULL; + args_info->msisdn_arg = gengetopt_strdup("46702123456"); + args_info->msisdn_orig = NULL; + args_info->qos_arg = 0x000b921f; + args_info->qos_orig = NULL; + args_info->qose1_arg = 0x9396404074f9ffff; + args_info->qose1_orig = NULL; + args_info->qose2_arg = 0x11; + args_info->qose2_orig = NULL; + args_info->qose3_arg = 0x0101; + args_info->qose3_orig = NULL; + args_info->qose4_arg = 0x4040; + args_info->qose4_orig = NULL; + args_info->charging_arg = 0x0800; + args_info->charging_orig = NULL; + args_info->uid_arg = gengetopt_strdup("mig"); + args_info->uid_orig = NULL; + args_info->pwd_arg = gengetopt_strdup("hemmelig"); + args_info->pwd_orig = NULL; + args_info->createif_flag = 0; + args_info->net_arg = NULL; + args_info->net_orig = NULL; + args_info->defaultroute_flag = 0; + args_info->ipup_arg = NULL; + args_info->ipup_orig = NULL; + args_info->ipdown_arg = NULL; + args_info->ipdown_orig = NULL; + args_info->pinghost_arg = NULL; + args_info->pinghost_orig = NULL; + args_info->pingrate_arg = 1; + args_info->pingrate_orig = NULL; + args_info->pingsize_arg = 56; + args_info->pingsize_orig = NULL; + args_info->pingcount_arg = 0; + args_info->pingcount_orig = NULL; + args_info->pingquiet_flag = 0; + args_info->norecovery_flag = 0; + } static void init_args_info(struct gengetopt_args_info *args_info) { - args_info->help_help = gengetopt_args_info_help[0] ; - args_info->version_help = gengetopt_args_info_help[1] ; - args_info->debug_help = gengetopt_args_info_help[2] ; - args_info->conf_help = gengetopt_args_info_help[3] ; - args_info->pidfile_help = gengetopt_args_info_help[4] ; - args_info->statedir_help = gengetopt_args_info_help[5] ; - args_info->dns_help = gengetopt_args_info_help[6] ; - args_info->listen_help = gengetopt_args_info_help[7] ; - args_info->remote_help = gengetopt_args_info_help[8] ; - args_info->contexts_help = gengetopt_args_info_help[9] ; - args_info->timelimit_help = gengetopt_args_info_help[10] ; - args_info->gtpversion_help = gengetopt_args_info_help[11] ; - args_info->apn_help = gengetopt_args_info_help[12] ; - args_info->selmode_help = gengetopt_args_info_help[13] ; - args_info->imsi_help = gengetopt_args_info_help[14] ; - args_info->nsapi_help = gengetopt_args_info_help[15] ; - args_info->msisdn_help = gengetopt_args_info_help[16] ; - args_info->qos_help = gengetopt_args_info_help[17] ; - args_info->charging_help = gengetopt_args_info_help[18] ; - args_info->uid_help = gengetopt_args_info_help[19] ; - args_info->pwd_help = gengetopt_args_info_help[20] ; - args_info->createif_help = gengetopt_args_info_help[21] ; - args_info->net_help = gengetopt_args_info_help[22] ; - args_info->defaultroute_help = gengetopt_args_info_help[23] ; - args_info->ipup_help = gengetopt_args_info_help[24] ; - args_info->ipdown_help = gengetopt_args_info_help[25] ; - args_info->pinghost_help = gengetopt_args_info_help[26] ; - args_info->pingrate_help = gengetopt_args_info_help[27] ; - args_info->pingsize_help = gengetopt_args_info_help[28] ; - args_info->pingcount_help = gengetopt_args_info_help[29] ; - args_info->pingquiet_help = gengetopt_args_info_help[30] ; - args_info->norecovery_help = gengetopt_args_info_help[31] ; - + args_info->help_help = gengetopt_args_info_help[0]; + args_info->version_help = gengetopt_args_info_help[1]; + args_info->debug_help = gengetopt_args_info_help[2]; + args_info->conf_help = gengetopt_args_info_help[3]; + args_info->pidfile_help = gengetopt_args_info_help[4]; + args_info->statedir_help = gengetopt_args_info_help[5]; + args_info->dns_help = gengetopt_args_info_help[6]; + args_info->listen_help = gengetopt_args_info_help[7]; + args_info->remote_help = gengetopt_args_info_help[8]; + args_info->contexts_help = gengetopt_args_info_help[9]; + args_info->timelimit_help = gengetopt_args_info_help[10]; + args_info->gtpversion_help = gengetopt_args_info_help[11]; + args_info->apn_help = gengetopt_args_info_help[12]; + args_info->selmode_help = gengetopt_args_info_help[13]; + args_info->imsi_help = gengetopt_args_info_help[14]; + args_info->nsapi_help = gengetopt_args_info_help[15]; + args_info->msisdn_help = gengetopt_args_info_help[16]; + args_info->qos_help = gengetopt_args_info_help[17]; + args_info->charging_help = gengetopt_args_info_help[18]; + args_info->uid_help = gengetopt_args_info_help[19]; + args_info->pwd_help = gengetopt_args_info_help[20]; + args_info->createif_help = gengetopt_args_info_help[21]; + args_info->net_help = gengetopt_args_info_help[22]; + args_info->defaultroute_help = gengetopt_args_info_help[23]; + args_info->ipup_help = gengetopt_args_info_help[24]; + args_info->ipdown_help = gengetopt_args_info_help[25]; + args_info->pinghost_help = gengetopt_args_info_help[26]; + args_info->pingrate_help = gengetopt_args_info_help[27]; + args_info->pingsize_help = gengetopt_args_info_help[28]; + args_info->pingcount_help = gengetopt_args_info_help[29]; + args_info->pingquiet_help = gengetopt_args_info_help[30]; + args_info->norecovery_help = gengetopt_args_info_help[31]; + } -void -cmdline_parser_print_version (void) +void cmdline_parser_print_version(void) { - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); + printf("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); } -void -cmdline_parser_print_help (void) +void cmdline_parser_print_help(void) { - int i = 0; - cmdline_parser_print_version (); + int i = 0; + cmdline_parser_print_version(); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); - printf("\n%s\n\n", gengetopt_args_info_usage); - while (gengetopt_args_info_help[i]) - printf("%s\n", gengetopt_args_info_help[i++]); + printf("\n%s\n\n", gengetopt_args_info_usage); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); } -void -cmdline_parser_init (struct gengetopt_args_info *args_info) +void cmdline_parser_init(struct gengetopt_args_info *args_info) { - clear_given (args_info); - clear_args (args_info); - init_args_info (args_info); + clear_given(args_info); + clear_args(args_info); + init_args_info(args_info); } -static void -cmdline_parser_release (struct gengetopt_args_info *args_info) +static void cmdline_parser_release(struct gengetopt_args_info *args_info) { - - if (args_info->conf_arg) - { - free (args_info->conf_arg); /* free previous argument */ - args_info->conf_arg = 0; - } - if (args_info->conf_orig) - { - free (args_info->conf_orig); /* free previous argument */ - args_info->conf_orig = 0; - } - if (args_info->pidfile_arg) - { - free (args_info->pidfile_arg); /* free previous argument */ - args_info->pidfile_arg = 0; - } - if (args_info->pidfile_orig) - { - free (args_info->pidfile_orig); /* free previous argument */ - args_info->pidfile_orig = 0; - } - if (args_info->statedir_arg) - { - free (args_info->statedir_arg); /* free previous argument */ - args_info->statedir_arg = 0; - } - if (args_info->statedir_orig) - { - free (args_info->statedir_orig); /* free previous argument */ - args_info->statedir_orig = 0; - } - if (args_info->dns_arg) - { - free (args_info->dns_arg); /* free previous argument */ - args_info->dns_arg = 0; - } - if (args_info->dns_orig) - { - free (args_info->dns_orig); /* free previous argument */ - args_info->dns_orig = 0; - } - if (args_info->listen_arg) - { - free (args_info->listen_arg); /* free previous argument */ - args_info->listen_arg = 0; - } - if (args_info->listen_orig) - { - free (args_info->listen_orig); /* free previous argument */ - args_info->listen_orig = 0; - } - if (args_info->remote_arg) - { - free (args_info->remote_arg); /* free previous argument */ - args_info->remote_arg = 0; - } - if (args_info->remote_orig) - { - free (args_info->remote_orig); /* free previous argument */ - args_info->remote_orig = 0; - } - if (args_info->contexts_orig) - { - free (args_info->contexts_orig); /* free previous argument */ - args_info->contexts_orig = 0; - } - if (args_info->timelimit_orig) - { - free (args_info->timelimit_orig); /* free previous argument */ - args_info->timelimit_orig = 0; - } - if (args_info->gtpversion_orig) - { - free (args_info->gtpversion_orig); /* free previous argument */ - args_info->gtpversion_orig = 0; - } - if (args_info->apn_arg) - { - free (args_info->apn_arg); /* free previous argument */ - args_info->apn_arg = 0; - } - if (args_info->apn_orig) - { - free (args_info->apn_orig); /* free previous argument */ - args_info->apn_orig = 0; - } - if (args_info->selmode_orig) - { - free (args_info->selmode_orig); /* free previous argument */ - args_info->selmode_orig = 0; - } - if (args_info->imsi_arg) - { - free (args_info->imsi_arg); /* free previous argument */ - args_info->imsi_arg = 0; - } - if (args_info->imsi_orig) - { - free (args_info->imsi_orig); /* free previous argument */ - args_info->imsi_orig = 0; - } - if (args_info->nsapi_orig) - { - free (args_info->nsapi_orig); /* free previous argument */ - args_info->nsapi_orig = 0; - } - if (args_info->msisdn_arg) - { - free (args_info->msisdn_arg); /* free previous argument */ - args_info->msisdn_arg = 0; - } - if (args_info->msisdn_orig) - { - free (args_info->msisdn_orig); /* free previous argument */ - args_info->msisdn_orig = 0; - } - if (args_info->qos_orig) - { - free (args_info->qos_orig); /* free previous argument */ - args_info->qos_orig = 0; - } - if (args_info->charging_orig) - { - free (args_info->charging_orig); /* free previous argument */ - args_info->charging_orig = 0; - } - if (args_info->uid_arg) - { - free (args_info->uid_arg); /* free previous argument */ - args_info->uid_arg = 0; - } - if (args_info->uid_orig) - { - free (args_info->uid_orig); /* free previous argument */ - args_info->uid_orig = 0; - } - if (args_info->pwd_arg) - { - free (args_info->pwd_arg); /* free previous argument */ - args_info->pwd_arg = 0; - } - if (args_info->pwd_orig) - { - free (args_info->pwd_orig); /* free previous argument */ - args_info->pwd_orig = 0; - } - if (args_info->net_arg) - { - free (args_info->net_arg); /* free previous argument */ - args_info->net_arg = 0; - } - if (args_info->net_orig) - { - free (args_info->net_orig); /* free previous argument */ - args_info->net_orig = 0; - } - if (args_info->ipup_arg) - { - free (args_info->ipup_arg); /* free previous argument */ - args_info->ipup_arg = 0; - } - if (args_info->ipup_orig) - { - free (args_info->ipup_orig); /* free previous argument */ - args_info->ipup_orig = 0; - } - if (args_info->ipdown_arg) - { - free (args_info->ipdown_arg); /* free previous argument */ - args_info->ipdown_arg = 0; - } - if (args_info->ipdown_orig) - { - free (args_info->ipdown_orig); /* free previous argument */ - args_info->ipdown_orig = 0; - } - if (args_info->pinghost_arg) - { - free (args_info->pinghost_arg); /* free previous argument */ - args_info->pinghost_arg = 0; - } - if (args_info->pinghost_orig) - { - free (args_info->pinghost_orig); /* free previous argument */ - args_info->pinghost_orig = 0; - } - if (args_info->pingrate_orig) - { - free (args_info->pingrate_orig); /* free previous argument */ - args_info->pingrate_orig = 0; - } - if (args_info->pingsize_orig) - { - free (args_info->pingsize_orig); /* free previous argument */ - args_info->pingsize_orig = 0; - } - if (args_info->pingcount_orig) - { - free (args_info->pingcount_orig); /* free previous argument */ - args_info->pingcount_orig = 0; - } - - clear_given (args_info); + + if (args_info->conf_arg) { + free(args_info->conf_arg); /* free previous argument */ + args_info->conf_arg = 0; + } + if (args_info->conf_orig) { + free(args_info->conf_orig); /* free previous argument */ + args_info->conf_orig = 0; + } + if (args_info->pidfile_arg) { + free(args_info->pidfile_arg); /* free previous argument */ + args_info->pidfile_arg = 0; + } + if (args_info->pidfile_orig) { + free(args_info->pidfile_orig); /* free previous argument */ + args_info->pidfile_orig = 0; + } + if (args_info->statedir_arg) { + free(args_info->statedir_arg); /* free previous argument */ + args_info->statedir_arg = 0; + } + if (args_info->statedir_orig) { + free(args_info->statedir_orig); /* free previous argument */ + args_info->statedir_orig = 0; + } + if (args_info->dns_arg) { + free(args_info->dns_arg); /* free previous argument */ + args_info->dns_arg = 0; + } + if (args_info->dns_orig) { + free(args_info->dns_orig); /* free previous argument */ + args_info->dns_orig = 0; + } + if (args_info->listen_arg) { + free(args_info->listen_arg); /* free previous argument */ + args_info->listen_arg = 0; + } + if (args_info->listen_orig) { + free(args_info->listen_orig); /* free previous argument */ + args_info->listen_orig = 0; + } + if (args_info->remote_arg) { + free(args_info->remote_arg); /* free previous argument */ + args_info->remote_arg = 0; + } + if (args_info->remote_orig) { + free(args_info->remote_orig); /* free previous argument */ + args_info->remote_orig = 0; + } + if (args_info->contexts_orig) { + free(args_info->contexts_orig); /* free previous argument */ + args_info->contexts_orig = 0; + } + if (args_info->timelimit_orig) { + free(args_info->timelimit_orig); /* free previous argument */ + args_info->timelimit_orig = 0; + } + if (args_info->gtpversion_orig) { + free(args_info->gtpversion_orig); /* free previous argument */ + args_info->gtpversion_orig = 0; + } + if (args_info->apn_arg) { + free(args_info->apn_arg); /* free previous argument */ + args_info->apn_arg = 0; + } + if (args_info->apn_orig) { + free(args_info->apn_orig); /* free previous argument */ + args_info->apn_orig = 0; + } + if (args_info->selmode_orig) { + free(args_info->selmode_orig); /* free previous argument */ + args_info->selmode_orig = 0; + } + if (args_info->imsi_arg) { + free(args_info->imsi_arg); /* free previous argument */ + args_info->imsi_arg = 0; + } + if (args_info->imsi_orig) { + free(args_info->imsi_orig); /* free previous argument */ + args_info->imsi_orig = 0; + } + if (args_info->nsapi_orig) { + free(args_info->nsapi_orig); /* free previous argument */ + args_info->nsapi_orig = 0; + } + if (args_info->msisdn_arg) { + free(args_info->msisdn_arg); /* free previous argument */ + args_info->msisdn_arg = 0; + } + if (args_info->msisdn_orig) { + free(args_info->msisdn_orig); /* free previous argument */ + args_info->msisdn_orig = 0; + } + if (args_info->qos_orig) { + free(args_info->qos_orig); /* free previous argument */ + args_info->qos_orig = 0; + } + if (args_info->charging_orig) { + free(args_info->charging_orig); /* free previous argument */ + args_info->charging_orig = 0; + } + if (args_info->uid_arg) { + free(args_info->uid_arg); /* free previous argument */ + args_info->uid_arg = 0; + } + if (args_info->uid_orig) { + free(args_info->uid_orig); /* free previous argument */ + args_info->uid_orig = 0; + } + if (args_info->pwd_arg) { + free(args_info->pwd_arg); /* free previous argument */ + args_info->pwd_arg = 0; + } + if (args_info->pwd_orig) { + free(args_info->pwd_orig); /* free previous argument */ + args_info->pwd_orig = 0; + } + if (args_info->net_arg) { + free(args_info->net_arg); /* free previous argument */ + args_info->net_arg = 0; + } + if (args_info->net_orig) { + free(args_info->net_orig); /* free previous argument */ + args_info->net_orig = 0; + } + if (args_info->ipup_arg) { + free(args_info->ipup_arg); /* free previous argument */ + args_info->ipup_arg = 0; + } + if (args_info->ipup_orig) { + free(args_info->ipup_orig); /* free previous argument */ + args_info->ipup_orig = 0; + } + if (args_info->ipdown_arg) { + free(args_info->ipdown_arg); /* free previous argument */ + args_info->ipdown_arg = 0; + } + if (args_info->ipdown_orig) { + free(args_info->ipdown_orig); /* free previous argument */ + args_info->ipdown_orig = 0; + } + if (args_info->pinghost_arg) { + free(args_info->pinghost_arg); /* free previous argument */ + args_info->pinghost_arg = 0; + } + if (args_info->pinghost_orig) { + free(args_info->pinghost_orig); /* free previous argument */ + args_info->pinghost_orig = 0; + } + if (args_info->pingrate_orig) { + free(args_info->pingrate_orig); /* free previous argument */ + args_info->pingrate_orig = 0; + } + if (args_info->pingsize_orig) { + free(args_info->pingsize_orig); /* free previous argument */ + args_info->pingsize_orig = 0; + } + if (args_info->pingcount_orig) { + free(args_info->pingcount_orig); /* free previous argument */ + args_info->pingcount_orig = 0; + } + + clear_given(args_info); } int -cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info) { - FILE *outfile; - int i = 0; + FILE *outfile; + int i = 0; - outfile = fopen(filename, "w"); + outfile = fopen(filename, "w"); - if (!outfile) - { - fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); - return EXIT_FAILURE; - } + if (!outfile) { + fprintf(stderr, "%s: cannot open file for writing: %s\n", + CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } - if (args_info->help_given) { - fprintf(outfile, "%s\n", "help"); - } - if (args_info->version_given) { - fprintf(outfile, "%s\n", "version"); - } - if (args_info->debug_given) { - fprintf(outfile, "%s\n", "debug"); - } - if (args_info->conf_given) { - if (args_info->conf_orig) { - fprintf(outfile, "%s=\"%s\"\n", "conf", args_info->conf_orig); - } else { - fprintf(outfile, "%s\n", "conf"); - } - } - if (args_info->pidfile_given) { - if (args_info->pidfile_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pidfile", args_info->pidfile_orig); - } else { - fprintf(outfile, "%s\n", "pidfile"); - } - } - if (args_info->statedir_given) { - if (args_info->statedir_orig) { - fprintf(outfile, "%s=\"%s\"\n", "statedir", args_info->statedir_orig); - } else { - fprintf(outfile, "%s\n", "statedir"); - } - } - if (args_info->dns_given) { - if (args_info->dns_orig) { - fprintf(outfile, "%s=\"%s\"\n", "dns", args_info->dns_orig); - } else { - fprintf(outfile, "%s\n", "dns"); - } - } - if (args_info->listen_given) { - if (args_info->listen_orig) { - fprintf(outfile, "%s=\"%s\"\n", "listen", args_info->listen_orig); - } else { - fprintf(outfile, "%s\n", "listen"); - } - } - if (args_info->remote_given) { - if (args_info->remote_orig) { - fprintf(outfile, "%s=\"%s\"\n", "remote", args_info->remote_orig); - } else { - fprintf(outfile, "%s\n", "remote"); - } - } - if (args_info->contexts_given) { - if (args_info->contexts_orig) { - fprintf(outfile, "%s=\"%s\"\n", "contexts", args_info->contexts_orig); - } else { - fprintf(outfile, "%s\n", "contexts"); - } - } - if (args_info->timelimit_given) { - if (args_info->timelimit_orig) { - fprintf(outfile, "%s=\"%s\"\n", "timelimit", args_info->timelimit_orig); - } else { - fprintf(outfile, "%s\n", "timelimit"); - } - } - if (args_info->gtpversion_given) { - if (args_info->gtpversion_orig) { - fprintf(outfile, "%s=\"%s\"\n", "gtpversion", args_info->gtpversion_orig); - } else { - fprintf(outfile, "%s\n", "gtpversion"); - } - } - if (args_info->apn_given) { - if (args_info->apn_orig) { - fprintf(outfile, "%s=\"%s\"\n", "apn", args_info->apn_orig); - } else { - fprintf(outfile, "%s\n", "apn"); - } - } - if (args_info->selmode_given) { - if (args_info->selmode_orig) { - fprintf(outfile, "%s=\"%s\"\n", "selmode", args_info->selmode_orig); - } else { - fprintf(outfile, "%s\n", "selmode"); - } - } - if (args_info->imsi_given) { - if (args_info->imsi_orig) { - fprintf(outfile, "%s=\"%s\"\n", "imsi", args_info->imsi_orig); - } else { - fprintf(outfile, "%s\n", "imsi"); - } - } - if (args_info->nsapi_given) { - if (args_info->nsapi_orig) { - fprintf(outfile, "%s=\"%s\"\n", "nsapi", args_info->nsapi_orig); - } else { - fprintf(outfile, "%s\n", "nsapi"); - } - } - if (args_info->msisdn_given) { - if (args_info->msisdn_orig) { - fprintf(outfile, "%s=\"%s\"\n", "msisdn", args_info->msisdn_orig); - } else { - fprintf(outfile, "%s\n", "msisdn"); - } - } - if (args_info->qos_given) { - if (args_info->qos_orig) { - fprintf(outfile, "%s=\"%s\"\n", "qos", args_info->qos_orig); - } else { - fprintf(outfile, "%s\n", "qos"); - } - } - if (args_info->charging_given) { - if (args_info->charging_orig) { - fprintf(outfile, "%s=\"%s\"\n", "charging", args_info->charging_orig); - } else { - fprintf(outfile, "%s\n", "charging"); - } - } - if (args_info->uid_given) { - if (args_info->uid_orig) { - fprintf(outfile, "%s=\"%s\"\n", "uid", args_info->uid_orig); - } else { - fprintf(outfile, "%s\n", "uid"); - } - } - if (args_info->pwd_given) { - if (args_info->pwd_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pwd", args_info->pwd_orig); - } else { - fprintf(outfile, "%s\n", "pwd"); - } - } - if (args_info->createif_given) { - fprintf(outfile, "%s\n", "createif"); - } - if (args_info->net_given) { - if (args_info->net_orig) { - fprintf(outfile, "%s=\"%s\"\n", "net", args_info->net_orig); - } else { - fprintf(outfile, "%s\n", "net"); - } - } - if (args_info->defaultroute_given) { - fprintf(outfile, "%s\n", "defaultroute"); - } - if (args_info->ipup_given) { - if (args_info->ipup_orig) { - fprintf(outfile, "%s=\"%s\"\n", "ipup", args_info->ipup_orig); - } else { - fprintf(outfile, "%s\n", "ipup"); - } - } - if (args_info->ipdown_given) { - if (args_info->ipdown_orig) { - fprintf(outfile, "%s=\"%s\"\n", "ipdown", args_info->ipdown_orig); - } else { - fprintf(outfile, "%s\n", "ipdown"); - } - } - if (args_info->pinghost_given) { - if (args_info->pinghost_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pinghost", args_info->pinghost_orig); - } else { - fprintf(outfile, "%s\n", "pinghost"); - } - } - if (args_info->pingrate_given) { - if (args_info->pingrate_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pingrate", args_info->pingrate_orig); - } else { - fprintf(outfile, "%s\n", "pingrate"); - } - } - if (args_info->pingsize_given) { - if (args_info->pingsize_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pingsize", args_info->pingsize_orig); - } else { - fprintf(outfile, "%s\n", "pingsize"); - } - } - if (args_info->pingcount_given) { - if (args_info->pingcount_orig) { - fprintf(outfile, "%s=\"%s\"\n", "pingcount", args_info->pingcount_orig); - } else { - fprintf(outfile, "%s\n", "pingcount"); - } - } - if (args_info->pingquiet_given) { - fprintf(outfile, "%s\n", "pingquiet"); - } - if (args_info->norecovery_given) { - fprintf(outfile, "%s\n", "norecovery"); - } - - fclose (outfile); + if (args_info->help_given) { + fprintf(outfile, "%s\n", "help"); + } + if (args_info->version_given) { + fprintf(outfile, "%s\n", "version"); + } + if (args_info->debug_given) { + fprintf(outfile, "%s\n", "debug"); + } + if (args_info->conf_given) { + if (args_info->conf_orig) { + fprintf(outfile, "%s=\"%s\"\n", "conf", + args_info->conf_orig); + } else { + fprintf(outfile, "%s\n", "conf"); + } + } + if (args_info->pidfile_given) { + if (args_info->pidfile_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pidfile", + args_info->pidfile_orig); + } else { + fprintf(outfile, "%s\n", "pidfile"); + } + } + if (args_info->statedir_given) { + if (args_info->statedir_orig) { + fprintf(outfile, "%s=\"%s\"\n", "statedir", + args_info->statedir_orig); + } else { + fprintf(outfile, "%s\n", "statedir"); + } + } + if (args_info->dns_given) { + if (args_info->dns_orig) { + fprintf(outfile, "%s=\"%s\"\n", "dns", + args_info->dns_orig); + } else { + fprintf(outfile, "%s\n", "dns"); + } + } + if (args_info->listen_given) { + if (args_info->listen_orig) { + fprintf(outfile, "%s=\"%s\"\n", "listen", + args_info->listen_orig); + } else { + fprintf(outfile, "%s\n", "listen"); + } + } + if (args_info->remote_given) { + if (args_info->remote_orig) { + fprintf(outfile, "%s=\"%s\"\n", "remote", + args_info->remote_orig); + } else { + fprintf(outfile, "%s\n", "remote"); + } + } + if (args_info->contexts_given) { + if (args_info->contexts_orig) { + fprintf(outfile, "%s=\"%s\"\n", "contexts", + args_info->contexts_orig); + } else { + fprintf(outfile, "%s\n", "contexts"); + } + } + if (args_info->timelimit_given) { + if (args_info->timelimit_orig) { + fprintf(outfile, "%s=\"%s\"\n", "timelimit", + args_info->timelimit_orig); + } else { + fprintf(outfile, "%s\n", "timelimit"); + } + } + if (args_info->gtpversion_given) { + if (args_info->gtpversion_orig) { + fprintf(outfile, "%s=\"%s\"\n", "gtpversion", + args_info->gtpversion_orig); + } else { + fprintf(outfile, "%s\n", "gtpversion"); + } + } + if (args_info->apn_given) { + if (args_info->apn_orig) { + fprintf(outfile, "%s=\"%s\"\n", "apn", + args_info->apn_orig); + } else { + fprintf(outfile, "%s\n", "apn"); + } + } + if (args_info->selmode_given) { + if (args_info->selmode_orig) { + fprintf(outfile, "%s=\"%s\"\n", "selmode", + args_info->selmode_orig); + } else { + fprintf(outfile, "%s\n", "selmode"); + } + } + if (args_info->imsi_given) { + if (args_info->imsi_orig) { + fprintf(outfile, "%s=\"%s\"\n", "imsi", + args_info->imsi_orig); + } else { + fprintf(outfile, "%s\n", "imsi"); + } + } + if (args_info->nsapi_given) { + if (args_info->nsapi_orig) { + fprintf(outfile, "%s=\"%s\"\n", "nsapi", + args_info->nsapi_orig); + } else { + fprintf(outfile, "%s\n", "nsapi"); + } + } + if (args_info->msisdn_given) { + if (args_info->msisdn_orig) { + fprintf(outfile, "%s=\"%s\"\n", "msisdn", + args_info->msisdn_orig); + } else { + fprintf(outfile, "%s\n", "msisdn"); + } + } + if (args_info->qos_given) { + if (args_info->qos_orig) { + fprintf(outfile, "%s=\"%s\"\n", "qos", + args_info->qos_orig); + } else { + fprintf(outfile, "%s\n", "qos"); + } + } + if (args_info->charging_given) { + if (args_info->charging_orig) { + fprintf(outfile, "%s=\"%s\"\n", "charging", + args_info->charging_orig); + } else { + fprintf(outfile, "%s\n", "charging"); + } + } + if (args_info->uid_given) { + if (args_info->uid_orig) { + fprintf(outfile, "%s=\"%s\"\n", "uid", + args_info->uid_orig); + } else { + fprintf(outfile, "%s\n", "uid"); + } + } + if (args_info->pwd_given) { + if (args_info->pwd_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pwd", + args_info->pwd_orig); + } else { + fprintf(outfile, "%s\n", "pwd"); + } + } + if (args_info->createif_given) { + fprintf(outfile, "%s\n", "createif"); + } + if (args_info->net_given) { + if (args_info->net_orig) { + fprintf(outfile, "%s=\"%s\"\n", "net", + args_info->net_orig); + } else { + fprintf(outfile, "%s\n", "net"); + } + } + if (args_info->defaultroute_given) { + fprintf(outfile, "%s\n", "defaultroute"); + } + if (args_info->ipup_given) { + if (args_info->ipup_orig) { + fprintf(outfile, "%s=\"%s\"\n", "ipup", + args_info->ipup_orig); + } else { + fprintf(outfile, "%s\n", "ipup"); + } + } + if (args_info->ipdown_given) { + if (args_info->ipdown_orig) { + fprintf(outfile, "%s=\"%s\"\n", "ipdown", + args_info->ipdown_orig); + } else { + fprintf(outfile, "%s\n", "ipdown"); + } + } + if (args_info->pinghost_given) { + if (args_info->pinghost_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pinghost", + args_info->pinghost_orig); + } else { + fprintf(outfile, "%s\n", "pinghost"); + } + } + if (args_info->pingrate_given) { + if (args_info->pingrate_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pingrate", + args_info->pingrate_orig); + } else { + fprintf(outfile, "%s\n", "pingrate"); + } + } + if (args_info->pingsize_given) { + if (args_info->pingsize_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pingsize", + args_info->pingsize_orig); + } else { + fprintf(outfile, "%s\n", "pingsize"); + } + } + if (args_info->pingcount_given) { + if (args_info->pingcount_orig) { + fprintf(outfile, "%s=\"%s\"\n", "pingcount", + args_info->pingcount_orig); + } else { + fprintf(outfile, "%s\n", "pingcount"); + } + } + if (args_info->pingquiet_given) { + fprintf(outfile, "%s\n", "pingquiet"); + } + if (args_info->norecovery_given) { + fprintf(outfile, "%s\n", "norecovery"); + } - i = EXIT_SUCCESS; - return i; + fclose(outfile); + + i = EXIT_SUCCESS; + return i; } -void -cmdline_parser_free (struct gengetopt_args_info *args_info) +void cmdline_parser_free(struct gengetopt_args_info *args_info) { - cmdline_parser_release (args_info); + cmdline_parser_release(args_info); } - /* gengetopt_strdup() */ /* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) +char *gengetopt_strdup(const char *s) { - char *result = NULL; - if (!s) - return result; + char *result = NULL; + if (!s) + return result; - result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; + result = (char *)malloc(strlen(s) + 1); + if (result == (char *)0) + return (char *)0; + strcpy(result, s); + return result; } int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +cmdline_parser(int argc, char *const *argv, + struct gengetopt_args_info *args_info) { - return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); + return cmdline_parser2(argc, argv, args_info, 0, 1, 1); } int -cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +cmdline_parser2(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required) { - int result; + int result; - result = cmdline_parser_internal (argc, argv, args_info, override, initialize, check_required, NULL); + result = + cmdline_parser_internal(argc, argv, args_info, override, initialize, + check_required, NULL); - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; + if (result == EXIT_FAILURE) { + cmdline_parser_free(args_info); + exit(EXIT_FAILURE); + } + + return result; } int -cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +cmdline_parser_required(struct gengetopt_args_info *args_info, + const char *prog_name) { - return EXIT_SUCCESS; + return EXIT_SUCCESS; } int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error) +cmdline_parser_internal(int argc, char *const *argv, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required, + const char *additional_error) { - int c; /* Character of the parsed option. */ + int c; /* Character of the parsed option. */ - int error = 0; - struct gengetopt_args_info local_args_info; + int error = 0; + struct gengetopt_args_info local_args_info; - if (initialize) - cmdline_parser_init (args_info); + if (initialize) + cmdline_parser_init(args_info); - cmdline_parser_init (&local_args_info); + cmdline_parser_init(&local_args_info); - optarg = 0; - optind = 0; - opterr = 1; - optopt = '?'; + optarg = 0; + optind = 0; + opterr = 1; + optopt = '?'; - while (1) - { - int option_index = 0; - char *stop_char; + while (1) { + int option_index = 0; + char *stop_char; - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "debug", 0, NULL, 'd' }, - { "conf", 1, NULL, 'c' }, - { "pidfile", 1, NULL, 0 }, - { "statedir", 1, NULL, 0 }, - { "dns", 1, NULL, 0 }, - { "listen", 1, NULL, 'l' }, - { "remote", 1, NULL, 'r' }, - { "contexts", 1, NULL, 0 }, - { "timelimit", 1, NULL, 0 }, - { "gtpversion", 1, NULL, 0 }, - { "apn", 1, NULL, 'a' }, - { "selmode", 1, NULL, 0 }, - { "rattype", 1, NULL, 0}, - { "userloc", 1, NULL, 0}, - { "rai", 1, NULL, 0}, - { "mstz", 1, NULL, 0}, - { "imeisv", 1, NULL, 0}, - { "imsi", 1, NULL, 'i' }, - { "nsapi", 1, NULL, 0 }, - { "msisdn", 1, NULL, 'm' }, - { "qos", 1, NULL, 'q' }, - { "qose1", 1, NULL, 0 }, - { "qose2", 1, NULL, 0 }, - { "qose3", 1, NULL, 0 }, - { "qose4", 1, NULL, 0 }, - { "charging", 1, NULL, 0 }, - { "uid", 1, NULL, 'u' }, - { "pwd", 1, NULL, 'p' }, - { "createif", 0, NULL, 0 }, - { "net", 1, NULL, 'n' }, - { "defaultroute", 0, NULL, 0 }, - { "ipup", 1, NULL, 0 }, - { "ipdown", 1, NULL, 0 }, - { "pinghost", 1, NULL, 0 }, - { "pingrate", 1, NULL, 0 }, - { "pingsize", 1, NULL, 0 }, - { "pingcount", 1, NULL, 0 }, - { "pingquiet", 0, NULL, 0 }, - { "norecovery", 0, NULL, 0 }, - { NULL, 0, NULL, 0 } - }; + static struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'V'}, + {"debug", 0, NULL, 'd'}, + {"conf", 1, NULL, 'c'}, + {"pidfile", 1, NULL, 0}, + {"statedir", 1, NULL, 0}, + {"dns", 1, NULL, 0}, + {"listen", 1, NULL, 'l'}, + {"remote", 1, NULL, 'r'}, + {"contexts", 1, NULL, 0}, + {"timelimit", 1, NULL, 0}, + {"gtpversion", 1, NULL, 0}, + {"apn", 1, NULL, 'a'}, + {"selmode", 1, NULL, 0}, + {"rattype", 1, NULL, 0}, + {"userloc", 1, NULL, 0}, + {"rai", 1, NULL, 0}, + {"mstz", 1, NULL, 0}, + {"imeisv", 1, NULL, 0}, + {"imsi", 1, NULL, 'i'}, + {"nsapi", 1, NULL, 0}, + {"msisdn", 1, NULL, 'm'}, + {"qos", 1, NULL, 'q'}, + {"qose1", 1, NULL, 0}, + {"qose2", 1, NULL, 0}, + {"qose3", 1, NULL, 0}, + {"qose4", 1, NULL, 0}, + {"charging", 1, NULL, 0}, + {"uid", 1, NULL, 'u'}, + {"pwd", 1, NULL, 'p'}, + {"createif", 0, NULL, 0}, + {"net", 1, NULL, 'n'}, + {"defaultroute", 0, NULL, 0}, + {"ipup", 1, NULL, 0}, + {"ipdown", 1, NULL, 0}, + {"pinghost", 1, NULL, 0}, + {"pingrate", 1, NULL, 0}, + {"pingsize", 1, NULL, 0}, + {"pingcount", 1, NULL, 0}, + {"pingquiet", 0, NULL, 0}, + {"norecovery", 0, NULL, 0}, + {NULL, 0, NULL, 0} + }; - stop_char = 0; - c = getopt_long (argc, argv, "hVdc:l:r:a:i:m:q:u:p:n:", long_options, &option_index); + stop_char = 0; + c = getopt_long(argc, argv, "hVdc:l:r:a:i:m:q:u:p:n:", + long_options, &option_index); - if (c == -1) break; /* Exit from `while (1)' loop. */ + if (c == -1) + break; /* Exit from `while (1)' loop. */ - switch (c) - { - case 'h': /* Print help and exit. */ - cmdline_parser_print_help (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); + switch (c) { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help(); + cmdline_parser_free(&local_args_info); + exit(EXIT_SUCCESS); - case 'V': /* Print version and exit. */ - cmdline_parser_print_version (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); + case 'V': /* Print version and exit. */ + cmdline_parser_print_version(); + cmdline_parser_free(&local_args_info); + exit(EXIT_SUCCESS); - case 'd': /* Run in debug mode. */ - if (local_args_info.debug_given) - { - fprintf (stderr, "%s: `--debug' (`-d') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->debug_given && ! override) - continue; - local_args_info.debug_given = 1; - args_info->debug_given = 1; - args_info->debug_flag = !(args_info->debug_flag); - break; + case 'd': /* Run in debug mode. */ + if (local_args_info.debug_given) { + fprintf(stderr, + "%s: `--debug' (`-d') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->debug_given && !override) + continue; + local_args_info.debug_given = 1; + args_info->debug_given = 1; + args_info->debug_flag = !(args_info->debug_flag); + break; - case 'c': /* Read configuration file. */ - if (local_args_info.conf_given) - { - fprintf (stderr, "%s: `--conf' (`-c') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->conf_given && ! override) - continue; - local_args_info.conf_given = 1; - args_info->conf_given = 1; - if (args_info->conf_arg) - free (args_info->conf_arg); /* free previous string */ - args_info->conf_arg = gengetopt_strdup (optarg); - if (args_info->conf_orig) - free (args_info->conf_orig); /* free previous string */ - args_info->conf_orig = gengetopt_strdup (optarg); - break; + case 'c': /* Read configuration file. */ + if (local_args_info.conf_given) { + fprintf(stderr, + "%s: `--conf' (`-c') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->conf_given && !override) + continue; + local_args_info.conf_given = 1; + args_info->conf_given = 1; + if (args_info->conf_arg) + free(args_info->conf_arg); /* free previous string */ + args_info->conf_arg = gengetopt_strdup(optarg); + if (args_info->conf_orig) + free(args_info->conf_orig); /* free previous string */ + args_info->conf_orig = gengetopt_strdup(optarg); + break; - case 'l': /* Local interface. */ - if (local_args_info.listen_given) - { - fprintf (stderr, "%s: `--listen' (`-l') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->listen_given && ! override) - continue; - local_args_info.listen_given = 1; - args_info->listen_given = 1; - if (args_info->listen_arg) - free (args_info->listen_arg); /* free previous string */ - args_info->listen_arg = gengetopt_strdup (optarg); - if (args_info->listen_orig) - free (args_info->listen_orig); /* free previous string */ - args_info->listen_orig = gengetopt_strdup (optarg); - break; + case 'l': /* Local interface. */ + if (local_args_info.listen_given) { + fprintf(stderr, + "%s: `--listen' (`-l') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->listen_given && !override) + continue; + local_args_info.listen_given = 1; + args_info->listen_given = 1; + if (args_info->listen_arg) + free(args_info->listen_arg); /* free previous string */ + args_info->listen_arg = gengetopt_strdup(optarg); + if (args_info->listen_orig) + free(args_info->listen_orig); /* free previous string */ + args_info->listen_orig = gengetopt_strdup(optarg); + break; - case 'r': /* Remote host. */ - if (local_args_info.remote_given) - { - fprintf (stderr, "%s: `--remote' (`-r') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->remote_given && ! override) - continue; - local_args_info.remote_given = 1; - args_info->remote_given = 1; - if (args_info->remote_arg) - free (args_info->remote_arg); /* free previous string */ - args_info->remote_arg = gengetopt_strdup (optarg); - if (args_info->remote_orig) - free (args_info->remote_orig); /* free previous string */ - args_info->remote_orig = gengetopt_strdup (optarg); - break; + case 'r': /* Remote host. */ + if (local_args_info.remote_given) { + fprintf(stderr, + "%s: `--remote' (`-r') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->remote_given && !override) + continue; + local_args_info.remote_given = 1; + args_info->remote_given = 1; + if (args_info->remote_arg) + free(args_info->remote_arg); /* free previous string */ + args_info->remote_arg = gengetopt_strdup(optarg); + if (args_info->remote_orig) + free(args_info->remote_orig); /* free previous string */ + args_info->remote_orig = gengetopt_strdup(optarg); + break; - case 'a': /* Access point name. */ - if (local_args_info.apn_given) - { - fprintf (stderr, "%s: `--apn' (`-a') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->apn_given && ! override) - continue; - local_args_info.apn_given = 1; - args_info->apn_given = 1; - if (args_info->apn_arg) - free (args_info->apn_arg); /* free previous string */ - args_info->apn_arg = gengetopt_strdup (optarg); - if (args_info->apn_orig) - free (args_info->apn_orig); /* free previous string */ - args_info->apn_orig = gengetopt_strdup (optarg); - break; + case 'a': /* Access point name. */ + if (local_args_info.apn_given) { + fprintf(stderr, + "%s: `--apn' (`-a') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->apn_given && !override) + continue; + local_args_info.apn_given = 1; + args_info->apn_given = 1; + if (args_info->apn_arg) + free(args_info->apn_arg); /* free previous string */ + args_info->apn_arg = gengetopt_strdup(optarg); + if (args_info->apn_orig) + free(args_info->apn_orig); /* free previous string */ + args_info->apn_orig = gengetopt_strdup(optarg); + break; - case 'i': /* IMSI. */ - if (local_args_info.imsi_given) - { - fprintf (stderr, "%s: `--imsi' (`-i') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->imsi_given && ! override) - continue; - local_args_info.imsi_given = 1; - args_info->imsi_given = 1; - if (args_info->imsi_arg) - free (args_info->imsi_arg); /* free previous string */ - args_info->imsi_arg = gengetopt_strdup (optarg); - if (args_info->imsi_orig) - free (args_info->imsi_orig); /* free previous string */ - args_info->imsi_orig = gengetopt_strdup (optarg); - break; + case 'i': /* IMSI. */ + if (local_args_info.imsi_given) { + fprintf(stderr, + "%s: `--imsi' (`-i') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->imsi_given && !override) + continue; + local_args_info.imsi_given = 1; + args_info->imsi_given = 1; + if (args_info->imsi_arg) + free(args_info->imsi_arg); /* free previous string */ + args_info->imsi_arg = gengetopt_strdup(optarg); + if (args_info->imsi_orig) + free(args_info->imsi_orig); /* free previous string */ + args_info->imsi_orig = gengetopt_strdup(optarg); + break; - case 'm': /* Mobile Station ISDN number. */ - if (local_args_info.msisdn_given) - { - fprintf (stderr, "%s: `--msisdn' (`-m') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->msisdn_given && ! override) - continue; - local_args_info.msisdn_given = 1; - args_info->msisdn_given = 1; - if (args_info->msisdn_arg) - free (args_info->msisdn_arg); /* free previous string */ - args_info->msisdn_arg = gengetopt_strdup (optarg); - if (args_info->msisdn_orig) - free (args_info->msisdn_orig); /* free previous string */ - args_info->msisdn_orig = gengetopt_strdup (optarg); - break; + case 'm': /* Mobile Station ISDN number. */ + if (local_args_info.msisdn_given) { + fprintf(stderr, + "%s: `--msisdn' (`-m') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->msisdn_given && !override) + continue; + local_args_info.msisdn_given = 1; + args_info->msisdn_given = 1; + if (args_info->msisdn_arg) + free(args_info->msisdn_arg); /* free previous string */ + args_info->msisdn_arg = gengetopt_strdup(optarg); + if (args_info->msisdn_orig) + free(args_info->msisdn_orig); /* free previous string */ + args_info->msisdn_orig = gengetopt_strdup(optarg); + break; - case 'q': /* Requested quality of service. */ - if (local_args_info.qos_given) - { - fprintf (stderr, "%s: `--qos' (`-q') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->qos_given && ! override) - continue; - local_args_info.qos_given = 1; - args_info->qos_given = 1; - args_info->qos_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qos_orig) - free (args_info->qos_orig); /* free previous string */ - args_info->qos_orig = gengetopt_strdup (optarg); - break; + case 'q': /* Requested quality of service. */ + if (local_args_info.qos_given) { + fprintf(stderr, + "%s: `--qos' (`-q') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->qos_given && !override) + continue; + local_args_info.qos_given = 1; + args_info->qos_given = 1; + args_info->qos_arg = strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qos_orig) + free(args_info->qos_orig); /* free previous string */ + args_info->qos_orig = gengetopt_strdup(optarg); + break; - case 'u': /* Login user ID. */ - if (local_args_info.uid_given) - { - fprintf (stderr, "%s: `--uid' (`-u') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->uid_given && ! override) - continue; - local_args_info.uid_given = 1; - args_info->uid_given = 1; - if (args_info->uid_arg) - free (args_info->uid_arg); /* free previous string */ - args_info->uid_arg = gengetopt_strdup (optarg); - if (args_info->uid_orig) - free (args_info->uid_orig); /* free previous string */ - args_info->uid_orig = gengetopt_strdup (optarg); - break; + case 'u': /* Login user ID. */ + if (local_args_info.uid_given) { + fprintf(stderr, + "%s: `--uid' (`-u') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->uid_given && !override) + continue; + local_args_info.uid_given = 1; + args_info->uid_given = 1; + if (args_info->uid_arg) + free(args_info->uid_arg); /* free previous string */ + args_info->uid_arg = gengetopt_strdup(optarg); + if (args_info->uid_orig) + free(args_info->uid_orig); /* free previous string */ + args_info->uid_orig = gengetopt_strdup(optarg); + break; - case 'p': /* Login password. */ - if (local_args_info.pwd_given) - { - fprintf (stderr, "%s: `--pwd' (`-p') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pwd_given && ! override) - continue; - local_args_info.pwd_given = 1; - args_info->pwd_given = 1; - if (args_info->pwd_arg) - free (args_info->pwd_arg); /* free previous string */ - args_info->pwd_arg = gengetopt_strdup (optarg); - if (args_info->pwd_orig) - free (args_info->pwd_orig); /* free previous string */ - args_info->pwd_orig = gengetopt_strdup (optarg); - break; + case 'p': /* Login password. */ + if (local_args_info.pwd_given) { + fprintf(stderr, + "%s: `--pwd' (`-p') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->pwd_given && !override) + continue; + local_args_info.pwd_given = 1; + args_info->pwd_given = 1; + if (args_info->pwd_arg) + free(args_info->pwd_arg); /* free previous string */ + args_info->pwd_arg = gengetopt_strdup(optarg); + if (args_info->pwd_orig) + free(args_info->pwd_orig); /* free previous string */ + args_info->pwd_orig = gengetopt_strdup(optarg); + break; - case 'n': /* Network address for local interface. */ - if (local_args_info.net_given) - { - fprintf (stderr, "%s: `--net' (`-n') option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->net_given && ! override) - continue; - local_args_info.net_given = 1; - args_info->net_given = 1; - if (args_info->net_arg) - free (args_info->net_arg); /* free previous string */ - args_info->net_arg = gengetopt_strdup (optarg); - if (args_info->net_orig) - free (args_info->net_orig); /* free previous string */ - args_info->net_orig = gengetopt_strdup (optarg); - break; + case 'n': /* Network address for local interface. */ + if (local_args_info.net_given) { + fprintf(stderr, + "%s: `--net' (`-n') option given more than once%s\n", + argv[0], + (additional_error ? additional_error : + "")); + goto failure; + } + if (args_info->net_given && !override) + continue; + local_args_info.net_given = 1; + args_info->net_given = 1; + if (args_info->net_arg) + free(args_info->net_arg); /* free previous string */ + args_info->net_arg = gengetopt_strdup(optarg); + if (args_info->net_orig) + free(args_info->net_orig); /* free previous string */ + args_info->net_orig = gengetopt_strdup(optarg); + break; + case 0: /* Long option with no short option */ + /* Filename of process id file. */ + if (strcmp(long_options[option_index].name, "pidfile") + == 0) { + if (local_args_info.pidfile_given) { + fprintf(stderr, + "%s: `--pidfile' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pidfile_given && !override) + continue; + local_args_info.pidfile_given = 1; + args_info->pidfile_given = 1; + if (args_info->pidfile_arg) + free(args_info->pidfile_arg); /* free previous string */ + args_info->pidfile_arg = + gengetopt_strdup(optarg); + if (args_info->pidfile_orig) + free(args_info->pidfile_orig); /* free previous string */ + args_info->pidfile_orig = + gengetopt_strdup(optarg); + } + /* Directory of nonvolatile data. */ + else if (strcmp + (long_options[option_index].name, + "statedir") == 0) { + if (local_args_info.statedir_given) { + fprintf(stderr, + "%s: `--statedir' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->statedir_given && !override) + continue; + local_args_info.statedir_given = 1; + args_info->statedir_given = 1; + if (args_info->statedir_arg) + free(args_info->statedir_arg); /* free previous string */ + args_info->statedir_arg = + gengetopt_strdup(optarg); + if (args_info->statedir_orig) + free(args_info->statedir_orig); /* free previous string */ + args_info->statedir_orig = + gengetopt_strdup(optarg); + } + /* DNS Server to use. */ + else if (strcmp(long_options[option_index].name, "dns") + == 0) { + if (local_args_info.dns_given) { + fprintf(stderr, + "%s: `--dns' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->dns_given && !override) + continue; + local_args_info.dns_given = 1; + args_info->dns_given = 1; + if (args_info->dns_arg) + free(args_info->dns_arg); /* free previous string */ + args_info->dns_arg = gengetopt_strdup(optarg); + if (args_info->dns_orig) + free(args_info->dns_orig); /* free previous string */ + args_info->dns_orig = gengetopt_strdup(optarg); + } + /* Number of contexts. */ + else if (strcmp + (long_options[option_index].name, + "contexts") == 0) { + if (local_args_info.contexts_given) { + fprintf(stderr, + "%s: `--contexts' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->contexts_given && !override) + continue; + local_args_info.contexts_given = 1; + args_info->contexts_given = 1; + args_info->contexts_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->contexts_orig) + free(args_info->contexts_orig); /* free previous string */ + args_info->contexts_orig = + gengetopt_strdup(optarg); + } + /* Exit after timelimit seconds. */ + else if (strcmp + (long_options[option_index].name, + "timelimit") == 0) { + if (local_args_info.timelimit_given) { + fprintf(stderr, + "%s: `--timelimit' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->timelimit_given && !override) + continue; + local_args_info.timelimit_given = 1; + args_info->timelimit_given = 1; + args_info->timelimit_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->timelimit_orig) + free(args_info->timelimit_orig); /* free previous string */ + args_info->timelimit_orig = + gengetopt_strdup(optarg); + } + /* GTP version to use. */ + else if (strcmp + (long_options[option_index].name, + "gtpversion") == 0) { + if (local_args_info.gtpversion_given) { + fprintf(stderr, + "%s: `--gtpversion' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->gtpversion_given && !override) + continue; + local_args_info.gtpversion_given = 1; + args_info->gtpversion_given = 1; + args_info->gtpversion_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->gtpversion_orig) + free(args_info->gtpversion_orig); /* free previous string */ + args_info->gtpversion_orig = + gengetopt_strdup(optarg); + } + /* Selection mode. */ + else if (strcmp + (long_options[option_index].name, + "selmode") == 0) { + if (local_args_info.selmode_given) { + fprintf(stderr, + "%s: `--selmode' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->selmode_given && !override) + continue; + local_args_info.selmode_given = 1; + args_info->selmode_given = 1; + args_info->selmode_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->selmode_orig) + free(args_info->selmode_orig); /* free previous string */ + args_info->selmode_orig = + gengetopt_strdup(optarg); + } + /* QoS Extension 1. */ + else if (strcmp + (long_options[option_index].name, + "qose1") == 0) { + if (args_info->qose1_given) { + fprintf(stderr, + "%s: `--qose1' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->qose1_given = 1; + args_info->qose1_arg = + strtoull(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qose1_orig) + free(args_info->qose1_orig); /* free previous string */ + args_info->qose1_orig = + gengetopt_strdup(optarg); + break; + } + /* QoS Extension 2. */ + else if (strcmp + (long_options[option_index].name, + "qose2") == 0) { + if (args_info->qose2_given) { + fprintf(stderr, + "%s: `--qose2' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->qose2_given = 1; + args_info->qose2_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qose2_orig) + free(args_info->qose2_orig); /* free previous string */ + args_info->qose2_orig = + gengetopt_strdup(optarg); + break; + } + /* QoS Extension 3. */ + else if (strcmp + (long_options[option_index].name, + "qose3") == 0) { + if (args_info->qose3_given) { + fprintf(stderr, + "%s: `--qose3' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->qose3_given = 1; + args_info->qose3_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qose3_orig) + free(args_info->qose3_orig); /* free previous string */ + args_info->qose3_orig = + gengetopt_strdup(optarg); + break; + } + /* QoS Extension 4. */ + else if (strcmp + (long_options[option_index].name, + "qose4") == 0) { + if (args_info->qose4_given) { + fprintf(stderr, + "%s: `--qose4' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->qose4_given = 1; + args_info->qose4_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->qose4_orig) + free(args_info->qose4_orig); /* free previous string */ + args_info->qose4_orig = + gengetopt_strdup(optarg); + break; + } + /* Radio Access Technology Type. */ + else if (strcmp + (long_options[option_index].name, + "rattype") == 0) { + if (args_info->rattype_given) { + fprintf(stderr, + "%s: `--rattype' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->rattype_given = 1; + /* args_info->rattype_arg = strtol (optarg,&stop_char,0); */ + args_info->rattype_arg = strdup(optarg); + break; + } + /* User Location Information. */ + else if (strcmp + (long_options[option_index].name, + "userloc") == 0) { + if (args_info->userloc_given) { + fprintf(stderr, + "%s: `--userloc' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->userloc_given = 1; + args_info->userloc_arg = strdup(optarg); + break; + } + /* Routing Area Information. */ + else if (strcmp(long_options[option_index].name, "rai") + == 0) { + if (args_info->rai_given) { + fprintf(stderr, + "%s: `--rai' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->rai_given = 1; + args_info->rai_arg = strdup(optarg); + break; + } + /* MS Time Zone */ + else if (strcmp(long_options[option_index].name, "mstz") + == 0) { + if (args_info->mstz_given) { + fprintf(stderr, + "%s: `--mstz' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->mstz_given = 1; + args_info->mstz_arg = strdup(optarg); + break; + } + /* IMEI(SV) */ + else if (strcmp + (long_options[option_index].name, + "imeisv") == 0) { + if (args_info->imeisv_given) { + fprintf(stderr, + "%s: `--imeisv' option given more than once\n", + PACKAGE); + exit(EXIT_FAILURE); + } + args_info->imeisv_given = 1; + args_info->imeisv_arg = strdup(optarg); + break; + } + /* NSAPI. */ + else if (strcmp + (long_options[option_index].name, + "nsapi") == 0) { + if (local_args_info.nsapi_given) { + fprintf(stderr, + "%s: `--nsapi' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->nsapi_given && !override) + continue; + local_args_info.nsapi_given = 1; + args_info->nsapi_given = 1; + args_info->nsapi_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->nsapi_orig) + free(args_info->nsapi_orig); /* free previous string */ + args_info->nsapi_orig = + gengetopt_strdup(optarg); + } + /* Charging characteristics. */ + else if (strcmp + (long_options[option_index].name, + "charging") == 0) { + if (local_args_info.charging_given) { + fprintf(stderr, + "%s: `--charging' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->charging_given && !override) + continue; + local_args_info.charging_given = 1; + args_info->charging_given = 1; + args_info->charging_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->charging_orig) + free(args_info->charging_orig); /* free previous string */ + args_info->charging_orig = + gengetopt_strdup(optarg); + } + /* Create local network interface. */ + else if (strcmp + (long_options[option_index].name, + "createif") == 0) { + if (local_args_info.createif_given) { + fprintf(stderr, + "%s: `--createif' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->createif_given && !override) + continue; + local_args_info.createif_given = 1; + args_info->createif_given = 1; + args_info->createif_flag = + !(args_info->createif_flag); + } + /* Create default route. */ + else if (strcmp + (long_options[option_index].name, + "defaultroute") == 0) { + if (local_args_info.defaultroute_given) { + fprintf(stderr, + "%s: `--defaultroute' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->defaultroute_given && !override) + continue; + local_args_info.defaultroute_given = 1; + args_info->defaultroute_given = 1; + args_info->defaultroute_flag = + !(args_info->defaultroute_flag); + } + /* Script to run after link-up. */ + else if (strcmp(long_options[option_index].name, "ipup") + == 0) { + if (local_args_info.ipup_given) { + fprintf(stderr, + "%s: `--ipup' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->ipup_given && !override) + continue; + local_args_info.ipup_given = 1; + args_info->ipup_given = 1; + if (args_info->ipup_arg) + free(args_info->ipup_arg); /* free previous string */ + args_info->ipup_arg = gengetopt_strdup(optarg); + if (args_info->ipup_orig) + free(args_info->ipup_orig); /* free previous string */ + args_info->ipup_orig = gengetopt_strdup(optarg); + } + /* Script to run after link-down. */ + else if (strcmp + (long_options[option_index].name, + "ipdown") == 0) { + if (local_args_info.ipdown_given) { + fprintf(stderr, + "%s: `--ipdown' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->ipdown_given && !override) + continue; + local_args_info.ipdown_given = 1; + args_info->ipdown_given = 1; + if (args_info->ipdown_arg) + free(args_info->ipdown_arg); /* free previous string */ + args_info->ipdown_arg = + gengetopt_strdup(optarg); + if (args_info->ipdown_orig) + free(args_info->ipdown_orig); /* free previous string */ + args_info->ipdown_orig = + gengetopt_strdup(optarg); + } + /* Ping remote host. */ + else if (strcmp + (long_options[option_index].name, + "pinghost") == 0) { + if (local_args_info.pinghost_given) { + fprintf(stderr, + "%s: `--pinghost' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pinghost_given && !override) + continue; + local_args_info.pinghost_given = 1; + args_info->pinghost_given = 1; + if (args_info->pinghost_arg) + free(args_info->pinghost_arg); /* free previous string */ + args_info->pinghost_arg = + gengetopt_strdup(optarg); + if (args_info->pinghost_orig) + free(args_info->pinghost_orig); /* free previous string */ + args_info->pinghost_orig = + gengetopt_strdup(optarg); + } + /* Number of ping req per second. */ + else if (strcmp + (long_options[option_index].name, + "pingrate") == 0) { + if (local_args_info.pingrate_given) { + fprintf(stderr, + "%s: `--pingrate' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pingrate_given && !override) + continue; + local_args_info.pingrate_given = 1; + args_info->pingrate_given = 1; + args_info->pingrate_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->pingrate_orig) + free(args_info->pingrate_orig); /* free previous string */ + args_info->pingrate_orig = + gengetopt_strdup(optarg); + } + /* Number of ping data bytes. */ + else if (strcmp + (long_options[option_index].name, + "pingsize") == 0) { + if (local_args_info.pingsize_given) { + fprintf(stderr, + "%s: `--pingsize' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pingsize_given && !override) + continue; + local_args_info.pingsize_given = 1; + args_info->pingsize_given = 1; + args_info->pingsize_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->pingsize_orig) + free(args_info->pingsize_orig); /* free previous string */ + args_info->pingsize_orig = + gengetopt_strdup(optarg); + } + /* Number of ping req to send. */ + else if (strcmp + (long_options[option_index].name, + "pingcount") == 0) { + if (local_args_info.pingcount_given) { + fprintf(stderr, + "%s: `--pingcount' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pingcount_given && !override) + continue; + local_args_info.pingcount_given = 1; + args_info->pingcount_given = 1; + args_info->pingcount_arg = + strtol(optarg, &stop_char, 0); + if (!(stop_char && *stop_char == '\0')) { + fprintf(stderr, + "%s: invalid numeric value: %s\n", + argv[0], optarg); + goto failure; + } + if (args_info->pingcount_orig) + free(args_info->pingcount_orig); /* free previous string */ + args_info->pingcount_orig = + gengetopt_strdup(optarg); + } + /* Do not print ping packet info. */ + else if (strcmp + (long_options[option_index].name, + "pingquiet") == 0) { + if (local_args_info.pingquiet_given) { + fprintf(stderr, + "%s: `--pingquiet' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->pingquiet_given && !override) + continue; + local_args_info.pingquiet_given = 1; + args_info->pingquiet_given = 1; + args_info->pingquiet_flag = + !(args_info->pingquiet_flag); + } + /* Do not send recovery. */ + else if (strcmp + (long_options[option_index].name, + "norecovery") == 0) { + if (local_args_info.norecovery_given) { + fprintf(stderr, + "%s: `--norecovery' option given more than once%s\n", + argv[0], + (additional_error ? + additional_error : "")); + goto failure; + } + if (args_info->norecovery_given && !override) + continue; + local_args_info.norecovery_given = 1; + args_info->norecovery_given = 1; + args_info->norecovery_flag = + !(args_info->norecovery_flag); + } - case 0: /* Long option with no short option */ - /* Filename of process id file. */ - if (strcmp (long_options[option_index].name, "pidfile") == 0) - { - if (local_args_info.pidfile_given) - { - fprintf (stderr, "%s: `--pidfile' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pidfile_given && ! override) - continue; - local_args_info.pidfile_given = 1; - args_info->pidfile_given = 1; - if (args_info->pidfile_arg) - free (args_info->pidfile_arg); /* free previous string */ - args_info->pidfile_arg = gengetopt_strdup (optarg); - if (args_info->pidfile_orig) - free (args_info->pidfile_orig); /* free previous string */ - args_info->pidfile_orig = gengetopt_strdup (optarg); - } - /* Directory of nonvolatile data. */ - else if (strcmp (long_options[option_index].name, "statedir") == 0) - { - if (local_args_info.statedir_given) - { - fprintf (stderr, "%s: `--statedir' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->statedir_given && ! override) - continue; - local_args_info.statedir_given = 1; - args_info->statedir_given = 1; - if (args_info->statedir_arg) - free (args_info->statedir_arg); /* free previous string */ - args_info->statedir_arg = gengetopt_strdup (optarg); - if (args_info->statedir_orig) - free (args_info->statedir_orig); /* free previous string */ - args_info->statedir_orig = gengetopt_strdup (optarg); - } - /* DNS Server to use. */ - else if (strcmp (long_options[option_index].name, "dns") == 0) - { - if (local_args_info.dns_given) - { - fprintf (stderr, "%s: `--dns' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->dns_given && ! override) - continue; - local_args_info.dns_given = 1; - args_info->dns_given = 1; - if (args_info->dns_arg) - free (args_info->dns_arg); /* free previous string */ - args_info->dns_arg = gengetopt_strdup (optarg); - if (args_info->dns_orig) - free (args_info->dns_orig); /* free previous string */ - args_info->dns_orig = gengetopt_strdup (optarg); - } - /* Number of contexts. */ - else if (strcmp (long_options[option_index].name, "contexts") == 0) - { - if (local_args_info.contexts_given) - { - fprintf (stderr, "%s: `--contexts' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->contexts_given && ! override) - continue; - local_args_info.contexts_given = 1; - args_info->contexts_given = 1; - args_info->contexts_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->contexts_orig) - free (args_info->contexts_orig); /* free previous string */ - args_info->contexts_orig = gengetopt_strdup (optarg); - } - /* Exit after timelimit seconds. */ - else if (strcmp (long_options[option_index].name, "timelimit") == 0) - { - if (local_args_info.timelimit_given) - { - fprintf (stderr, "%s: `--timelimit' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->timelimit_given && ! override) - continue; - local_args_info.timelimit_given = 1; - args_info->timelimit_given = 1; - args_info->timelimit_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->timelimit_orig) - free (args_info->timelimit_orig); /* free previous string */ - args_info->timelimit_orig = gengetopt_strdup (optarg); - } - /* GTP version to use. */ - else if (strcmp (long_options[option_index].name, "gtpversion") == 0) - { - if (local_args_info.gtpversion_given) - { - fprintf (stderr, "%s: `--gtpversion' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->gtpversion_given && ! override) - continue; - local_args_info.gtpversion_given = 1; - args_info->gtpversion_given = 1; - args_info->gtpversion_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->gtpversion_orig) - free (args_info->gtpversion_orig); /* free previous string */ - args_info->gtpversion_orig = gengetopt_strdup (optarg); - } - /* Selection mode. */ - else if (strcmp (long_options[option_index].name, "selmode") == 0) - { - if (local_args_info.selmode_given) - { - fprintf (stderr, "%s: `--selmode' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->selmode_given && ! override) - continue; - local_args_info.selmode_given = 1; - args_info->selmode_given = 1; - args_info->selmode_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->selmode_orig) - free (args_info->selmode_orig); /* free previous string */ - args_info->selmode_orig = gengetopt_strdup (optarg); - } - /* QoS Extension 1. */ - else if (strcmp (long_options[option_index].name, "qose1") == 0) - { - if (args_info->qose1_given) - { - fprintf (stderr, "%s: `--qose1' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->qose1_given = 1; - args_info->qose1_arg = strtoull (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qose1_orig) - free (args_info->qose1_orig); /* free previous string */ - args_info->qose1_orig = gengetopt_strdup (optarg); - break; - } - /* QoS Extension 2. */ - else if (strcmp (long_options[option_index].name, "qose2") == 0) - { - if (args_info->qose2_given) - { - fprintf (stderr, "%s: `--qose2' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->qose2_given = 1; - args_info->qose2_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qose2_orig) - free (args_info->qose2_orig); /* free previous string */ - args_info->qose2_orig = gengetopt_strdup (optarg); - break; - } - /* QoS Extension 3. */ - else if (strcmp (long_options[option_index].name, "qose3") == 0) - { - if (args_info->qose3_given) - { - fprintf (stderr, "%s: `--qose3' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->qose3_given = 1; - args_info->qose3_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qose3_orig) - free (args_info->qose3_orig); /* free previous string */ - args_info->qose3_orig = gengetopt_strdup (optarg); - break; - } - /* QoS Extension 4. */ - else if (strcmp (long_options[option_index].name, "qose4") == 0) - { - if (args_info->qose4_given) - { - fprintf (stderr, "%s: `--qose4' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->qose4_given = 1; - args_info->qose4_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->qose4_orig) - free (args_info->qose4_orig); /* free previous string */ - args_info->qose4_orig = gengetopt_strdup (optarg); - break; - } - /* Radio Access Technology Type. */ - else if (strcmp (long_options[option_index].name, "rattype") == 0) - { - if (args_info->rattype_given) - { - fprintf (stderr, "%s: `--rattype' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->rattype_given = 1; - /* args_info->rattype_arg = strtol (optarg,&stop_char,0); */ - args_info->rattype_arg = strdup (optarg); - break; - } - /* User Location Information. */ - else if (strcmp (long_options[option_index].name, "userloc") == 0) - { - if (args_info->userloc_given) - { - fprintf (stderr, "%s: `--userloc' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->userloc_given = 1; - args_info->userloc_arg = strdup (optarg); - break; - } - /* Routing Area Information. */ - else if (strcmp (long_options[option_index].name, "rai") == 0) - { - if (args_info->rai_given) - { - fprintf (stderr, "%s: `--rai' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->rai_given = 1; - args_info->rai_arg = strdup (optarg); - break; - } - /* MS Time Zone */ - else if (strcmp (long_options[option_index].name, "mstz") == 0) - { - if (args_info->mstz_given) - { - fprintf (stderr, "%s: `--mstz' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->mstz_given = 1; - args_info->mstz_arg = strdup (optarg); - break; - } - /* IMEI(SV) */ - else if (strcmp (long_options[option_index].name, "imeisv") == 0) - { - if (args_info->imeisv_given) - { - fprintf (stderr, "%s: `--imeisv' option given more than once\n", PACKAGE); - exit (EXIT_FAILURE); - } - args_info->imeisv_given = 1; - args_info->imeisv_arg = strdup (optarg); - break; - } - /* NSAPI. */ - else if (strcmp (long_options[option_index].name, "nsapi") == 0) - { - if (local_args_info.nsapi_given) - { - fprintf (stderr, "%s: `--nsapi' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->nsapi_given && ! override) - continue; - local_args_info.nsapi_given = 1; - args_info->nsapi_given = 1; - args_info->nsapi_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->nsapi_orig) - free (args_info->nsapi_orig); /* free previous string */ - args_info->nsapi_orig = gengetopt_strdup (optarg); - } - /* Charging characteristics. */ - else if (strcmp (long_options[option_index].name, "charging") == 0) - { - if (local_args_info.charging_given) - { - fprintf (stderr, "%s: `--charging' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->charging_given && ! override) - continue; - local_args_info.charging_given = 1; - args_info->charging_given = 1; - args_info->charging_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->charging_orig) - free (args_info->charging_orig); /* free previous string */ - args_info->charging_orig = gengetopt_strdup (optarg); - } - /* Create local network interface. */ - else if (strcmp (long_options[option_index].name, "createif") == 0) - { - if (local_args_info.createif_given) - { - fprintf (stderr, "%s: `--createif' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->createif_given && ! override) - continue; - local_args_info.createif_given = 1; - args_info->createif_given = 1; - args_info->createif_flag = !(args_info->createif_flag); - } - /* Create default route. */ - else if (strcmp (long_options[option_index].name, "defaultroute") == 0) - { - if (local_args_info.defaultroute_given) - { - fprintf (stderr, "%s: `--defaultroute' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->defaultroute_given && ! override) - continue; - local_args_info.defaultroute_given = 1; - args_info->defaultroute_given = 1; - args_info->defaultroute_flag = !(args_info->defaultroute_flag); - } - /* Script to run after link-up. */ - else if (strcmp (long_options[option_index].name, "ipup") == 0) - { - if (local_args_info.ipup_given) - { - fprintf (stderr, "%s: `--ipup' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->ipup_given && ! override) - continue; - local_args_info.ipup_given = 1; - args_info->ipup_given = 1; - if (args_info->ipup_arg) - free (args_info->ipup_arg); /* free previous string */ - args_info->ipup_arg = gengetopt_strdup (optarg); - if (args_info->ipup_orig) - free (args_info->ipup_orig); /* free previous string */ - args_info->ipup_orig = gengetopt_strdup (optarg); - } - /* Script to run after link-down. */ - else if (strcmp (long_options[option_index].name, "ipdown") == 0) - { - if (local_args_info.ipdown_given) - { - fprintf (stderr, "%s: `--ipdown' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->ipdown_given && ! override) - continue; - local_args_info.ipdown_given = 1; - args_info->ipdown_given = 1; - if (args_info->ipdown_arg) - free (args_info->ipdown_arg); /* free previous string */ - args_info->ipdown_arg = gengetopt_strdup (optarg); - if (args_info->ipdown_orig) - free (args_info->ipdown_orig); /* free previous string */ - args_info->ipdown_orig = gengetopt_strdup (optarg); - } - /* Ping remote host. */ - else if (strcmp (long_options[option_index].name, "pinghost") == 0) - { - if (local_args_info.pinghost_given) - { - fprintf (stderr, "%s: `--pinghost' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pinghost_given && ! override) - continue; - local_args_info.pinghost_given = 1; - args_info->pinghost_given = 1; - if (args_info->pinghost_arg) - free (args_info->pinghost_arg); /* free previous string */ - args_info->pinghost_arg = gengetopt_strdup (optarg); - if (args_info->pinghost_orig) - free (args_info->pinghost_orig); /* free previous string */ - args_info->pinghost_orig = gengetopt_strdup (optarg); - } - /* Number of ping req per second. */ - else if (strcmp (long_options[option_index].name, "pingrate") == 0) - { - if (local_args_info.pingrate_given) - { - fprintf (stderr, "%s: `--pingrate' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pingrate_given && ! override) - continue; - local_args_info.pingrate_given = 1; - args_info->pingrate_given = 1; - args_info->pingrate_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->pingrate_orig) - free (args_info->pingrate_orig); /* free previous string */ - args_info->pingrate_orig = gengetopt_strdup (optarg); - } - /* Number of ping data bytes. */ - else if (strcmp (long_options[option_index].name, "pingsize") == 0) - { - if (local_args_info.pingsize_given) - { - fprintf (stderr, "%s: `--pingsize' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pingsize_given && ! override) - continue; - local_args_info.pingsize_given = 1; - args_info->pingsize_given = 1; - args_info->pingsize_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->pingsize_orig) - free (args_info->pingsize_orig); /* free previous string */ - args_info->pingsize_orig = gengetopt_strdup (optarg); - } - /* Number of ping req to send. */ - else if (strcmp (long_options[option_index].name, "pingcount") == 0) - { - if (local_args_info.pingcount_given) - { - fprintf (stderr, "%s: `--pingcount' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pingcount_given && ! override) - continue; - local_args_info.pingcount_given = 1; - args_info->pingcount_given = 1; - args_info->pingcount_arg = strtol (optarg, &stop_char, 0); - if (!(stop_char && *stop_char == '\0')) { - fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); - goto failure; - } - if (args_info->pingcount_orig) - free (args_info->pingcount_orig); /* free previous string */ - args_info->pingcount_orig = gengetopt_strdup (optarg); - } - /* Do not print ping packet info. */ - else if (strcmp (long_options[option_index].name, "pingquiet") == 0) - { - if (local_args_info.pingquiet_given) - { - fprintf (stderr, "%s: `--pingquiet' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->pingquiet_given && ! override) - continue; - local_args_info.pingquiet_given = 1; - args_info->pingquiet_given = 1; - args_info->pingquiet_flag = !(args_info->pingquiet_flag); - } - /* Do not send recovery. */ - else if (strcmp (long_options[option_index].name, "norecovery") == 0) - { - if (local_args_info.norecovery_given) - { - fprintf (stderr, "%s: `--norecovery' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); - goto failure; - } - if (args_info->norecovery_given && ! override) - continue; - local_args_info.norecovery_given = 1; - args_info->norecovery_given = 1; - args_info->norecovery_flag = !(args_info->norecovery_flag); - } - - break; - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - goto failure; + break; + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); - abort (); - } /* switch */ - } /* while */ + default: /* bug: option not considered. */ + fprintf(stderr, "%s: option unknown: %c%s\n", + CMDLINE_PARSER_PACKAGE, c, + (additional_error ? additional_error : "")); + abort(); + } /* switch */ + } /* while */ + cmdline_parser_release(&local_args_info); + if (error) + return (EXIT_FAILURE); - - cmdline_parser_release (&local_args_info); - - if ( error ) - return (EXIT_FAILURE); - - return 0; + return 0; failure: - - cmdline_parser_release (&local_args_info); - return (EXIT_FAILURE); + + cmdline_parser_release(&local_args_info); + return (EXIT_FAILURE); } #ifndef CONFIG_FILE_LINE_SIZE @@ -1587,168 +1759,167 @@ failure: #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) /* 3 is for "--" and "=" */ -char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; +char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE + 1]; int -cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +cmdline_parser_configfile(char *const filename, + struct gengetopt_args_info *args_info, int override, + int initialize, int check_required) { - FILE* file; - char linebuf[CONFIG_FILE_LINE_SIZE]; - int line_num = 0; - int i, result, equal; - char *fopt, *farg; - char *str_index; - size_t len, next_token; - char delimiter; - int my_argc = 0; - char **my_argv_arg; - char *additional_error; + FILE *file; + char linebuf[CONFIG_FILE_LINE_SIZE]; + int line_num = 0; + int i, result, equal; + char *fopt, *farg; + char *str_index; + size_t len, next_token; + char delimiter; + int my_argc = 0; + char **my_argv_arg; + char *additional_error; - /* store the program name */ - cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); - cmd_line_list_tmp->next = cmd_line_list; - cmd_line_list = cmd_line_list_tmp; - cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); + /* store the program name */ + cmd_line_list_tmp = + (struct line_list *)malloc(sizeof(struct line_list)); + cmd_line_list_tmp->next = cmd_line_list; + cmd_line_list = cmd_line_list_tmp; + cmd_line_list->string_arg = gengetopt_strdup(CMDLINE_PARSER_PACKAGE); - if ((file = fopen(filename, "r")) == NULL) - { - fprintf (stderr, "%s: Error opening configuration file '%s'\n", - CMDLINE_PARSER_PACKAGE, filename); - result = EXIT_FAILURE; - goto conf_failure; - } + if ((file = fopen(filename, "r")) == NULL) { + fprintf(stderr, "%s: Error opening configuration file '%s'\n", + CMDLINE_PARSER_PACKAGE, filename); + result = EXIT_FAILURE; + goto conf_failure; + } - while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) - { - ++line_num; - my_argv[0] = '\0'; - len = strlen(linebuf); - if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) - { - fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } + while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) { + ++line_num; + my_argv[0] = '\0'; + len = strlen(linebuf); + if (len > (CONFIG_FILE_LINE_BUFFER_SIZE - 1)) { + fprintf(stderr, + "%s:%s:%d: Line too long in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, line_num); + result = EXIT_FAILURE; + goto conf_failure; + } - /* find first non-whitespace character in the line */ - next_token = strspn ( linebuf, " \t\r\n"); - str_index = linebuf + next_token; + /* find first non-whitespace character in the line */ + next_token = strspn(linebuf, " \t\r\n"); + str_index = linebuf + next_token; - if ( str_index[0] == '\0' || str_index[0] == '#') - continue; /* empty line or comment line is skipped */ + if (str_index[0] == '\0' || str_index[0] == '#') + continue; /* empty line or comment line is skipped */ - fopt = str_index; + fopt = str_index; - /* truncate fopt at the end of the first non-valid character */ - next_token = strcspn (fopt, " \t\r\n="); + /* truncate fopt at the end of the first non-valid character */ + next_token = strcspn(fopt, " \t\r\n="); - if (fopt[next_token] == '\0') /* the line is over */ - { - farg = NULL; - equal = 0; - goto noarg; - } + if (fopt[next_token] == '\0') { /* the line is over */ + farg = NULL; + equal = 0; + goto noarg; + } - /* remember if equal sign is present */ - equal = (fopt[next_token] == '='); - fopt[next_token++] = '\0'; + /* remember if equal sign is present */ + equal = (fopt[next_token] == '='); + fopt[next_token++] = '\0'; - /* advance pointers to the next token after the end of fopt */ - next_token += strspn (fopt + next_token, " \t\r\n"); - /* check for the presence of equal sign, and if so, skip it */ - if ( !equal ) - if ((equal = (fopt[next_token] == '='))) - { - next_token++; - next_token += strspn (fopt + next_token, " \t\r\n"); - } - str_index += next_token; + /* advance pointers to the next token after the end of fopt */ + next_token += strspn(fopt + next_token, " \t\r\n"); + /* check for the presence of equal sign, and if so, skip it */ + if (!equal) + if ((equal = (fopt[next_token] == '='))) { + next_token++; + next_token += + strspn(fopt + next_token, " \t\r\n"); + } + str_index += next_token; - /* find argument */ - farg = str_index; - if ( farg[0] == '\"' || farg[0] == '\'' ) - { /* quoted argument */ - str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ - if (! str_index) - { - fprintf - (stderr, - "%s:%s:%d: unterminated string in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } - } - else - { /* read up the remaining part up to a delimiter */ - next_token = strcspn (farg, " \t\r\n#\'\""); - str_index += next_token; - } + /* find argument */ + farg = str_index; + if (farg[0] == '\"' || farg[0] == '\'') { /* quoted argument */ + str_index = strchr(++farg, str_index[0]); /* skip opening quote */ + if (!str_index) { + fprintf + (stderr, + "%s:%s:%d: unterminated string in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, + line_num); + result = EXIT_FAILURE; + goto conf_failure; + } + } else { /* read up the remaining part up to a delimiter */ + next_token = strcspn(farg, " \t\r\n#\'\""); + str_index += next_token; + } - /* truncate farg at the delimiter and store it for further check */ - delimiter = *str_index, *str_index++ = '\0'; + /* truncate farg at the delimiter and store it for further check */ + delimiter = *str_index, *str_index++ = '\0'; - /* everything but comment is illegal at the end of line */ - if (delimiter != '\0' && delimiter != '#') - { - str_index += strspn(str_index, " \t\r\n"); - if (*str_index != '\0' && *str_index != '#') - { - fprintf - (stderr, - "%s:%s:%d: malformed string in configuration file\n", - CMDLINE_PARSER_PACKAGE, filename, line_num); - result = EXIT_FAILURE; - goto conf_failure; - } - } + /* everything but comment is illegal at the end of line */ + if (delimiter != '\0' && delimiter != '#') { + str_index += strspn(str_index, " \t\r\n"); + if (*str_index != '\0' && *str_index != '#') { + fprintf + (stderr, + "%s:%s:%d: malformed string in configuration file\n", + CMDLINE_PARSER_PACKAGE, filename, + line_num); + result = EXIT_FAILURE; + goto conf_failure; + } + } - noarg: - ++my_argc; - len = strlen(fopt); +noarg: + ++my_argc; + len = strlen(fopt); - strcat (my_argv, len > 1 ? "--" : "-"); - strcat (my_argv, fopt); - if (len > 1 && ((farg &&*farg) || equal)) - strcat (my_argv, "="); - if (farg && *farg) - strcat (my_argv, farg); + strcat(my_argv, len > 1 ? "--" : "-"); + strcat(my_argv, fopt); + if (len > 1 && ((farg && *farg) || equal)) + strcat(my_argv, "="); + if (farg && *farg) + strcat(my_argv, farg); - cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); - cmd_line_list_tmp->next = cmd_line_list; - cmd_line_list = cmd_line_list_tmp; - cmd_line_list->string_arg = gengetopt_strdup(my_argv); - } /* while */ + cmd_line_list_tmp = + (struct line_list *)malloc(sizeof(struct line_list)); + cmd_line_list_tmp->next = cmd_line_list; + cmd_line_list = cmd_line_list_tmp; + cmd_line_list->string_arg = gengetopt_strdup(my_argv); + } /* while */ - ++my_argc; /* for program name */ - my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); - cmd_line_list_tmp = cmd_line_list; - for (i = my_argc - 1; i >= 0; --i) { - my_argv_arg[i] = cmd_line_list_tmp->string_arg; - cmd_line_list_tmp = cmd_line_list_tmp->next; - } - my_argv_arg[my_argc] = 0; + ++my_argc; /* for program name */ + my_argv_arg = (char **)malloc((my_argc + 1) * sizeof(char *)); + cmd_line_list_tmp = cmd_line_list; + for (i = my_argc - 1; i >= 0; --i) { + my_argv_arg[i] = cmd_line_list_tmp->string_arg; + cmd_line_list_tmp = cmd_line_list_tmp->next; + } + my_argv_arg[my_argc] = 0; - additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); - strcpy (additional_error, ADDITIONAL_ERROR); - strcat (additional_error, filename); - result = - cmdline_parser_internal (my_argc, my_argv_arg, args_info, override, initialize, check_required, additional_error); + additional_error = + (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); + strcpy(additional_error, ADDITIONAL_ERROR); + strcat(additional_error, filename); + result = + cmdline_parser_internal(my_argc, my_argv_arg, args_info, override, + initialize, check_required, + additional_error); - free (additional_error); - free (my_argv_arg); + free(additional_error); + free(my_argv_arg); conf_failure: - if (file) - fclose(file); + if (file) + fclose(file); - free_cmd_list(); - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; + free_cmd_list(); + if (result == EXIT_FAILURE) { + cmdline_parser_free(args_info); + exit(EXIT_FAILURE); + } + + return result; } diff --git a/sgsnemu/cmdline.h b/sgsnemu/cmdline.h index 24185f4..17f7c18 100644 --- a/sgsnemu/cmdline.h +++ b/sgsnemu/cmdline.h @@ -12,7 +12,7 @@ #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE #define CMDLINE_PARSER_PACKAGE PACKAGE @@ -22,190 +22,189 @@ extern "C" { #define CMDLINE_PARSER_VERSION VERSION #endif -struct gengetopt_args_info -{ - const char *help_help; /* Print help and exit help description. */ - const char *version_help; /* Print version and exit help description. */ - int debug_flag; /* Run in debug mode (default=off). */ - const char *debug_help; /* Run in debug mode help description. */ - char * conf_arg; /* Read configuration file. */ - char * conf_orig; /* Read configuration file original value given at command line. */ - const char *conf_help; /* Read configuration file help description. */ - char * pidfile_arg; /* Filename of process id file (default='./sgsnemu.pid'). */ - char * pidfile_orig; /* Filename of process id file original value given at command line. */ - const char *pidfile_help; /* Filename of process id file help description. */ - char * statedir_arg; /* Directory of nonvolatile data (default='./'). */ - char * statedir_orig; /* Directory of nonvolatile data original value given at command line. */ - const char *statedir_help; /* Directory of nonvolatile data help description. */ - char * dns_arg; /* DNS Server to use. */ - char * dns_orig; /* DNS Server to use original value given at command line. */ - const char *dns_help; /* DNS Server to use help description. */ - char * listen_arg; /* Local interface. */ - char * listen_orig; /* Local interface original value given at command line. */ - const char *listen_help; /* Local interface help description. */ - char * remote_arg; /* Remote host. */ - char * remote_orig; /* Remote host original value given at command line. */ - const char *remote_help; /* Remote host help description. */ - int contexts_arg; /* Number of contexts (default='1'). */ - char * contexts_orig; /* Number of contexts original value given at command line. */ - const char *contexts_help; /* Number of contexts help description. */ - int timelimit_arg; /* Exit after timelimit seconds (default='0'). */ - char * timelimit_orig; /* Exit after timelimit seconds original value given at command line. */ - const char *timelimit_help; /* Exit after timelimit seconds help description. */ - int gtpversion_arg; /* GTP version to use (default='1'). */ - char * gtpversion_orig; /* GTP version to use original value given at command line. */ - const char *gtpversion_help; /* GTP version to use help description. */ - char * apn_arg; /* Access point name (default='internet'). */ - char * apn_orig; /* Access point name original value given at command line. */ - const char *apn_help; /* Access point name help description. */ - int selmode_arg; /* Selection mode (default='0x01'). */ - char * selmode_orig; /* Selection mode original value given at command line. */ - const char *selmode_help; /* Selection mode help description. */ - char * rattype_arg; /* Radio Access Technology Type (optional). */ - char * rattype_orig; - char * rattype_help; - char * userloc_arg; /* User Location Information (optional). */ - char * userloc_orig; - char * userloc_help; - char * rai_arg; /* Routing Area Information (optional). */ - char * rai_orig; - char * rai_help; - char * mstz_arg; /* MS Time Zone (optional). */ - char * mstz_orig; - char * mstz_help; - char * imeisv_arg; /* IMEI(SV) (optional). */ - char * imeisv_orig; - char * imeisv_help; - char * imsi_arg; /* IMSI (default='240010123456789'). */ - char * imsi_orig; /* IMSI original value given at command line. */ - const char *imsi_help; /* IMSI help description. */ - int nsapi_arg; /* NSAPI (default='0'). */ - char * nsapi_orig; /* NSAPI original value given at command line. */ - const char *nsapi_help; /* NSAPI help description. */ - char * msisdn_arg; /* Mobile Station ISDN number (default='46702123456'). */ - char * msisdn_orig; /* Mobile Station ISDN number original value given at command line. */ - const char *msisdn_help; /* Mobile Station ISDN number help description. */ - int qos_arg; /* Requested quality of service (default='0x0b921f'). */ - char * qos_orig; /* Requested quality of service original value given at command line. */ - const char *qos_help; /* Requested quality of service help description. */ - unsigned long long int qose1_arg; /* Requested quality of service Extension 1 */ - char * qose1_orig; /* Requested quality of service Extension 1 original value given at command line. */ - int qose2_arg; /* Requested quality of service Extension 2 */ - char * qose2_orig; /* Requested quality of service Extension 2 original value given at command line. */ - int qose3_arg; /* Requested quality of service Extension 3 */ - char * qose3_orig; /* Requested quality of service Extension 3 original value given at command line. */ - int qose4_arg; /* Requested quality of service Extension 4 */ - char * qose4_orig; /* Requested quality of service Extension 4 original value given at command line. */ - int charging_arg; /* Charging characteristics (default='0x0800'). */ - char * charging_orig; /* Charging characteristics original value given at command line. */ - const char *charging_help; /* Charging characteristics help description. */ - char * uid_arg; /* Login user ID (default='mig'). */ - char * uid_orig; /* Login user ID original value given at command line. */ - const char *uid_help; /* Login user ID help description. */ - char * pwd_arg; /* Login password (default='hemmelig'). */ - char * pwd_orig; /* Login password original value given at command line. */ - const char *pwd_help; /* Login password help description. */ - int createif_flag; /* Create local network interface (default=off). */ - const char *createif_help; /* Create local network interface help description. */ - char * net_arg; /* Network address for local interface. */ - char * net_orig; /* Network address for local interface original value given at command line. */ - const char *net_help; /* Network address for local interface help description. */ - int defaultroute_flag; /* Create default route (default=off). */ - const char *defaultroute_help; /* Create default route help description. */ - char * ipup_arg; /* Script to run after link-up. */ - char * ipup_orig; /* Script to run after link-up original value given at command line. */ - const char *ipup_help; /* Script to run after link-up help description. */ - char * ipdown_arg; /* Script to run after link-down. */ - char * ipdown_orig; /* Script to run after link-down original value given at command line. */ - const char *ipdown_help; /* Script to run after link-down help description. */ - char * pinghost_arg; /* Ping remote host. */ - char * pinghost_orig; /* Ping remote host original value given at command line. */ - const char *pinghost_help; /* Ping remote host help description. */ - int pingrate_arg; /* Number of ping req per second (default='1'). */ - char * pingrate_orig; /* Number of ping req per second original value given at command line. */ - const char *pingrate_help; /* Number of ping req per second help description. */ - int pingsize_arg; /* Number of ping data bytes (default='56'). */ - char * pingsize_orig; /* Number of ping data bytes original value given at command line. */ - const char *pingsize_help; /* Number of ping data bytes help description. */ - int pingcount_arg; /* Number of ping req to send (default='0'). */ - char * pingcount_orig; /* Number of ping req to send original value given at command line. */ - const char *pingcount_help; /* Number of ping req to send help description. */ - int pingquiet_flag; /* Do not print ping packet info (default=off). */ - const char *pingquiet_help; /* Do not print ping packet info help description. */ - int norecovery_flag; /* Do not print ping packet info (default=off). */ - const char *norecovery_help; /* Do not print ping packet info help description. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int debug_given ; /* Whether debug was given. */ - int conf_given ; /* Whether conf was given. */ - int pidfile_given ; /* Whether pidfile was given. */ - int statedir_given ; /* Whether statedir was given. */ - int dns_given ; /* Whether dns was given. */ - int listen_given ; /* Whether listen was given. */ - int remote_given ; /* Whether remote was given. */ - int contexts_given ; /* Whether contexts was given. */ - int timelimit_given ; /* Whether timelimit was given. */ - int gtpversion_given ; /* Whether gtpversion was given. */ - int apn_given ; /* Whether apn was given. */ - int selmode_given ; /* Whether selmode was given. */ - int rattype_given ; /* Whether rattype was given. */ - int userloc_given ; /* Whether userloc was given. */ - int rai_given ; /* Whether RAI was given. */ - int mstz_given ; /* Whether mstz was given. */ - int imeisv_given ; /* Whether imeisv was given. */ - int imsi_given ; /* Whether imsi was given. */ - int nsapi_given ; /* Whether nsapi was given. */ - int msisdn_given ; /* Whether msisdn was given. */ - int qos_given ; /* Whether qos was given. */ - int qose1_given ; /* Whether qos Extension 1 was given. */ - int qose2_given ; /* Whether qos Extension 2 was given. */ - int qose3_given ; /* Whether qos Extension 3 was given. */ - int qose4_given ; /* Whether qos Extension 4 was given. */ - int charging_given ; /* Whether charging was given. */ - int uid_given ; /* Whether uid was given. */ - int pwd_given ; /* Whether pwd was given. */ - int createif_given ; /* Whether createif was given. */ - int net_given ; /* Whether net was given. */ - int defaultroute_given ; /* Whether defaultroute was given. */ - int ipup_given ; /* Whether ipup was given. */ - int ipdown_given ; /* Whether ipdown was given. */ - int pinghost_given ; /* Whether pinghost was given. */ - int pingrate_given ; /* Whether pingrate was given. */ - int pingsize_given ; /* Whether pingsize was given. */ - int pingcount_given ; /* Whether pingcount was given. */ - int pingquiet_given ; /* Whether pingquiet was given. */ - int norecovery_given ; /* Whether norecovery was given. */ + struct gengetopt_args_info { + const char *help_help; /* Print help and exit help description. */ + const char *version_help; /* Print version and exit help description. */ + int debug_flag; /* Run in debug mode (default=off). */ + const char *debug_help; /* Run in debug mode help description. */ + char *conf_arg; /* Read configuration file. */ + char *conf_orig; /* Read configuration file original value given at command line. */ + const char *conf_help; /* Read configuration file help description. */ + char *pidfile_arg; /* Filename of process id file (default='./sgsnemu.pid'). */ + char *pidfile_orig; /* Filename of process id file original value given at command line. */ + const char *pidfile_help; /* Filename of process id file help description. */ + char *statedir_arg; /* Directory of nonvolatile data (default='./'). */ + char *statedir_orig; /* Directory of nonvolatile data original value given at command line. */ + const char *statedir_help; /* Directory of nonvolatile data help description. */ + char *dns_arg; /* DNS Server to use. */ + char *dns_orig; /* DNS Server to use original value given at command line. */ + const char *dns_help; /* DNS Server to use help description. */ + char *listen_arg; /* Local interface. */ + char *listen_orig; /* Local interface original value given at command line. */ + const char *listen_help; /* Local interface help description. */ + char *remote_arg; /* Remote host. */ + char *remote_orig; /* Remote host original value given at command line. */ + const char *remote_help; /* Remote host help description. */ + int contexts_arg; /* Number of contexts (default='1'). */ + char *contexts_orig; /* Number of contexts original value given at command line. */ + const char *contexts_help; /* Number of contexts help description. */ + int timelimit_arg; /* Exit after timelimit seconds (default='0'). */ + char *timelimit_orig; /* Exit after timelimit seconds original value given at command line. */ + const char *timelimit_help; /* Exit after timelimit seconds help description. */ + int gtpversion_arg; /* GTP version to use (default='1'). */ + char *gtpversion_orig; /* GTP version to use original value given at command line. */ + const char *gtpversion_help; /* GTP version to use help description. */ + char *apn_arg; /* Access point name (default='internet'). */ + char *apn_orig; /* Access point name original value given at command line. */ + const char *apn_help; /* Access point name help description. */ + int selmode_arg; /* Selection mode (default='0x01'). */ + char *selmode_orig; /* Selection mode original value given at command line. */ + const char *selmode_help; /* Selection mode help description. */ + char *rattype_arg; /* Radio Access Technology Type (optional). */ + char *rattype_orig; + char *rattype_help; + char *userloc_arg; /* User Location Information (optional). */ + char *userloc_orig; + char *userloc_help; + char *rai_arg; /* Routing Area Information (optional). */ + char *rai_orig; + char *rai_help; + char *mstz_arg; /* MS Time Zone (optional). */ + char *mstz_orig; + char *mstz_help; + char *imeisv_arg; /* IMEI(SV) (optional). */ + char *imeisv_orig; + char *imeisv_help; + char *imsi_arg; /* IMSI (default='240010123456789'). */ + char *imsi_orig; /* IMSI original value given at command line. */ + const char *imsi_help; /* IMSI help description. */ + int nsapi_arg; /* NSAPI (default='0'). */ + char *nsapi_orig; /* NSAPI original value given at command line. */ + const char *nsapi_help; /* NSAPI help description. */ + char *msisdn_arg; /* Mobile Station ISDN number (default='46702123456'). */ + char *msisdn_orig; /* Mobile Station ISDN number original value given at command line. */ + const char *msisdn_help; /* Mobile Station ISDN number help description. */ + int qos_arg; /* Requested quality of service (default='0x0b921f'). */ + char *qos_orig; /* Requested quality of service original value given at command line. */ + const char *qos_help; /* Requested quality of service help description. */ + unsigned long long int qose1_arg; /* Requested quality of service Extension 1 */ + char *qose1_orig; /* Requested quality of service Extension 1 original value given at command line. */ + int qose2_arg; /* Requested quality of service Extension 2 */ + char *qose2_orig; /* Requested quality of service Extension 2 original value given at command line. */ + int qose3_arg; /* Requested quality of service Extension 3 */ + char *qose3_orig; /* Requested quality of service Extension 3 original value given at command line. */ + int qose4_arg; /* Requested quality of service Extension 4 */ + char *qose4_orig; /* Requested quality of service Extension 4 original value given at command line. */ + int charging_arg; /* Charging characteristics (default='0x0800'). */ + char *charging_orig; /* Charging characteristics original value given at command line. */ + const char *charging_help; /* Charging characteristics help description. */ + char *uid_arg; /* Login user ID (default='mig'). */ + char *uid_orig; /* Login user ID original value given at command line. */ + const char *uid_help; /* Login user ID help description. */ + char *pwd_arg; /* Login password (default='hemmelig'). */ + char *pwd_orig; /* Login password original value given at command line. */ + const char *pwd_help; /* Login password help description. */ + int createif_flag; /* Create local network interface (default=off). */ + const char *createif_help; /* Create local network interface help description. */ + char *net_arg; /* Network address for local interface. */ + char *net_orig; /* Network address for local interface original value given at command line. */ + const char *net_help; /* Network address for local interface help description. */ + int defaultroute_flag; /* Create default route (default=off). */ + const char *defaultroute_help; /* Create default route help description. */ + char *ipup_arg; /* Script to run after link-up. */ + char *ipup_orig; /* Script to run after link-up original value given at command line. */ + const char *ipup_help; /* Script to run after link-up help description. */ + char *ipdown_arg; /* Script to run after link-down. */ + char *ipdown_orig; /* Script to run after link-down original value given at command line. */ + const char *ipdown_help; /* Script to run after link-down help description. */ + char *pinghost_arg; /* Ping remote host. */ + char *pinghost_orig; /* Ping remote host original value given at command line. */ + const char *pinghost_help; /* Ping remote host help description. */ + int pingrate_arg; /* Number of ping req per second (default='1'). */ + char *pingrate_orig; /* Number of ping req per second original value given at command line. */ + const char *pingrate_help; /* Number of ping req per second help description. */ + int pingsize_arg; /* Number of ping data bytes (default='56'). */ + char *pingsize_orig; /* Number of ping data bytes original value given at command line. */ + const char *pingsize_help; /* Number of ping data bytes help description. */ + int pingcount_arg; /* Number of ping req to send (default='0'). */ + char *pingcount_orig; /* Number of ping req to send original value given at command line. */ + const char *pingcount_help; /* Number of ping req to send help description. */ + int pingquiet_flag; /* Do not print ping packet info (default=off). */ + const char *pingquiet_help; /* Do not print ping packet info help description. */ + int norecovery_flag; /* Do not print ping packet info (default=off). */ + const char *norecovery_help; /* Do not print ping packet info help description. */ -} ; + int help_given; /* Whether help was given. */ + int version_given; /* Whether version was given. */ + int debug_given; /* Whether debug was given. */ + int conf_given; /* Whether conf was given. */ + int pidfile_given; /* Whether pidfile was given. */ + int statedir_given; /* Whether statedir was given. */ + int dns_given; /* Whether dns was given. */ + int listen_given; /* Whether listen was given. */ + int remote_given; /* Whether remote was given. */ + int contexts_given; /* Whether contexts was given. */ + int timelimit_given; /* Whether timelimit was given. */ + int gtpversion_given; /* Whether gtpversion was given. */ + int apn_given; /* Whether apn was given. */ + int selmode_given; /* Whether selmode was given. */ + int rattype_given; /* Whether rattype was given. */ + int userloc_given; /* Whether userloc was given. */ + int rai_given; /* Whether RAI was given. */ + int mstz_given; /* Whether mstz was given. */ + int imeisv_given; /* Whether imeisv was given. */ + int imsi_given; /* Whether imsi was given. */ + int nsapi_given; /* Whether nsapi was given. */ + int msisdn_given; /* Whether msisdn was given. */ + int qos_given; /* Whether qos was given. */ + int qose1_given; /* Whether qos Extension 1 was given. */ + int qose2_given; /* Whether qos Extension 2 was given. */ + int qose3_given; /* Whether qos Extension 3 was given. */ + int qose4_given; /* Whether qos Extension 4 was given. */ + int charging_given; /* Whether charging was given. */ + int uid_given; /* Whether uid was given. */ + int pwd_given; /* Whether pwd was given. */ + int createif_given; /* Whether createif was given. */ + int net_given; /* Whether net was given. */ + int defaultroute_given; /* Whether defaultroute was given. */ + int ipup_given; /* Whether ipup was given. */ + int ipdown_given; /* Whether ipdown was given. */ + int pinghost_given; /* Whether pinghost was given. */ + int pingrate_given; /* Whether pingrate was given. */ + int pingsize_given; /* Whether pingsize was given. */ + int pingcount_given; /* Whether pingcount was given. */ + int pingquiet_given; /* Whether pingquiet was given. */ + int norecovery_given; /* Whether norecovery was given. */ -extern const char *gengetopt_args_info_purpose; -extern const char *gengetopt_args_info_usage; -extern const char *gengetopt_args_info_help[]; + }; -int cmdline_parser (int argc, char * const *argv, - struct gengetopt_args_info *args_info); -int cmdline_parser2 (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); -int cmdline_parser_file_save(const char *filename, - struct gengetopt_args_info *args_info); + extern const char *gengetopt_args_info_purpose; + extern const char *gengetopt_args_info_usage; + extern const char *gengetopt_args_info_help[]; -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); + int cmdline_parser(int argc, char *const *argv, + struct gengetopt_args_info *args_info); + int cmdline_parser2(int argc, char *const *argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); -void cmdline_parser_init (struct gengetopt_args_info *args_info); -void cmdline_parser_free (struct gengetopt_args_info *args_info); + void cmdline_parser_print_help(void); + void cmdline_parser_print_version(void); -int cmdline_parser_configfile (char * const filename, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); + void cmdline_parser_init(struct gengetopt_args_info *args_info); + void cmdline_parser_free(struct gengetopt_args_info *args_info); -int cmdline_parser_required (struct gengetopt_args_info *args_info, - const char *prog_name); + int cmdline_parser_configfile(char *const filename, + struct gengetopt_args_info *args_info, + int override, int initialize, + int check_required); + int cmdline_parser_required(struct gengetopt_args_info *args_info, + const char *prog_name); #ifdef __cplusplus } -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 48a33ea..79494c9 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -14,12 +14,10 @@ * */ - #ifdef __linux__ -#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ +#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ #endif - #include #include #include @@ -51,15 +49,15 @@ #include "../gtp/gtp.h" #include "cmdline.h" -#define IPADDRLEN 256 /* Character length of addresses */ -#define MAXCONTEXTS 1024 /* Max number of allowed contexts */ +#define IPADDRLEN 256 /* Character length of addresses */ +#define MAXCONTEXTS 1024 /* Max number of allowed contexts */ /* HASH tables for IP address allocation */ struct iphash_t { - uint8_t inuse; /* 0=free. 1=used by somebody */ - struct iphash_t *ipnext; - struct pdp_t *pdp; - struct in_addr addr; + uint8_t inuse; /* 0=free. 1=used by somebody */ + struct iphash_t *ipnext; + struct pdp_t *pdp; + struct in_addr addr; }; struct iphash_t iparr[MAXCONTEXTS]; struct iphash_t *iphash[MAXCONTEXTS]; @@ -73,52 +71,51 @@ struct iphash_t *iphash[MAXCONTEXTS]; /* 5: Disconnected */ int state = 0; -struct gsn_t *gsn = NULL; /* GSN instance */ -struct tun_t *tun = NULL; /* TUN instance */ -int maxfd = 0; /* For select() */ -int echoversion = 1; /* First try this version */ +struct gsn_t *gsn = NULL; /* GSN instance */ +struct tun_t *tun = NULL; /* TUN instance */ +int maxfd = 0; /* For select() */ +int echoversion = 1; /* First try this version */ /* Struct with local versions of gengetopt options */ struct { - int debug; /* Print debug messages */ - int createif; /* Create local network interface */ - struct in_addr netaddr, destaddr, net, mask; /* Network interface */ - char *ipup, *ipdown; /* Filename of scripts */ - int defaultroute; /* Set up default route */ - struct in_addr pinghost; /* Remote ping host */ - int pingrate; - int pingsize; - int pingcount; - int pingquiet; - struct in_addr listen; - struct in_addr remote; - struct in_addr dns; - int contexts; /* Number of contexts to create */ - int timelimit; /* Number of seconds to be connected */ - char *statedir; - uint64_t imsi; - uint8_t nsapi; - int gtpversion; - struct ul255_t pco; - struct ul255_t qos; - uint16_t cch; - struct ul255_t apn; - uint8_t selmode; - struct ul255_t rattype; - int rattype_given; - struct ul255_t userloc; - int userloc_given; - struct ul255_t rai; - int rai_given; - struct ul255_t mstz; - int mstz_given; - struct ul255_t imeisv; - int imeisv_given; - struct ul16_t msisdn; - int norecovery_given; + int debug; /* Print debug messages */ + int createif; /* Create local network interface */ + struct in_addr netaddr, destaddr, net, mask; /* Network interface */ + char *ipup, *ipdown; /* Filename of scripts */ + int defaultroute; /* Set up default route */ + struct in_addr pinghost; /* Remote ping host */ + int pingrate; + int pingsize; + int pingcount; + int pingquiet; + struct in_addr listen; + struct in_addr remote; + struct in_addr dns; + int contexts; /* Number of contexts to create */ + int timelimit; /* Number of seconds to be connected */ + char *statedir; + uint64_t imsi; + uint8_t nsapi; + int gtpversion; + struct ul255_t pco; + struct ul255_t qos; + uint16_t cch; + struct ul255_t apn; + uint8_t selmode; + struct ul255_t rattype; + int rattype_given; + struct ul255_t userloc; + int userloc_given; + struct ul255_t rai; + int rai_given; + struct ul255_t mstz; + int mstz_given; + struct ul255_t imeisv; + int imeisv_given; + struct ul16_t msisdn; + int norecovery_given; } options; - /* Definitions to use for PING. Most of the ping code was derived from */ /* the original ping program by Mike Muuss */ @@ -128,23 +125,23 @@ struct { #define CREATEPING_ICMP 8 struct ip_ping { - uint8_t ipver; /* Type and header length*/ - uint8_t tos; /* Type of Service */ - uint16_t length; /* Total length */ - uint16_t fragid; /* Identifier */ - uint16_t offset; /* Flags and fragment offset */ - uint8_t ttl; /* Time to live */ - uint8_t protocol; /* Protocol */ - uint16_t ipcheck; /* Header checksum */ - uint32_t src; /* Source address */ - uint32_t dst; /* Destination */ - uint8_t type; /* Type and header length*/ - uint8_t code; /* Code */ - uint16_t checksum; /* Header checksum */ - uint16_t ident; /* Identifier */ - uint16_t seq; /* Sequence number */ - uint8_t data[CREATEPING_MAX]; /* Data */ -} __attribute__((packed)); + uint8_t ipver; /* Type and header length */ + uint8_t tos; /* Type of Service */ + uint16_t length; /* Total length */ + uint16_t fragid; /* Identifier */ + uint16_t offset; /* Flags and fragment offset */ + uint8_t ttl; /* Time to live */ + uint8_t protocol; /* Protocol */ + uint16_t ipcheck; /* Header checksum */ + uint32_t src; /* Source address */ + uint32_t dst; /* Destination */ + uint8_t type; /* Type and header length */ + uint8_t code; /* Code */ + uint16_t checksum; /* Header checksum */ + uint16_t ident; /* Identifier */ + uint16_t seq; /* Sequence number */ + uint8_t data[CREATEPING_MAX]; /* Data */ +} __attribute__ ((packed)); /* Statistical values for ping */ int nreceived = 0; @@ -153,1489 +150,1562 @@ int ntransmitted = 0; int tmin = 999999999; int tmax = 0; int tsum = 0; -int pingseq = 0; /* Ping sequence counter */ +int pingseq = 0; /* Ping sequence counter */ struct timeval firstping; -int ipset(struct iphash_t *ipaddr, struct in_addr *addr) { - int hash = ippool_hash4(addr) % MAXCONTEXTS; - struct iphash_t *h; - struct iphash_t *prev = NULL; - ipaddr->ipnext = NULL; - ipaddr->addr.s_addr = addr->s_addr; - for (h = iphash[hash]; h; h = h->ipnext) - prev = h; - if (!prev) - iphash[hash] = ipaddr; - else - prev->ipnext = ipaddr; - return 0; +int ipset(struct iphash_t *ipaddr, struct in_addr *addr) +{ + int hash = ippool_hash4(addr) % MAXCONTEXTS; + struct iphash_t *h; + struct iphash_t *prev = NULL; + ipaddr->ipnext = NULL; + ipaddr->addr.s_addr = addr->s_addr; + for (h = iphash[hash]; h; h = h->ipnext) + prev = h; + if (!prev) + iphash[hash] = ipaddr; + else + prev->ipnext = ipaddr; + return 0; } -int ipdel(struct iphash_t *ipaddr) { - int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS; - struct iphash_t *h; - struct iphash_t *prev = NULL; - for (h = iphash[hash]; h; h = h->ipnext) { - if (h == ipaddr) { - if (!prev) - iphash[hash] = h->ipnext; - else - prev->ipnext = h->ipnext; - return 0; - } - prev = h; - } - return EOF; /* End of linked list and not found */ +int ipdel(struct iphash_t *ipaddr) +{ + int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS; + struct iphash_t *h; + struct iphash_t *prev = NULL; + for (h = iphash[hash]; h; h = h->ipnext) { + if (h == ipaddr) { + if (!prev) + iphash[hash] = h->ipnext; + else + prev->ipnext = h->ipnext; + return 0; + } + prev = h; + } + return EOF; /* End of linked list and not found */ } -int ipget(struct iphash_t **ipaddr, struct in_addr *addr) { - int hash = ippool_hash4(addr) % MAXCONTEXTS; - struct iphash_t *h; - for (h = iphash[hash]; h; h = h->ipnext) { - if ((h->addr.s_addr == addr->s_addr)) { - *ipaddr = h; - return 0; - } - } - return EOF; /* End of linked list and not found */ +int ipget(struct iphash_t **ipaddr, struct in_addr *addr) +{ + int hash = ippool_hash4(addr) % MAXCONTEXTS; + struct iphash_t *h; + for (h = iphash[hash]; h; h = h->ipnext) { + if ((h->addr.s_addr == addr->s_addr)) { + *ipaddr = h; + return 0; + } + } + return EOF; /* End of linked list and not found */ } - /* Used to write process ID to file. Assume someone else will delete */ -void log_pid(char *pidfile) { - FILE *file; - mode_t oldmask; - - oldmask = umask(022); - file = fopen(pidfile, "w"); - umask(oldmask); - if(!file) - return; - fprintf(file, "%d\n", (int) getpid()); - fclose(file); +void log_pid(char *pidfile) +{ + FILE *file; + mode_t oldmask; + + oldmask = umask(022); + file = fopen(pidfile, "w"); + umask(oldmask); + if (!file) + return; + fprintf(file, "%d\n", (int)getpid()); + fclose(file); } +int process_options(int argc, char **argv) +{ + /* gengeopt declarations */ + struct gengetopt_args_info args_info; -int process_options(int argc, char **argv) { - /* gengeopt declarations */ - struct gengetopt_args_info args_info; + struct hostent *host; + unsigned int n; + uint16_t i; + uint8_t a; + uint8_t b; + char *tmp; + char *pch; + char *type; + char *mcc; + char *mnc; + char *lac; + int lac_d; + char *rest; + char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" }; + char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" }; + char *mstz_el[] = { "SIGN", "QUARTERS", "DST" }; + int sign; + int nbquarters; + int DST; - struct hostent *host; - unsigned int n; - uint16_t i; - uint8_t a; - uint8_t b; - char * tmp; - char * pch; - char * type; - char * mcc; - char * mnc; - char * lac; - int lac_d; - char * rest; - char *userloc_el[] = {"TYPE","MCC","MNC","LAC","REST"}; - char *rai_el[] = {"MCC","MNC","LAC","RAC"}; - char *mstz_el[] = {"SIGN","QUARTERS","DST"}; - int sign ; - int nbquarters ; - int DST ; - - - if (cmdline_parser (argc, argv, &args_info) != 0) - return -1; - if (args_info.debug_flag) { - if (args_info.remote_arg) printf("remote: %s\n", args_info.remote_arg); - if (args_info.listen_arg) printf("listen: %s\n", args_info.listen_arg); - if (args_info.conf_arg) printf("conf: %s\n", args_info.conf_arg); - printf("debug: %d\n", args_info.debug_flag); - if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg); - printf("qos: %#08x\n", args_info.qos_arg); - printf("qose1: %#0.16llx\n", args_info.qose1_arg); - printf("qose2: %#04x\n", args_info.qose2_arg); - printf("qose3: %#06x\n", args_info.qose3_arg); - printf("qose4: %#06x\n", args_info.qose4_arg); - printf("charging: %#04x\n", args_info.charging_arg); - if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg); - if (args_info.msisdn_arg) printf("msisdn: %s\n", args_info.msisdn_arg); - if (args_info.uid_arg) printf("uid: %s\n", args_info.uid_arg); - if (args_info.pwd_arg) printf("pwd: %s\n", args_info.pwd_arg); - if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg); - if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); - if (args_info.dns_arg) printf("dns: %s\n", args_info.dns_arg); - printf("contexts: %d\n", args_info.contexts_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - printf("createif: %d\n", args_info.createif_flag); - if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg); - if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg); - printf("defaultroute: %d\n", args_info.defaultroute_flag); - if (args_info.pinghost_arg) printf("pinghost: %s\n", args_info.pinghost_arg); - printf("pingrate: %d\n", args_info.pingrate_arg); - printf("pingsize: %d\n", args_info.pingsize_arg); - printf("pingcount: %d\n", args_info.pingcount_arg); - printf("pingquiet: %d\n", args_info.pingquiet_flag); - printf("norecovery: %d\n", args_info.norecovery_flag); - } - - /* Try out our new parser */ - - if (args_info.conf_arg) { - if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0, 0, 0) != 0) - return -1; - if (args_info.debug_flag) { - printf("cmdline_parser_configfile\n"); - if (args_info.remote_arg) printf("remote: %s\n", args_info.remote_arg); - if (args_info.listen_arg) printf("listen: %s\n", args_info.listen_arg); - if (args_info.conf_arg) printf("conf: %s\n", args_info.conf_arg); - printf("debug: %d\n", args_info.debug_flag); - if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg); - printf("qos: %#08x\n", args_info.qos_arg); - printf("qose1: %#0.16llx\n", args_info.qose1_arg); - printf("qose2: %#04x\n", args_info.qose2_arg); - printf("qose3: %#06x\n", args_info.qose3_arg); - printf("qose4: %#06x\n", args_info.qose4_arg); - printf("charging: %#04x\n", args_info.charging_arg); - if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg); - if (args_info.msisdn_arg) printf("msisdn: %s\n", args_info.msisdn_arg); - if (args_info.uid_arg) printf("uid: %s\n", args_info.uid_arg); - if (args_info.pwd_arg) printf("pwd: %s\n", args_info.pwd_arg); - if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg); - if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); - if (args_info.dns_arg) printf("dns: %s\n", args_info.dns_arg); - printf("contexts: %d\n", args_info.contexts_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - printf("createif: %d\n", args_info.createif_flag); - if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg); - if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg); - printf("defaultroute: %d\n", args_info.defaultroute_flag); - if (args_info.pinghost_arg) printf("pinghost: %s\n", args_info.pinghost_arg); - printf("pingrate: %d\n", args_info.pingrate_arg); - printf("pingsize: %d\n", args_info.pingsize_arg); - printf("pingcount: %d\n", args_info.pingcount_arg); - printf("pingquiet: %d\n", args_info.pingquiet_flag); - printf("norecovery: %d\n", args_info.norecovery_flag); - } - } - - /* Handle each option */ - - /* foreground */ - /* If fg flag not given run as a daemon */ - /* Do not allow sgsnemu to run as deamon - if (!args_info.fg_flag) - { - closelog(); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); - freopen("/dev/null", "r", stdin); - daemon(0, 0); - openlog(PACKAGE, LOG_PID, LOG_DAEMON); - } */ - - /* debug */ - options.debug = args_info.debug_flag; - - /* pidfile */ - /* This has to be done after we have our final pid */ - if (args_info.pidfile_arg) { - log_pid(args_info.pidfile_arg); - } - - /* dns */ - /* If no dns option is given use system default */ - /* Do hostname lookup to translate hostname to IP address */ - printf("\n"); - if (args_info.dns_arg) { - if (!(host = gethostbyname(args_info.dns_arg))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid DNS address: %s!", args_info.dns_arg); - return -1; - } - else { - memcpy(&options.dns.s_addr, host->h_addr, host->h_length); - _res.nscount = 1; - _res.nsaddr_list[0].sin_addr = options.dns; - printf("Using DNS server: %s (%s)\n", - args_info.dns_arg, inet_ntoa(options.dns)); - } - } - else { - options.dns.s_addr= 0; - printf("Using default DNS server\n"); - } - - /* listen */ - /* If no listen option is specified listen to any local port */ - /* Do hostname lookup to translate hostname to IP address */ - if (args_info.listen_arg) { - if (!(host = gethostbyname(args_info.listen_arg))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid listening address: %s!", args_info.listen_arg); - return -1; - } - else { - memcpy(&options.listen.s_addr, host->h_addr, host->h_length); - printf("Local IP address is: %s (%s)\n", - args_info.listen_arg, inet_ntoa(options.listen)); - } - } - else { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Listening address must be specified: %s!", args_info.listen_arg); - return -1; - } - - - /* remote */ - /* If no remote option is specified terminate */ - /* Do hostname lookup to translate hostname to IP address */ - if (args_info.remote_arg) { - if (!(host = gethostbyname(args_info.remote_arg))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid remote address: %s!", args_info.remote_arg); - return -1; - } - else { - memcpy(&options.remote.s_addr, host->h_addr, host->h_length); - printf("Remote IP address is: %s (%s)\n", - args_info.remote_arg, inet_ntoa(options.remote)); - } - } - else { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "No remote address given!"); - return -1; - } - - - /* imsi */ - if (strlen(args_info.imsi_arg)!=15) { - printf("Invalid IMSI\n"); - return -1; - } - - options.imsi = 0xf000000000000000ull; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 0]-48)); - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32; - options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36; - options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40; - options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44; - options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48; - options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52; - options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56; - - printf("IMSI is: %s (%#08llx)\n", - args_info.imsi_arg, options.imsi); - - - /* nsapi */ - if ((args_info.nsapi_arg > 15) || - (args_info.nsapi_arg < 0)) { - printf("Invalid NSAPI\n"); - return -1; - } - options.nsapi = args_info.nsapi_arg; - printf("Using NSAPI: %d\n", args_info.nsapi_arg); - - - /* qos */ - options.qos.l = 4; - options.qos.v[3] = (args_info.qos_arg) & 0xff; - options.qos.v[2] = ((args_info.qos_arg) >> 8)& 0xff; - options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff; - options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff; - /* Extensions according to 3GPP TS 24.008 */ - if (args_info.qose1_given == 1 ) { - options.qos.l = 12; - options.qos.v[11] = (args_info.qose1_arg) & 0xff; - options.qos.v[10] = ((args_info.qose1_arg) >> 8)& 0xff; - options.qos.v[9] = ((args_info.qose1_arg) >> 16)& 0xff; - options.qos.v[8] = ((args_info.qose1_arg) >> 24)& 0xff; - options.qos.v[7] = ((args_info.qose1_arg) >> 32)& 0xff; - options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff; - options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff; - options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff; - if (args_info.qose2_given == 1 ) { - options.qos.l = 13; - options.qos.v[12] = (args_info.qose2_arg) & 0xff; - if (args_info.qose3_given == 1 ) { - options.qos.l = 15; - options.qos.v[14] = (args_info.qose3_arg) & 0xff; - options.qos.v[13] = ((args_info.qose3_arg) >> 8)& 0xff; - if (args_info.qose4_given == 1 ) { - options.qos.l = 17; - options.qos.v[16] = (args_info.qose4_arg) & 0xff; - options.qos.v[15] = ((args_info.qose4_arg) >> 8)& 0xff; + if (cmdline_parser(argc, argv, &args_info) != 0) + return -1; + if (args_info.debug_flag) { + if (args_info.remote_arg) + printf("remote: %s\n", args_info.remote_arg); + if (args_info.listen_arg) + printf("listen: %s\n", args_info.listen_arg); + if (args_info.conf_arg) + printf("conf: %s\n", args_info.conf_arg); + printf("debug: %d\n", args_info.debug_flag); + if (args_info.imsi_arg) + printf("imsi: %s\n", args_info.imsi_arg); + printf("qos: %#08x\n", args_info.qos_arg); + printf("qose1: %#0.16llx\n", args_info.qose1_arg); + printf("qose2: %#04x\n", args_info.qose2_arg); + printf("qose3: %#06x\n", args_info.qose3_arg); + printf("qose4: %#06x\n", args_info.qose4_arg); + printf("charging: %#04x\n", args_info.charging_arg); + if (args_info.apn_arg) + printf("apn: %s\n", args_info.apn_arg); + if (args_info.msisdn_arg) + printf("msisdn: %s\n", args_info.msisdn_arg); + if (args_info.uid_arg) + printf("uid: %s\n", args_info.uid_arg); + if (args_info.pwd_arg) + printf("pwd: %s\n", args_info.pwd_arg); + if (args_info.pidfile_arg) + printf("pidfile: %s\n", args_info.pidfile_arg); + if (args_info.statedir_arg) + printf("statedir: %s\n", args_info.statedir_arg); + if (args_info.dns_arg) + printf("dns: %s\n", args_info.dns_arg); + printf("contexts: %d\n", args_info.contexts_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + printf("createif: %d\n", args_info.createif_flag); + if (args_info.ipup_arg) + printf("ipup: %s\n", args_info.ipup_arg); + if (args_info.ipdown_arg) + printf("ipdown: %s\n", args_info.ipdown_arg); + printf("defaultroute: %d\n", args_info.defaultroute_flag); + if (args_info.pinghost_arg) + printf("pinghost: %s\n", args_info.pinghost_arg); + printf("pingrate: %d\n", args_info.pingrate_arg); + printf("pingsize: %d\n", args_info.pingsize_arg); + printf("pingcount: %d\n", args_info.pingcount_arg); + printf("pingquiet: %d\n", args_info.pingquiet_flag); + printf("norecovery: %d\n", args_info.norecovery_flag); } - } - } - } - - /* charging */ - options.cch = args_info.charging_arg; - - /* contexts */ - if (args_info.contexts_arg > MAXCONTEXTS) { - printf("Contexts has to be less than %d\n", MAXCONTEXTS); - return -1; - } - options.contexts = args_info.contexts_arg; - /* Timelimit */ - options.timelimit = args_info.timelimit_arg; - - /* gtpversion */ - if ((args_info.gtpversion_arg > 1) || - (args_info.gtpversion_arg < 0)) { - printf("Invalid GTP version\n"); - return -1; - } - options.gtpversion = args_info.gtpversion_arg; - printf("Using GTP version: %d\n", args_info.gtpversion_arg); + /* Try out our new parser */ + if (args_info.conf_arg) { + if (cmdline_parser_configfile + (args_info.conf_arg, &args_info, 0, 0, 0) != 0) + return -1; + if (args_info.debug_flag) { + printf("cmdline_parser_configfile\n"); + if (args_info.remote_arg) + printf("remote: %s\n", args_info.remote_arg); + if (args_info.listen_arg) + printf("listen: %s\n", args_info.listen_arg); + if (args_info.conf_arg) + printf("conf: %s\n", args_info.conf_arg); + printf("debug: %d\n", args_info.debug_flag); + if (args_info.imsi_arg) + printf("imsi: %s\n", args_info.imsi_arg); + printf("qos: %#08x\n", args_info.qos_arg); + printf("qose1: %#0.16llx\n", args_info.qose1_arg); + printf("qose2: %#04x\n", args_info.qose2_arg); + printf("qose3: %#06x\n", args_info.qose3_arg); + printf("qose4: %#06x\n", args_info.qose4_arg); + printf("charging: %#04x\n", args_info.charging_arg); + if (args_info.apn_arg) + printf("apn: %s\n", args_info.apn_arg); + if (args_info.msisdn_arg) + printf("msisdn: %s\n", args_info.msisdn_arg); + if (args_info.uid_arg) + printf("uid: %s\n", args_info.uid_arg); + if (args_info.pwd_arg) + printf("pwd: %s\n", args_info.pwd_arg); + if (args_info.pidfile_arg) + printf("pidfile: %s\n", args_info.pidfile_arg); + if (args_info.statedir_arg) + printf("statedir: %s\n", + args_info.statedir_arg); + if (args_info.dns_arg) + printf("dns: %s\n", args_info.dns_arg); + printf("contexts: %d\n", args_info.contexts_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + printf("createif: %d\n", args_info.createif_flag); + if (args_info.ipup_arg) + printf("ipup: %s\n", args_info.ipup_arg); + if (args_info.ipdown_arg) + printf("ipdown: %s\n", args_info.ipdown_arg); + printf("defaultroute: %d\n", + args_info.defaultroute_flag); + if (args_info.pinghost_arg) + printf("pinghost: %s\n", + args_info.pinghost_arg); + printf("pingrate: %d\n", args_info.pingrate_arg); + printf("pingsize: %d\n", args_info.pingsize_arg); + printf("pingcount: %d\n", args_info.pingcount_arg); + printf("pingquiet: %d\n", args_info.pingquiet_flag); + printf("norecovery: %d\n", args_info.norecovery_flag); + } + } - /* apn */ - if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) { - printf("Invalid APN\n"); - return -1; - } - options.apn.l = strlen(args_info.apn_arg); - strncpy((char *)options.apn.v, args_info.apn_arg, sizeof(options.apn.v)); - options.apn.v[sizeof(options.apn.v)-1] = 0; - printf("Using APN: %s\n", args_info.apn_arg); + /* Handle each option */ + /* foreground */ + /* If fg flag not given run as a daemon */ + /* Do not allow sgsnemu to run as deamon + if (!args_info.fg_flag) + { + closelog(); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + freopen("/dev/null", "r", stdin); + daemon(0, 0); + openlog(PACKAGE, LOG_PID, LOG_DAEMON); + } */ - /* selmode */ - options.selmode = args_info.selmode_arg; - printf("Using selection mode: %d\n", args_info.selmode_arg); + /* debug */ + options.debug = args_info.debug_flag; - /* rattype */ - if (args_info.rattype_given == 1 ) { - options.rattype_given = 1 ; - options.rattype.l = strlen(args_info.rattype_arg) ; - options.rattype.v[0] = atoi(args_info.rattype_arg) ; - printf("Using RAT Type: %s\n", args_info.rattype_arg); - } + /* pidfile */ + /* This has to be done after we have our final pid */ + if (args_info.pidfile_arg) { + log_pid(args_info.pidfile_arg); + } - /* userloc */ - if (args_info.userloc_given == 1 ) { - printf("Using User Location Information: %s\n", args_info.userloc_arg); - tmp = args_info.userloc_arg ; - n=0; - pch = strtok (tmp,"."); - while (pch != NULL) { - userloc_el[n] = pch ; - pch = strtok (NULL, "."); - n++; - } + /* dns */ + /* If no dns option is given use system default */ + /* Do hostname lookup to translate hostname to IP address */ + printf("\n"); + if (args_info.dns_arg) { + if (!(host = gethostbyname(args_info.dns_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid DNS address: %s!", args_info.dns_arg); + return -1; + } else { + memcpy(&options.dns.s_addr, host->h_addr, + host->h_length); + _res.nscount = 1; + _res.nsaddr_list[0].sin_addr = options.dns; + printf("Using DNS server: %s (%s)\n", + args_info.dns_arg, inet_ntoa(options.dns)); + } + } else { + options.dns.s_addr = 0; + printf("Using default DNS server\n"); + } - options.userloc_given = 1 ; - options.userloc.l = 8 ; + /* listen */ + /* If no listen option is specified listen to any local port */ + /* Do hostname lookup to translate hostname to IP address */ + if (args_info.listen_arg) { + if (!(host = gethostbyname(args_info.listen_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid listening address: %s!", + args_info.listen_arg); + return -1; + } else { + memcpy(&options.listen.s_addr, host->h_addr, + host->h_length); + printf("Local IP address is: %s (%s)\n", + args_info.listen_arg, inet_ntoa(options.listen)); + } + } else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Listening address must be specified: %s!", + args_info.listen_arg); + return -1; + } - /* 3GPP Geographic Location Type t0 / t1 / t2 */ - type = userloc_el[0]; - printf("->type : %c\n", type[0]); - if ( (strlen(type)!=1) || (!isdigit(type[0])) ) { - printf("Invalid type \n"); - return -1; - } - /* options.userloc.v[0] = 0x00 */ - options.userloc.v[0] = type[0] - 48; + /* remote */ + /* If no remote option is specified terminate */ + /* Do hostname lookup to translate hostname to IP address */ + if (args_info.remote_arg) { + if (!(host = gethostbyname(args_info.remote_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid remote address: %s!", + args_info.remote_arg); + return -1; + } else { + memcpy(&options.remote.s_addr, host->h_addr, + host->h_length); + printf("Remote IP address is: %s (%s)\n", + args_info.remote_arg, inet_ntoa(options.remote)); + } + } else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "No remote address given!"); + return -1; + } - /* MCC */ - mcc = userloc_el[1] ; - printf("->mcc : %s\n", mcc); - if (strlen(mcc)!=3) { - printf("Invalid MCC lenght\n"); - return -1; - } + /* imsi */ + if (strlen(args_info.imsi_arg) != 15) { + printf("Invalid IMSI\n"); + return -1; + } - /* MNC */ - mnc = userloc_el[2] ; - printf("->mnc : %s\n", mnc); + options.imsi = 0xf000000000000000ull; + options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48)); + options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4; + options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8; + options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12; + options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16; + options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20; + options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24; + options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28; + options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32; + options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36; + options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40; + options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44; + options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48; + options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52; + options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56; - /* octet 5 - MCC Digit 2 - MCC Digit 1 */ - /* options.userloc.v[1] = 0x52 */ - a = (uint8_t) (mcc[0] - 48); - b = (uint8_t) (mcc[1] - 48); - options.userloc.v[1] = 16*b+a ; + printf("IMSI is: %s (%#08llx)\n", + args_info.imsi_arg, options.imsi); - /* octet 6 - MNC Digit 3 - MCC Digit 3 */ - /* options.userloc.v[2] = 0xf0 */ - a = (uint8_t) (mcc[2] - 48); + /* nsapi */ + if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) { + printf("Invalid NSAPI\n"); + return -1; + } + options.nsapi = args_info.nsapi_arg; + printf("Using NSAPI: %d\n", args_info.nsapi_arg); - if ( (strlen(mnc) > 3) || (strlen(mnc) < 2)) { - printf("Invalid MNC lenght\n"); - return -1; - } - if (strlen(mnc)==2) { - b = 15 ; - } - if (strlen(mnc)==3) { - b = (uint8_t) (mnc[2] - 48); - } - options.userloc.v[2] = 16*b+a ; + /* qos */ + options.qos.l = 4; + options.qos.v[3] = (args_info.qos_arg) & 0xff; + options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff; + options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff; + options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff; + /* Extensions according to 3GPP TS 24.008 */ + if (args_info.qose1_given == 1) { + options.qos.l = 12; + options.qos.v[11] = (args_info.qose1_arg) & 0xff; + options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff; + options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff; + options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff; + options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff; + options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff; + options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff; + options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff; + if (args_info.qose2_given == 1) { + options.qos.l = 13; + options.qos.v[12] = (args_info.qose2_arg) & 0xff; + if (args_info.qose3_given == 1) { + options.qos.l = 15; + options.qos.v[14] = + (args_info.qose3_arg) & 0xff; + options.qos.v[13] = + ((args_info.qose3_arg) >> 8) & 0xff; + if (args_info.qose4_given == 1) { + options.qos.l = 17; + options.qos.v[16] = + (args_info.qose4_arg) & 0xff; + options.qos.v[15] = + ((args_info.qose4_arg) >> 8) & 0xff; + } + } + } + } - /* octet 7 - MNC Digit 2 - MNC Digit 1 */ - /* options.userloc.v[3] = 0x99*/ - a = (uint8_t) (mnc[0]- 48); - b = (uint8_t) (mnc[1]- 48); - options.userloc.v[3] = 16*b+a ; + /* charging */ + options.cch = args_info.charging_arg; - /* LAC */ - lac = userloc_el[3] ; - /*options.userloc.v[4] = 0x12 ; */ - /*options.userloc.v[5] = 0x10 ; */ - printf("->LAC: %s\n", lac); - lac_d = atoi(lac); - if (lac_d>65535 || lac_d<1) { - printf("Invalid LAC\n"); - return -1; - } - i = lac_d >> 8 ; - options.userloc.v[4] = i; /* octet 8 - LAC */ - options.userloc.v[5] = lac_d; /* octet 9 - LAC */ + /* contexts */ + if (args_info.contexts_arg > MAXCONTEXTS) { + printf("Contexts has to be less than %d\n", MAXCONTEXTS); + return -1; + } + options.contexts = args_info.contexts_arg; - /* CI/SAC/RAC */ - rest = userloc_el[4] ; - printf("->CI/SAC/RAC : %s\n", rest); - lac_d = atoi(rest); - if (lac_d>65535 || lac_d<1) { - printf("Invalid CI/SAC/RAC\n"); - return -1; - } - /*options.userloc.v[6] = 0x04 ; */ - /*options.userloc.v[7] = 0xb7 ; */ - i = lac_d >> 8 ; - options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */ - options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */ - } + /* Timelimit */ + options.timelimit = args_info.timelimit_arg; - /* RAI */ - if (args_info.rai_given == 1 ) { - printf("Using RAI: %s\n", args_info.rai_arg); - tmp = args_info.rai_arg ; - n=0; - pch = strtok (tmp,"."); - while (pch != NULL) { - rai_el[n] = pch ; - pch = strtok (NULL, "."); - n++; - } + /* gtpversion */ + if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) { + printf("Invalid GTP version\n"); + return -1; + } + options.gtpversion = args_info.gtpversion_arg; + printf("Using GTP version: %d\n", args_info.gtpversion_arg); - options.rai_given = 1 ; - options.rai.l = 6 ; + /* apn */ + if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) { + printf("Invalid APN\n"); + return -1; + } + options.apn.l = strlen(args_info.apn_arg); + strncpy((char *)options.apn.v, args_info.apn_arg, + sizeof(options.apn.v)); + options.apn.v[sizeof(options.apn.v) - 1] = 0; + printf("Using APN: %s\n", args_info.apn_arg); + /* selmode */ + options.selmode = args_info.selmode_arg; + printf("Using selection mode: %d\n", args_info.selmode_arg); - /* MCC */ - mcc = rai_el[0] ; - printf("->mcc : %s\n", mcc); - if (strlen(mcc)!=3) { - printf("Invalid MCC lenght\n"); - return -1; - } + /* rattype */ + if (args_info.rattype_given == 1) { + options.rattype_given = 1; + options.rattype.l = strlen(args_info.rattype_arg); + options.rattype.v[0] = atoi(args_info.rattype_arg); + printf("Using RAT Type: %s\n", args_info.rattype_arg); + } - /* MNC */ - mnc = rai_el[1] ; - printf("->mnc : %s\n", mnc); + /* userloc */ + if (args_info.userloc_given == 1) { + printf("Using User Location Information: %s\n", + args_info.userloc_arg); + tmp = args_info.userloc_arg; + n = 0; + pch = strtok(tmp, "."); + while (pch != NULL) { + userloc_el[n] = pch; + pch = strtok(NULL, "."); + n++; + } - a = (uint8_t) (mcc[0] - 48); - b = (uint8_t) (mcc[1] - 48); - options.rai.v[0] = 16*b+a ; + options.userloc_given = 1; + options.userloc.l = 8; - /* octet 3 - MNC Digit 3 - MCC Digit 3 */ - a = (uint8_t) (mcc[2] - 48); + /* 3GPP Geographic Location Type t0 / t1 / t2 */ + type = userloc_el[0]; + printf("->type : %c\n", type[0]); + if ((strlen(type) != 1) || (!isdigit(type[0]))) { + printf("Invalid type \n"); + return -1; + } + /* options.userloc.v[0] = 0x00 */ + options.userloc.v[0] = type[0] - 48; - if ( (strlen(mnc) > 3) || (strlen(mnc) < 2)) { - printf("Invalid MNC lenght\n"); - return -1; - } - if (strlen(mnc)==2) { - b = 15 ; - } - if (strlen(mnc)==3) { - b = (uint8_t) (mnc[2] - 48); - } - options.rai.v[1] = 16*b+a ; + /* MCC */ + mcc = userloc_el[1]; + printf("->mcc : %s\n", mcc); + if (strlen(mcc) != 3) { + printf("Invalid MCC lenght\n"); + return -1; + } - /* octet 4 - MNC Digit 2 - MNC Digit 1 */ - a = (uint8_t) (mnc[0]- 48); - b = (uint8_t) (mnc[1]- 48); - options.rai.v[2] = 16*b+a ; + /* MNC */ + mnc = userloc_el[2]; + printf("->mnc : %s\n", mnc); - /* LAC */ - lac = rai_el[2] ; - printf("->LAC: %s\n", lac); - lac_d = atoi(lac); - if (lac_d>65535 || lac_d<1) { - printf("Invalid LAC\n"); - return -1; - } - i = lac_d >> 8 ; - options.rai.v[3] = i; /* octet 5 - LAC */ - options.rai.v[4] = lac_d; /* octet 6 - LAC */ + /* octet 5 - MCC Digit 2 - MCC Digit 1 */ + /* options.userloc.v[1] = 0x52 */ + a = (uint8_t) (mcc[0] - 48); + b = (uint8_t) (mcc[1] - 48); + options.userloc.v[1] = 16 * b + a; - /* RAC */ - rest = rai_el[3] ; - printf("->RAC : %s\n", rest); - lac_d = atoi(rest); - if (lac_d>255 || lac_d<1) { - printf("Invalid RAC\n"); - return -1; - } - options.rai.v[5] = lac_d; /* octet 7 - RAC */ - } + /* octet 6 - MNC Digit 3 - MCC Digit 3 */ + /* options.userloc.v[2] = 0xf0 */ + a = (uint8_t) (mcc[2] - 48); - /* mstz */ - if (args_info.mstz_given == 1 ) { - options.mstz_given = 1 ; - options.mstz.l = 2 ; + if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) { + printf("Invalid MNC lenght\n"); + return -1; + } + if (strlen(mnc) == 2) { + b = 15; + } + if (strlen(mnc) == 3) { + b = (uint8_t) (mnc[2] - 48); + } + options.userloc.v[2] = 16 * b + a; - printf("Using MS Time Zone: %s\n", args_info.mstz_arg); - tmp = args_info.mstz_arg ; - n=0; - pch = strtok (tmp,"."); - while (pch != NULL) { - mstz_el[n] = pch ; - pch = strtok (NULL, "."); - n++; - } + /* octet 7 - MNC Digit 2 - MNC Digit 1 */ + /* options.userloc.v[3] = 0x99 */ + a = (uint8_t) (mnc[0] - 48); + b = (uint8_t) (mnc[1] - 48); + options.userloc.v[3] = 16 * b + a; - /* sign */ - sign = atoi(mstz_el[0]) ; - printf("->Sign (0=+ / 1=-): %d\n", sign); - if ( sign!=0 && sign!=1 ) { - printf("Invalid Sign \n"); - return -1; - } - /* nbquarters */ - nbquarters = atoi(mstz_el[1]) ; - printf("->Number of Quarters of an Hour : %d\n", nbquarters); - if ( nbquarters<0 || nbquarters>79 ) { - printf("Invalid Number of Quarters \n"); - return -1; - } - /* DST */ - DST = atoi(mstz_el[2]) ; - printf("->Daylight Saving Time Adjustment : %d\n", DST); - if ( DST<0 || DST>3 ) { - printf("Invalid DST Adjustment \n"); - return -1; - } - /* 12345678 - bits 123 = unit of # of quarters of an hour - bits 678 = # of quarters of an hour / 10 - bit 5 = sign - */ - i= nbquarters % 10 ; - i = i << 4 ; - i = i + nbquarters / 10 + 8 * sign; - /* options.mstz.v[0] = 0x69 ; */ - /* options.mstz.v[1] = 0x01 ; */ - options.mstz.v[0] = i ; - options.mstz.v[1] = DST ; - n = (i & 0x08) ? '-' : '+'; - printf("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n", n , nbquarters / 4, nbquarters % 4 * 15); - } + /* LAC */ + lac = userloc_el[3]; + /*options.userloc.v[4] = 0x12 ; */ + /*options.userloc.v[5] = 0x10 ; */ + printf("->LAC: %s\n", lac); + lac_d = atoi(lac); + if (lac_d > 65535 || lac_d < 1) { + printf("Invalid LAC\n"); + return -1; + } + i = lac_d >> 8; + options.userloc.v[4] = i; /* octet 8 - LAC */ + options.userloc.v[5] = lac_d; /* octet 9 - LAC */ - /* imeisv */ - if (args_info.imeisv_given == 1 ) { - options.imeisv_given = 1 ; - if (strlen(args_info.imeisv_arg)!=16) { - printf("Invalid IMEI(SV)\n"); - return -1; - } - options.imeisv.l = 8 ; - for(n=0; n<8; n++) { - a = (uint8_t) (args_info.imeisv_arg [2*n] - 48) ; - b = (uint8_t) (args_info.imeisv_arg [2*n + 1] - 48) ; - options.imeisv.v[n] = 16*b+a ; - } - printf("Using IMEI(SV): %s\n", args_info.imeisv_arg); - } - - /* msisdn */ - if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) { - printf("Invalid MSISDN\n"); - return -1; - } - options.msisdn.l = 1; - options.msisdn.v[0] = 0x91; /* International format */ - for(n=0; nCI/SAC/RAC : %s\n", rest); + lac_d = atoi(rest); + if (lac_d > 65535 || lac_d < 1) { + printf("Invalid CI/SAC/RAC\n"); + return -1; + } + /*options.userloc.v[6] = 0x04 ; */ + /*options.userloc.v[7] = 0xb7 ; */ + i = lac_d >> 8; + options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */ + options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */ + } - /* UID and PWD */ - /* Might need to also insert stuff like DNS etc. */ - if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)> - (sizeof(options.pco.v)-1)) { - printf("invalid UID and PWD\n"); - return -1; - } - options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10; - options.pco.v[0] = 0x80; /* PPP */ - options.pco.v[1] = 0xc0; /* PAP */ - options.pco.v[2] = 0x23; - options.pco.v[3] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; - options.pco.v[4] = 0x01; /* Authenticate request */ - options.pco.v[5] = 0x01; - options.pco.v[6] = 0x00; /* MSB of length */ - options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; - options.pco.v[8] = strlen(args_info.uid_arg); - memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg)); - options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg); - memcpy(&options.pco.v[10+strlen(args_info.uid_arg)], - args_info.pwd_arg, strlen(args_info.pwd_arg)); - - /* createif */ - options.createif = args_info.createif_flag; + /* RAI */ + if (args_info.rai_given == 1) { + printf("Using RAI: %s\n", args_info.rai_arg); + tmp = args_info.rai_arg; + n = 0; + pch = strtok(tmp, "."); + while (pch != NULL) { + rai_el[n] = pch; + pch = strtok(NULL, "."); + n++; + } - /* net */ - /* Store net as in_addr net and mask */ - if (args_info.net_arg) { - if(ippool_aton(&options.net, &options.mask, args_info.net_arg, 0)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid network address: %s!", args_info.net_arg); - exit(1); - } + options.rai_given = 1; + options.rai.l = 6; + /* MCC */ + mcc = rai_el[0]; + printf("->mcc : %s\n", mcc); + if (strlen(mcc) != 3) { + printf("Invalid MCC lenght\n"); + return -1; + } + + /* MNC */ + mnc = rai_el[1]; + printf("->mnc : %s\n", mnc); + + a = (uint8_t) (mcc[0] - 48); + b = (uint8_t) (mcc[1] - 48); + options.rai.v[0] = 16 * b + a; + + /* octet 3 - MNC Digit 3 - MCC Digit 3 */ + a = (uint8_t) (mcc[2] - 48); + + if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) { + printf("Invalid MNC lenght\n"); + return -1; + } + if (strlen(mnc) == 2) { + b = 15; + } + if (strlen(mnc) == 3) { + b = (uint8_t) (mnc[2] - 48); + } + options.rai.v[1] = 16 * b + a; + + /* octet 4 - MNC Digit 2 - MNC Digit 1 */ + a = (uint8_t) (mnc[0] - 48); + b = (uint8_t) (mnc[1] - 48); + options.rai.v[2] = 16 * b + a; + + /* LAC */ + lac = rai_el[2]; + printf("->LAC: %s\n", lac); + lac_d = atoi(lac); + if (lac_d > 65535 || lac_d < 1) { + printf("Invalid LAC\n"); + return -1; + } + i = lac_d >> 8; + options.rai.v[3] = i; /* octet 5 - LAC */ + options.rai.v[4] = lac_d; /* octet 6 - LAC */ + + /* RAC */ + rest = rai_el[3]; + printf("->RAC : %s\n", rest); + lac_d = atoi(rest); + if (lac_d > 255 || lac_d < 1) { + printf("Invalid RAC\n"); + return -1; + } + options.rai.v[5] = lac_d; /* octet 7 - RAC */ + } + + /* mstz */ + if (args_info.mstz_given == 1) { + options.mstz_given = 1; + options.mstz.l = 2; + + printf("Using MS Time Zone: %s\n", args_info.mstz_arg); + tmp = args_info.mstz_arg; + n = 0; + pch = strtok(tmp, "."); + while (pch != NULL) { + mstz_el[n] = pch; + pch = strtok(NULL, "."); + n++; + } + + /* sign */ + sign = atoi(mstz_el[0]); + printf("->Sign (0=+ / 1=-): %d\n", sign); + if (sign != 0 && sign != 1) { + printf("Invalid Sign \n"); + return -1; + } + /* nbquarters */ + nbquarters = atoi(mstz_el[1]); + printf("->Number of Quarters of an Hour : %d\n", nbquarters); + if (nbquarters < 0 || nbquarters > 79) { + printf("Invalid Number of Quarters \n"); + return -1; + } + /* DST */ + DST = atoi(mstz_el[2]); + printf("->Daylight Saving Time Adjustment : %d\n", DST); + if (DST < 0 || DST > 3) { + printf("Invalid DST Adjustment \n"); + return -1; + } + /* 12345678 + bits 123 = unit of # of quarters of an hour + bits 678 = # of quarters of an hour / 10 + bit 5 = sign + */ + i = nbquarters % 10; + i = i << 4; + i = i + nbquarters / 10 + 8 * sign; + /* options.mstz.v[0] = 0x69 ; */ + /* options.mstz.v[1] = 0x01 ; */ + options.mstz.v[0] = i; + options.mstz.v[1] = DST; + n = (i & 0x08) ? '-' : '+'; + printf + ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n", + n, nbquarters / 4, nbquarters % 4 * 15); + } + + /* imeisv */ + if (args_info.imeisv_given == 1) { + options.imeisv_given = 1; + if (strlen(args_info.imeisv_arg) != 16) { + printf("Invalid IMEI(SV)\n"); + return -1; + } + options.imeisv.l = 8; + for (n = 0; n < 8; n++) { + a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48); + b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48); + options.imeisv.v[n] = 16 * b + a; + } + printf("Using IMEI(SV): %s\n", args_info.imeisv_arg); + } + + /* msisdn */ + if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) { + printf("Invalid MSISDN\n"); + return -1; + } + options.msisdn.l = 1; + options.msisdn.v[0] = 0x91; /* International format */ + for (n = 0; n < strlen(args_info.msisdn_arg); n++) { + if ((n % 2) == 0) { + options.msisdn.v[((int)n / 2) + 1] = + args_info.msisdn_arg[n] - 48 + 0xf0; + options.msisdn.l += 1; + } else { + options.msisdn.v[((int)n / 2) + 1] = + (options.msisdn.v[((int)n / 2) + 1] & 0x0f) + + (args_info.msisdn_arg[n] - 48) * 16; + } + } + printf("Using MSISDN: %s\n", args_info.msisdn_arg); + + /* UID and PWD */ + /* Might need to also insert stuff like DNS etc. */ + if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) > + (sizeof(options.pco.v) - 1)) { + printf("invalid UID and PWD\n"); + return -1; + } + options.pco.l = + strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10; + options.pco.v[0] = 0x80; /* PPP */ + options.pco.v[1] = 0xc0; /* PAP */ + options.pco.v[2] = 0x23; + options.pco.v[3] = + strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; + options.pco.v[4] = 0x01; /* Authenticate request */ + options.pco.v[5] = 0x01; + options.pco.v[6] = 0x00; /* MSB of length */ + options.pco.v[7] = + strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; + options.pco.v[8] = strlen(args_info.uid_arg); + memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg)); + options.pco.v[9 + strlen(args_info.uid_arg)] = + strlen(args_info.pwd_arg); + memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)], + args_info.pwd_arg, strlen(args_info.pwd_arg)); + + /* createif */ + options.createif = args_info.createif_flag; + + /* net */ + /* Store net as in_addr net and mask */ + if (args_info.net_arg) { + if (ippool_aton + (&options.net, &options.mask, args_info.net_arg, 0)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid network address: %s!", + args_info.net_arg); + exit(1); + } #if defined (__sun__) - options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1); - options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1); + options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1); + options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1); #else - options.netaddr.s_addr = options.net.s_addr; - options.destaddr.s_addr = options.net.s_addr; + options.netaddr.s_addr = options.net.s_addr; + options.destaddr.s_addr = options.net.s_addr; #endif - } - else { - options.net.s_addr = 0; - options.mask.s_addr = 0; - options.netaddr.s_addr = 0; - options.destaddr.s_addr = 0; - } + } else { + options.net.s_addr = 0; + options.mask.s_addr = 0; + options.netaddr.s_addr = 0; + options.destaddr.s_addr = 0; + } - /* ipup */ - options.ipup = args_info.ipup_arg; + /* ipup */ + options.ipup = args_info.ipup_arg; - /* ipdown */ - options.ipdown = args_info.ipdown_arg; + /* ipdown */ + options.ipdown = args_info.ipdown_arg; - /* statedir */ - options.statedir = args_info.statedir_arg; + /* statedir */ + options.statedir = args_info.statedir_arg; - /* defaultroute */ - options.defaultroute = args_info.defaultroute_flag; + /* defaultroute */ + options.defaultroute = args_info.defaultroute_flag; + /* pinghost */ + /* Store ping host as in_addr */ + if (args_info.pinghost_arg) { + if (!(host = gethostbyname(args_info.pinghost_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid ping host: %s!", + args_info.pinghost_arg); + return -1; + } else { + memcpy(&options.pinghost.s_addr, host->h_addr, + host->h_length); + printf("Using ping host: %s (%s)\n", + args_info.pinghost_arg, + inet_ntoa(options.pinghost)); + } + } - /* pinghost */ - /* Store ping host as in_addr */ - if (args_info.pinghost_arg) { - if (!(host = gethostbyname(args_info.pinghost_arg))) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Invalid ping host: %s!", args_info.pinghost_arg); - return -1; - } - else { - memcpy(&options.pinghost.s_addr, host->h_addr, host->h_length); - printf("Using ping host: %s (%s)\n", - args_info.pinghost_arg, inet_ntoa(options.pinghost)); - } - } + /* Other ping parameters */ + options.pingrate = args_info.pingrate_arg; + options.pingsize = args_info.pingsize_arg; + options.pingcount = args_info.pingcount_arg; + options.pingquiet = args_info.pingquiet_flag; - /* Other ping parameters */ - options.pingrate = args_info.pingrate_arg; - options.pingsize = args_info.pingsize_arg; - options.pingcount = args_info.pingcount_arg; - options.pingquiet = args_info.pingquiet_flag; + /* norecovery */ + options.norecovery_given = args_info.norecovery_flag; - /* norecovery */ - options.norecovery_given = args_info.norecovery_flag; - - return 0; + return 0; } - -int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) { - unsigned int i; - printf("The packet looks like this:\n"); - for( i=0; i 16 ) - return("OUT-OF-RANGE"); - return(ttab[t]); +char *print_icmptype(int t) +{ + static char *ttab[] = { + "Echo Reply", + "ICMP 1", + "ICMP 2", + "Dest Unreachable", + "Source Quench", + "Redirect", + "ICMP 6", + "ICMP 7", + "Echo", + "ICMP 9", + "ICMP 10", + "Time Exceeded", + "Parameter Problem", + "Timestamp", + "Timestamp Reply", + "Info Request", + "Info Reply" + }; + if (t < 0 || t > 16) + return ("OUT-OF-RANGE"); + return (ttab[t]); } -int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) { - unsigned int n; - uint64_t i64 = 0; - uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */ - unsigned int msalen = 0; +int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) +{ + unsigned int n; + uint64_t i64 = 0; + uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */ + unsigned int msalen = 0; - /* Convert to uint64_t from ul16_t format (most significant digit first) */ - /* ul16_t format always starts with 0x91 to indicate international format */ - /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */ - for (n=0; n< src->l; n++) { - if ((src->v[n] & 0x0f) != 0x0f) { - i64 *= 10; - i64 += src->v[n] & 0x0f; - } - if ((src->v[n] & 0xf0) != 0xf0) { - i64 *= 10; - i64 += (src->v[n] & 0xf0) >> 4; - } - } + /* Convert to uint64_t from ul16_t format (most significant digit first) */ + /* ul16_t format always starts with 0x91 to indicate international format */ + /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */ + for (n = 0; n < src->l; n++) { + if ((src->v[n] & 0x0f) != 0x0f) { + i64 *= 10; + i64 += src->v[n] & 0x0f; + } + if ((src->v[n] & 0xf0) != 0xf0) { + i64 *= 10; + i64 += (src->v[n] & 0xf0) >> 4; + } + } - i64 += add; + i64 += add; - /* Generate array with least significant digit in first octet */ - while (i64) { - msa[msalen++] = i64 % 10; - i64 = i64 / 10; - } + /* Generate array with least significant digit in first octet */ + while (i64) { + msa[msalen++] = i64 % 10; + i64 = i64 / 10; + } - /* Convert back to ul16_t format */ - for(n=0; nv[((int)n/2)] = msa[msalen-n-1] + 0xf0; - dst->l += 1; - } - else { - dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) + - msa[msalen-n-1] * 16; - } - } + /* Convert back to ul16_t format */ + for (n = 0; n < msalen; n++) { + if ((n % 2) == 0) { + dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0; + dst->l += 1; + } else { + dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) + + msa[msalen - n - 1] * 16; + } + } - return 0; + return 0; } -int imsi_add(uint64_t src, uint64_t *dst, int add) { - /* TODO: big endian / small endian ??? */ - uint64_t i64 = 0; +int imsi_add(uint64_t src, uint64_t * dst, int add) +{ + /* TODO: big endian / small endian ??? */ + uint64_t i64 = 0; - /* Convert from uint64_t bcd to uint64_t integer format */ - /* The resulting integer format is multiplied by 10 */ - while (src) { - if ((src & 0x0f) != 0x0f) { - i64 *= 10; - i64 += (src & 0x0f); - } - if ((src & 0xf0) != 0xf0) { - i64 *= 10; - i64 += (src & 0xf0) >> 4; - } - src = src >> 8; - } + /* Convert from uint64_t bcd to uint64_t integer format */ + /* The resulting integer format is multiplied by 10 */ + while (src) { + if ((src & 0x0f) != 0x0f) { + i64 *= 10; + i64 += (src & 0x0f); + } + if ((src & 0xf0) != 0xf0) { + i64 *= 10; + i64 += (src & 0xf0) >> 4; + } + src = src >> 8; + } - i64 += add * 10; + i64 += add * 10; - *dst = 0; - while (i64) { - *dst = *dst << 4; - *dst += (i64 % 10); - i64 = i64 / 10; - } + *dst = 0; + while (i64) { + *dst = *dst << 4; + *dst += (i64 % 10); + i64 = i64 / 10; + } - *dst |= 0xf000000000000000ull; + *dst |= 0xf000000000000000ull; - return 0; + return 0; } /* Calculate time left until we have to send off next ping packet */ -int ping_timeout(struct timeval *tp) { - struct timezone tz; - struct timeval tv; - int diff; - if ((options.pinghost.s_addr) && (2 == state) && - ((pingseq < options.pingcount) || (options.pingcount == 0))) { - gettimeofday(&tv, &tz); - diff = 1000000 / options.pingrate * pingseq - - 1000000 * (tv.tv_sec - firstping.tv_sec) - - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */ - tp->tv_sec = 0; - if (diff > 0) - tp->tv_usec = diff; - else { - /* For some reason we get packet loss if set to zero */ - tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */ - tp->tv_usec = 0; - } - } - return 0; +int ping_timeout(struct timeval *tp) +{ + struct timezone tz; + struct timeval tv; + int diff; + if ((options.pinghost.s_addr) && (2 == state) && + ((pingseq < options.pingcount) || (options.pingcount == 0))) { + gettimeofday(&tv, &tz); + diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */ + tp->tv_sec = 0; + if (diff > 0) + tp->tv_usec = diff; + else { + /* For some reason we get packet loss if set to zero */ + tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */ + tp->tv_usec = 0; + } + } + return 0; } /* Print out statistics when at the end of ping sequence */ int ping_finish() { - struct timezone tz; - struct timeval tv; - int elapsed; - gettimeofday(&tv, &tz); - elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + - (tv.tv_usec - firstping.tv_usec); /* Microseconds */ - printf("\n"); - printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost)); - printf("%d packets transmitted in %.3f seconds, ", ntransmitted, - elapsed / 1000000.0); - printf("%d packets received, ", nreceived ); - if (ntransmitted) { - if( nreceived > ntransmitted) - printf("-- somebody's printing up packets!"); - else - printf("%d%% packet loss", - (int) (((ntransmitted-nreceived)*100) / - ntransmitted)); - } - printf("\n"); - if (options.debug) printf("%d packets received in total\n", ntreceived ); - if (nreceived && tsum) - printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n", - tmin/1000.0, - tsum/1000.0/nreceived, - tmax/1000.0 ); - printf("%d packets transmitted \n", ntreceived ); + struct timezone tz; + struct timeval tv; + int elapsed; + gettimeofday(&tv, &tz); + elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */ + printf("\n"); + printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost)); + printf("%d packets transmitted in %.3f seconds, ", ntransmitted, + elapsed / 1000000.0); + printf("%d packets received, ", nreceived); + if (ntransmitted) { + if (nreceived > ntransmitted) + printf("-- somebody's printing up packets!"); + else + printf("%d%% packet loss", + (int)(((ntransmitted - nreceived) * 100) / + ntransmitted)); + } + printf("\n"); + if (options.debug) + printf("%d packets received in total\n", ntreceived); + if (nreceived && tsum) + printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n", + tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0); + printf("%d packets transmitted \n", ntreceived); - ntransmitted = 0; - return 0; + ntransmitted = 0; + return 0; } /* Handle a received ping packet. Print out line and update statistics. */ -int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) { - struct timezone tz; - struct timeval tv; - struct timeval *tp; - struct ip_ping *pingpack = pack; - struct in_addr src; - int triptime; +int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) +{ + struct timezone tz; + struct timeval tv; + struct timeval *tp; + struct ip_ping *pingpack = pack; + struct in_addr src; + int triptime; - src.s_addr = pingpack->src; + src.s_addr = pingpack->src; - gettimeofday(&tv, &tz); - if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec); + gettimeofday(&tv, &tz); + if (options.debug) + printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec); - if (len < CREATEPING_IP + CREATEPING_ICMP) { - printf("packet too short (%d bytes) from %s\n", len, - inet_ntoa(src)); - return 0; - } + if (len < CREATEPING_IP + CREATEPING_ICMP) { + printf("packet too short (%d bytes) from %s\n", len, + inet_ntoa(src)); + return 0; + } - ntreceived++; - if (pingpack->protocol != 1) { - if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n", - len, inet_ntoa(src), pingpack->protocol, - print_ipprot(pingpack->protocol)); - return 0; - } + ntreceived++; + if (pingpack->protocol != 1) { + if (!options.pingquiet) + printf("%d bytes from %s: ip_protocol=%d (%s)\n", + len, inet_ntoa(src), pingpack->protocol, + print_ipprot(pingpack->protocol)); + return 0; + } - if (pingpack->type != 0) { - if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", - len, inet_ntoa(src), pingpack->type, - print_icmptype(pingpack->type), pingpack->code); - return 0; - } + if (pingpack->type != 0) { + if (!options.pingquiet) + printf + ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", + len, inet_ntoa(src), pingpack->type, + print_icmptype(pingpack->type), pingpack->code); + return 0; + } - nreceived++; - if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len, - inet_ntoa(src), ntohs(pingpack->seq)); + nreceived++; + if (!options.pingquiet) + printf("%d bytes from %s: icmp_seq=%d", len, + inet_ntoa(src), ntohs(pingpack->seq)); - if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) { - gettimeofday(&tv, &tz); - tp = (struct timeval *) pingpack->data; - if( (tv.tv_usec -= tp->tv_usec) < 0 ) { - tv.tv_sec--; - tv.tv_usec += 1000000; - } - tv.tv_sec -= tp->tv_sec; + if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) { + gettimeofday(&tv, &tz); + tp = (struct timeval *)pingpack->data; + if ((tv.tv_usec -= tp->tv_usec) < 0) { + tv.tv_sec--; + tv.tv_usec += 1000000; + } + tv.tv_sec -= tp->tv_sec; - triptime = tv.tv_sec*1000000+(tv.tv_usec); - tsum += triptime; - if( triptime < tmin ) - tmin = triptime; - if( triptime > tmax ) - tmax = triptime; + triptime = tv.tv_sec * 1000000 + (tv.tv_usec); + tsum += triptime; + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; - if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0); + if (!options.pingquiet) + printf(" time=%.3f ms\n", triptime / 1000.0); - } - else - if (!options.pingquiet) printf("\n"); - return 0; + } else if (!options.pingquiet) + printf("\n"); + return 0; } /* Create a new ping packet and send it off to peer. */ int create_ping(void *gsn, struct pdp_t *pdp, - struct in_addr *dst, int seq, unsigned int datasize) { + struct in_addr *dst, int seq, unsigned int datasize) +{ - struct ip_ping pack; - uint16_t *p = (uint16_t *) &pack; - uint8_t *p8 = (uint8_t *) &pack; - struct in_addr src; - unsigned int n; - long int sum = 0; - int count = 0; + struct ip_ping pack; + uint16_t *p = (uint16_t *) & pack; + uint8_t *p8 = (uint8_t *) & pack; + struct in_addr src; + unsigned int n; + long int sum = 0; + int count = 0; - struct timezone tz; - struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP]; + struct timezone tz; + struct timeval *tp = + (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP]; - if (datasize > CREATEPING_MAX) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Ping size to large: %d!", datasize); - return -1; - } + if (datasize > CREATEPING_MAX) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Ping size to large: %d!", datasize); + return -1; + } - memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */ + memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */ - pack.ipver = 0x45; - pack.tos = 0x00; - pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize); - pack.fragid = 0x0000; - pack.offset = 0x0040; - pack.ttl = 0x40; - pack.protocol = 0x01; - pack.ipcheck = 0x0000; - pack.src = src.s_addr; - pack.dst = dst->s_addr; - pack.type = 0x08; - pack.code = 0x00; - pack.checksum = 0x0000; - pack.ident = 0x0000; - pack.seq = htons(seq); + pack.ipver = 0x45; + pack.tos = 0x00; + pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize); + pack.fragid = 0x0000; + pack.offset = 0x0040; + pack.ttl = 0x40; + pack.protocol = 0x01; + pack.ipcheck = 0x0000; + pack.src = src.s_addr; + pack.dst = dst->s_addr; + pack.type = 0x08; + pack.code = 0x00; + pack.checksum = 0x0000; + pack.ident = 0x0000; + pack.seq = htons(seq); - /* Generate ICMP payload */ - p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP; - for (n=0; n<(datasize); n++) p8[n] = n; + /* Generate ICMP payload */ + p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP; + for (n = 0; n < (datasize); n++) + p8[n] = n; - if (datasize >= sizeof(struct timeval)) - gettimeofday(tp, &tz); + if (datasize >= sizeof(struct timeval)) + gettimeofday(tp, &tz); - /* Calculate IP header checksum */ - p = (uint16_t *) &pack; - count = CREATEPING_IP; - sum = 0; - while (count>1) { - sum += *p++; - count -= 2; - } - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - pack.ipcheck = ~sum; + /* Calculate IP header checksum */ + p = (uint16_t *) & pack; + count = CREATEPING_IP; + sum = 0; + while (count > 1) { + sum += *p++; + count -= 2; + } + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + pack.ipcheck = ~sum; + /* Calculate ICMP checksum */ + count = CREATEPING_ICMP + datasize; /* Length of ICMP message */ + sum = 0; + p = (uint16_t *) & pack; + p += CREATEPING_IP / 2; + while (count > 1) { + sum += *p++; + count -= 2; + } + if (count > 0) + sum += *(unsigned char *)p; + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + pack.checksum = ~sum; - /* Calculate ICMP checksum */ - count = CREATEPING_ICMP + datasize; /* Length of ICMP message */ - sum = 0; - p = (uint16_t *) &pack; - p += CREATEPING_IP / 2; - while (count>1) { - sum += *p++; - count -= 2; - } - if (count>0) - sum += * (unsigned char *) p; - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - pack.checksum = ~sum; - - ntransmitted++; - return gtp_data_req(gsn, pdp, &pack, 28 + datasize); -} - - -int delete_context(struct pdp_t *pdp) { - - if (tun && options.ipdown) tun_runscript(tun, options.ipdown); - - ipdel((struct iphash_t*) pdp->peer); - memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */ - - if (1 == options.contexts) - state = 5; /* Disconnected */ - - return 0; + ntransmitted++; + return gtp_data_req(gsn, pdp, &pack, 28 + datasize); } +int delete_context(struct pdp_t *pdp) +{ + + if (tun && options.ipdown) + tun_runscript(tun, options.ipdown); + + ipdel((struct iphash_t *)pdp->peer); + memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */ + + if (1 == options.contexts) + state = 5; /* Disconnected */ + + return 0; +} /* Callback for receiving messages from tun */ -int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) { - struct iphash_t *ipm; - struct in_addr src; - struct tun_packet_t *iph = (struct tun_packet_t*) pack; +int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) +{ + struct iphash_t *ipm; + struct in_addr src; + struct tun_packet_t *iph = (struct tun_packet_t *)pack; - src.s_addr = iph->src; + src.s_addr = iph->src; - if (ipget(&ipm, &src)) { - printf("Received packet without a valid source address!!!\n"); - return 0; - } - - if (ipm->pdp) /* Check if a peer protocol is defined */ - gtp_data_req(gsn, ipm->pdp, pack, len); - return 0; + if (ipget(&ipm, &src)) { + printf("Received packet without a valid source address!!!\n"); + return 0; + } + + if (ipm->pdp) /* Check if a peer protocol is defined */ + gtp_data_req(gsn, ipm->pdp, pack, len); + return 0; } -int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { - struct in_addr addr; +int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) +{ + struct in_addr addr; - struct iphash_t *iph = (struct iphash_t*) cbp; + struct iphash_t *iph = (struct iphash_t *)cbp; - if (cause < 0) { - printf("Create PDP Context Request timed out\n"); - if (iph->pdp->version == 1) { - printf("Retrying with version 0\n"); - iph->pdp->version = 0; - gtp_create_context_req(gsn, iph->pdp, iph); - return 0; - } - else { - state = 0; - pdp_freepdp(iph->pdp); - iph->pdp = NULL; - return EOF; - } - } + if (cause < 0) { + printf("Create PDP Context Request timed out\n"); + if (iph->pdp->version == 1) { + printf("Retrying with version 0\n"); + iph->pdp->version = 0; + gtp_create_context_req(gsn, iph->pdp, iph); + return 0; + } else { + state = 0; + pdp_freepdp(iph->pdp); + iph->pdp = NULL; + return EOF; + } + } - if (cause != 128) { - printf("Received create PDP context response. Cause value: %d\n", cause); - state = 0; - pdp_freepdp(iph->pdp); - iph->pdp = NULL; - return EOF; /* Not what we expected */ - } + if (cause != 128) { + printf + ("Received create PDP context response. Cause value: %d\n", + cause); + state = 0; + pdp_freepdp(iph->pdp); + iph->pdp = NULL; + return EOF; /* Not what we expected */ + } - if (pdp_euaton(&pdp->eua, &addr)) { - printf("Received create PDP context response. Cause value: %d\n", cause); - pdp_freepdp(iph->pdp); - iph->pdp = NULL; - state = 0; - return EOF; /* Not a valid IP address */ - } + if (pdp_euaton(&pdp->eua, &addr)) { + printf + ("Received create PDP context response. Cause value: %d\n", + cause); + pdp_freepdp(iph->pdp); + iph->pdp = NULL; + state = 0; + return EOF; /* Not a valid IP address */ + } - printf("Received create PDP context response. IP address: %s\n", - inet_ntoa(addr)); + printf("Received create PDP context response. IP address: %s\n", + inet_ntoa(addr)); - if ((options.createif) && (!options.net.s_addr)) { - struct in_addr m; + if ((options.createif) && (!options.net.s_addr)) { + struct in_addr m; #ifdef HAVE_INET_ATON - inet_aton("255.255.255.255", &m); + inet_aton("255.255.255.255", &m); #else - m.s_addr = -1; + m.s_addr = -1; #endif - /* printf("Setting up interface and routing\n");*/ - tun_addaddr(tun, &addr, &addr, &m); - if (options.defaultroute) { - struct in_addr rm; - rm.s_addr = 0; - tun_addroute(tun, &rm, &addr, &rm); - } - if (options.ipup) tun_runscript(tun, options.ipup); - } - - ipset((struct iphash_t*) pdp->peer, &addr); - - state = 2; /* Connected */ + /* printf("Setting up interface and routing\n"); */ + tun_addaddr(tun, &addr, &addr, &m); + if (options.defaultroute) { + struct in_addr rm; + rm.s_addr = 0; + tun_addroute(tun, &rm, &addr, &rm); + } + if (options.ipup) + tun_runscript(tun, options.ipup); + } - return 0; + ipset((struct iphash_t *)pdp->peer, &addr); + + state = 2; /* Connected */ + + return 0; } -int delete_pdp_conf(struct pdp_t *pdp, int cause) { - printf("Received delete PDP context response. Cause value: %d\n", cause); - return 0; +int delete_pdp_conf(struct pdp_t *pdp, int cause) +{ + printf("Received delete PDP context response. Cause value: %d\n", + cause); + return 0; } -int echo_conf(int recovery) { +int echo_conf(int recovery) +{ - if (recovery < 0) { - printf("Echo Request timed out\n"); - if (echoversion == 1) { - printf("Retrying with version 0\n"); - echoversion = 0; - gtp_echo_req(gsn, echoversion, NULL, &options.remote); - return 0; - } - else { - state = 0; - return EOF; - } - } - else { - printf("Received echo response\n"); - if (!options.contexts) state = 5; - } - return 0; + if (recovery < 0) { + printf("Echo Request timed out\n"); + if (echoversion == 1) { + printf("Retrying with version 0\n"); + echoversion = 0; + gtp_echo_req(gsn, echoversion, NULL, &options.remote); + return 0; + } else { + state = 0; + return EOF; + } + } else { + printf("Received echo response\n"); + if (!options.contexts) + state = 5; + } + return 0; } -int conf(int type, int cause, struct pdp_t* pdp, void *cbp) { - /* if (cause < 0) return 0; Some error occurred. We don't care */ - switch (type) { - case GTP_ECHO_REQ: - return echo_conf(cause); - case GTP_CREATE_PDP_REQ: - return create_pdp_conf(pdp, cbp, cause); - case GTP_DELETE_PDP_REQ: - if (cause !=128) return 0; /* Request not accepted. We don't care */ - return delete_pdp_conf(pdp, cause); - default: - return 0; - } +int conf(int type, int cause, struct pdp_t *pdp, void *cbp) +{ + /* if (cause < 0) return 0; Some error occurred. We don't care */ + switch (type) { + case GTP_ECHO_REQ: + return echo_conf(cause); + case GTP_CREATE_PDP_REQ: + return create_pdp_conf(pdp, cbp, cause); + case GTP_DELETE_PDP_REQ: + if (cause != 128) + return 0; /* Request not accepted. We don't care */ + return delete_pdp_conf(pdp, cause); + default: + 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); +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); } int main(int argc, char **argv) { - fd_set fds; /* For select() */ - struct timeval idleTime; /* How long to select() */ - struct pdp_t *pdp; - int n; - int starttime = time(NULL); /* Time program was started */ - int stoptime = 0; /* Time to exit */ - int pingtimeout = 0; /* Time to print ping statistics */ + fd_set fds; /* For select() */ + struct timeval idleTime; /* How long to select() */ + struct pdp_t *pdp; + int n; + int starttime = time(NULL); /* Time program was started */ + int stoptime = 0; /* Time to exit */ + int pingtimeout = 0; /* Time to print ping statistics */ - struct timezone tz; /* Used for calculating ping times */ - struct timeval tv; - int diff; + struct timezone tz; /* Used for calculating ping times */ + struct timeval tv; + int diff; - /* open a connection to the syslog daemon */ - /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/ - /* TODO: Only use LOG__PERROR for linux */ + /* open a connection to the syslog daemon */ + /*openlog(PACKAGE, LOG_PID, LOG_DAEMON); */ + /* TODO: Only use LOG__PERROR for linux */ #ifdef __linux__ - openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON); + openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON); #else - openlog(PACKAGE, (LOG_PID), LOG_DAEMON); + openlog(PACKAGE, (LOG_PID), LOG_DAEMON); #endif + /* Process options given in configuration file and command line */ + if (process_options(argc, argv)) + exit(1); - /* Process options given in configuration file and command line */ - if (process_options(argc, argv)) - exit(1); + printf("\nInitialising GTP library\n"); + if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Failed to create gtp"); + exit(1); + } + if (gsn->fd0 > maxfd) + maxfd = gsn->fd0; + if (gsn->fd1c > maxfd) + maxfd = gsn->fd1c; + if (gsn->fd1u > maxfd) + maxfd = gsn->fd1u; - printf("\nInitialising GTP library\n"); - if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Failed to create gtp"); - exit(1); - } - if (gsn->fd0 > maxfd) maxfd = gsn->fd0; - if (gsn->fd1c > maxfd) maxfd = gsn->fd1c; - if (gsn->fd1u > maxfd) maxfd = gsn->fd1u; + gtp_set_cb_delete_context(gsn, delete_context); + gtp_set_cb_conf(gsn, conf); + if (options.createif) + gtp_set_cb_data_ind(gsn, encaps_tun); + else + gtp_set_cb_data_ind(gsn, encaps_ping); - gtp_set_cb_delete_context(gsn, delete_context); - gtp_set_cb_conf(gsn, conf); - if (options.createif) - gtp_set_cb_data_ind(gsn, encaps_tun); - else - gtp_set_cb_data_ind(gsn, encaps_ping); + if (options.createif) { + printf("Setting up interface\n"); + /* 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_set_cb_ind(tun, cb_tun_ind); + if (tun->fd > maxfd) + maxfd = tun->fd; + } - if (options.createif) { - printf("Setting up interface\n"); - /* 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_set_cb_ind(tun, cb_tun_ind); - if (tun->fd > maxfd) maxfd = tun->fd; - } + if ((options.createif) && (options.net.s_addr)) { + /* printf("Setting up interface and routing\n"); */ + tun_addaddr(tun, &options.netaddr, &options.destaddr, + &options.mask); + if (options.defaultroute) { + struct in_addr rm; + rm.s_addr = 0; + tun_addroute(tun, &rm, &options.destaddr, &rm); + } + if (options.ipup) + tun_runscript(tun, options.ipup); + } - if ((options.createif) && (options.net.s_addr)) { - /* printf("Setting up interface and routing\n");*/ - tun_addaddr(tun, &options.netaddr, &options.destaddr, &options.mask); - if (options.defaultroute) { - struct in_addr rm; - rm.s_addr = 0; - tun_addroute(tun, &rm, &options.destaddr, &rm); - } - if (options.ipup) tun_runscript(tun, options.ipup); - } + /* Initialise hash tables */ + memset(&iphash, 0, sizeof(iphash)); + memset(&iparr, 0, sizeof(iparr)); + printf("Done initialising GTP library\n\n"); - /* Initialise hash tables */ - memset(&iphash, 0, sizeof(iphash)); - memset(&iparr, 0, sizeof(iparr)); + /* See if anybody is there */ + printf("Sending off echo request\n"); + echoversion = options.gtpversion; + gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */ - printf("Done initialising GTP library\n\n"); + for (n = 0; n < options.contexts; n++) { + uint64_t myimsi; + printf("Setting up PDP context #%d\n", n); + iparr[n].inuse = 1; /* TODO */ - /* See if anybody is there */ - printf("Sending off echo request\n"); - echoversion = options.gtpversion; - gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */ + imsi_add(options.imsi, &myimsi, n); - for(n=0; npeer = &iparr[n]; + pdp->ipif = tun; /* TODO */ + iparr[n].pdp = pdp; - /* Allocated here. */ - /* If create context failes we have to deallocate ourselves. */ - /* Otherwise it is deallocated by gtplib */ - pdp_newpdp(&pdp, myimsi, options.nsapi, NULL); + if (options.gtpversion == 0) { + if (options.qos.l - 1 > sizeof(pdp->qos_req0)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "QoS length too big"); + exit(1); + } else { + memcpy(pdp->qos_req0, options.qos.v, + options.qos.l); + } + } - pdp->peer = &iparr[n]; - pdp->ipif = tun; /* TODO */ - iparr[n].pdp = pdp; + pdp->qos_req.l = options.qos.l; + memcpy(pdp->qos_req.v, options.qos.v, options.qos.l); - if (options.gtpversion == 0) { - if (options.qos.l - 1 > sizeof(pdp->qos_req0)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big"); - exit(1); - } - else { - memcpy(pdp->qos_req0, options.qos.v, options.qos.l); - } - } + pdp->selmode = options.selmode; - pdp->qos_req.l = options.qos.l ; - memcpy(pdp->qos_req.v, options.qos.v, options.qos.l); - - pdp->selmode = options.selmode; - - pdp->rattype.l = options.rattype.l; - memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l); - pdp->rattype_given = options.rattype_given; + pdp->rattype.l = options.rattype.l; + memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l); + pdp->rattype_given = options.rattype_given; - pdp->userloc.l = options.userloc.l; - memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l); - pdp->userloc_given = options.userloc_given; + pdp->userloc.l = options.userloc.l; + memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l); + pdp->userloc_given = options.userloc_given; - pdp->rai.l = options.rai.l; - memcpy(pdp->rai.v, options.rai.v, options.rai.l); - pdp->rai_given = options.rai_given; + pdp->rai.l = options.rai.l; + memcpy(pdp->rai.v, options.rai.v, options.rai.l); + pdp->rai_given = options.rai_given; - pdp->mstz.l = options.mstz.l; - memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l); - pdp->mstz_given = options.mstz_given; + pdp->mstz.l = options.mstz.l; + memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l); + pdp->mstz_given = options.mstz_given; - pdp->imeisv.l = options.imeisv.l; - memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l); - pdp->imeisv_given = options.imeisv_given; + pdp->imeisv.l = options.imeisv.l; + memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l); + pdp->imeisv_given = options.imeisv_given; - pdp->norecovery_given = options.norecovery_given; + pdp->norecovery_given = options.norecovery_given; - if (options.apn.l > sizeof(pdp->apn_use.v)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big"); - exit(1); - } - else { - pdp->apn_use.l = options.apn.l; - memcpy(pdp->apn_use.v, options.apn.v, options.apn.l); - } - - pdp->gsnlc.l = sizeof(options.listen); - memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen)); - pdp->gsnlu.l = sizeof(options.listen); - memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen)); - - if (options.msisdn.l > sizeof(pdp->msisdn.v)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big"); - exit(1); - } - else { - msisdn_add(&options.msisdn, &pdp->msisdn, n); - } - - ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */ - - if (options.pco.l > sizeof(pdp->pco_req.v)) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big"); - exit(1); - } - else { - pdp->pco_req.l = options.pco.l; - memcpy(pdp->pco_req.v, options.pco.v, options.pco.l); - } - - pdp->version = options.gtpversion; + if (options.apn.l > sizeof(pdp->apn_use.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "APN length too big"); + exit(1); + } else { + pdp->apn_use.l = options.apn.l; + memcpy(pdp->apn_use.v, options.apn.v, options.apn.l); + } - pdp->hisaddr0 = options.remote; - pdp->hisaddr1 = options.remote; + pdp->gsnlc.l = sizeof(options.listen); + memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen)); + pdp->gsnlu.l = sizeof(options.listen); + memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen)); - pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid, - 512 = Flat rate, 256 = Hot billing */ + if (options.msisdn.l > sizeof(pdp->msisdn.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "MSISDN length too big"); + exit(1); + } else { + msisdn_add(&options.msisdn, &pdp->msisdn, n); + } - /* Create context */ - /* We send this of once. Retransmissions are handled by gtplib */ - gtp_create_context_req(gsn, pdp, &iparr[n]); - } + ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */ - state = 1; /* Enter wait_connection state */ + if (options.pco.l > sizeof(pdp->pco_req.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "PCO length too big"); + exit(1); + } else { + pdp->pco_req.l = options.pco.l; + memcpy(pdp->pco_req.v, options.pco.v, options.pco.l); + } - printf("Waiting for response from ggsn........\n\n"); + pdp->version = options.gtpversion; + pdp->hisaddr0 = options.remote; + pdp->hisaddr1 = options.remote; + + pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid, + 512 = Flat rate, 256 = Hot billing */ + + /* Create context */ + /* We send this of once. Retransmissions are handled by gtplib */ + gtp_create_context_req(gsn, pdp, &iparr[n]); + } + + state = 1; /* Enter wait_connection state */ + + printf("Waiting for response from ggsn........\n\n"); /******************************************************************/ - /* Main select loop */ + /* Main select loop */ /******************************************************************/ - while ((0 != state) && (5 != state)) { + while ((0 != state) && (5 != state)) { - /* Take down client after timeout after disconnect */ - if ((4 == state) && ((stoptime) <= time(NULL))) { - state = 5; - } + /* Take down client after timeout after disconnect */ + if ((4 == state) && ((stoptime) <= time(NULL))) { + state = 5; + } - /* Take down client after timelimit timeout */ - if ((2 == state) && (options.timelimit) && - ((starttime + options.timelimit) <= time(NULL))) { - state = 3; - } + /* Take down client after timelimit timeout */ + if ((2 == state) && (options.timelimit) && + ((starttime + options.timelimit) <= time(NULL))) { + state = 3; + } - /* Take down client after ping timeout */ - if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) { - state = 3; - } + /* Take down client after ping timeout */ + if ((2 == state) && (pingtimeout) + && (pingtimeout <= time(NULL))) { + state = 3; + } - /* Set pingtimeout for later disconnection */ - if (options.pingcount && ntransmitted >= options.pingcount) { - pingtimeout = time(NULL) + 5; /* Extra seconds */ - } + /* Set pingtimeout for later disconnection */ + if (options.pingcount && ntransmitted >= options.pingcount) { + pingtimeout = time(NULL) + 5; /* Extra seconds */ + } - /* Print statistics if no more ping packets are missing */ - if (ntransmitted && options.pingcount && nreceived >= options.pingcount) { - ping_finish(); - if (!options.createif) - state = 3; - } + /* Print statistics if no more ping packets are missing */ + if (ntransmitted && options.pingcount + && nreceived >= options.pingcount) { + ping_finish(); + if (!options.createif) + state = 3; + } - /* Send off disconnect */ - if (3 == state) { - state = 4; - stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */ - for(n=0; nfd, &fds); - FD_SET(gsn->fd0, &fds); - FD_SET(gsn->fd1c, &fds); - FD_SET(gsn->fd1u, &fds); - - gtp_retranstimeout(gsn, &idleTime); - ping_timeout(&idleTime); - - if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n", - (int) idleTime.tv_sec, (int) idleTime.tv_usec); - - switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { - case -1: - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "Select returned -1"); - break; - case 0: - gtp_retrans(gsn); /* Only retransmit if nothing else */ - break; - default: - break; - } - - if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, - "TUN decaps failed"); - } - - if (FD_ISSET(gsn->fd0, &fds)) - gtp_decaps0(gsn); + FD_ZERO(&fds); + if (tun) + FD_SET(tun->fd, &fds); + FD_SET(gsn->fd0, &fds); + FD_SET(gsn->fd1c, &fds); + FD_SET(gsn->fd1u, &fds); - if (FD_ISSET(gsn->fd1c, &fds)) - gtp_decaps1c(gsn); + gtp_retranstimeout(gsn, &idleTime); + ping_timeout(&idleTime); - if (FD_ISSET(gsn->fd1u, &fds)) - gtp_decaps1u(gsn); - } - - gtp_free(gsn); /* Clean up the gsn instance */ - - if (options.createif) - tun_free(tun); + if (options.debug) + printf("idletime.tv_sec %d, idleTime.tv_usec %d\n", + (int)idleTime.tv_sec, (int)idleTime.tv_usec); - if (0 == state) - exit(1); /* Indicate error */ - - return 0; + switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { + case -1: + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Select returned -1"); + break; + case 0: + gtp_retrans(gsn); /* Only retransmit if nothing else */ + break; + default: + break; + } + + if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "TUN decaps failed"); + } + + if (FD_ISSET(gsn->fd0, &fds)) + gtp_decaps0(gsn); + + if (FD_ISSET(gsn->fd1c, &fds)) + gtp_decaps1c(gsn); + + if (FD_ISSET(gsn->fd1u, &fds)) + gtp_decaps1u(gsn); + } + + gtp_free(gsn); /* Clean up the gsn instance */ + + if (options.createif) + tun_free(tun); + + if (0 == state) + exit(1); /* Indicate error */ + + return 0; } -