]> err.no Git - linux-2.6/blobdiff - net/ipv4/ip_fragment.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / net / ipv4 / ip_fragment.c
index 0d6cff1de5a32544cd90529cecfafbafc15df344..2143bf30597a84b528e0cced57bc657dbe577417 100644 (file)
@@ -128,18 +128,17 @@ static unsigned int ip4_hashfn(struct inet_frag_queue *q)
        return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol);
 }
 
-static int ip4_frag_equal(struct inet_frag_queue *q1,
-               struct inet_frag_queue *q2)
+static int ip4_frag_match(struct inet_frag_queue *q, void *a)
 {
-       struct ipq *qp1, *qp2;
-
-       qp1 = container_of(q1, struct ipq, q);
-       qp2 = container_of(q2, struct ipq, q);
-       return (qp1->id == qp2->id &&
-                       qp1->saddr == qp2->saddr &&
-                       qp1->daddr == qp2->daddr &&
-                       qp1->protocol == qp2->protocol &&
-                       qp1->user == qp2->user);
+       struct ipq *qp;
+       struct ip4_create_arg *arg = a;
+
+       qp = container_of(q, struct ipq, q);
+       return (qp->id == arg->iph->id &&
+                       qp->saddr == arg->iph->saddr &&
+                       qp->daddr == arg->iph->daddr &&
+                       qp->protocol == arg->iph->protocol &&
+                       qp->user == arg->user);
 }
 
 /* Memory Tracking Functions. */
@@ -172,7 +171,6 @@ static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
        qp = container_of(q, struct ipq, q);
        if (qp->peer)
                inet_putpeer(qp->peer);
-       kfree(qp);
 }
 
 
@@ -235,18 +233,20 @@ out:
        ipq_put(qp);
 }
 
-/* Creation primitives. */
-
-/* Add an entry to the 'ipq' queue for a newly received IP datagram. */
-static struct ipq *ip_frag_create(struct iphdr *iph, u32 user, unsigned int h)
+/* Find the correct entry in the "incomplete datagrams" queue for
+ * this IP datagram, and create new one, if nothing is found.
+ */
+static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 {
        struct inet_frag_queue *q;
        struct ip4_create_arg arg;
+       unsigned int hash;
 
        arg.iph = iph;
        arg.user = user;
+       hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
-       q = inet_frag_create(&ip4_frags, &arg, h);
+       q = inet_frag_find(&ip4_frags, &arg, hash);
        if (q == NULL)
                goto out_nomem;
 
@@ -257,37 +257,6 @@ out_nomem:
        return NULL;
 }
 
-/* Find the correct entry in the "incomplete datagrams" queue for
- * this IP datagram, and create new one, if nothing is found.
- */
-static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
-{
-       __be16 id = iph->id;
-       __be32 saddr = iph->saddr;
-       __be32 daddr = iph->daddr;
-       __u8 protocol = iph->protocol;
-       unsigned int hash;
-       struct ipq *qp;
-       struct hlist_node *n;
-
-       read_lock(&ip4_frags.lock);
-       hash = ipqhashfn(id, saddr, daddr, protocol);
-       hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
-               if (qp->id == id                &&
-                   qp->saddr == saddr  &&
-                   qp->daddr == daddr  &&
-                   qp->protocol == protocol &&
-                   qp->user == user) {
-                       atomic_inc(&qp->q.refcnt);
-                       read_unlock(&ip4_frags.lock);
-                       return qp;
-               }
-       }
-       read_unlock(&ip4_frags.lock);
-
-       return ip_frag_create(iph, user, hash);
-}
-
 /* Is the fragment too far ahead to be part of ipq? */
 static inline int ip_frag_too_far(struct ipq *qp)
 {
@@ -517,7 +486,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
        if (prev) {
                head = prev->next;
                fp = skb_clone(head, GFP_ATOMIC);
-
                if (!fp)
                        goto out_nomem;
 
@@ -543,7 +511,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                goto out_oversize;
 
        /* Head of list must not be cloned. */
-       err = -ENOMEM;
        if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
                goto out_nomem;
 
@@ -599,6 +566,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
 out_nomem:
        LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
                              "queue %p\n", qp);
+       err = -ENOMEM;
        goto out_fail;
 out_oversize:
        if (net_ratelimit())
@@ -647,7 +615,7 @@ void __init ipfrag_init(void)
        ip4_frags.destructor = ip4_frag_free;
        ip4_frags.skb_free = NULL;
        ip4_frags.qsize = sizeof(struct ipq);
-       ip4_frags.equal = ip4_frag_equal;
+       ip4_frags.match = ip4_frag_match;
        ip4_frags.frag_expire = ip_expire;
        inet_frags_init(&ip4_frags);
 }