netfilter: nf_conntrack: add allocation flag to nf_conntrack_alloc
[pandora-kernel.git] / net / netfilter / nf_conntrack_netlink.c
index 4a1b42b..dd23339 100644 (file)
@@ -4,7 +4,7 @@
  * (C) 2001 by Jay Schulist <jschlst@samba.org>
  * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
  *
  * Initial connection tracking via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -145,10 +145,11 @@ nla_put_failure:
 static inline int
 ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
 {
-       struct nf_conntrack_l4proto *l4proto = nf_ct_l4proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
+       struct nf_conntrack_l4proto *l4proto;
        struct nlattr *nest_proto;
        int ret;
 
+       l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (!l4proto->to_nlattr) {
                nf_ct_l4proto_put(l4proto);
                return 0;
@@ -368,8 +369,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
        nfmsg  = NLMSG_DATA(nlh);
 
        nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
-       nfmsg->nfgen_family =
-               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+       nfmsg->nfgen_family = nf_ct_l3num(ct);
        nfmsg->version      = NFNETLINK_V0;
        nfmsg->res_id       = 0;
 
@@ -454,7 +454,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
        nfmsg = NLMSG_DATA(nlh);
 
        nlh->nlmsg_flags    = flags;
-       nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+       nfmsg->nfgen_family = nf_ct_l3num(ct);
        nfmsg->version  = NFNETLINK_V0;
        nfmsg->res_id   = 0;
 
@@ -472,14 +472,17 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
                goto nla_put_failure;
        nla_nest_end(skb, nest_parms);
 
+       if (ctnetlink_dump_id(skb, ct) < 0)
+               goto nla_put_failure;
+
+       if (ctnetlink_dump_status(skb, ct) < 0)
+               goto nla_put_failure;
+
        if (events & IPCT_DESTROY) {
                if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
                    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
                        goto nla_put_failure;
        } else {
-               if (ctnetlink_dump_status(skb, ct) < 0)
-                       goto nla_put_failure;
-
                if (ctnetlink_dump_timeout(skb, ct) < 0)
                        goto nla_put_failure;
 
@@ -535,8 +538,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
        return 0;
 }
 
-#define L3PROTO(ct) (ct)->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num
-
 static int
 ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 {
@@ -558,7 +559,7 @@ restart:
                        /* Dump entries of a given L3 protocol number.
                         * If it is not specified, ie. l3proto == 0,
                         * then dump everything. */
-                       if (l3proto && L3PROTO(ct) != l3proto)
+                       if (l3proto && nf_ct_l3num(ct) != l3proto)
                                continue;
                        if (cb->args[1]) {
                                if (ct != last)
@@ -704,20 +705,11 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr,
        if (err < 0)
                return err;
 
-       npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
-
-       if (!npt->nlattr_to_range) {
-               nf_nat_proto_put(npt);
-               return 0;
-       }
-
-       /* nlattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
-       if (npt->nlattr_to_range(tb, range) > 0)
-               range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-
+       npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
+       if (npt->nlattr_to_range)
+               err = npt->nlattr_to_range(tb, range);
        nf_nat_proto_put(npt);
-
-       return 0;
+       return err;
 }
 
 static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
@@ -820,9 +812,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        return -ENOENT;
                }
        }
-       if (del_timer(&ct->timeout))
-               ct->timeout.function((unsigned long)ct);
 
+       nf_ct_kill(ct);
        nf_ct_put(ct);
 
        return 0;
@@ -899,20 +890,19 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
 
        if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
                /* unchangeable */
-               return -EINVAL;
+               return -EBUSY;
 
        if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
                /* SEEN_REPLY bit can only be set */
-               return -EINVAL;
-
+               return -EBUSY;
 
        if (d & IPS_ASSURED && !(status & IPS_ASSURED))
                /* ASSURED bit can only be set */
-               return -EINVAL;
+               return -EBUSY;
 
        if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
 #ifndef CONFIG_NF_NAT_NEEDED
-               return -EINVAL;
+               return -EOPNOTSUPP;
 #else
                struct nf_nat_range range;
 
@@ -953,7 +943,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
 
        /* don't change helper of sibling connections */
        if (ct->master)
-               return -EINVAL;
+               return -EBUSY;
 
        err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
        if (err < 0)
@@ -971,7 +961,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
 
        helper = __nf_conntrack_helper_find_byname(helpname);
        if (helper == NULL)
-               return -EINVAL;
+               return -EOPNOTSUPP;
 
        if (help) {
                if (help->helper == helper)
@@ -1010,14 +1000,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
 {
        struct nlattr *tb[CTA_PROTOINFO_MAX+1], *attr = cda[CTA_PROTOINFO];
        struct nf_conntrack_l4proto *l4proto;
-       u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-       u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
        int err = 0;
 
        nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL);
 
-       l4proto = nf_ct_l4proto_find_get(l3num, npt);
-
+       l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (l4proto->from_nlattr)
                err = l4proto->from_nlattr(tb, ct);
        nf_ct_l4proto_put(l4proto);
@@ -1141,7 +1128,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
        struct nf_conn_help *help;
        struct nf_conntrack_helper *helper;
 
-       ct = nf_conntrack_alloc(otuple, rtuple);
+       ct = nf_conntrack_alloc(otuple, rtuple, GFP_KERNEL);
        if (ct == NULL || IS_ERR(ct))
                return -ENOMEM;
 
@@ -1269,12 +1256,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
        if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
                /* we only allow nat config for new conntracks */
                if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
-                       err = -EINVAL;
+                       err = -EOPNOTSUPP;
                        goto out_unlock;
                }
                /* can't link an existing conntrack to a master */
                if (cda[CTA_TUPLE_MASTER]) {
-                       err = -EINVAL;
+                       err = -EOPNOTSUPP;
                        goto out_unlock;
                }
                err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
@@ -1619,7 +1606,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                h = __nf_conntrack_helper_find_byname(name);
                if (!h) {
                        spin_unlock_bh(&nf_conntrack_lock);
-                       return -EINVAL;
+                       return -EOPNOTSUPP;
                }
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, n, next,