This commit was generated by cvs2svn to compensate for changes in r2587,
[iproute2.git] / tc / m_ipt.c
index 518e4a3..ca39555 100644 (file)
@@ -69,6 +69,7 @@ static struct option original_opts[] = {
 };
 
 static struct iptables_target *t_list = NULL;
+static struct option *opts = original_opts;
 static unsigned int global_option_offset = 0;
 #define OPTION_OFFSET 256
 
@@ -169,18 +170,13 @@ int string_to_number(const char *s, unsigned int min, unsigned int max,
        return result;
 }
 
-static struct option *
-copy_options(struct option *oldopts)
+static void free_opts(struct option *opts)
 {
-       struct option *merge;
-       unsigned int num_old;
-       for (num_old = 0; oldopts[num_old].name; num_old++) ;
-       merge = malloc(sizeof (struct option) * (num_old + 1));
-       if (NULL == merge)
-               return NULL;
-       memcpy(merge, oldopts, num_old * sizeof (struct option));
-       memset(merge + num_old, 0, sizeof (struct option));
-       return merge;
+       if (opts != original_opts) {
+               free(opts);
+               opts = original_opts;
+               global_option_offset = 0;
+       }
 }
 
 static struct option *
@@ -337,6 +333,17 @@ struct in_addr *dotted_to_addr(const char *dotted)
        return &addr;
 }
 
+static void set_revision(char *name, u_int8_t revision)
+{
+       /* Old kernel sources don't have ".revision" field,
+       *  but we stole a byte from name. */
+       name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
+       name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
+}
+
+/* 
+ * we may need to check for version mismatch
+*/
 int
 build_st(struct iptables_target *target, struct ipt_entry_target *t)
 {
@@ -350,8 +357,11 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t)
 
                if (NULL == t) {
                        target->t = fw_calloc(1, size);
-                       target->init(target->t, &nfcache);
                        target->t->u.target_size = size;
+
+                       if (target->init != NULL)
+                               target->init(target->t, &nfcache);
+                       set_revision(target->t->u.user.name, target->revision);
                } else {
                        target->t = t;
                }
@@ -371,7 +381,6 @@ static int parse_ipt(struct action_util *a,int *argc_p,
        int c;
        int rargc = *argc_p;
        char **argv = *argv_p;
-       struct option *opts;
        int argc = 0, iargc = 0;
        char k[16];
        int res = -1;
@@ -395,11 +404,6 @@ static int parse_ipt(struct action_util *a,int *argc_p,
                return -1;
        }
 
-       opts = copy_options(original_opts);
-
-       if (NULL == opts)
-               return -1;
-
        while (1) {
                c = getopt_long(argc, argv, "j:", opts, NULL);
                if (c == -1)
@@ -426,23 +430,14 @@ static int parse_ipt(struct action_util *a,int *argc_p,
                default:
                        memset(&fw, 0, sizeof (fw));
                        if (m) {
-                               unsigned int fake_flags = 0;
                                m->parse(c - m->option_offset, argv, 0,
-                                        &fake_flags, NULL, &m->t);
+                                        &m->tflags, NULL, &m->t);
                        } else {
                                fprintf(stderr," failed to find target %s\n\n", optarg);
                                return -1;
 
                        }
                        ok++;
-
-                       /*m->final_check(m->t); -- Is this necessary?
-                       ** useful when theres depencies
-                       ** eg ipt_TCPMSS.c has have the TCP match loaded
-                       ** before this can be used;
-                       **  also seems the ECN target needs it 
-                       */
-
                        break;
 
                }
@@ -452,6 +447,7 @@ static int parse_ipt(struct action_util *a,int *argc_p,
                if (matches(argv[optind], "index") == 0) {
                        if (get_u32(&index, argv[optind + 1], 10)) {
                                fprintf(stderr, "Illegal \"index\"\n");
+                               free_opts(opts);
                                return -1;
                        }
                        iok++;
@@ -465,6 +461,10 @@ static int parse_ipt(struct action_util *a,int *argc_p,
                return -1;
        }
 
+       /* check that we passed the correct parameters to the target */
+       if (m)
+               m->final_check(m->tflags);
+
        {
                struct tcmsg *t = NLMSG_DATA(n);
                if (t->tcm_parent != TC_H_ROOT
@@ -505,6 +505,7 @@ static int parse_ipt(struct action_util *a,int *argc_p,
        *argv_p = argv;
        
        optind = 1;
+       free_opts(opts);
 
        return 0;
 
@@ -515,16 +516,10 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg)
 {
        struct rtattr *tb[TCA_IPT_MAX + 1];
        struct ipt_entry_target *t = NULL;
-       struct option *opts;
 
        if (arg == NULL)
                return -1;
 
-       opts = copy_options(original_opts);
-
-       if (NULL == opts)
-               return -1;
-
        parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
 
        if (tb[TCA_IPT_TABLE] == NULL) {
@@ -587,6 +582,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg)
                fprintf(f, " \n");
 
        }
+       free_opts(opts);
 
        return 0;
 }