net/atm: move all compat_ioctl handling to atm/ioctl.c
[safe/jmp/linux-2.6] / net / atm / br2684.c
index 334fcd4..26a646d 100644 (file)
@@ -69,7 +69,7 @@ struct br2684_vcc {
        struct net_device *device;
        /* keep old push, pop functions for chaining */
        void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
-       /* void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); */
+       void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
        enum br2684_encaps encaps;
        struct list_head brvccs;
 #ifdef CONFIG_ATM_BR2684_IPFILTER
@@ -142,6 +142,22 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
        return NULL;
 }
 
+/* chained vcc->pop function.  Check if we should wake the netif_queue */
+static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+       struct br2684_vcc *brvcc = BR2684_VCC(vcc);
+       struct net_device *net_dev = skb->dev;
+
+       pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev);
+       brvcc->old_pop(vcc, skb);
+
+       if (!net_dev)
+               return;
+
+       if (atm_may_send(vcc, 0))
+               netif_wake_queue(net_dev);
+
+}
 /*
  * Send a packet out a particular vcc.  Not to useful right now, but paves
  * the way for multiple vcc's per itf.  Returns true if we can send,
@@ -200,20 +216,19 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
 
        ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
        pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
-       if (!atm_may_send(atmvcc, skb->truesize)) {
-               /*
-                * We free this here for now, because we cannot know in a higher
-                * layer whether the skb pointer it supplied wasn't freed yet.
-                * Now, it always is.
-                */
-               dev_kfree_skb(skb);
-               return 0;
-       }
        atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
        ATM_SKB(skb)->atm_options = atmvcc->atm_options;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
        atmvcc->send(atmvcc, skb);
+
+       if (!atm_may_send(atmvcc, 0)) {
+               netif_stop_queue(brvcc->device);
+               /*check for race with br2684_pop*/
+               if (atm_may_send(atmvcc, 0))
+                       netif_start_queue(brvcc->device);
+       }
+
        return 1;
 }
 
@@ -223,12 +238,13 @@ static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb,
        return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next);        /* 1 vcc/dev right now */
 }
 
-static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
+                                    struct net_device *dev)
 {
        struct br2684_dev *brdev = BRPRIV(dev);
        struct br2684_vcc *brvcc;
 
-       pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst);
+       pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb));
        read_lock(&devs_lock);
        brvcc = pick_outgoing_vcc(skb, brdev);
        if (brvcc == NULL) {
@@ -238,7 +254,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* netif_stop_queue(dev); */
                dev_kfree_skb(skb);
                read_unlock(&devs_lock);
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (!br2684_xmit_vcc(skb, dev, brvcc)) {
                /*
@@ -252,7 +268,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_fifo_errors++;
        }
        read_unlock(&devs_lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -445,9 +461,10 @@ free_skb:
  */
 static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
 {
+       struct sk_buff_head queue;
        int err;
        struct br2684_vcc *brvcc;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *tmp;
        struct sk_buff_head *rq;
        struct br2684_dev *brdev;
        struct net_device *net_dev;
@@ -502,32 +519,25 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        atmvcc->user_back = brvcc;
        brvcc->encaps = (enum br2684_encaps)be.encaps;
        brvcc->old_push = atmvcc->push;
+       brvcc->old_pop = atmvcc->pop;
        barrier();
        atmvcc->push = br2684_push;
+       atmvcc->pop = br2684_pop;
 
+       __skb_queue_head_init(&queue);
        rq = &sk_atm(atmvcc)->sk_receive_queue;
 
        spin_lock_irqsave(&rq->lock, flags);
-       if (skb_queue_empty(rq)) {
-               skb = NULL;
-       } else {
-               /* NULL terminate the list.  */
-               rq->prev->next = NULL;
-               skb = rq->next;
-       }
-       rq->prev = rq->next = (struct sk_buff *)rq;
-       rq->qlen = 0;
+       skb_queue_splice_init(rq, &queue);
        spin_unlock_irqrestore(&rq->lock, flags);
 
-       while (skb) {
-               struct sk_buff *next = skb->next;
+       skb_queue_walk_safe(&queue, skb, tmp) {
+               struct net_device *dev = skb->dev;
 
-               skb->next = skb->prev = NULL;
-               br2684_push(atmvcc, skb);
-               skb->dev->stats.rx_bytes -= skb->len;
-               skb->dev->stats.rx_packets--;
+               dev->stats.rx_bytes -= skb->len;
+               dev->stats.rx_packets--;
 
-               skb = next;
+               br2684_push(atmvcc, skb);
        }
        __module_get(THIS_MODULE);
        return 0;
@@ -549,6 +559,7 @@ static void br2684_setup(struct net_device *netdev)
        struct br2684_dev *brdev = BRPRIV(netdev);
 
        ether_setup(netdev);
+       brdev->net_dev = netdev;
 
        netdev->netdev_ops = &br2684_netdev_ops;