patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / net / core / dev.c
index b6dc213..9456559 100644 (file)
@@ -220,9 +220,15 @@ int netdev_fastroute;
 int netdev_fastroute_obstacles;
 #endif
 
+#ifdef CONFIG_SYSFS
 extern int netdev_sysfs_init(void);
 extern int netdev_register_sysfs(struct net_device *);
-extern int netdev_unregister_sysfs(struct net_device *);
+extern void netdev_unregister_sysfs(struct net_device *);
+#else
+#define netdev_sysfs_init()            (0)
+#define netdev_register_sysfs(dev)     (0)
+#define        netdev_unregister_sysfs(dev)    do { } while(0)
+#endif
 
 
 /*******************************************************************************
@@ -785,13 +791,15 @@ int dev_alloc_name(struct net_device *dev, const char *name)
 /**
  *     dev_change_name - change name of a device
  *     @dev: device
- *     @name: name (or format string) must be at least IFNAMSIZ
+ *     @newname: name (or format string) must be at least IFNAMSIZ
  *
  *     Change name of a device, can pass format strings "eth%d".
  *     for wildcarding.
  */
 int dev_change_name(struct net_device *dev, char *newname)
 {
+       int err = 0;
+
        ASSERT_RTNL();
 
        if (dev->flags & IFF_UP)
@@ -801,7 +809,7 @@ int dev_change_name(struct net_device *dev, char *newname)
                return -EINVAL;
 
        if (strchr(newname, '%')) {
-               int err = dev_alloc_name(dev, newname);
+               err = dev_alloc_name(dev, newname);
                if (err < 0)
                        return err;
                strcpy(newname, dev->name);
@@ -811,12 +819,14 @@ int dev_change_name(struct net_device *dev, char *newname)
        else
                strlcpy(dev->name, newname, IFNAMSIZ);
 
-       hlist_del(&dev->name_hlist);
-       hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+       err = class_device_rename(&dev->class_dev, dev->name);
+       if (!err) {
+               hlist_del(&dev->name_hlist);
+               hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+       }
 
-       class_device_rename(&dev->class_dev, dev->name);
-       notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
-       return 0;
+       return err;
 }
 
 /**
@@ -1170,28 +1180,46 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
        rcu_read_unlock();
 }
 
-/* Calculate csum in the case, when packet is misrouted.
- * If it failed by some reason, ignore and send skb with wrong
- * checksum.
+/*
+ * Invalidate hardware checksum when packet is to be mangled, and
+ * complete checksum manually on outgoing path.
  */
-struct sk_buff *skb_checksum_help(struct sk_buff *skb)
+int skb_checksum_help(struct sk_buff **pskb, int inward)
 {
        unsigned int csum;
-       int offset = skb->h.raw - skb->data;
+       int ret = 0, offset = (*pskb)->h.raw - (*pskb)->data;
+
+       if (inward) {
+               (*pskb)->ip_summed = CHECKSUM_NONE;
+               goto out;
+       }
+
+       if (skb_shared(*pskb)  || skb_cloned(*pskb)) {
+               struct sk_buff *newskb = skb_copy(*pskb, GFP_ATOMIC);
+               if (!newskb) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               if ((*pskb)->sk)
+                       skb_set_owner_w(newskb, (*pskb)->sk);
+               kfree_skb(*pskb);
+               *pskb = newskb;
+       }
 
-       if (offset > (int)skb->len)
+       if (offset > (int)(*pskb)->len)
                BUG();
-       csum = skb_checksum(skb, offset, skb->len-offset, 0);
+       csum = skb_checksum(*pskb, offset, (*pskb)->len-offset, 0);
 
-       offset = skb->tail - skb->h.raw;
+       offset = (*pskb)->tail - (*pskb)->h.raw;
        if (offset <= 0)
                BUG();
-       if (skb->csum + 2 > offset)
+       if ((*pskb)->csum + 2 > offset)
                BUG();
 
-       *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
-       skb->ip_summed = CHECKSUM_NONE;
-       return skb;
+       *(u16*)((*pskb)->h.raw + (*pskb)->csum) = csum_fold(csum);
+       (*pskb)->ip_summed = CHECKSUM_NONE;
+out:   
+       return ret;
 }
 
 #ifdef CONFIG_HIGHMEM
@@ -1316,10 +1344,9 @@ int dev_queue_xmit(struct sk_buff *skb)
        if (skb->ip_summed == CHECKSUM_HW &&
            (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
             (!(dev->features & NETIF_F_IP_CSUM) ||
-             skb->protocol != htons(ETH_P_IP)))) {
-               if ((skb = skb_checksum_help(skb)) == NULL)
-                       goto out;
-       }
+             skb->protocol != htons(ETH_P_IP))))
+               if (skb_checksum_help(&skb, 0))
+                       goto out_kfree_skb;
 
        /* Grab device queue */
        spin_lock_bh(&dev->queue_lock);
@@ -1948,7 +1975,7 @@ static int dev_ifconf(char __user *arg)
 {
        struct ifconf ifc;
        struct net_device *dev;
-       char *pos;
+       char __user *pos;
        int len;
        int total;
        int i;
@@ -2521,6 +2548,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
                            cmd == SIOCGMIIPHY ||
                            cmd == SIOCGMIIREG ||
                            cmd == SIOCSMIIREG ||
+                           cmd == SIOCBRADDIF ||
+                           cmd == SIOCBRDELIF ||
                            cmd == SIOCWANDEV) {
                                err = -EOPNOTSUPP;
                                if (dev->do_ioctl) {
@@ -2675,6 +2704,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
                case SIOCBONDSLAVEINFOQUERY:
                case SIOCBONDINFOQUERY:
                case SIOCBONDCHANGEACTIVE:
+               case SIOCBRADDIF:
+               case SIOCBRDELIF:
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
                        dev_load(ifr.ifr_name);
@@ -2969,16 +3000,20 @@ static DECLARE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
        struct list_head list = LIST_HEAD_INIT(list);
+       int err;
 
-       /* Safe outside mutex since we only care about entries that
-        * this cpu put into queue while under RTNL.
-        */
-       if (list_empty(&net_todo_list))
-               return;
 
        /* Need to guard against multiple cpu's getting out of order. */
        down(&net_todo_run_mutex);
 
+       /* Not safe to do outside the semaphore.  We must not return
+        * until all unregister events invoked by the local processor
+        * have been completed (either by this todo run, or one on
+        * another cpu).
+        */
+       if (list_empty(&net_todo_list))
+               goto out;
+
        /* Snapshot list, allow later requests */
        spin_lock(&net_todo_list_lock);
        list_splice_init(&net_todo_list, &list);
@@ -2991,7 +3026,10 @@ void netdev_run_todo(void)
 
                switch(dev->reg_state) {
                case NETREG_REGISTERING:
-                       netdev_register_sysfs(dev);
+                       err = netdev_register_sysfs(dev);
+                       if (err)
+                               printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
+                                      dev->name, err);
                        dev->reg_state = NETREG_REGISTERED;
                        break;
 
@@ -3022,6 +3060,7 @@ void netdev_run_todo(void)
                }
        }
 
+out:
        up(&net_todo_run_mutex);
 }
 
@@ -3035,6 +3074,7 @@ void netdev_run_todo(void)
  */
 void free_netdev(struct net_device *dev)
 {
+#ifdef CONFIG_SYSFS
        /*  Compatiablity with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
                kfree((char *)dev - dev->padded);
@@ -3046,6 +3086,9 @@ void free_netdev(struct net_device *dev)
 
        /* will free via class release */
        class_device_put(&dev->class_dev);
+#else
+       kfree((char *)dev - dev->padded);
+#endif
 }
  
 /* Synchronize with packet receive processing. */