fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / atm / br2684.c
index f469813..83a1c1b 100644 (file)
@@ -5,7 +5,6 @@ Author: Marcell GAL, 2000, XDSL Ltd, Hungary
 */
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -18,12 +17,12 @@ Author: Marcell GAL, 2000, XDSL Ltd, Hungary
 #include <net/arp.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
+#include <linux/capability.h>
 #include <linux/seq_file.h>
 
 #include <linux/atmbr2684.h>
 
 #include "common.h"
-#include "ipcommon.h"
 
 /*
  * Define this to use a version of the code which interacts with the higher
@@ -97,7 +96,7 @@ struct br2684_dev {
  * do read-locking under interrupt context, so write locking must block
  * the current CPU's interrupts
  */
-static rwlock_t devs_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(devs_lock);
 
 static LIST_HEAD(br2684_devs);
 
@@ -190,7 +189,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
                dev_kfree_skb(skb);
                return 0;
                }
-       atomic_add(skb->truesize, &atmvcc->sk->sk_wmem_alloc);
+       atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
        ATM_SKB(skb)->atm_options = atmvcc->atm_options;
        brdev->stats.tx_packets++;
        brdev->stats.tx_bytes += skb->len;
@@ -220,7 +219,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 -EUNATCH;
+               return 0;
        }
        if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
                /*
@@ -289,21 +288,20 @@ xmit will add the additional header part in that case */
  * This is similar to eth_type_trans, which cannot be used because of
  * our dev->hard_header_len
  */
-static inline unsigned short br_type_trans(struct sk_buff *skb,
-                                              struct net_device *dev)
+static inline __be16 br_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        struct ethhdr *eth;
        unsigned char *rawp;
-       eth = skb->mac.ethernet;
+       eth = eth_hdr(skb);
 
-       if (*eth->h_dest & 1) {
-               if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+       if (is_multicast_ether_addr(eth->h_dest)) {
+               if (!compare_ether_addr(eth->h_dest, dev->broadcast))
                        skb->pkt_type = PACKET_BROADCAST;
                else
                        skb->pkt_type = PACKET_MULTICAST;
        }
 
-       else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+       else if (compare_ether_addr(eth->h_dest, dev->dev_addr))
                skb->pkt_type = PACKET_OTHERHOST;
 
        if (ntohs(eth->h_proto) >= 1536)
@@ -342,12 +340,12 @@ static int br2684_mac_addr(struct net_device *dev, void *p)
 
 #ifdef CONFIG_ATM_BR2684_IPFILTER
 /* this IOCTL is experimental. */
-static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
+static int br2684_setfilt(struct atm_vcc *atmvcc, void __user *arg)
 {
        struct br2684_vcc *brvcc;
        struct br2684_filter_set fs;
 
-       if (copy_from_user(&fs, (void *) arg, sizeof fs))
+       if (copy_from_user(&fs, arg, sizeof fs))
                return -EFAULT;
        if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
                /*
@@ -373,7 +371,7 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
 
 /* Returns 1 if packet should be dropped */
 static inline int
-packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
+packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
 {
        if (brvcc->filter.netmask == 0)
                return 0;                       /* no filter in place */
@@ -494,25 +492,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
        netif_rx(skb);
 }
 
-static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg)
+static int br2684_regvcc(struct atm_vcc *atmvcc, void __user *arg)
 {
 /* assign a vcc to a dev
 Note: we do not have explicit unassign, but look at _push()
 */
        int err;
        struct br2684_vcc *brvcc;
-       struct sk_buff_head copy;
        struct sk_buff *skb;
+       struct sk_buff_head *rq;
        struct br2684_dev *brdev;
        struct net_device *net_dev;
        struct atm_backend_br2684 be;
+       unsigned long flags;
 
-       if (copy_from_user(&be, (void *) arg, sizeof be))
+       if (copy_from_user(&be, arg, sizeof be))
                return -EFAULT;
-       brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
+       brvcc = kzalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
        if (!brvcc)
                return -ENOMEM;
-       memset(brvcc, 0, sizeof(struct br2684_vcc));
        write_lock_irq(&devs_lock);
        net_dev = br2684_find_dev(&be.ifspec);
        if (net_dev == NULL) {
@@ -556,14 +554,32 @@ Note: we do not have explicit unassign, but look at _push()
        brvcc->old_push = atmvcc->push;
        barrier();
        atmvcc->push = br2684_push;
-       skb_queue_head_init(&copy);
-       skb_migrate(&atmvcc->sk->sk_receive_queue, &copy);
-       while ((skb = skb_dequeue(&copy))) {
+
+       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;
+       spin_unlock_irqrestore(&rq->lock, flags);
+
+       while (skb) {
+               struct sk_buff *next = skb->next;
+
+               skb->next = skb->prev = NULL;
                BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
                BRPRIV(skb->dev)->stats.rx_packets--;
                br2684_push(atmvcc, skb);
+
+               skb = next;
        }
-       (void) try_module_get(THIS_MODULE);
+       __module_get(THIS_MODULE);
        return 0;
     error:
        write_unlock_irq(&devs_lock);
@@ -593,7 +609,7 @@ static void br2684_setup(struct net_device *netdev)
        INIT_LIST_HEAD(&brdev->brvccs);
 }
 
-static int br2684_create(unsigned long arg)
+static int br2684_create(void __user *arg)
 {
        int err;
        struct net_device *netdev;
@@ -602,7 +618,7 @@ static int br2684_create(unsigned long arg)
 
        DPRINTK("br2684_create\n");
 
-       if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
+       if (copy_from_user(&ni, arg, sizeof ni)) {
                return -EFAULT;
        }
        if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
@@ -642,13 +658,14 @@ static int br2684_ioctl(struct socket *sock, unsigned int cmd,
        unsigned long arg)
 {
        struct atm_vcc *atmvcc = ATM_SD(sock);
+       void __user *argp = (void __user *)arg;
 
        int err;
        switch(cmd) {
        case ATM_SETBACKEND:
        case ATM_NEWBACKENDIF: {
                atm_backend_t b;
-               err = get_user(b, (atm_backend_t *) arg);
+               err = get_user(b, (atm_backend_t __user *) argp);
                if (err)
                        return -EFAULT;
                if (b != ATM_BACKEND_BR2684)
@@ -656,9 +673,9 @@ static int br2684_ioctl(struct socket *sock, unsigned int cmd,
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
                if (cmd == ATM_SETBACKEND)
-                       return br2684_regvcc(atmvcc, arg);
+                       return br2684_regvcc(atmvcc, argp);
                else
-                       return br2684_create(arg);
+                       return br2684_create(argp);
                }
 #ifdef CONFIG_ATM_BR2684_IPFILTER
        case BR2684_SETFILT:
@@ -666,7 +683,7 @@ static int br2684_ioctl(struct socket *sock, unsigned int cmd,
                        return -ENOIOCTLCMD;
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               err = br2684_setfilt(atmvcc, arg);
+               err = br2684_setfilt(atmvcc, argp);
                return err;
 #endif /* CONFIG_ATM_BR2684_IPFILTER */
        }