vserver 2.0 rc7
[linux-2.6.git] / net / core / dev.c
index 43c273e..8782030 100644 (file)
@@ -7,7 +7,7 @@
  *             2 of the License, or (at your option) any later version.
  *
  *     Derived from the non IP parts of dev.c 1.0.19
- *             Authors:        Ross Biro, <bir7@leland.Stanford.Edu>
+ *             Authors:        Ross Biro
  *                             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *                             Mark Evans, <evansmp@uhura.aston.ac.uk>
  *
@@ -74,7 +74,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/config.h>
 #include <linux/cpu.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/netpoll.h>
+#include <linux/rcupdate.h>
+#include <linux/delay.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>            /* Note : will define WIRELESS_EXT */
 #include <net/iw_handler.h>
 #endif /* CONFIG_NET_RADIO */
+#include <linux/vs_network.h>
 #include <asm/current.h>
 
 /* This define, if set, will randomly drop a packet when congestion
  *             86DD    IPv6
  */
 
-static spinlock_t ptype_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ptype_lock);
 static struct list_head ptype_base[16];        /* 16 way hashed list */
 static struct list_head ptype_all;             /* Taps */
 
@@ -182,8 +185,8 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
  * semaphore held.
  */
 struct net_device *dev_base;
-struct net_device **dev_tail = &dev_base;
-rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
+static struct net_device **dev_tail = &dev_base;
+DEFINE_RWLOCK(dev_base_lock);
 
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_base_lock);
@@ -215,14 +218,15 @@ static struct notifier_block *netdev_chain;
  */
 DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };
 
-#ifdef CONFIG_NET_FASTROUTE
-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
 
 
 /*******************************************************************************
@@ -271,12 +275,6 @@ void dev_add_pack(struct packet_type *pt)
        int hash;
 
        spin_lock_bh(&ptype_lock);
-#ifdef CONFIG_NET_FASTROUTE
-       if (pt->af_packet_priv) {
-               netdev_fastroute_obstacles++;
-               dev_clear_fastroute(pt->dev);
-       }
-#endif
        if (pt->type == htons(ETH_P_ALL)) {
                netdev_nit++;
                list_add_rcu(&pt->list, &ptype_all);
@@ -319,10 +317,6 @@ void __dev_remove_pack(struct packet_type *pt)
 
        list_for_each_entry(pt1, head, list) {
                if (pt == pt1) {
-#ifdef CONFIG_NET_FASTROUTE
-                       if (pt->af_packet_priv)
-                               netdev_fastroute_obstacles--;
-#endif
                        list_del_rcu(&pt->list);
                        goto out;
                }
@@ -369,7 +363,7 @@ static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX];
  *     returns 0 on error and 1 on success.  This is a generic routine to
  *     all netdevices.
  */
-int netdev_boot_setup_add(char *name, struct ifmap *map)
+static int netdev_boot_setup_add(char *name, struct ifmap *map)
 {
        struct netdev_boot_setup *s;
        int i;
@@ -528,35 +522,6 @@ struct net_device *dev_get_by_name(const char *name)
        return dev;
 }
 
-/*
-   Return value is changed to int to prevent illegal usage in future.
-   It is still legal to use to check for device existence.
-
-   User should understand, that the result returned by this function
-   is meaningless, if it was not issued under rtnl semaphore.
- */
-
-/**
- *     dev_get -       test if a device exists
- *     @name:  name to test for
- *
- *     Test if a name exists. Returns true if the name is found. In order
- *     to be sure the name is not allocated or removed during the test the
- *     caller must hold the rtnl semaphore.
- *
- *     This function exists only for back compatibility with older
- *     drivers.
- */
-int __dev_get(const char *name)
-{
-       struct net_device *dev;
-
-       read_lock(&dev_base_lock);
-       dev = __dev_get_by_name(name);
-       read_unlock(&dev_base_lock);
-       return dev != NULL;
-}
-
 /**
  *     __dev_get_by_index - find a device by its ifindex
  *     @ifindex: index of device
@@ -631,26 +596,17 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
        return dev;
 }
 
-struct net_device *__dev_getfirstbyhwtype(unsigned short type)
-{
-       struct net_device *dev;
-
-       for (dev = dev_base; dev; dev = dev->next)
-               if (dev->type == type)
-                       break;
-       return dev;
-}
-
-EXPORT_SYMBOL(__dev_getfirstbyhwtype);
-
 struct net_device *dev_getfirstbyhwtype(unsigned short type)
 {
        struct net_device *dev;
 
        rtnl_lock();
-       dev = __dev_getfirstbyhwtype(type);
-       if (dev)
-               dev_hold(dev);
+       for (dev = dev_base; dev; dev = dev->next) {
+               if (dev->type == type) {
+                       dev_hold(dev);
+                       break;
+               }
+       }
        rtnl_unlock();
        return dev;
 }
@@ -673,32 +629,14 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas
        struct net_device *dev;
 
        read_lock(&dev_base_lock);
-       dev = __dev_get_by_flags(if_flags, mask);
-       if (dev)
-               dev_hold(dev);
-       read_unlock(&dev_base_lock);
-       return dev;
-}
-
-/**
- *     __dev_get_by_flags - find any device with given flags
- *     @if_flags: IFF_* values
- *     @mask: bitmask of bits in if_flags to check
- *
- *     Search for any interface with the given flags. Returns NULL if a device
- *     is not found or a pointer to the device. The caller must hold either
- *     the RTNL semaphore or @dev_base_lock.
- */
-
-struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short mask)
-{
-       struct net_device *dev;
-
        for (dev = dev_base; dev != NULL; dev = dev->next) {
-               if (((dev->flags ^ if_flags) & mask) == 0)
-                       return dev;
+               if (((dev->flags ^ if_flags) & mask) == 0) {
+                       dev_hold(dev);
+                       break;
+               }
        }
-       return NULL;
+       read_unlock(&dev_base_lock);
+       return dev;
 }
 
 /**
@@ -708,7 +646,7 @@ struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short ma
  *     Network device names need to be valid file names to
  *     to allow sysfs to work
  */
-int dev_valid_name(const char *name)
+static int dev_valid_name(const char *name)
 {
        return !(*name == '\0' 
                 || !strcmp(name, ".")
@@ -785,13 +723,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 +741,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,14 +751,28 @@ 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;
 }
 
+/**
+ *     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)
+{
+       notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+}
+EXPORT_SYMBOL(netdev_features_change);
+
 /**
  *     netdev_state_change - device changes state
  *     @dev: device to cause notification
@@ -865,18 +819,6 @@ static int default_rebuild_header(struct sk_buff *skb)
 }
 
 
-/*
- * Some old buggy device drivers change get_stats after registering
- * the device.  Try and trap them here.
- * This can be elimnated when all devices are known fixed.
- */
-static inline int get_stats_changed(struct net_device *dev)
-{
-       int changed = dev->last_stats != dev->get_stats;
-       dev->last_stats = dev->get_stats;
-       return changed;
-}
-
 /**
  *     dev_open        - prepare an interface for use.
  *     @dev:   device to open
@@ -900,14 +842,6 @@ int dev_open(struct net_device *dev)
        if (dev->flags & IFF_UP)
                return 0;
 
-       /*
-        *       Check for broken device drivers.
-        */
-       if (get_stats_changed(dev) && net_ratelimit()) {
-               printk(KERN_ERR "%s: driver changed get_stats after register\n",
-                      dev->name);
-       }
-
        /*
         *      Is it even present?
         */
@@ -924,14 +858,6 @@ int dev_open(struct net_device *dev)
                        clear_bit(__LINK_STATE_START, &dev->state);
        }
 
-       /*
-        *      Check for more broken device drivers.
-        */
-       if (get_stats_changed(dev) && net_ratelimit()) {
-               printk(KERN_ERR "%s: driver changed get_stats in open\n",
-                      dev->name);
-       }
-
        /*
         *      If it went open OK then:
         */
@@ -960,39 +886,6 @@ int dev_open(struct net_device *dev)
        return ret;
 }
 
-#ifdef CONFIG_NET_FASTROUTE
-
-static void dev_do_clear_fastroute(struct net_device *dev)
-{
-       if (dev->accept_fastpath) {
-               int i;
-
-               for (i = 0; i <= NETDEV_FASTROUTE_HMASK; i++) {
-                       struct dst_entry *dst;
-
-                       write_lock_irq(&dev->fastpath_lock);
-                       dst = dev->fastpath[i];
-                       dev->fastpath[i] = NULL;
-                       write_unlock_irq(&dev->fastpath_lock);
-
-                       dst_release(dst);
-               }
-       }
-}
-
-void dev_clear_fastroute(struct net_device *dev)
-{
-       if (dev) {
-               dev_do_clear_fastroute(dev);
-       } else {
-               read_lock(&dev_base_lock);
-               for (dev = dev_base; dev; dev = dev->next)
-                       dev_do_clear_fastroute(dev);
-               read_unlock(&dev_base_lock);
-       }
-}
-#endif
-
 /**
  *     dev_close - shutdown an interface.
  *     @dev: device to shutdown
@@ -1045,9 +938,6 @@ int dev_close(struct net_device *dev)
         */
 
        dev->flags &= ~IFF_UP;
-#ifdef CONFIG_NET_FASTROUTE
-       dev_clear_fastroute(dev);
-#endif
 
        /*
         * Tell people we are down
@@ -1125,6 +1015,29 @@ int call_netdevice_notifiers(unsigned long val, void *v)
        return notifier_call_chain(&netdev_chain, val, v);
 }
 
+/* When > 0 there are consumers of rx skb time stamps */
+static atomic_t netstamp_needed = ATOMIC_INIT(0);
+
+void net_enable_timestamp(void)
+{
+       atomic_inc(&netstamp_needed);
+}
+
+void net_disable_timestamp(void)
+{
+       atomic_dec(&netstamp_needed);
+}
+
+static inline void net_timestamp(struct timeval *stamp)
+{
+       if (atomic_read(&netstamp_needed))
+               do_gettimeofday(stamp);
+       else {
+               stamp->tv_sec = 0;
+               stamp->tv_usec = 0;
+       }
+}
+
 /*
  *     Support routine. Sends outgoing frames to any network
  *     taps currently in use.
@@ -1170,14 +1083,25 @@ 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 *skb, int inward)
 {
        unsigned int csum;
-       int offset = skb->h.raw - skb->data;
+       int ret = 0, offset = skb->h.raw - skb->data;
+
+       if (inward) {
+               skb->ip_summed = CHECKSUM_NONE;
+               goto out;
+       }
+
+       if (skb_cloned(skb)) {
+               ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+               if (ret)
+                       goto out;
+       }
 
        if (offset > (int)skb->len)
                BUG();
@@ -1191,7 +1115,8 @@ struct sk_buff *skb_checksum_help(struct sk_buff *skb)
 
        *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
        skb->ip_summed = CHECKSUM_NONE;
-       return skb;
+out:   
+       return ret;
 }
 
 #ifdef CONFIG_HIGHMEM
@@ -1208,7 +1133,7 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
                return 0;
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               if (skb_shinfo(skb)->frags[i].page >= highmem_start_page)
+               if (PageHighMem(skb_shinfo(skb)->frags[i].page))
                        return 1;
 
        return 0;
@@ -1277,6 +1202,20 @@ int __skb_linearize(struct sk_buff *skb, int gfp_mask)
        return 0;
 }
 
+#define HARD_TX_LOCK(dev, cpu) {                       \
+       if ((dev->features & NETIF_F_LLTX) == 0) {      \
+               spin_lock(&dev->xmit_lock);             \
+               dev->xmit_lock_owner = cpu;             \
+       }                                               \
+}
+
+#define HARD_TX_UNLOCK(dev) {                          \
+       if ((dev->features & NETIF_F_LLTX) == 0) {      \
+               dev->xmit_lock_owner = -1;              \
+               spin_unlock(&dev->xmit_lock);           \
+       }                                               \
+}
+
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
@@ -1288,6 +1227,19 @@ int __skb_linearize(struct sk_buff *skb, int gfp_mask)
  *     A negative errno code is returned on a failure. A success does not
  *     guarantee the frame will be transmitted as it may be dropped due
  *     to congestion or traffic shaping.
+ *
+ * -----------------------------------------------------------------------------------
+ *      I notice this method can also return errors from the queue disciplines,
+ *      including NET_XMIT_DROP, which is a positive value.  So, errors can also
+ *      be positive.
+ *
+ *      Regardless of the return value, the skb is consumed, so it is currently
+ *      difficult to retry a send to this method.  (You can bump the ref count
+ *      before sending to hold a reference for retry if you are careful.)
+ *
+ *      When calling this method, interrupts MUST be enabled.  This is because
+ *      the BH enable code must have IRQs enabled so that it will not deadlock.
+ *          --BLG
  */
 
 int dev_queue_xmit(struct sk_buff *skb)
@@ -1316,20 +1268,40 @@ 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);
-       q = dev->qdisc;
+       /* Disable soft irqs for various locks below. Also 
+        * stops preemption for RCU. 
+        */
+       local_bh_disable(); 
+
+       /* Updates of qdisc are serialized by queue_lock. 
+        * The struct Qdisc which is pointed to by qdisc is now a 
+        * rcu structure - it may be accessed without acquiring 
+        * a lock (but the structure may be stale.) The freeing of the
+        * qdisc will be deferred until it's known that there are no 
+        * more references to it.
+        * 
+        * If the qdisc has an enqueue function, we still need to 
+        * hold the queue_lock before calling it, since queue_lock
+        * also serializes access to the device queue.
+        */
+
+       q = rcu_dereference(dev->qdisc);
+#ifdef CONFIG_NET_CLS_ACT
+       skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
+#endif
        if (q->enqueue) {
+               /* Grab device queue */
+               spin_lock(&dev->queue_lock);
+
                rc = q->enqueue(skb, q);
 
                qdisc_run(dev);
 
-               spin_unlock_bh(&dev->queue_lock);
+               spin_unlock(&dev->queue_lock);
                rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
                goto out;
        }
@@ -1347,18 +1319,11 @@ int dev_queue_xmit(struct sk_buff *skb)
           Either shot noqueue qdisc, it is even simpler 8)
         */
        if (dev->flags & IFF_UP) {
-               int cpu = smp_processor_id();
+               int cpu = smp_processor_id(); /* ok because BHs are off */
 
                if (dev->xmit_lock_owner != cpu) {
-                       /*
-                        * The spin_lock effectivly does a preempt lock, but 
-                        * we are about to drop that...
-                        */
-                       preempt_disable();
-                       spin_unlock(&dev->queue_lock);
-                       spin_lock(&dev->xmit_lock);
-                       dev->xmit_lock_owner = cpu;
-                       preempt_enable();
+
+                       HARD_TX_LOCK(dev, cpu);
 
                        if (!netif_queue_stopped(dev)) {
                                if (netdev_nit)
@@ -1366,17 +1331,14 @@ int dev_queue_xmit(struct sk_buff *skb)
 
                                rc = 0;
                                if (!dev->hard_start_xmit(skb, dev)) {
-                                       dev->xmit_lock_owner = -1;
-                                       spin_unlock_bh(&dev->xmit_lock);
+                                       HARD_TX_UNLOCK(dev);
                                        goto out;
                                }
                        }
-                       dev->xmit_lock_owner = -1;
-                       spin_unlock_bh(&dev->xmit_lock);
+                       HARD_TX_UNLOCK(dev);
                        if (net_ratelimit())
                                printk(KERN_CRIT "Virtual device %s asks to "
                                       "queue packet!\n", dev->name);
-                       goto out_enetdown;
                } else {
                        /* Recursion is detected! It is possible,
                         * unfortunately */
@@ -1385,12 +1347,15 @@ int dev_queue_xmit(struct sk_buff *skb)
                                       "%s, fix it urgently!\n", dev->name);
                }
        }
-       spin_unlock_bh(&dev->queue_lock);
-out_enetdown:
+
        rc = -ENETDOWN;
+       local_bh_enable();
+
 out_kfree_skb:
        kfree_skb(skb);
+       return rc;
 out:
+       local_bh_enable();
        return rc;
 }
 
@@ -1413,66 +1378,6 @@ int mod_cong = 290;
 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
 
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-atomic_t netdev_dropping = ATOMIC_INIT(0);
-static unsigned long netdev_fc_mask = 1;
-unsigned long netdev_fc_xoff;
-spinlock_t netdev_fc_lock = SPIN_LOCK_UNLOCKED;
-
-static struct
-{
-       void (*stimul)(struct net_device *);
-       struct net_device *dev;
-} netdev_fc_slots[BITS_PER_LONG];
-
-int netdev_register_fc(struct net_device *dev,
-                      void (*stimul)(struct net_device *dev))
-{
-       int bit = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&netdev_fc_lock, flags);
-       if (netdev_fc_mask != ~0UL) {
-               bit = ffz(netdev_fc_mask);
-               netdev_fc_slots[bit].stimul = stimul;
-               netdev_fc_slots[bit].dev = dev;
-               set_bit(bit, &netdev_fc_mask);
-               clear_bit(bit, &netdev_fc_xoff);
-       }
-       spin_unlock_irqrestore(&netdev_fc_lock, flags);
-       return bit;
-}
-
-void netdev_unregister_fc(int bit)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&netdev_fc_lock, flags);
-       if (bit > 0) {
-               netdev_fc_slots[bit].stimul = NULL;
-               netdev_fc_slots[bit].dev = NULL;
-               clear_bit(bit, &netdev_fc_mask);
-               clear_bit(bit, &netdev_fc_xoff);
-       }
-       spin_unlock_irqrestore(&netdev_fc_lock, flags);
-}
-
-static void netdev_wakeup(void)
-{
-       unsigned long xoff;
-
-       spin_lock(&netdev_fc_lock);
-       xoff = netdev_fc_xoff;
-       netdev_fc_xoff = 0;
-       while (xoff) {
-               int i = ffz(~xoff);
-               xoff &= ~(1 << i);
-               netdev_fc_slots[i].stimul(netdev_fc_slots[i].dev);
-       }
-       spin_unlock(&netdev_fc_lock);
-}
-#endif
-
 static void get_sample_stats(int cpu)
 {
 #ifdef RAND_LIE
@@ -1548,13 +1453,10 @@ int netif_rx(struct sk_buff *skb)
        struct softnet_data *queue;
        unsigned long flags;
 
-#ifdef CONFIG_NETPOLL_RX
-       if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
-               kfree_skb(skb);
+       /* if netpoll wants it, pretend we never saw it */
+       if (netpoll_rx(skb))
                return NET_RX_DROP;
-       }
-#endif
-       
+
        if (!skb->stamp.tv_sec)
                net_timestamp(&skb->stamp);
 
@@ -1582,13 +1484,8 @@ enqueue:
                        return queue->cng_level;
                }
 
-               if (queue->throttle) {
+               if (queue->throttle)
                        queue->throttle = 0;
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-                       if (atomic_dec_and_test(&netdev_dropping))
-                               netdev_wakeup();
-#endif
-               }
 
                netif_rx_schedule(&queue->backlog_dev);
                goto enqueue;
@@ -1597,9 +1494,6 @@ enqueue:
        if (!queue->throttle) {
                queue->throttle = 1;
                __get_cpu_var(netdev_rx_stat).throttled++;
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-               atomic_inc(&netdev_dropping);
-#endif
        }
 
 drop:
@@ -1610,6 +1504,21 @@ drop:
        return NET_RX_DROP;
 }
 
+int netif_rx_ni(struct sk_buff *skb)
+{
+       int err;
+
+       preempt_disable();
+       err = netif_rx(skb);
+       if (local_softirq_pending())
+               do_softirq();
+       preempt_enable();
+
+       return err;
+}
+
+EXPORT_SYMBOL(netif_rx_ni);
+
 static __inline__ void skb_bond(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
@@ -1667,42 +1576,79 @@ static void net_tx_action(struct softirq_action *h)
 }
 
 static __inline__ int deliver_skb(struct sk_buff *skb,
-                                 struct packet_type *pt_prev, int last)
+                                 struct packet_type *pt_prev)
 {
        atomic_inc(&skb->users);
        return pt_prev->func(skb, skb->dev, pt_prev);
 }
 
-
 #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-int (*br_handle_frame_hook)(struct sk_buff *skb);
+int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
+struct net_bridge;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+                                               unsigned char *addr);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
 
-static __inline__ int handle_bridge(struct sk_buff *skb,
-                                    struct packet_type *pt_prev)
+static __inline__ int handle_bridge(struct sk_buff **pskb,
+                                   struct packet_type **pt_prev, int *ret)
 {
-       int ret = NET_RX_DROP;
-       if (pt_prev)
-               ret = deliver_skb(skb, pt_prev, 0);
+       struct net_bridge_port *port;
 
-       return ret;
-}
+       if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
+           (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
+               return 0;
 
+       if (*pt_prev) {
+               *ret = deliver_skb(*pskb, *pt_prev);
+               *pt_prev = NULL;
+       } 
+       
+       return br_handle_frame_hook(port, pskb);
+}
+#else
+#define handle_bridge(skb, pt_prev, ret)       (0)
 #endif
 
-static inline int __handle_bridge(struct sk_buff *skb,
-                       struct packet_type **pt_prev, int *ret)
+#ifdef CONFIG_NET_CLS_ACT
+/* TODO: Maybe we should just force sch_ingress to be compiled in
+ * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
+ * a compare and 2 stores extra right now if we dont have it on
+ * but have CONFIG_NET_CLS_ACT
+ * NOTE: This doesnt stop any functionality; if you dont have 
+ * the ingress scheduler, you just cant add policies on ingress.
+ *
+ */
+static int ing_filter(struct sk_buff *skb) 
 {
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-       if (skb->dev->br_port && skb->pkt_type != PACKET_LOOPBACK) {
-               *ret = handle_bridge(skb, *pt_prev);
-               if (br_handle_frame_hook(skb) == 0)
-                       return 1;
+       struct Qdisc *q;
+       struct net_device *dev = skb->dev;
+       int result = TC_ACT_OK;
+       
+       if (dev->qdisc_ingress) {
+               __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
+               if (MAX_RED_LOOP < ttl++) {
+                       printk("Redir loop detected Dropping packet (%s->%s)\n",
+                               skb->input_dev?skb->input_dev->name:"??",skb->dev->name);
+                       return TC_ACT_SHOT;
+               }
+
+               skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
+
+               skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+               if (NULL == skb->input_dev) {
+                       skb->input_dev = skb->dev;
+                       printk("ing_filter:  fixed  %s out %s\n",skb->input_dev->name,skb->dev->name);
+               }
+               spin_lock(&dev->ingress_lock);
+               if ((q = dev->qdisc_ingress) != NULL)
+                       result = q->enqueue(skb, q);
+               spin_unlock(&dev->ingress_lock);
 
-               *pt_prev = NULL;
        }
-#endif
-       return 0;
+
+       return result;
 }
+#endif
 
 int netif_receive_skb(struct sk_buff *skb)
 {
@@ -1710,12 +1656,9 @@ int netif_receive_skb(struct sk_buff *skb)
        int ret = NET_RX_DROP;
        unsigned short type;
 
-#ifdef CONFIG_NETPOLL_RX
-       if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
-               kfree_skb(skb);
+       /* if we've gotten here through NAPI, check netpoll */
+       if (skb->dev->poll && netpoll_rx(skb))
                return NET_RX_DROP;
-       }
-#endif
 
        if (!skb->stamp.tv_sec)
                net_timestamp(&skb->stamp);
@@ -1724,29 +1667,50 @@ int netif_receive_skb(struct sk_buff *skb)
 
        __get_cpu_var(netdev_rx_stat).total++;
 
-#ifdef CONFIG_NET_FASTROUTE
-       if (skb->pkt_type == PACKET_FASTROUTE) {
-               __get_cpu_var(netdev_rx_stat).fastroute_deferred_out++;
-               return dev_queue_xmit(skb);
-       }
-#endif
-
        skb->h.raw = skb->nh.raw = skb->data;
        skb->mac_len = skb->nh.raw - skb->mac.raw;
 
        pt_prev = NULL;
+
        rcu_read_lock();
+
+#ifdef CONFIG_NET_CLS_ACT
+       if (skb->tc_verd & TC_NCLS) {
+               skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
+               goto ncls;
+       }
+#endif
+
        list_for_each_entry_rcu(ptype, &ptype_all, list) {
                if (!ptype->dev || ptype->dev == skb->dev) {
                        if (pt_prev) 
-                               ret = deliver_skb(skb, pt_prev, 0);
+                               ret = deliver_skb(skb, pt_prev);
                        pt_prev = ptype;
                }
        }
 
+#ifdef CONFIG_NET_CLS_ACT
+       if (pt_prev) {
+               ret = deliver_skb(skb, pt_prev);
+               pt_prev = NULL; /* noone else should process this after*/
+       } else {
+               skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
+       }
+
+       ret = ing_filter(skb);
+
+       if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
+               kfree_skb(skb);
+               goto out;
+       }
+
+       skb->tc_verd = 0;
+ncls:
+#endif
+
        handle_diverter(skb);
 
-       if (__handle_bridge(skb, &pt_prev, &ret))
+       if (handle_bridge(&skb, &pt_prev, &ret))
                goto out;
 
        type = skb->protocol;
@@ -1754,7 +1718,7 @@ int netif_receive_skb(struct sk_buff *skb)
                if (ptype->type == type &&
                    (!ptype->dev || ptype->dev == skb->dev)) {
                        if (pt_prev) 
-                               ret = deliver_skb(skb, pt_prev, 0);
+                               ret = deliver_skb(skb, pt_prev);
                        pt_prev = ptype;
                }
        }
@@ -1781,6 +1745,7 @@ static int process_backlog(struct net_device *backlog_dev, int *budget)
        struct softnet_data *queue = &__get_cpu_var(softnet_data);
        unsigned long start_time = jiffies;
 
+       backlog_dev->weight = weight_p;
        for (;;) {
                struct sk_buff *skb;
                struct net_device *dev;
@@ -1802,16 +1767,6 @@ static int process_backlog(struct net_device *backlog_dev, int *budget)
                if (work >= quota || jiffies - start_time > 1)
                        break;
 
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-               if (queue->throttle &&
-                   queue->input_pkt_queue.qlen < no_cong_thresh ) {
-                       queue->throttle = 0;
-                       if (atomic_dec_and_test(&netdev_dropping)) {
-                               netdev_wakeup();
-                               break;
-                       }
-               }
-#endif
        }
 
        backlog_dev->quota -= work;
@@ -1826,13 +1781,8 @@ job_done:
        smp_mb__before_clear_bit();
        netif_poll_enable(backlog_dev);
 
-       if (queue->throttle) {
+       if (queue->throttle)
                queue->throttle = 0;
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-               if (atomic_dec_and_test(&netdev_dropping))
-                       netdev_wakeup();
-#endif
-       }
        local_irq_enable();
        return 0;
 }
@@ -1856,8 +1806,10 @@ static void net_rx_action(struct softirq_action *h)
 
                dev = list_entry(queue->poll_list.next,
                                 struct net_device, poll_list);
+               netpoll_poll_lock(dev);
 
                if (dev->quota <= 0 || dev->poll(dev, &budget)) {
+                       netpoll_poll_unlock(dev);
                        local_irq_disable();
                        list_del(&dev->poll_list);
                        list_add_tail(&dev->poll_list, &queue->poll_list);
@@ -1866,6 +1818,7 @@ static void net_rx_action(struct softirq_action *h)
                        else
                                dev->quota = dev->weight;
                } else {
+                       netpoll_poll_unlock(dev);
                        dev_put(dev);
                        local_irq_disable();
                }
@@ -1948,7 +1901,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;
@@ -1969,6 +1922,9 @@ static int dev_ifconf(char __user *arg)
 
        total = 0;
        for (dev = dev_base; dev; dev = dev->next) {
+               if (vx_flags(VXF_HIDE_NETIF, 0) &&
+                       !dev_in_nx_info(dev, current->nx_info))
+                       continue;
                for (i = 0; i < NPROTO; i++) {
                        if (gifconf_list[i]) {
                                int done;
@@ -2029,6 +1985,10 @@ void dev_seq_stop(struct seq_file *seq, void *v)
 
 static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
 {
+       struct nx_info *nxi = current->nx_info;
+
+       if (vx_flags(VXF_HIDE_NETIF, 0) && !dev_in_nx_info(dev, nxi))
+               return;
        if (dev->get_stats) {
                struct net_device_stats *stats = dev->get_stats(dev);
 
@@ -2242,13 +2202,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
        if ((dev->promiscuity += inc) == 0)
                dev->flags &= ~IFF_PROMISC;
        if (dev->flags ^ old_flags) {
-#ifdef CONFIG_NET_FASTROUTE
-               if (dev->flags & IFF_PROMISC) {
-                       netdev_fastroute_obstacles++;
-                       dev_clear_fastroute(dev);
-               } else
-                       netdev_fastroute_obstacles--;
-#endif
                dev_mc_upload(dev);
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
@@ -2382,6 +2335,21 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
        return err;
 }
 
+int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
+{
+       int err;
+
+       if (!dev->set_mac_address)
+               return -EOPNOTSUPP;
+       if (sa->sa_family != dev->type)
+               return -EINVAL;
+       if (!netif_device_present(dev))
+               return -ENODEV;
+       err = dev->set_mac_address(dev, sa);
+       if (!err)
+               notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+       return err;
+}
 
 /*
  *     Perform the SIOCxIFxxx calls.
@@ -2419,23 +2387,16 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
                        return dev_set_mtu(dev, ifr->ifr_mtu);
 
                case SIOCGIFHWADDR:
-                       memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,
-                              min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
+                       if (!dev->addr_len)
+                               memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data);
+                       else
+                               memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,
+                                      min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
                        ifr->ifr_hwaddr.sa_family = dev->type;
                        return 0;
 
                case SIOCSIFHWADDR:
-                       if (!dev->set_mac_address)
-                               return -EOPNOTSUPP;
-                       if (ifr->ifr_hwaddr.sa_family != dev->type)
-                               return -EINVAL;
-                       if (!netif_device_present(dev))
-                               return -ENODEV;
-                       err = dev->set_mac_address(dev, &ifr->ifr_hwaddr);
-                       if (!err)
-                               notifier_call_chain(&netdev_chain,
-                                                   NETDEV_CHANGEADDR, dev);
-                       return err;
+                       return dev_set_mac_address(dev, &ifr->ifr_hwaddr);
 
                case SIOCSIFHWBROADCAST:
                        if (ifr->ifr_hwaddr.sa_family != dev->type)
@@ -2515,6 +2476,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) {
@@ -2669,6 +2632,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);
@@ -2717,7 +2682,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
                                /* Follow me in net/core/wireless.c */
                                ret = wireless_process_ioctl(&ifr, cmd);
                                rtnl_unlock();
-                               if (!ret && IW_IS_GET(cmd) &&
+                               if (IW_IS_GET(cmd) &&
                                    copy_to_user(arg, &ifr,
                                                 sizeof(struct ifreq)))
                                        ret = -EFAULT;
@@ -2736,7 +2701,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
  *     number.  The caller must hold the rtnl semaphore or the
  *     dev_base_lock to be sure it remains unique.
  */
-int dev_new_index(void)
+static int dev_new_index(void)
 {
        static int ifindex;
        for (;;) {
@@ -2750,7 +2715,7 @@ int dev_new_index(void)
 static int dev_boot_phase = 1;
 
 /* Delayed registration/unregisteration */
-static spinlock_t net_todo_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(net_todo_list_lock);
 static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list);
 
 static inline void net_set_todo(struct net_device *dev)
@@ -2769,8 +2734,7 @@ static inline void net_set_todo(struct net_device *dev)
  *     chain. 0 is returned on success. A negative errno code is returned
  *     on a failure to set up the device, or if the name is a duplicate.
  *
- *     Callers must hold the rtnl semaphore.  See the comment at the
- *     end of Space.c for details about the locking.  You may want
+ *     Callers must hold the rtnl semaphore. You may want
  *     register_netdev() instead of this.
  *
  *     BUGS:
@@ -2793,8 +2757,8 @@ int register_netdevice(struct net_device *dev)
        spin_lock_init(&dev->queue_lock);
        spin_lock_init(&dev->xmit_lock);
        dev->xmit_lock_owner = -1;
-#ifdef CONFIG_NET_FASTROUTE
-       dev->fastpath_lock = RW_LOCK_UNLOCKED;
+#ifdef CONFIG_NET_CLS_ACT
+       spin_lock_init(&dev->ingress_lock);
 #endif
 
        ret = alloc_divert_blk(dev);
@@ -2843,6 +2807,14 @@ int register_netdevice(struct net_device *dev)
                dev->features &= ~NETIF_F_SG;
        }
 
+       /* TSO requires that SG is present as well. */
+       if ((dev->features & NETIF_F_TSO) &&
+           !(dev->features & NETIF_F_SG)) {
+               printk("%s: Dropping NETIF_F_TSO since no SG feature.\n",
+                      dev->name);
+               dev->features &= ~NETIF_F_TSO;
+       }
+
        /*
         *      nil rebuild_header routine,
         *      that should be never called and used as just bug trap.
@@ -2883,6 +2855,51 @@ out_err:
        goto out;
 }
 
+/**
+ *     register_netdev - register a network device
+ *     @dev: device to register
+ *
+ *     Take a completed network device structure and add it to the kernel
+ *     interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier
+ *     chain. 0 is returned on success. A negative errno code is returned
+ *     on a failure to set up the device, or if the name is a duplicate.
+ *
+ *     This is a wrapper around register_netdev that takes the rtnl semaphore
+ *     and expands the device name if you passed a format string to
+ *     alloc_netdev.
+ */
+int register_netdev(struct net_device *dev)
+{
+       int err;
+
+       rtnl_lock();
+
+       /*
+        * If the name is a format string the caller wants us to do a
+        * name allocation.
+        */
+       if (strchr(dev->name, '%')) {
+               err = dev_alloc_name(dev, dev->name);
+               if (err < 0)
+                       goto out;
+       }
+       
+       /*
+        * Back compatibility hook. Kill this one in 2.5
+        */
+       if (dev->name[0] == 0 || dev->name[0] == ' ') {
+               err = dev_alloc_name(dev, "eth%d");
+               if (err < 0)
+                       goto out;
+       }
+
+       err = register_netdevice(dev);
+out:
+       rtnl_unlock();
+       return err;
+}
+EXPORT_SYMBOL(register_netdev);
+
 /*
  * netdev_wait_allrefs - wait until all references are gone.
  *
@@ -2902,7 +2919,6 @@ static void netdev_wait_allrefs(struct net_device *dev)
        while (atomic_read(&dev->refcnt) != 0) {
                if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
                        rtnl_shlock();
-                       rtnl_exlock();
 
                        /* Rebroadcast unregister notification */
                        notifier_call_chain(&netdev_chain,
@@ -2919,14 +2935,12 @@ static void netdev_wait_allrefs(struct net_device *dev)
                                linkwatch_run_queue();
                        }
 
-                       rtnl_exunlock();
                        rtnl_shunlock();
 
                        rebroadcast_time = jiffies;
                }
 
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ / 4);
+               msleep(250);
 
                if (time_after(jiffies, warning_time + 10 * HZ)) {
                        printk(KERN_EMERG "unregister_netdevice: "
@@ -2963,16 +2977,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);
@@ -2985,7 +3003,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;
 
@@ -3016,9 +3037,50 @@ void netdev_run_todo(void)
                }
        }
 
+out:
        up(&net_todo_run_mutex);
 }
 
+/**
+ *     alloc_netdev - allocate network device
+ *     @sizeof_priv:   size of private data to allocate space for
+ *     @name:          device name format string
+ *     @setup:         callback to initialize device
+ *
+ *     Allocates a struct net_device with private data area for driver use
+ *     and performs basic initialization.
+ */
+struct net_device *alloc_netdev(int sizeof_priv, const char *name,
+               void (*setup)(struct net_device *))
+{
+       void *p;
+       struct net_device *dev;
+       int alloc_size;
+
+       /* ensure 32-byte alignment of both the device and private area */
+       alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+       alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
+
+       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);
+       dev->padded = (char *)dev - (char *)p;
+
+       if (sizeof_priv)
+               dev->priv = netdev_priv(dev);
+
+       setup(dev);
+       strcpy(dev->name, name);
+       return dev;
+}
+EXPORT_SYMBOL(alloc_netdev);
+
 /**
  *     free_netdev - free network device
  *     @dev: device
@@ -3029,6 +3091,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);
@@ -3040,13 +3103,16 @@ 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. */
 void synchronize_net(void) 
 {
        might_sleep();
-       synchronize_kernel();
+       synchronize_rcu();
 }
 
 /**
@@ -3057,8 +3123,7 @@ void synchronize_net(void)
  *     from the kernel tables. On success 0 is returned, on a failure
  *     a negative errno code is returned.
  *
- *     Callers must hold the rtnl semaphore.  See the comment at the
- *     end of Space.c for details about the locking.  You may want
+ *     Callers must hold the rtnl semaphore.  You may want
  *     unregister_netdev() instead of this.
  */
 
@@ -3105,10 +3170,6 @@ int unregister_netdevice(struct net_device *dev)
 
        synchronize_net();
 
-#ifdef CONFIG_NET_FASTROUTE
-       dev_clear_fastroute(dev);
-#endif
-
        /* Shutdown queueing discipline. */
        dev_shutdown(dev);
 
@@ -3134,10 +3195,33 @@ int unregister_netdevice(struct net_device *dev)
        /* Finish processing unregister after unlock */
        net_set_todo(dev);
 
+       synchronize_net();
+
        dev_put(dev);
        return 0;
 }
 
+/**
+ *     unregister_netdev - remove device from the kernel
+ *     @dev: device
+ *
+ *     This function shuts down a device interface and removes it
+ *     from the kernel tables. On success 0 is returned, on a failure
+ *     a negative errno code is returned.
+ *
+ *     This is just a wrapper for unregister_netdevice that takes
+ *     the rtnl semaphore.  In general you want to use this and not
+ *     unregister_netdevice.
+ */
+void unregister_netdev(struct net_device *dev)
+{
+       rtnl_lock();
+       unregister_netdevice(dev);
+       rtnl_unlock();
+}
+
+EXPORT_SYMBOL(unregister_netdev);
+
 #ifdef CONFIG_HOTPLUG_CPU
 static int dev_cpu_callback(struct notifier_block *nfb,
                            unsigned long action,
@@ -3202,6 +3286,8 @@ static int __init net_dev_init(void)
 
        BUG_ON(!dev_boot_phase);
 
+       net_random_init();
+
        if (dev_proc_init())
                goto out;
 
@@ -3258,28 +3344,25 @@ out:
 
 subsys_initcall(net_dev_init);
 
-EXPORT_SYMBOL(__dev_get);
-EXPORT_SYMBOL(__dev_get_by_flags);
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_name);
 EXPORT_SYMBOL(__dev_remove_pack);
 EXPORT_SYMBOL(__skb_linearize);
-EXPORT_SYMBOL(call_netdevice_notifiers);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_alloc_name);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_get_by_flags);
 EXPORT_SYMBOL(dev_get_by_index);
 EXPORT_SYMBOL(dev_get_by_name);
-EXPORT_SYMBOL(dev_getbyhwaddr);
 EXPORT_SYMBOL(dev_ioctl);
-EXPORT_SYMBOL(dev_new_index);
 EXPORT_SYMBOL(dev_open);
 EXPORT_SYMBOL(dev_queue_xmit);
-EXPORT_SYMBOL(dev_queue_xmit_nit);
 EXPORT_SYMBOL(dev_remove_pack);
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
+EXPORT_SYMBOL(dev_change_flags);
+EXPORT_SYMBOL(dev_set_mtu);
+EXPORT_SYMBOL(dev_set_mac_address);
 EXPORT_SYMBOL(free_netdev);
 EXPORT_SYMBOL(netdev_boot_setup_check);
 EXPORT_SYMBOL(netdev_set_master);
@@ -3293,26 +3376,18 @@ EXPORT_SYMBOL(skb_checksum_help);
 EXPORT_SYMBOL(synchronize_net);
 EXPORT_SYMBOL(unregister_netdevice);
 EXPORT_SYMBOL(unregister_netdevice_notifier);
+EXPORT_SYMBOL(net_enable_timestamp);
+EXPORT_SYMBOL(net_disable_timestamp);
+EXPORT_SYMBOL(dev_get_flags);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);
+EXPORT_SYMBOL(br_fdb_get_hook);
+EXPORT_SYMBOL(br_fdb_put_hook);
 #endif
-/* for 801q VLAN support */
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-EXPORT_SYMBOL(dev_change_flags);
-#endif
+
 #ifdef CONFIG_KMOD
 EXPORT_SYMBOL(dev_load);
 #endif
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-EXPORT_SYMBOL(netdev_dropping);
-EXPORT_SYMBOL(netdev_fc_xoff);
-EXPORT_SYMBOL(netdev_register_fc);
-EXPORT_SYMBOL(netdev_unregister_fc);
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-EXPORT_SYMBOL(netdev_fastroute);
-EXPORT_SYMBOL(netdev_fastroute_obstacles);
-#endif
 
 EXPORT_PER_CPU_SYMBOL(softnet_data);