This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / ipv4 / ip_fragment.c
index 441a522..02961c5 100644 (file)
@@ -73,6 +73,7 @@ struct ipfrag_skb_cb
 struct ipq {
        struct ipq      *next;          /* linked list pointers                 */
        struct list_head lru_list;      /* lru list member                      */
+       u32             user;
        u32             saddr;
        u32             daddr;
        u16             id;
@@ -243,13 +244,13 @@ static void ipq_kill(struct ipq *ipq)
 /* Memory limiting on fragments.  Evictor trashes the oldest 
  * fragment queue until we are back under the threshold.
  */
-static void __ip_evictor(int threshold)
+static void ip_evictor(void)
 {
        struct ipq *qp;
        struct list_head *tmp;
        int work;
 
-       work = atomic_read(&ip_frag_mem) - threshold;
+       work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
        if (work <= 0)
                return;
 
@@ -274,11 +275,6 @@ static void __ip_evictor(int threshold)
        }
 }
 
-static inline void ip_evictor(void)
-{
-       __ip_evictor(sysctl_ipfrag_low_thresh);
-}
-
 /*
  * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
  */
@@ -325,7 +321,8 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
                if(qp->id == qp_in->id          &&
                   qp->saddr == qp_in->saddr    &&
                   qp->daddr == qp_in->daddr    &&
-                  qp->protocol == qp_in->protocol) {
+                  qp->protocol == qp_in->protocol &&
+                  qp->user == qp_in->user) {
                        atomic_inc(&qp->refcnt);
                        write_unlock(&ipfrag_lock);
                        qp_in->last_in |= COMPLETE;
@@ -352,7 +349,7 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
 }
 
 /* Add an entry to the 'ipq' queue for a newly received IP datagram. */
-static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph)
+static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
 {
        struct ipq *qp;
 
@@ -364,6 +361,7 @@ static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph)
        qp->id = iph->id;
        qp->saddr = iph->saddr;
        qp->daddr = iph->daddr;
+       qp->user = user;
        qp->len = 0;
        qp->meat = 0;
        qp->fragments = NULL;
@@ -386,7 +384,7 @@ out_nomem:
 /* 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)
+static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 {
        __u16 id = iph->id;
        __u32 saddr = iph->saddr;
@@ -400,7 +398,8 @@ static inline struct ipq *ip_find(struct iphdr *iph)
                if(qp->id == id         &&
                   qp->saddr == saddr   &&
                   qp->daddr == daddr   &&
-                  qp->protocol == protocol) {
+                  qp->protocol == protocol &&
+                  qp->user == user) {
                        atomic_inc(&qp->refcnt);
                        read_unlock(&ipfrag_lock);
                        return qp;
@@ -408,7 +407,7 @@ static inline struct ipq *ip_find(struct iphdr *iph)
        }
        read_unlock(&ipfrag_lock);
 
-       return ip_frag_create(hash, iph);
+       return ip_frag_create(hash, iph, user);
 }
 
 /* Add new segment to existing queue. */
@@ -642,7 +641,7 @@ out_fail:
 }
 
 /* Process an incoming IP datagram fragment. */
-struct sk_buff *ip_defrag(struct sk_buff *skb)
+struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 {
        struct iphdr *iph = skb->nh.iph;
        struct ipq *qp;
@@ -657,7 +656,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
        dev = skb->dev;
 
        /* Lookup (or create) queue header */
-       if ((qp = ip_find(iph)) != NULL) {
+       if ((qp = ip_find(iph, user)) != NULL) {
                struct sk_buff *ret = NULL;
 
                spin_lock(&qp->lock);
@@ -678,6 +677,29 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
        return NULL;
 }
 
+static unsigned long ip_defrag_id_bitmap;
+
+int ip_defrag_user_id_alloc(void)
+{
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               if (!test_and_set_bit(i, &ip_defrag_id_bitmap))
+                       return i + __IP_DEFRAG_DYNAMIC_FIRST;
+       }
+
+       return -ENFILE;
+}
+EXPORT_SYMBOL(ip_defrag_user_id_alloc);
+
+void ip_defrag_user_id_free(int user)
+{
+       user -= __IP_DEFRAG_DYNAMIC_FIRST;
+       if (user >= 0 && user < 32)
+               clear_bit(user, &ip_defrag_id_bitmap);
+}
+EXPORT_SYMBOL(ip_defrag_user_id_free);
+
 void ipfrag_init(void)
 {
        ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
@@ -689,10 +711,4 @@ void ipfrag_init(void)
        add_timer(&ipfrag_secret_timer);
 }
 
-void ipfrag_flush(void)
-{
-       __ip_evictor(0);
-}
-
 EXPORT_SYMBOL(ip_defrag);
-EXPORT_SYMBOL(ipfrag_flush);