Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[pandora-kernel.git] / net / netfilter / ipset / ip_set_hash_ipport.c
index 14281b6..6ee10f5 100644 (file)
@@ -60,7 +60,8 @@ struct hash_ipport4_telem {
 
 static inline bool
 hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
-                       const struct hash_ipport4_elem *ip2)
+                       const struct hash_ipport4_elem *ip2,
+                       u32 *multi)
 {
        return ip1->ip == ip2->ip &&
               ip1->port == ip2->port &&
@@ -124,31 +125,40 @@ nla_put_failure:
 #define HOST_MASK      32
 #include <linux/netfilter/ipset/ip_set_ahash.h>
 
+static inline void
+hash_ipport4_data_next(struct ip_set_hash *h,
+                      const struct hash_ipport4_elem *d)
+{
+       h->next.ip = ntohl(d->ip);
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
 
-       if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
 
-       return adtfn(set, &data, h->timeout);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
-                 enum ipset_adt adt, u32 *lineno, u32 flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
-       u32 ip, ip_to, p, port, port_to;
+       u32 ip, ip_to, p = 0, port, port_to;
        u32 timeout = h->timeout;
        bool with_ports = false;
        int ret;
@@ -192,7 +202,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST ||
            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
              tb[IPSET_ATTR_PORT_TO])) {
-               ret = adtfn(set, &data, timeout);
+               ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -208,8 +218,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(ip, ip_to, cidr);
        } else
                ip_to = ip;
 
@@ -220,17 +229,21 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
                        swap(port, port_to);
        }
 
-       for (; !before(ip_to, ip); ip++)
-               for (p = port; p <= port_to; p++) {
+       if (retried)
+               ip = h->next.ip;
+       for (; !before(ip_to, ip); ip++) {
+               p = retried && ip == h->next.ip ? h->next.port : port;
+               for (; p <= port_to; p++) {
                        data.ip = htonl(ip);
                        data.port = htons(p);
-                       ret = adtfn(set, &data, timeout);
+                       ret = adtfn(set, &data, timeout, flags);
 
                        if (ret && !ip_set_eexist(ret, flags))
                                return ret;
                        else
                                ret = 0;
                }
+       }
        return ret;
 }
 
@@ -264,7 +277,8 @@ struct hash_ipport6_telem {
 
 static inline bool
 hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
-                       const struct hash_ipport6_elem *ip2)
+                       const struct hash_ipport6_elem *ip2,
+                       u32 *multi)
 {
        return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
               ip1->port == ip2->port &&
@@ -328,26 +342,34 @@ nla_put_failure:
 #define HOST_MASK      128
 #include <linux/netfilter/ipset/ip_set_ahash.h>
 
+static inline void
+hash_ipport6_data_next(struct ip_set_hash *h,
+                      const struct hash_ipport6_elem *d)
+{
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport6_elem data = { };
 
-       if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
 
-       return adtfn(set, &data, h->timeout);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
-                 enum ipset_adt adt, u32 *lineno, u32 flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -396,7 +418,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
        }
 
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
-               ret = adtfn(set, &data, timeout);
+               ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -405,9 +427,11 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (port > port_to)
                swap(port, port_to);
 
+       if (retried)
+               port = h->next.port;
        for (; port <= port_to; port++) {
                data.port = htons(port);
-               ret = adtfn(set, &data, timeout);
+               ret = adtfn(set, &data, timeout, flags);
 
                if (ret && !ip_set_eexist(ret, flags))
                        return ret;
@@ -491,7 +515,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_TWO,
        .family         = AF_UNSPEC,
-       .revision       = 1,
+       .revision_min   = 0,
+       .revision_max   = 1,    /* SCTP and UDPLITE support added */
        .create         = hash_ipport_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },