linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / core / dev.c
index 39253c9..18accef 100644 (file)
 #include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
+#include <linux/config.h>
 #include <linux/cpu.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/socket.h>
 #include <linux/netpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/delay.h>
-#include <linux/wireless.h>
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>            /* Note : will define WIRELESS_EXT */
 #include <net/iw_handler.h>
-#include <asm/current.h>
-#include <linux/audit.h>
-#include <linux/dmaengine.h>
-#include <linux/err.h>
-#include <linux/ctype.h>
+#endif /* CONFIG_NET_RADIO */
 #include <linux/vs_network.h>
-
-#ifdef CONFIG_XEN
-#include <net/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#endif
+#include <asm/current.h>
 
 /*
  *     The list of packet types we will receive (as opposed to discard)
  *             sure which should go first, but I bet it won't make much
  *             difference if we are running VLANs.  The good news is that
  *             this protocol won't be in the list unless compiled in, so
- *             the average user (w/out VLANs) will not be adversely affected.
+ *             the average user (w/out VLANs) will not be adversly affected.
  *             --BLG
  *
  *             0800    IP
@@ -157,14 +149,8 @@ static DEFINE_SPINLOCK(ptype_lock);
 static struct list_head ptype_base[16];        /* 16 way hashed list */
 static struct list_head ptype_all;             /* Taps */
 
-#ifdef CONFIG_NET_DMA
-static struct dma_client *net_dma_client;
-static unsigned int net_dma_count;
-static spinlock_t net_dma_event_lock;
-#endif
-
 /*
- * The @dev_base list is protected by @dev_base_lock and the rtnl
+ * The @dev_base list is protected by @dev_base_lock and the rtln
  * semaphore.
  *
  * Pure readers hold dev_base_lock for reading.
@@ -208,7 +194,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex)
  *     Our notifier list
  */
 
-static RAW_NOTIFIER_HEAD(netdev_chain);
+static struct notifier_block *netdev_chain;
 
 /*
  *     Device drivers call our routines to queue packets here. We empty the
@@ -237,7 +223,7 @@ extern void netdev_unregister_sysfs(struct net_device *);
  *     For efficiency
  */
 
-static int netdev_nit;
+int netdev_nit;
 
 /*
  *     Add a protocol ID to the list. Now that the input handler is
@@ -640,22 +626,14 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas
  *     @name: name string
  *
  *     Network device names need to be valid file names to
- *     to allow sysfs to work.  We also disallow any kind of
- *     whitespace.
+ *     to allow sysfs to work
  */
 int dev_valid_name(const char *name)
 {
-       if (*name == '\0')
-               return 0;
-       if (!strcmp(name, ".") || !strcmp(name, ".."))
-               return 0;
-
-       while (*name) {
-               if (*name == '/' || isspace(*name))
-                       return 0;
-               name++;
-       }
-       return 1;
+       return !(*name == '\0' 
+                || !strcmp(name, ".")
+                || !strcmp(name, "..")
+                || strchr(name, '/'));
 }
 
 /**
@@ -664,12 +642,10 @@ int dev_valid_name(const char *name)
  *     @name: name format string
  *
  *     Passed a format string - eg "lt%d" it will try and find a suitable
- *     id. It scans list of devices to build up a free map, then chooses
- *     the first empty slot. The caller must hold the dev_base or rtnl lock
- *     while allocating the name and adding the device in order to avoid
- *     duplicates.
- *     Limited to bits_per_byte * page size devices (ie 32K on most platforms).
- *     Returns the number of the unit assigned or a negative errno code.
+ *     id. Not efficient for many devices, not called a lot. The caller
+ *     must hold the dev_base or rtnl lock while allocating the name and
+ *     adding the device in order to avoid duplicates. Returns the number
+ *     of the unit assigned or a negative errno code.
  */
 
 int dev_alloc_name(struct net_device *dev, const char *name)
@@ -761,22 +737,21 @@ int dev_change_name(struct net_device *dev, char *newname)
        if (!err) {
                hlist_del(&dev->name_hlist);
                hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGENAME, dev);
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
        }
 
        return err;
 }
 
 /**
- *     netdev_features_change - device changes features
+ *     netdev_features_change - device changes fatures
  *     @dev: device to cause notification
  *
  *     Called to indicate a device has changed features.
  */
 void netdev_features_change(struct net_device *dev)
 {
-       raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+       notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
 }
 EXPORT_SYMBOL(netdev_features_change);
 
@@ -791,8 +766,7 @@ EXPORT_SYMBOL(netdev_features_change);
 void netdev_state_change(struct net_device *dev)
 {
        if (dev->flags & IFF_UP) {
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGE, dev);
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
                rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
        }
 }
@@ -889,7 +863,7 @@ int dev_open(struct net_device *dev)
                /*
                 *      ... and announce new interface.
                 */
-               raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+               notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
        }
        return ret;
 }
@@ -912,7 +886,7 @@ int dev_close(struct net_device *dev)
         *      Tell people we are going down, so that they can
         *      prepare to death, when device is still operating.
         */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
+       notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
 
        dev_deactivate(dev);
 
@@ -949,7 +923,7 @@ int dev_close(struct net_device *dev)
        /*
         * Tell people we are down
         */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+       notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
 
        return 0;
 }
@@ -980,7 +954,7 @@ int register_netdevice_notifier(struct notifier_block *nb)
        int err;
 
        rtnl_lock();
-       err = raw_notifier_chain_register(&netdev_chain, nb);
+       err = notifier_chain_register(&netdev_chain, nb);
        if (!err) {
                for (dev = dev_base; dev; dev = dev->next) {
                        nb->notifier_call(nb, NETDEV_REGISTER, dev);
@@ -1005,12 +979,7 @@ int register_netdevice_notifier(struct notifier_block *nb)
 
 int unregister_netdevice_notifier(struct notifier_block *nb)
 {
-       int err;
-
-       rtnl_lock();
-       err = raw_notifier_chain_unregister(&netdev_chain, nb);
-       rtnl_unlock();
-       return err;
+       return notifier_chain_unregister(&netdev_chain, nb);
 }
 
 /**
@@ -1019,12 +988,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
  *      @v:   pointer passed unmodified to notifier function
  *
  *     Call all network notifier blocks.  Parameters and return value
- *     are as for raw_notifier_call_chain().
+ *     are as for notifier_call_chain().
  */
 
 int call_netdevice_notifiers(unsigned long val, void *v)
 {
-       return raw_notifier_call_chain(&netdev_chain, val, v);
+       return notifier_call_chain(&netdev_chain, val, v);
 }
 
 /* When > 0 there are consumers of rx skb time stamps */
@@ -1064,7 +1033,7 @@ static inline void net_timestamp(struct sk_buff *skb)
  *     taps currently in use.
  */
 
-static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
+void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
        struct packet_type *ptype;
 
@@ -1105,70 +1074,6 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
        rcu_read_unlock();
 }
 
-
-void __netif_schedule(struct net_device *dev)
-{
-       if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) {
-               unsigned long flags;
-               struct softnet_data *sd;
-
-               local_irq_save(flags);
-               sd = &__get_cpu_var(softnet_data);
-               dev->next_sched = sd->output_queue;
-               sd->output_queue = dev;
-               raise_softirq_irqoff(NET_TX_SOFTIRQ);
-               local_irq_restore(flags);
-       }
-}
-EXPORT_SYMBOL(__netif_schedule);
-
-void __netif_rx_schedule(struct net_device *dev)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       dev_hold(dev);
-       list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
-       if (dev->quota < 0)
-               dev->quota += dev->weight;
-       else
-               dev->quota = dev->weight;
-       __raise_softirq_irqoff(NET_RX_SOFTIRQ);
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL(__netif_rx_schedule);
-
-void dev_kfree_skb_any(struct sk_buff *skb)
-{
-       if (in_irq() || irqs_disabled())
-               dev_kfree_skb_irq(skb);
-       else
-               dev_kfree_skb(skb);
-}
-EXPORT_SYMBOL(dev_kfree_skb_any);
-
-
-/* Hot-plugging. */
-void netif_device_detach(struct net_device *dev)
-{
-       if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
-           netif_running(dev)) {
-               netif_stop_queue(dev);
-       }
-}
-EXPORT_SYMBOL(netif_device_detach);
-
-void netif_device_attach(struct net_device *dev)
-{
-       if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
-           netif_running(dev)) {
-               netif_wake_queue(dev);
-               __netdev_watchdog_up(dev);
-       }
-}
-EXPORT_SYMBOL(netif_device_attach);
-
-
 /*
  * Invalidate hardware checksum when packet is to be mangled, and
  * complete checksum manually on outgoing path.
@@ -1178,12 +1083,9 @@ int skb_checksum_help(struct sk_buff *skb, int inward)
        unsigned int csum;
        int ret = 0, offset = skb->h.raw - skb->data;
 
-       if (inward)
-               goto out_set_summed;
-
-       if (unlikely(skb_shinfo(skb)->gso_size)) {
-               /* Let GSO fix up the checksum. */
-               goto out_set_summed;
+       if (inward) {
+               skb->ip_summed = CHECKSUM_NONE;
+               goto out;
        }
 
        if (skb_cloned(skb)) {
@@ -1200,65 +1102,11 @@ int skb_checksum_help(struct sk_buff *skb, int inward)
        BUG_ON(skb->csum + 2 > offset);
 
        *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
-
-out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:   
        return ret;
 }
 
-/**
- *     skb_gso_segment - Perform segmentation on skb.
- *     @skb: buffer to segment
- *     @features: features for the output path (see dev->features)
- *
- *     This function segments the given skb and returns a list of segments.
- *
- *     It may return NULL if the skb requires no segmentation.  This is
- *     only possible when GSO is used for verifying header integrity.
- */
-struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
-{
-       struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
-       struct packet_type *ptype;
-       int type = skb->protocol;
-       int err;
-
-       BUG_ON(skb_shinfo(skb)->frag_list);
-
-       skb->mac.raw = skb->data;
-       skb->mac_len = skb->nh.raw - skb->data;
-       __skb_pull(skb, skb->mac_len);
-
-       if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
-               if (skb_header_cloned(skb) &&
-                   (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
-                       return ERR_PTR(err);
-       }
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
-               if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
-                       if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
-                               err = ptype->gso_send_check(skb);
-                               segs = ERR_PTR(err);
-                               if (err || skb_gso_ok(skb, features))
-                                       break;
-                               __skb_push(skb, skb->data - skb->nh.raw);
-                       }
-                       segs = ptype->gso_segment(skb, features);
-                       break;
-               }
-       }
-       rcu_read_unlock();
-
-       __skb_push(skb, skb->data - skb->mac.raw);
-
-       return segs;
-}
-
-EXPORT_SYMBOL(skb_gso_segment);
-
 /* Take action when hardware reception checksum errors are detected. */
 #ifdef CONFIG_BUG
 void netdev_rx_csum_fault(struct net_device *dev)
@@ -1272,6 +1120,7 @@ void netdev_rx_csum_fault(struct net_device *dev)
 EXPORT_SYMBOL(netdev_rx_csum_fault);
 #endif
 
+#ifdef CONFIG_HIGHMEM
 /* Actually, we should eliminate this check as soon as we know, that:
  * 1. IOMMU is present and allows to map all the memory.
  * 2. No high memory really exists on this machine.
@@ -1279,7 +1128,6 @@ EXPORT_SYMBOL(netdev_rx_csum_fault);
 
 static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 {
-#ifdef CONFIG_HIGHMEM
        int i;
 
        if (dev->features & NETIF_F_HIGHDMA)
@@ -1289,152 +1137,85 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
                if (PageHighMem(skb_shinfo(skb)->frags[i].page))
                        return 1;
 
-#endif
        return 0;
 }
+#else
+#define illegal_highdma(dev, skb)      (0)
+#endif
 
-struct dev_gso_cb {
-       void (*destructor)(struct sk_buff *skb);
-};
-
-#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
-
-static void dev_gso_skb_destructor(struct sk_buff *skb)
+/* Keep head the same: replace data */
+int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
 {
-       struct dev_gso_cb *cb;
-
-       do {
-               struct sk_buff *nskb = skb->next;
+       unsigned int size;
+       u8 *data;
+       long offset;
+       struct skb_shared_info *ninfo;
+       int headerlen = skb->data - skb->head;
+       int expand = (skb->tail + skb->data_len) - skb->end;
 
-               skb->next = nskb->next;
-               nskb->next = NULL;
-               kfree_skb(nskb);
-       } while (skb->next);
+       if (skb_shared(skb))
+               BUG();
 
-       cb = DEV_GSO_CB(skb);
-       if (cb->destructor)
-               cb->destructor(skb);
-}
+       if (expand <= 0)
+               expand = 0;
 
-/**
- *     dev_gso_segment - Perform emulated hardware segmentation on skb.
- *     @skb: buffer to segment
- *
- *     This function segments the given skb and stores the list of segments
- *     in skb->next.
- */
-static int dev_gso_segment(struct sk_buff *skb)
-{
-       struct net_device *dev = skb->dev;
-       struct sk_buff *segs;
-       int features = dev->features & ~(illegal_highdma(dev, skb) ?
-                                        NETIF_F_SG : 0);
-
-       segs = skb_gso_segment(skb, features);
-
-       /* Verifying header integrity only. */
-       if (!segs)
-               return 0;
+       size = skb->end - skb->head + expand;
+       size = SKB_DATA_ALIGN(size);
+       data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+       if (!data)
+               return -ENOMEM;
 
-       if (unlikely(IS_ERR(segs)))
-               return PTR_ERR(segs);
+       /* Copy entire thing */
+       if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
+               BUG();
 
-       skb->next = segs;
-       DEV_GSO_CB(skb)->destructor = skb->destructor;
-       skb->destructor = dev_gso_skb_destructor;
+       /* Set up shinfo */
+       ninfo = (struct skb_shared_info*)(data + size);
+       atomic_set(&ninfo->dataref, 1);
+       ninfo->tso_size = skb_shinfo(skb)->tso_size;
+       ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
+       ninfo->ufo_size = skb_shinfo(skb)->ufo_size;
+       ninfo->nr_frags = 0;
+       ninfo->frag_list = NULL;
 
-       return 0;
-}
+       /* Offset between the two in bytes */
+       offset = data - skb->head;
 
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       if (likely(!skb->next)) {
-               if (netdev_nit)
-                       dev_queue_xmit_nit(skb, dev);
+       /* Free old data. */
+       skb_release_data(skb);
 
-               if (netif_needs_gso(dev, skb)) {
-                       if (unlikely(dev_gso_segment(skb)))
-                               goto out_kfree_skb;
-                       if (skb->next)
-                               goto gso;
-               }
+       skb->head = data;
+       skb->end  = data + size;
 
-               return dev->hard_start_xmit(skb, dev);
-       }
+       /* Set up new pointers */
+       skb->h.raw   += offset;
+       skb->nh.raw  += offset;
+       skb->mac.raw += offset;
+       skb->tail    += offset;
+       skb->data    += offset;
 
-gso:
-       do {
-               struct sk_buff *nskb = skb->next;
-               int rc;
-
-               skb->next = nskb->next;
-               nskb->next = NULL;
-               rc = dev->hard_start_xmit(nskb, dev);
-               if (unlikely(rc)) {
-                       nskb->next = skb->next;
-                       skb->next = nskb;
-                       return rc;
-               }
-               if (unlikely(netif_queue_stopped(dev) && skb->next))
-                       return NETDEV_TX_BUSY;
-       } while (skb->next);
-       
-       skb->destructor = DEV_GSO_CB(skb)->destructor;
+       /* We are no longer a clone, even if we were. */
+       skb->cloned    = 0;
 
-out_kfree_skb:
-       kfree_skb(skb);
+       skb->tail     += skb->data_len;
+       skb->data_len  = 0;
        return 0;
 }
 
 #define HARD_TX_LOCK(dev, cpu) {                       \
        if ((dev->features & NETIF_F_LLTX) == 0) {      \
-               netif_tx_lock(dev);                     \
+               spin_lock(&dev->xmit_lock);             \
+               dev->xmit_lock_owner = cpu;             \
        }                                               \
 }
 
 #define HARD_TX_UNLOCK(dev) {                          \
        if ((dev->features & NETIF_F_LLTX) == 0) {      \
-               netif_tx_unlock(dev);                   \
+               dev->xmit_lock_owner = -1;              \
+               spin_unlock(&dev->xmit_lock);           \
        }                                               \
 }
 
-#ifdef CONFIG_XEN
-inline int skb_checksum_setup(struct sk_buff *skb)
-{
-       if (skb->proto_csum_blank) {
-               if (skb->protocol != htons(ETH_P_IP))
-                       goto out;
-               skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
-               if (skb->h.raw >= skb->tail)
-                       goto out;
-               switch (skb->nh.iph->protocol) {
-               case IPPROTO_TCP:
-                       skb->csum = offsetof(struct tcphdr, check);
-                       break;
-               case IPPROTO_UDP:
-                       skb->csum = offsetof(struct udphdr, check);
-                       break;
-               default:
-                       if (net_ratelimit())
-                               printk(KERN_ERR "Attempting to checksum a non-"
-                                      "TCP/UDP packet, dropping a protocol"
-                                      " %d packet", skb->nh.iph->protocol);
-                       goto out;
-               }
-               if ((skb->h.raw + skb->csum + 2) > skb->tail)
-                       goto out;
-               skb->ip_summed = CHECKSUM_HW;
-               skb->proto_csum_blank = 0;
-       }
-       return 0;
-out:
-       return -EPROTO;
-}
-#else
-inline int skb_checksum_setup(struct sk_buff *skb) { return 0; }
-#endif
-
-
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
@@ -1467,19 +1248,9 @@ int dev_queue_xmit(struct sk_buff *skb)
        struct Qdisc *q;
        int rc = -ENOMEM;
 
-       /* If a checksum-deferred packet is forwarded to a device that needs a
-        * checksum, correct the pointers and force checksumming.
-        */
-       if (skb_checksum_setup(skb))
-               goto out_kfree_skb;
-
-       /* GSO will handle the following emulations directly. */
-       if (netif_needs_gso(dev, skb))
-               goto gso;
-
        if (skb_shinfo(skb)->frag_list &&
            !(dev->features & NETIF_F_FRAGLIST) &&
-           __skb_linearize(skb))
+           __skb_linearize(skb, GFP_ATOMIC))
                goto out_kfree_skb;
 
        /* Fragmented skb is linearized if device does not support SG,
@@ -1488,26 +1259,25 @@ int dev_queue_xmit(struct sk_buff *skb)
         */
        if (skb_shinfo(skb)->nr_frags &&
            (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
-           __skb_linearize(skb))
+           __skb_linearize(skb, GFP_ATOMIC))
                goto out_kfree_skb;
 
        /* If packet is not checksummed and device does not support
         * checksumming for this protocol, complete checksumming here.
         */
        if (skb->ip_summed == CHECKSUM_HW &&
-           (!(dev->features & NETIF_F_GEN_CSUM) &&
+           (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
             (!(dev->features & NETIF_F_IP_CSUM) ||
              skb->protocol != htons(ETH_P_IP))))
                if (skb_checksum_help(skb, 0))
                        goto out_kfree_skb;
 
-gso:
        spin_lock_prefetch(&dev->queue_lock);
 
        /* Disable soft irqs for various locks below. Also 
         * stops preemption for RCU. 
         */
-       rcu_read_lock_bh(); 
+       local_bh_disable(); 
 
        /* Updates of qdisc are serialized by queue_lock. 
         * The struct Qdisc which is pointed to by qdisc is now a 
@@ -1543,8 +1313,8 @@ gso:
        /* The device has no queue. Common case for software devices:
           loopback, all the sorts of tunnels...
 
-          Really, it is unlikely that netif_tx_lock protection is necessary
-          here.  (f.e. loopback and IP tunnels are clean ignoring statistics
+          Really, it is unlikely that xmit_lock protection is necessary here.
+          (f.e. loopback and IP tunnels are clean ignoring statistics
           counters.)
           However, it is possible, that they rely on protection
           made by us here.
@@ -1560,8 +1330,11 @@ gso:
                        HARD_TX_LOCK(dev, cpu);
 
                        if (!netif_queue_stopped(dev)) {
+                               if (netdev_nit)
+                                       dev_queue_xmit_nit(skb, dev);
+
                                rc = 0;
-                               if (!dev_hard_start_xmit(skb, dev)) {
+                               if (!dev->hard_start_xmit(skb, dev)) {
                                        HARD_TX_UNLOCK(dev);
                                        goto out;
                                }
@@ -1580,13 +1353,13 @@ gso:
        }
 
        rc = -ENETDOWN;
-       rcu_read_unlock_bh();
+       local_bh_enable();
 
 out_kfree_skb:
        kfree_skb(skb);
        return rc;
 out:
-       rcu_read_unlock_bh();
+       local_bh_enable();
        return rc;
 }
 
@@ -1679,13 +1452,8 @@ static inline struct net_device *skb_bond(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
 
-       if (dev->master) {
-               if (skb_bond_should_drop(skb)) {
-                       kfree_skb(skb);
-                       return NULL;
-               }
+       if (dev->master)
                skb->dev = dev->master;
-       }
 
        return dev;
 }
@@ -1790,7 +1558,7 @@ static int ing_filter(struct sk_buff *skb)
        if (dev->qdisc_ingress) {
                __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
                if (MAX_RED_LOOP < ttl++) {
-                       printk(KERN_WARNING "Redir loop detected Dropping packet (%s->%s)\n",
+                       printk("Redir loop detected Dropping packet (%s->%s)\n",
                                skb->input_dev->name, skb->dev->name);
                        return TC_ACT_SHOT;
                }
@@ -1829,9 +1597,6 @@ int netif_receive_skb(struct sk_buff *skb)
 
        orig_dev = skb_bond(skb);
 
-       if (!orig_dev)
-               return NET_RX_DROP;
-
        __get_cpu_var(netdev_rx_stat).total++;
 
        skb->h.raw = skb->nh.raw = skb->data;
@@ -1848,19 +1613,6 @@ int netif_receive_skb(struct sk_buff *skb)
        }
 #endif
 
-#ifdef CONFIG_XEN
-       switch (skb->ip_summed) {
-       case CHECKSUM_UNNECESSARY:
-               skb->proto_data_valid = 1;
-               break;
-       case CHECKSUM_HW:
-               /* XXX Implement me. */
-       default:
-               skb->proto_data_valid = 0;
-               break;
-       }
-#endif
-
        list_for_each_entry_rcu(ptype, &ptype_all, list) {
                if (!ptype->dev || ptype->dev == skb->dev) {
                        if (pt_prev) 
@@ -1989,7 +1741,8 @@ static void net_rx_action(struct softirq_action *h)
                if (dev->quota <= 0 || dev->poll(dev, &budget)) {
                        netpoll_poll_unlock(have);
                        local_irq_disable();
-                       list_move_tail(&dev->poll_list, &queue->poll_list);
+                       list_del(&dev->poll_list);
+                       list_add_tail(&dev->poll_list, &queue->poll_list);
                        if (dev->quota < 0)
                                dev->quota += dev->weight;
                        else
@@ -2001,19 +1754,6 @@ static void net_rx_action(struct softirq_action *h)
                }
        }
 out:
-#ifdef CONFIG_NET_DMA
-       /*
-        * There may not be any more sk_buffs coming right now, so push
-        * any pending DMA copies to hardware
-        */
-       if (net_dma_client) {
-               struct dma_chan *chan;
-               rcu_read_lock();
-               list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node)
-                       dma_async_memcpy_issue_pending(chan);
-               rcu_read_unlock();
-       }
-#endif
        local_irq_enable();
        return;
 
@@ -2299,7 +2039,7 @@ static struct file_operations softnet_seq_fops = {
        .release = seq_release,
 };
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef WIRELESS_EXT
 extern int wireless_proc_init(void);
 #else
 #define wireless_proc_init() 0
@@ -2373,7 +2113,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
  *     @dev: device
  *     @inc: modifier
  *
- *     Add or remove promiscuity from a device. While the count in the device
+ *     Add or remove promsicuity from a device. While the count in the device
  *     remains above zero the interface remains promiscuous. Once it hits zero
  *     the device reverts back to normal filtering operation. A negative inc
  *     value is used to drop promiscuity on the device.
@@ -2391,12 +2131,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
                                                               "left");
-               audit_log(current->audit_context, GFP_ATOMIC,
-                       AUDIT_ANOM_PROMISCUOUS,
-                       "dev=%s prom=%d old_prom=%d auid=%u",
-                       dev->name, (dev->flags & IFF_PROMISC),
-                       (old_flags & IFF_PROMISC),
-                       audit_get_loginuid(current->audit_context)); 
        }
 }
 
@@ -2429,20 +2163,12 @@ unsigned dev_get_flags(const struct net_device *dev)
 
        flags = (dev->flags & ~(IFF_PROMISC |
                                IFF_ALLMULTI |
-                               IFF_RUNNING |
-                               IFF_LOWER_UP |
-                               IFF_DORMANT)) |
+                               IFF_RUNNING)) | 
                (dev->gflags & (IFF_PROMISC |
                                IFF_ALLMULTI));
 
-       if (netif_running(dev)) {
-               if (netif_oper_up(dev))
-                       flags |= IFF_RUNNING;
-               if (netif_carrier_ok(dev))
-                       flags |= IFF_LOWER_UP;
-               if (netif_dormant(dev))
-                       flags |= IFF_DORMANT;
-       }
+       if (netif_running(dev) && netif_carrier_ok(dev))
+               flags |= IFF_RUNNING;
 
        return flags;
 }
@@ -2485,8 +2211,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
        if (dev->flags & IFF_UP &&
            ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
                                          IFF_VOLATILE)))
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGE, dev);
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
 
        if ((flags ^ dev->gflags) & IFF_PROMISC) {
                int inc = (flags & IFF_PROMISC) ? +1 : -1;
@@ -2530,8 +2255,8 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
        else
                dev->mtu = new_mtu;
        if (!err && dev->flags & IFF_UP)
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGEMTU, dev);
+               notifier_call_chain(&netdev_chain,
+                                   NETDEV_CHANGEMTU, dev);
        return err;
 }
 
@@ -2547,8 +2272,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
                return -ENODEV;
        err = dev->set_mac_address(dev, sa);
        if (!err)
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGEADDR, dev);
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
        return err;
 }
 
@@ -2604,7 +2328,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
                                return -EINVAL;
                        memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
                               min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
-                       raw_notifier_call_chain(&netdev_chain,
+                       notifier_call_chain(&netdev_chain,
                                            NETDEV_CHANGEADDR, dev);
                        return 0;
 
@@ -2723,9 +2447,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
         */
 
        if (cmd == SIOCGIFCONF) {
-               rtnl_lock();
+               rtnl_shlock();
                ret = dev_ifconf((char __user *) arg);
-               rtnl_unlock();
+               rtnl_shunlock();
                return ret;
        }
        if (cmd == SIOCGIFNAME)
@@ -2869,14 +2593,13 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
                                        ret = -EFAULT;
                                return ret;
                        }
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef WIRELESS_EXT
                        /* Take care of Wireless Extensions */
                        if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
                                /* If command is `set a parameter', or
                                 * `get the encoding parameters', check if
                                 * the user has the right to do it */
-                               if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE
-                                   || cmd == SIOCGIWENCODEEXT) {
+                               if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) {
                                        if (!capable(CAP_NET_ADMIN))
                                                return -EPERM;
                                }
@@ -2891,7 +2614,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
                                        ret = -EFAULT;
                                return ret;
                        }
-#endif /* CONFIG_WIRELESS_EXT */
+#endif /* WIRELESS_EXT */
                        return -EINVAL;
        }
 }
@@ -2954,13 +2677,11 @@ int register_netdevice(struct net_device *dev)
        BUG_ON(dev_boot_phase);
        ASSERT_RTNL();
 
-       might_sleep();
-
        /* When net_device's are persistent, this will be fatal. */
        BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
 
        spin_lock_init(&dev->queue_lock);
-       spin_lock_init(&dev->_xmit_lock);
+       spin_lock_init(&dev->xmit_lock);
        dev->xmit_lock_owner = -1;
 #ifdef CONFIG_NET_CLS_ACT
        spin_lock_init(&dev->ingress_lock);
@@ -3004,8 +2725,10 @@ int register_netdevice(struct net_device *dev)
 
        /* Fix illegal SG+CSUM combinations. */
        if ((dev->features & NETIF_F_SG) &&
-           !(dev->features & NETIF_F_ALL_CSUM)) {
-               printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no checksum feature.\n",
+           !(dev->features & (NETIF_F_IP_CSUM |
+                              NETIF_F_NO_CSUM |
+                              NETIF_F_HW_CSUM))) {
+               printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
                       dev->name);
                dev->features &= ~NETIF_F_SG;
        }
@@ -3013,7 +2736,7 @@ int register_netdevice(struct net_device *dev)
        /* TSO requires that SG is present as well. */
        if ((dev->features & NETIF_F_TSO) &&
            !(dev->features & NETIF_F_SG)) {
-               printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no SG feature.\n",
+               printk("%s: Dropping NETIF_F_TSO since no SG feature.\n",
                       dev->name);
                dev->features &= ~NETIF_F_TSO;
        }
@@ -3040,11 +2763,6 @@ int register_netdevice(struct net_device *dev)
        if (!dev->rebuild_header)
                dev->rebuild_header = default_rebuild_header;
 
-       ret = netdev_register_sysfs(dev);
-       if (ret)
-               goto out_err;
-       dev->reg_state = NETREG_REGISTERED;
-
        /*
         *      Default initial state at registry is that the
         *      device is present.
@@ -3060,11 +2778,14 @@ int register_netdevice(struct net_device *dev)
        hlist_add_head(&dev->name_hlist, head);
        hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
        dev_hold(dev);
+       dev->reg_state = NETREG_REGISTERING;
        write_unlock_bh(&dev_base_lock);
 
        /* Notify protocols, that a new device appeared. */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+       notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
+       /* Finish registration after unlock */
+       net_set_todo(dev);
        ret = 0;
 
 out:
@@ -3137,10 +2858,10 @@ static void netdev_wait_allrefs(struct net_device *dev)
        rebroadcast_time = warning_time = jiffies;
        while (atomic_read(&dev->refcnt) != 0) {
                if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
-                       rtnl_lock();
+                       rtnl_shlock();
 
                        /* Rebroadcast unregister notification */
-                       raw_notifier_call_chain(&netdev_chain,
+                       notifier_call_chain(&netdev_chain,
                                            NETDEV_UNREGISTER, dev);
 
                        if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
@@ -3154,7 +2875,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
                                linkwatch_run_queue();
                        }
 
-                       __rtnl_unlock();
+                       rtnl_shunlock();
 
                        rebroadcast_time = jiffies;
                }
@@ -3187,18 +2908,20 @@ static void netdev_wait_allrefs(struct net_device *dev)
  *
  * We are invoked by rtnl_unlock() after it drops the semaphore.
  * This allows us to deal with problems:
- * 1) We can delete sysfs objects which invoke hotplug
+ * 1) We can create/delete sysfs objects which invoke hotplug
  *    without deadlocking with linkwatch via keventd.
  * 2) Since we run with the RTNL semaphore not held, we can sleep
  *    safely in order to wait for the netdev refcnt to drop to zero.
  */
-static DEFINE_MUTEX(net_todo_run_mutex);
+static DECLARE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
-       struct list_head list;
+       struct list_head list = LIST_HEAD_INIT(list);
+       int err;
+
 
        /* Need to guard against multiple cpu's getting out of order. */
-       mutex_lock(&net_todo_run_mutex);
+       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
@@ -3210,41 +2933,52 @@ void netdev_run_todo(void)
 
        /* Snapshot list, allow later requests */
        spin_lock(&net_todo_list_lock);
-       list_replace_init(&net_todo_list, &list);
+       list_splice_init(&net_todo_list, &list);
        spin_unlock(&net_todo_list_lock);
-
+               
        while (!list_empty(&list)) {
                struct net_device *dev
                        = list_entry(list.next, struct net_device, todo_list);
                list_del(&dev->todo_list);
 
-               if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) {
-                       printk(KERN_ERR "network todo '%s' but state %d\n",
-                              dev->name, dev->reg_state);
-                       dump_stack();
-                       continue;
-               }
+               switch(dev->reg_state) {
+               case NETREG_REGISTERING:
+                       dev->reg_state = NETREG_REGISTERED;
+                       err = netdev_register_sysfs(dev);
+                       if (err)
+                               printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
+                                      dev->name, err);
+                       break;
 
-               netdev_unregister_sysfs(dev);
-               dev->reg_state = NETREG_UNREGISTERED;
+               case NETREG_UNREGISTERING:
+                       netdev_unregister_sysfs(dev);
+                       dev->reg_state = NETREG_UNREGISTERED;
 
-               netdev_wait_allrefs(dev);
+                       netdev_wait_allrefs(dev);
 
-               /* paranoia */
-               BUG_ON(atomic_read(&dev->refcnt));
-               BUG_TRAP(!dev->ip_ptr);
-               BUG_TRAP(!dev->ip6_ptr);
-               BUG_TRAP(!dev->dn_ptr);
+                       /* paranoia */
+                       BUG_ON(atomic_read(&dev->refcnt));
+                       BUG_TRAP(!dev->ip_ptr);
+                       BUG_TRAP(!dev->ip6_ptr);
+                       BUG_TRAP(!dev->dn_ptr);
 
-               /* It must be the very last action,
-                * after this 'dev' may point to freed up memory.
-                */
-               if (dev->destructor)
-                       dev->destructor(dev);
+
+                       /* It must be the very last action, 
+                        * after this 'dev' may point to freed up memory.
+                        */
+                       if (dev->destructor)
+                               dev->destructor(dev);
+                       break;
+
+               default:
+                       printk(KERN_ERR "network todo '%s' but state %d\n",
+                              dev->name, dev->reg_state);
+                       break;
+               }
        }
 
 out:
-       mutex_unlock(&net_todo_run_mutex);
+       up(&net_todo_run_mutex);
 }
 
 /**
@@ -3267,11 +3001,12 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
        alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
        alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
 
-       p = kzalloc(alloc_size, GFP_KERNEL);
+       p = kmalloc(alloc_size, GFP_KERNEL);
        if (!p) {
                printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
                return NULL;
        }
+       memset(p, 0, alloc_size);
 
        dev = (struct net_device *)
                (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
@@ -3297,7 +3032,7 @@ EXPORT_SYMBOL(alloc_netdev);
 void free_netdev(struct net_device *dev)
 {
 #ifdef CONFIG_SYSFS
-       /*  Compatibility with error handling in drivers */
+       /*  Compatiablity with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
                kfree((char *)dev - dev->padded);
                return;
@@ -3382,7 +3117,7 @@ int unregister_netdevice(struct net_device *dev)
        /* Notify protocols, that we are about to destroy
           this device. They should clean all the things.
        */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+       notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
        
        /*
         *      Flush the multicast chain
@@ -3473,83 +3208,6 @@ static int dev_cpu_callback(struct notifier_block *nfb,
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-#ifdef CONFIG_NET_DMA
-/**
- * net_dma_rebalance -
- * This is called when the number of channels allocated to the net_dma_client
- * changes.  The net_dma_client tries to have one DMA channel per CPU.
- */
-static void net_dma_rebalance(void)
-{
-       unsigned int cpu, i, n;
-       struct dma_chan *chan;
-
-       if (net_dma_count == 0) {
-               for_each_online_cpu(cpu)
-                       rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL);
-               return;
-       }
-
-       i = 0;
-       cpu = first_cpu(cpu_online_map);
-
-       rcu_read_lock();
-       list_for_each_entry(chan, &net_dma_client->channels, client_node) {
-               n = ((num_online_cpus() / net_dma_count)
-                  + (i < (num_online_cpus() % net_dma_count) ? 1 : 0));
-
-               while(n) {
-                       per_cpu(softnet_data, cpu).net_dma = chan;
-                       cpu = next_cpu(cpu, cpu_online_map);
-                       n--;
-               }
-               i++;
-       }
-       rcu_read_unlock();
-}
-
-/**
- * netdev_dma_event - event callback for the net_dma_client
- * @client: should always be net_dma_client
- * @chan: DMA channel for the event
- * @event: event type
- */
-static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
-       enum dma_event event)
-{
-       spin_lock(&net_dma_event_lock);
-       switch (event) {
-       case DMA_RESOURCE_ADDED:
-               net_dma_count++;
-               net_dma_rebalance();
-               break;
-       case DMA_RESOURCE_REMOVED:
-               net_dma_count--;
-               net_dma_rebalance();
-               break;
-       default:
-               break;
-       }
-       spin_unlock(&net_dma_event_lock);
-}
-
-/**
- * netdev_dma_regiser - register the networking subsystem as a DMA client
- */
-static int __init netdev_dma_register(void)
-{
-       spin_lock_init(&net_dma_event_lock);
-       net_dma_client = dma_async_client_register(netdev_dma_event);
-       if (net_dma_client == NULL)
-               return -ENOMEM;
-
-       dma_async_client_chan_request(net_dma_client, num_online_cpus());
-       return 0;
-}
-
-#else
-static int __init netdev_dma_register(void) { return -ENODEV; }
-#endif /* CONFIG_NET_DMA */
 
 /*
  *     Initialize the DEV module. At boot time this walks the device list and
@@ -3590,7 +3248,7 @@ static int __init net_dev_init(void)
         *      Initialise the packet receive queues.
         */
 
-       for_each_possible_cpu(i) {
+       for_each_cpu(i) {
                struct softnet_data *queue;
 
                queue = &per_cpu(softnet_data, i);
@@ -3603,8 +3261,6 @@ static int __init net_dev_init(void)
                atomic_set(&queue->backlog_dev.refcnt, 1);
        }
 
-       netdev_dma_register();
-
        dev_boot_phase = 0;
 
        open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
@@ -3623,6 +3279,7 @@ subsys_initcall(net_dev_init);
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_name);
 EXPORT_SYMBOL(__dev_remove_pack);
+EXPORT_SYMBOL(__skb_linearize);
 EXPORT_SYMBOL(dev_valid_name);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_alloc_name);
@@ -3654,7 +3311,6 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
 EXPORT_SYMBOL(net_enable_timestamp);
 EXPORT_SYMBOL(net_disable_timestamp);
 EXPORT_SYMBOL(dev_get_flags);
-EXPORT_SYMBOL(skb_checksum_setup);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);