Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Fri, 17 Jul 2009 03:21:24 +0000 (20:21 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 17 Jul 2009 03:21:24 +0000 (20:21 -0700)
Conflicts:
drivers/net/wireless/orinoco/main.c

17 files changed:
1  2 
MAINTAINERS
drivers/net/8139too.c
drivers/net/bonding/bond_main.c
drivers/net/cs89x0.c
drivers/net/e100.c
drivers/net/fec.c
drivers/net/gianfar.c
drivers/net/isa-skeleton.c
drivers/net/plip.c
drivers/net/smc91x.c
drivers/net/usb/kaweth.c
drivers/net/usb/pegasus.c
drivers/net/via-rhine.c
drivers/net/wireless/orinoco/main.c
net/ipv4/ip_gre.c
net/ipv6/ip6_output.c
net/ipv6/sit.c

diff --combined MAINTAINERS
@@@ -867,22 -867,12 +867,22 @@@ M:      alex@shark-linux.d
  W:    http://www.shark-linux.de/shark.html
  S:    Maintained
  
 +ARM/SAMSUNG ARM ARCHITECTURES
 +P:    Ben Dooks
 +M:    ben-linux@fluff.org
 +L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 +W:    http://www.fluff.org/ben/linux/
 +S:    Maintained
 +F:    arch/arm/plat-s3c/
 +F:    arch/arm/plat-s3c24xx/
 +
  ARM/S3C2410 ARM ARCHITECTURE
  P:    Ben Dooks
  M:    ben-linux@fluff.org
  L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
  W:    http://www.fluff.org/ben/linux/
  S:    Maintained
 +F:    arch/arm/mach-s3c2410/
  
  ARM/S3C2440 ARM ARCHITECTURE
  P:    Ben Dooks
@@@ -890,39 -880,6 +890,39 @@@ M:       ben-linux@fluff.or
  L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
  W:    http://www.fluff.org/ben/linux/
  S:    Maintained
 +F:    arch/arm/mach-s3c2440/
 +
 +ARM/S3C2442 ARM ARCHITECTURE
 +P:    Ben Dooks
 +M:    ben-linux@fluff.org
 +L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 +W:    http://www.fluff.org/ben/linux/
 +S:    Maintained
 +F:    arch/arm/mach-s3c2442/
 +
 +ARM/S3C2443 ARM ARCHITECTURE
 +P:    Ben Dooks
 +M:    ben-linux@fluff.org
 +L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 +W:    http://www.fluff.org/ben/linux/
 +S:    Maintained
 +F:    arch/arm/mach-s3c2443/
 +
 +ARM/S3C6400 ARM ARCHITECTURE
 +P:    Ben Dooks
 +M:    ben-linux@fluff.org
 +L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 +W:    http://www.fluff.org/ben/linux/
 +S:    Maintained
 +F:    arch/arm/mach-s3c6400/
 +
 +ARM/S3C6410 ARM ARCHITECTURE
 +P:    Ben Dooks
 +M:    ben-linux@fluff.org
 +L:    linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 +W:    http://www.fluff.org/ben/linux/
 +S:    Maintained
 +F:    arch/arm/mach-s3c6410/
  
  ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
  P:    Lennert Buytenhek
@@@ -2130,9 -2087,9 +2130,9 @@@ F:      drivers/edac/i5400_edac.
  
  EDAC-I82975X
  P:    Ranganathan Desikan
 -M:    rdesikan@jetzbroadband.com
 +M:    ravi@jetztechnologies.com
  P:    Arvind R.
 -M:    arvind@acarlab.com
 +M:    arvind@jetztechnologies.com
  L:    bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
  W:    bluesmoke.sourceforge.net
  S:    Maintained
@@@ -2851,9 -2808,7 +2851,9 @@@ S:      Maintaine
  
  IA64 (Itanium) PLATFORM
  P:    Tony Luck
 +P:    Fenghua Yu
  M:    tony.luck@intel.com
 +M:    fenghua.yu@intel.com
  L:    linux-ia64@vger.kernel.org
  W:    http://www.ia64-linux.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
@@@ -4089,6 -4044,7 +4089,7 @@@ L:      netfilter@vger.kernel.or
  L:    coreteam@netfilter.org
  W:    http://www.netfilter.org/
  W:    http://www.iptables.org/
+ T:    git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git
  S:    Supported
  F:    include/linux/netfilter*
  F:    include/linux/netfilter/
@@@ -5578,8 -5534,8 +5579,8 @@@ F:      drivers/staging
  
  STARFIRE/DURALAN NETWORK DRIVER
  P:    Ion Badulescu
 -M:    ionut@cs.columbia.edu
 -S:    Maintained
 +M:    ionut@badula.org
 +S:    Odd Fixes
  F:    drivers/net/starfire*
  
  STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
@@@ -5713,13 -5669,6 +5714,13 @@@ F:    drivers/misc/tifm
  F:    drivers/mmc/host/tifm_sd.c
  F:    include/linux/tifm.h
  
 +TI TWL4030 SERIES SOC CODEC DRIVER
 +P:    Peter Ujfalusi
 +M:    peter.ujfalusi@nokia.com
 +L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
 +S:    Maintained
 +F:    sound/soc/codecs/twl4030*
 +
  TIPC NETWORK LAYER
  P:    Per Liden
  M:    per.liden@ericsson.com
diff --combined drivers/net/8139too.c
@@@ -908,6 -908,7 +908,7 @@@ static const struct net_device_ops rtl8
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
        .ndo_get_stats          = rtl8139_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = rtl8139_set_mac_address,
        .ndo_start_xmit         = rtl8139_start_xmit,
@@@ -1706,7 -1707,7 +1707,7 @@@ static int rtl8139_start_xmit (struct s
        } else {
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
 -              return 0;
 +              return NETDEV_TX_OK;
        }
  
        spin_lock_irqsave(&tp->lock, flags);
                pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
                        dev->name, len, entry);
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  
@@@ -1459,8 -1459,16 +1459,16 @@@ int bond_enslave(struct net_device *bon
         * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
         */
        if (bond->slave_cnt == 0) {
-               if (slave_dev->type != ARPHRD_ETHER)
-                       bond_setup_by_slave(bond_dev, slave_dev);
+               if (bond_dev->type != slave_dev->type) {
+                       dev_close(bond_dev);
+                       pr_debug("%s: change device type from %d to %d\n",
+                               bond_dev->name, bond_dev->type, slave_dev->type);
+                       if (slave_dev->type != ARPHRD_ETHER)
+                               bond_setup_by_slave(bond_dev, slave_dev);
+                       else
+                               ether_setup(bond_dev);
+                       dev_open(bond_dev);
+               }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err(DRV_NAME ": %s ether type (%d) is different "
                        "from other slaves (%d), can not enslave it.\n",
@@@ -4277,7 -4285,7 +4285,7 @@@ out
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  
@@@ -4308,7 -4316,7 +4316,7 @@@ out
  
        read_unlock(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /*
@@@ -4354,7 -4362,7 +4362,7 @@@ out
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /*
@@@ -4414,7 -4422,7 +4422,7 @@@ out
  
        /* frame sent to all suitable interfaces */
        read_unlock(&bond->lock);
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /*------------------------- Device initialization ---------------------------*/
diff --combined drivers/net/cs89x0.c
@@@ -1367,7 -1367,7 +1367,7 @@@ net_open(struct net_device *dev
                        spin_lock_irqsave(&lp->lock, flags);
                        disable_dma(dev->dma);
                        clear_dma_ff(dev->dma);
 -                      set_dma_mode(dev->dma, 0x14); /* auto_init as well */
 +                      set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
                        set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
                        set_dma_count(dev->dma, lp->dmasize*1024);
                        enable_dma(dev->dma);
@@@ -1524,6 -1524,7 +1524,7 @@@ static void net_timeout(struct net_devi
  static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
  {
        struct net_local *lp = netdev_priv(dev);
+       unsigned long flags;
  
        if (net_debug > 3) {
                printk("%s: sent %d byte packet of type %x\n",
                    ask the chip to start transmitting before the
                    whole packet has been completely uploaded. */
  
-       spin_lock_irq(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        netif_stop_queue(dev);
  
        /* initiate a transmit sequence */
                 * we're waiting for TxOk, so return 1 and requeue this packet.
                 */
  
-               spin_unlock_irq(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                if (net_debug) printk("cs89x0: Tx buffer not free!\n");
                return NETDEV_TX_BUSY;
        }
        /* Write the contents of the packet */
        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-       spin_unlock_irq(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
         * to restart the netdevice layer
         */
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /* The typical workload of the driver:
diff --combined drivers/net/e100.c
@@@ -1720,7 -1720,7 +1720,7 @@@ static int e100_xmit_frame(struct sk_bu
        }
  
        netdev->trans_start = jiffies;
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static int e100_tx_clean(struct nic *nic)
@@@ -1897,6 -1897,9 +1897,9 @@@ static int e100_rx_indicate(struct nic 
  
                        if (ioread8(&nic->csr->scb.status) & rus_no_res)
                                nic->ru_running = RU_SUSPENDED;
+               pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
+                                              sizeof(struct rfd),
+                                              PCI_DMA_BIDIRECTIONAL);
                return -ENODATA;
        }
  
diff --combined drivers/net/fec.c
@@@ -366,7 -366,7 +366,7 @@@ fec_enet_start_xmit(struct sk_buff *skb
  
        spin_unlock_irqrestore(&fep->hw_lock, flags);
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static void
@@@ -1642,6 -1642,7 +1642,7 @@@ static const struct net_device_ops fec_
        .ndo_stop               = fec_enet_close,
        .ndo_start_xmit         = fec_enet_start_xmit,
        .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = fec_timeout,
        .ndo_set_mac_address    = fec_set_mac_address,
diff --combined drivers/net/gianfar.c
@@@ -156,6 -156,8 +156,8 @@@ static const struct net_device_ops gfar
        .ndo_tx_timeout = gfar_timeout,
        .ndo_do_ioctl = gfar_ioctl,
        .ndo_vlan_rx_register = gfar_vlan_rx_register,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
  #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gfar_netpoll,
  #endif
@@@ -304,6 -306,7 +306,6 @@@ static int gfar_probe(struct of_device 
        u32 tempval;
        struct net_device *dev = NULL;
        struct gfar_private *priv = NULL;
 -      DECLARE_MAC_BUF(mac);
        int err = 0;
        int len_devname;
  
@@@ -430,7 -430,8 +430,8 @@@ static int net_send_packet(struct sk_bu
         * hardware interrupt handler.  Queue flow control is
         * thus managed under this lock as well.
         */
-       spin_lock_irq(&np->lock);
+       unsigned long flags;
+       spin_lock_irqsave(&np->lock, flags);
  
        add_to_tx_ring(np, skb, length);
        dev->trans_start = jiffies;
         * is when the transmit statistics are updated.
         */
  
-       spin_unlock_irq(&np->lock);
+       spin_unlock_irqrestore(&np->lock, flags);
  #else
        /* This is the case for older hardware which takes
         * a single transmit buffer at a time, and it is
        dev_kfree_skb (skb);
  #endif
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  #if TX_RING
diff --combined drivers/net/plip.c
@@@ -270,6 -270,9 +270,9 @@@ static const struct net_device_ops plip
        .ndo_stop                = plip_close,
        .ndo_start_xmit          = plip_tx_packet,
        .ndo_do_ioctl            = plip_ioctl,
+       .ndo_change_mtu          = eth_change_mtu,
+       .ndo_set_mac_address     = eth_mac_addr,
+       .ndo_validate_addr       = eth_validate_addr,
  };
  
  /* Entry point of PLIP driver.
@@@ -987,7 -990,7 +990,7 @@@ plip_tx_packet(struct sk_buff *skb, str
        schedule_work(&nl->immediate);
        spin_unlock_irq(&nl->lock);
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static void
diff --combined drivers/net/smc91x.c
@@@ -655,7 -655,7 +655,7 @@@ static int smc_hard_start_xmit(struct s
                dev->stats.tx_errors++;
                dev->stats.tx_dropped++;
                dev_kfree_skb(skb);
 -              return 0;
 +              return NETDEV_TX_OK;
        }
  
        smc_special_lock(&lp->lock);
                smc_hardware_send_pkt((unsigned long)dev);
        }
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /*
@@@ -1774,6 -1774,7 +1774,7 @@@ static const struct net_device_ops smc_
        .ndo_start_xmit         = smc_hard_start_xmit,
        .ndo_tx_timeout         = smc_timeout,
        .ndo_set_multicast_list = smc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
  #ifdef CONFIG_NET_POLL_CONTROLLER
diff --combined drivers/net/usb/kaweth.c
@@@ -829,7 -829,7 +829,7 @@@ static int kaweth_start_xmit(struct sk_
                        kaweth->stats.tx_errors++;
                        netif_start_queue(net);
                        spin_unlock_irq(&kaweth->device_lock);
 -                      return 0;
 +                      return NETDEV_TX_OK;
                }
        }
  
@@@ -864,7 -864,7 +864,7 @@@ skip
  
        spin_unlock_irq(&kaweth->device_lock);
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /****************************************************************
@@@ -999,6 -999,9 +999,9 @@@ static const struct net_device_ops kawe
        .ndo_tx_timeout =               kaweth_tx_timeout,
        .ndo_set_multicast_list =       kaweth_set_rx_mode,
        .ndo_get_stats =                kaweth_netdev_stats,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
  };
  
  static int kaweth_probe(
@@@ -914,7 -914,7 +914,7 @@@ static int pegasus_start_xmit(struct sk
        }
        dev_kfree_skb(skb);
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
@@@ -1493,6 -1493,9 +1493,9 @@@ static const struct net_device_ops pega
        .ndo_set_multicast_list =       pegasus_set_multicast,
        .ndo_get_stats =                pegasus_netdev_stats,
        .ndo_tx_timeout =               pegasus_tx_timeout,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
  };
  
  static struct usb_driver pegasus_driver = {
diff --combined drivers/net/via-rhine.c
@@@ -621,6 -621,7 +621,7 @@@ static const struct net_device_ops rhin
        .ndo_start_xmit          = rhine_start_tx,
        .ndo_get_stats           = rhine_get_stats,
        .ndo_set_multicast_list  = rhine_set_rx_mode,
+       .ndo_change_mtu          = eth_change_mtu,
        .ndo_validate_addr       = eth_validate_addr,
        .ndo_set_mac_address     = eth_mac_addr,
        .ndo_do_ioctl            = netdev_ioctl,
@@@ -1225,7 -1226,7 +1226,7 @@@ static int rhine_start_tx(struct sk_buf
        entry = rp->cur_tx % TX_RING_SIZE;
  
        if (skb_padto(skb, ETH_ZLEN))
 -              return 0;
 +              return NETDEV_TX_OK;
  
        rp->tx_skbuff[entry] = skb;
  
                        dev_kfree_skb(skb);
                        rp->tx_skbuff[entry] = NULL;
                        dev->stats.tx_dropped++;
 -                      return 0;
 +                      return NETDEV_TX_OK;
                }
  
                /* Padding is not copied and so must be redone. */
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                       dev->name, rp->cur_tx-1, entry);
        }
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /* The interrupt handler does all of the Rx thread work and cleans up
@@@ -80,7 -80,6 +80,7 @@@
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
 +#include <linux/device.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/ethtool.h>
@@@ -89,7 -88,6 +89,7 @@@
  #include <linux/wireless.h>
  #include <linux/ieee80211.h>
  #include <net/iw_handler.h>
 +#include <net/cfg80211.h>
  
  #include "hermes_rid.h"
  #include "hermes_dld.h"
@@@ -98,7 -96,6 +98,7 @@@
  #include "mic.h"
  #include "fw.h"
  #include "wext.h"
 +#include "cfg.h"
  #include "main.h"
  
  #include "orinoco.h"
@@@ -145,11 -142,13 +145,11 @@@ static const u8 encaps_hdr[] = {0xaa, 0
  #define ORINOCO_MIN_MTU               256
  #define ORINOCO_MAX_MTU               (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
  
 -#define SYMBOL_MAX_VER_LEN    (14)
  #define MAX_IRQLOOPS_PER_IRQ  10
  #define MAX_IRQLOOPS_PER_JIFFY        (20000/HZ) /* Based on a guestimate of
                                            * how many events the
                                            * device could
                                            * legitimately generate */
 -#define TX_NICBUF_SIZE_BUG    1585            /* Bug in Symbol firmware */
  
  #define DUMMY_FID             0xFFFF
  
@@@ -206,21 -205,11 +206,21 @@@ struct orinoco_rx_data 
        struct list_head list;
  };
  
 +struct orinoco_scan_data {
 +      void *buf;
 +      size_t len;
 +      int type;
 +      struct list_head list;
 +};
 +
  /********************************************************************/
  /* Function prototypes                                              */
  /********************************************************************/
  
 -static void __orinoco_set_multicast_list(struct net_device *dev);
 +static int __orinoco_set_multicast_list(struct net_device *dev);
 +static int __orinoco_up(struct orinoco_private *priv);
 +static int __orinoco_down(struct orinoco_private *priv);
 +static int __orinoco_commit(struct orinoco_private *priv);
  
  /********************************************************************/
  /* Internal helper functions                                        */
  void set_port_type(struct orinoco_private *priv)
  {
        switch (priv->iw_mode) {
 -      case IW_MODE_INFRA:
 +      case NL80211_IFTYPE_STATION:
                priv->port_type = 1;
                priv->createibss = 0;
                break;
 -      case IW_MODE_ADHOC:
 +      case NL80211_IFTYPE_ADHOC:
                if (priv->prefer_port3) {
                        priv->port_type = 3;
                        priv->createibss = 0;
                        priv->createibss = 1;
                }
                break;
 -      case IW_MODE_MONITOR:
 +      case NL80211_IFTYPE_MONITOR:
                priv->port_type = 3;
                priv->createibss = 0;
                break;
  
  static int orinoco_open(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
        int err;
  
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
  
 -      err = __orinoco_up(dev);
 +      err = __orinoco_up(priv);
  
        if (!err)
                priv->open = 1;
  
  static int orinoco_stop(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
  
        /* We mustn't use orinoco_lock() here, because we need to be
  
        priv->open = 0;
  
 -      err = __orinoco_down(dev);
 +      err = __orinoco_down(priv);
  
        spin_unlock_irq(&priv->lock);
  
  
  static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
  
        return &priv->stats;
  }
  
  static void orinoco_set_multicast_list(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
  
        if (orinoco_lock(priv, &flags) != 0) {
  
  static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
  
        if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
                return -EINVAL;
  
  static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        hermes_t *hw = &priv->hw;
        int err = 0;
                return NETDEV_TX_BUSY;
        }
  
 -      if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
 +      if (!netif_carrier_ok(dev) ||
 +          (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
                /* Oops, the firmware hasn't established a connection,
                   silently drop the packet (this seems to be the
                   safest approach). */
  
  static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        u16 fid = hermes_read_regn(hw, ALLOCFID);
  
        if (fid != priv->txfid) {
  
  static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
  
        stats->tx_packets++;
  
  static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 fid = hermes_read_regn(hw, TXCOMPLFID);
        u16 status;
  
  static void orinoco_tx_timeout(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct hermes *hw = &priv->hw;
  
@@@ -662,7 -650,7 +662,7 @@@ static void orinoco_stat_gather(struct 
                                struct sk_buff *skb,
                                struct hermes_rx_descriptor *desc)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
  
        /* Using spy support with lots of Rx packets, like in an
         * infrastructure (AP), will really slow down everything, because
@@@ -699,7 -687,7 +699,7 @@@ static void orinoco_rx_monitor(struct n
        int err;
        int len;
        struct sk_buff *skb;
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        hermes_t *hw = &priv->hw;
  
  
  static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct iw_statistics *wstats = &priv->wstats;
        struct sk_buff *skb = NULL;
        }
  
        /* Handle frames in monitor mode */
 -      if (priv->iw_mode == IW_MODE_MONITOR) {
 +      if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                orinoco_rx_monitor(dev, rxfid, desc);
                goto out;
        }
@@@ -914,7 -902,7 +914,7 @@@ static void orinoco_rx(struct net_devic
                       struct hermes_rx_descriptor *desc,
                       struct sk_buff *skb)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 status, fc;
        int length;
  
  static void orinoco_rx_isr_tasklet(unsigned long data)
  {
 -      struct net_device *dev = (struct net_device *) data;
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = (struct orinoco_private *) data;
 +      struct net_device *dev = priv->ndev;
        struct orinoco_rx_data *rx_data, *temp;
        struct hermes_rx_descriptor *desc;
        struct sk_buff *skb;
@@@ -1272,81 -1260,9 +1272,81 @@@ static void orinoco_send_wevents(struc
        orinoco_unlock(priv, &flags);
  }
  
 +static void qbuf_scan(struct orinoco_private *priv, void *buf,
 +                    int len, int type)
 +{
 +      struct orinoco_scan_data *sd;
 +      unsigned long flags;
 +
 +      sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
 +      sd->buf = buf;
 +      sd->len = len;
 +      sd->type = type;
 +
 +      spin_lock_irqsave(&priv->scan_lock, flags);
 +      list_add_tail(&sd->list, &priv->scan_list);
 +      spin_unlock_irqrestore(&priv->scan_lock, flags);
 +
 +      schedule_work(&priv->process_scan);
 +}
 +
 +static void qabort_scan(struct orinoco_private *priv)
 +{
 +      struct orinoco_scan_data *sd;
 +      unsigned long flags;
 +
 +      sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
 +      sd->len = -1; /* Abort */
 +
 +      spin_lock_irqsave(&priv->scan_lock, flags);
 +      list_add_tail(&sd->list, &priv->scan_list);
 +      spin_unlock_irqrestore(&priv->scan_lock, flags);
 +
 +      schedule_work(&priv->process_scan);
 +}
 +
 +static void orinoco_process_scan_results(struct work_struct *work)
 +{
 +      struct orinoco_private *priv =
 +              container_of(work, struct orinoco_private, process_scan);
 +      struct orinoco_scan_data *sd, *temp;
 +      unsigned long flags;
 +      void *buf;
 +      int len;
 +      int type;
 +
 +      spin_lock_irqsave(&priv->scan_lock, flags);
 +      list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
 +              spin_unlock_irqrestore(&priv->scan_lock, flags);
 +
 +              buf = sd->buf;
 +              len = sd->len;
 +              type = sd->type;
 +
 +              list_del(&sd->list);
 +              kfree(sd);
 +
 +              if (len > 0) {
 +                      if (type == HERMES_INQ_CHANNELINFO)
 +                              orinoco_add_extscan_result(priv, buf, len);
 +                      else
 +                              orinoco_add_hostscan_results(priv, buf, len);
 +
 +                      kfree(buf);
 +              } else if (priv->scan_request) {
 +                      /* Either abort or complete the scan */
 +                      cfg80211_scan_done(priv->scan_request, (len < 0));
 +                      priv->scan_request = NULL;
 +              }
 +
 +              spin_lock_irqsave(&priv->scan_lock, flags);
 +      }
 +      spin_unlock_irqrestore(&priv->scan_lock, flags);
 +}
 +
  static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        u16 infofid;
        struct {
                __le16 len;
                u16 newstatus;
                int connected;
  
 -              if (priv->iw_mode == IW_MODE_MONITOR)
 +              if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
                        break;
  
                if (len != sizeof(linkstatus)) {
                 * the hostscan frame can be requested.  */
                if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
                    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
 -                  priv->has_hostscan && priv->scan_inprogress) {
 +                  priv->has_hostscan && priv->scan_request) {
                        hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
                        break;
                }
        }
        break;
        case HERMES_INQ_SCAN:
 -              if (!priv->scan_inprogress && priv->bssid_fixed &&
 +              if (!priv->scan_request && priv->bssid_fixed &&
                    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
                        schedule_work(&priv->join_work);
                        break;
        case HERMES_INQ_HOSTSCAN_SYMBOL: {
                /* Result of a scanning. Contains information about
                 * cells in the vicinity - Jean II */
 -              union iwreq_data        wrqu;
                unsigned char *buf;
  
 -              /* Scan is no longer in progress */
 -              priv->scan_inprogress = 0;
 -
                /* Sanity check */
                if (len > 4096) {
                        printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
                               dev->name, len);
 +                      qabort_scan(priv);
                        break;
                }
  
                /* Allocate buffer for results */
                buf = kmalloc(len, GFP_ATOMIC);
 -              if (buf == NULL)
 +              if (buf == NULL) {
                        /* No memory, so can't printk()... */
 +                      qabort_scan(priv);
                        break;
 +              }
  
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
                                       infofid, sizeof(info));
                if (err) {
                        kfree(buf);
 +                      qabort_scan(priv);
                        break;
                }
  
                }
  #endif        /* ORINOCO_DEBUG */
  
 -              if (orinoco_process_scan_results(priv, buf, len) == 0) {
 -                      /* Send an empty event to user space.
 -                       * We don't send the received data on the event because
 -                       * it would require us to do complex transcoding, and
 -                       * we want to minimise the work done in the irq handler
 -                       * Use a request to extract the data - Jean II */
 -                      wrqu.data.length = 0;
 -                      wrqu.data.flags = 0;
 -                      wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 -              }
 -              kfree(buf);
 +              qbuf_scan(priv, buf, len, type);
        }
        break;
        case HERMES_INQ_CHANNELINFO:
        {
                struct agere_ext_scan_info *bss;
  
 -              if (!priv->scan_inprogress) {
 +              if (!priv->scan_request) {
                        printk(KERN_DEBUG "%s: Got chaninfo without scan, "
                               "len=%d\n", dev->name, len);
                        break;
  
                /* An empty result indicates that the scan is complete */
                if (len == 0) {
 -                      union iwreq_data        wrqu;
 -
 -                      /* Scan is no longer in progress */
 -                      priv->scan_inprogress = 0;
 -
 -                      wrqu.data.length = 0;
 -                      wrqu.data.flags = 0;
 -                      wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 +                      qbuf_scan(priv, NULL, len, type);
                        break;
                }
  
                /* Sanity check */
 -              else if (len > sizeof(*bss)) {
 -                      printk(KERN_WARNING
 -                             "%s: Ext scan results too large (%d bytes). "
 -                             "Truncating results to %zd bytes.\n",
 -                             dev->name, len, sizeof(*bss));
 -                      len = sizeof(*bss);
 -              } else if (len < (offsetof(struct agere_ext_scan_info,
 +              else if (len < (offsetof(struct agere_ext_scan_info,
                                           data) + 2)) {
                        /* Drop this result now so we don't have to
                         * keep checking later */
                        break;
                }
  
 -              bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
 +              bss = kmalloc(len, GFP_ATOMIC);
                if (bss == NULL)
                        break;
  
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
                                       infofid, sizeof(info));
 -              if (err) {
 +              if (err)
                        kfree(bss);
 -                      break;
 -              }
 -
 -              orinoco_add_ext_scan_result(priv, bss);
 +              else
 +                      qbuf_scan(priv, bss, len, type);
  
 -              kfree(bss);
                break;
        }
        case HERMES_INQ_SEC_STAT_AGERE:
                /* We don't actually do anything about it */
                break;
        }
 +
 +      return;
  }
  
  static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
  /* Internal hardware control routines                               */
  /********************************************************************/
  
 -int __orinoco_up(struct net_device *dev)
 +static int __orinoco_up(struct orinoco_private *priv)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct net_device *dev = priv->ndev;
        struct hermes *hw = &priv->hw;
        int err;
  
        netif_carrier_off(dev); /* just to make sure */
  
 -      err = __orinoco_program_rids(dev);
 +      err = __orinoco_commit(priv);
        if (err) {
                printk(KERN_ERR "%s: Error %d configuring card\n",
                       dev->name, err);
  
        return 0;
  }
 -EXPORT_SYMBOL(__orinoco_up);
  
 -int __orinoco_down(struct net_device *dev)
 +static int __orinoco_down(struct orinoco_private *priv)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct net_device *dev = priv->ndev;
        struct hermes *hw = &priv->hw;
        int err;
  
  
        return 0;
  }
 -EXPORT_SYMBOL(__orinoco_down);
  
 -static int orinoco_allocate_fid(struct net_device *dev)
 +static int orinoco_reinit_firmware(struct orinoco_private *priv)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 -      struct hermes *hw = &priv->hw;
 -      int err;
 -
 -      err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
 -      if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
 -              /* Try workaround for old Symbol firmware bug */
 -              priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
 -              err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
 -
 -              printk(KERN_WARNING "%s: firmware ALLOC bug detected "
 -                     "(old Symbol firmware?). Work around %s\n",
 -                     dev->name, err ? "failed!" : "ok.");
 -      }
 -
 -      return err;
 -}
 -
 -int orinoco_reinit_firmware(struct net_device *dev)
 -{
 -      struct orinoco_private *priv = netdev_priv(dev);
        struct hermes *hw = &priv->hw;
        int err;
  
                        priv->do_fw_download = 0;
        }
        if (!err)
 -              err = orinoco_allocate_fid(dev);
 +              err = orinoco_hw_allocate_fid(priv);
  
        return err;
  }
 -EXPORT_SYMBOL(orinoco_reinit_firmware);
 -
 -int __orinoco_program_rids(struct net_device *dev)
 -{
 -      struct orinoco_private *priv = netdev_priv(dev);
 -      hermes_t *hw = &priv->hw;
 -      int err;
 -      struct hermes_idstring idbuf;
 -
 -      /* Set the MAC address */
 -      err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
 -                             HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting MAC address\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set up the link mode */
 -      err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
 -                                 priv->port_type);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting port type\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -      /* Set the channel/frequency */
 -      if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFOWNCHANNEL,
 -                                         priv->channel);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting channel %d\n",
 -                             dev->name, err, priv->channel);
 -                      return err;
 -              }
 -      }
 -
 -      if (priv->has_ibss) {
 -              u16 createibss;
 -
 -              if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
 -                      printk(KERN_WARNING "%s: This firmware requires an "
 -                             "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
 -                      /* With wvlan_cs, in this case, we would crash.
 -                       * hopefully, this driver will behave better...
 -                       * Jean II */
 -                      createibss = 0;
 -              } else {
 -                      createibss = priv->createibss;
 -              }
 -
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFCREATEIBSS,
 -                                         createibss);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -      }
 -
 -      /* Set the desired BSSID */
 -      err = __orinoco_hw_set_wap(priv);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting AP address\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -      /* Set the desired ESSID */
 -      idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
 -      memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
 -      /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
 -      err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
 -                      HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 -                      &idbuf);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -      err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
 -                      HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 -                      &idbuf);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set the station name */
 -      idbuf.len = cpu_to_le16(strlen(priv->nick));
 -      memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
 -      err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
 -                             HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
 -                             &idbuf);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting nickname\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set AP density */
 -      if (priv->has_sensitivity) {
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFSYSTEMSCALE,
 -                                         priv->ap_density);
 -              if (err) {
 -                      printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
 -                             "Disabling sensitivity control\n",
 -                             dev->name, err);
 -
 -                      priv->has_sensitivity = 0;
 -              }
 -      }
 -
 -      /* Set RTS threshold */
 -      err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
 -                                 priv->rts_thresh);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set fragmentation threshold or MWO robustness */
 -      if (priv->has_mwo)
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFMWOROBUST_AGERE,
 -                                         priv->mwo_robust);
 -      else
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 -                                         priv->frag_thresh);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting fragmentation\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set bitrate */
 -      err = __orinoco_hw_set_bitrate(priv);
 -      if (err) {
 -              printk(KERN_ERR "%s: Error %d setting bitrate\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      /* Set power management */
 -      if (priv->has_pm) {
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFPMENABLED,
 -                                         priv->pm_on);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting up PM\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFMULTICASTRECEIVE,
 -                                         priv->pm_mcast);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting up PM\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFMAXSLEEPDURATION,
 -                                         priv->pm_period);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting up PM\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFPMHOLDOVERDURATION,
 -                                         priv->pm_timeout);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting up PM\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -      }
 -
 -      /* Set preamble - only for Symbol so far... */
 -      if (priv->has_preamble) {
 -              err = hermes_write_wordrec(hw, USER_BAP,
 -                                         HERMES_RID_CNFPREAMBLE_SYMBOL,
 -                                         priv->preamble);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d setting preamble\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -      }
 -
 -      /* Set up encryption */
 -      if (priv->has_wep || priv->has_wpa) {
 -              err = __orinoco_hw_setup_enc(priv);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error %d activating encryption\n",
 -                             dev->name, err);
 -                      return err;
 -              }
 -      }
 -
 -      if (priv->iw_mode == IW_MODE_MONITOR) {
 -              /* Enable monitor mode */
 -              dev->type = ARPHRD_IEEE80211;
 -              err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
 -                                          HERMES_TEST_MONITOR, 0, NULL);
 -      } else {
 -              /* Disable monitor mode */
 -              dev->type = ARPHRD_ETHER;
 -              err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
 -                                          HERMES_TEST_STOP, 0, NULL);
 -      }
 -      if (err)
 -              return err;
 -
 -      /* Set promiscuity / multicast*/
 -      priv->promiscuous = 0;
 -      priv->mc_count = 0;
 -
 -      /* FIXME: what about netif_tx_lock */
 -      __orinoco_set_multicast_list(dev);
 -
 -      return 0;
 -}
  
 -/* FIXME: return int? */
 -static void
 +static int
  __orinoco_set_multicast_list(struct net_device *dev)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
        int promisc, mc_count;
  
  
        err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
                                              promisc);
 +
 +      return err;
  }
  
  /* This must be called from user context, without locks held - use
@@@ -1704,11 -1896,9 +1704,11 @@@ void orinoco_reset(struct work_struct *
  
        orinoco_unlock(priv, &flags);
  
 -      /* Scanning support: Cleanup of driver struct */
 -      orinoco_clear_scan_results(priv, 0);
 -      priv->scan_inprogress = 0;
 +      /* Scanning support: Notify scan cancellation */
 +      if (priv->scan_request) {
 +              cfg80211_scan_done(priv->scan_request, 1);
 +              priv->scan_request = NULL;
 +      }
  
        if (priv->hard_reset) {
                err = (*priv->hard_reset)(priv);
                }
        }
  
 -      err = orinoco_reinit_firmware(dev);
 +      err = orinoco_reinit_firmware(priv);
        if (err) {
                printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
                       dev->name, err);
        /* priv->open or priv->hw_unavailable might have changed while
         * we dropped the lock */
        if (priv->open && (!priv->hw_unavailable)) {
 -              err = __orinoco_up(dev);
 +              err = __orinoco_up(priv);
                if (err) {
                        printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
                               dev->name, err);
        printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
  }
  
 +static int __orinoco_commit(struct orinoco_private *priv)
 +{
 +      struct net_device *dev = priv->ndev;
 +      int err = 0;
 +
 +      err = orinoco_hw_program_rids(priv);
 +
 +      /* FIXME: what about netif_tx_lock */
 +      (void) __orinoco_set_multicast_list(dev);
 +
 +      return err;
 +}
 +
 +/* Ensures configuration changes are applied. May result in a reset.
 + * The caller should hold priv->lock
 + */
 +int orinoco_commit(struct orinoco_private *priv)
 +{
 +      struct net_device *dev = priv->ndev;
 +      hermes_t *hw = &priv->hw;
 +      int err;
 +
 +      if (priv->broken_disableport) {
 +              schedule_work(&priv->reset_work);
 +              return 0;
 +      }
 +
 +      err = hermes_disable_port(hw, 0);
 +      if (err) {
 +              printk(KERN_WARNING "%s: Unable to disable port "
 +                     "while reconfiguring card\n", dev->name);
 +              priv->broken_disableport = 1;
 +              goto out;
 +      }
 +
 +      err = __orinoco_commit(priv);
 +      if (err) {
 +              printk(KERN_WARNING "%s: Unable to reconfigure card\n",
 +                     dev->name);
 +              goto out;
 +      }
 +
 +      err = hermes_enable_port(hw, 0);
 +      if (err) {
 +              printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
 +                     dev->name);
 +              goto out;
 +      }
 +
 + out:
 +      if (err) {
 +              printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
 +              schedule_work(&priv->reset_work);
 +              err = 0;
 +      }
 +      return err;
 +}
 +
  /********************************************************************/
  /* Interrupt handler                                                */
  /********************************************************************/
@@@ -1828,8 -1960,8 +1828,8 @@@ static void __orinoco_ev_wterr(struct n
  
  irqreturn_t orinoco_interrupt(int irq, void *dev_id)
  {
 -      struct net_device *dev = dev_id;
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = dev_id;
 +      struct net_device *dev = priv->ndev;
        hermes_t *hw = &priv->hw;
        int count = MAX_IRQLOOPS_PER_IRQ;
        u16 evstat, events;
@@@ -1964,12 -2096,227 +1964,12 @@@ static void orinoco_unregister_pm_notif
  /* Initialization                                                   */
  /********************************************************************/
  
 -struct comp_id {
 -      u16 id, variant, major, minor;
 -} __attribute__ ((packed));
 -
 -static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
 -{
 -      if (nic_id->id < 0x8000)
 -              return FIRMWARE_TYPE_AGERE;
 -      else if (nic_id->id == 0x8000 && nic_id->major == 0)
 -              return FIRMWARE_TYPE_SYMBOL;
 -      else
 -              return FIRMWARE_TYPE_INTERSIL;
 -}
 -
 -/* Set priv->firmware type, determine firmware properties */
 -static int determine_firmware(struct net_device *dev)
 -{
 -      struct orinoco_private *priv = netdev_priv(dev);
 -      hermes_t *hw = &priv->hw;
 -      int err;
 -      struct comp_id nic_id, sta_id;
 -      unsigned int firmver;
 -      char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
 -
 -      /* Get the hardware version */
 -      err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
 -      if (err) {
 -              printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      le16_to_cpus(&nic_id.id);
 -      le16_to_cpus(&nic_id.variant);
 -      le16_to_cpus(&nic_id.major);
 -      le16_to_cpus(&nic_id.minor);
 -      printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
 -             dev->name, nic_id.id, nic_id.variant,
 -             nic_id.major, nic_id.minor);
 -
 -      priv->firmware_type = determine_firmware_type(&nic_id);
 -
 -      /* Get the firmware version */
 -      err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
 -      if (err) {
 -              printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
 -                     dev->name, err);
 -              return err;
 -      }
 -
 -      le16_to_cpus(&sta_id.id);
 -      le16_to_cpus(&sta_id.variant);
 -      le16_to_cpus(&sta_id.major);
 -      le16_to_cpus(&sta_id.minor);
 -      printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
 -             dev->name, sta_id.id, sta_id.variant,
 -             sta_id.major, sta_id.minor);
 -
 -      switch (sta_id.id) {
 -      case 0x15:
 -              printk(KERN_ERR "%s: Primary firmware is active\n",
 -                     dev->name);
 -              return -ENODEV;
 -      case 0x14b:
 -              printk(KERN_ERR "%s: Tertiary firmware is active\n",
 -                     dev->name);
 -              return -ENODEV;
 -      case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
 -      case 0x21:      /* Symbol Spectrum24 Trilogy */
 -              break;
 -      default:
 -              printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
 -                     dev->name);
 -              break;
 -      }
 -
 -      /* Default capabilities */
 -      priv->has_sensitivity = 1;
 -      priv->has_mwo = 0;
 -      priv->has_preamble = 0;
 -      priv->has_port3 = 1;
 -      priv->has_ibss = 1;
 -      priv->has_wep = 0;
 -      priv->has_big_wep = 0;
 -      priv->has_alt_txcntl = 0;
 -      priv->has_ext_scan = 0;
 -      priv->has_wpa = 0;
 -      priv->do_fw_download = 0;
 -
 -      /* Determine capabilities from the firmware version */
 -      switch (priv->firmware_type) {
 -      case FIRMWARE_TYPE_AGERE:
 -              /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
 -                 ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
 -              snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
 -                       "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
 -
 -              firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
 -
 -              priv->has_ibss = (firmver >= 0x60006);
 -              priv->has_wep = (firmver >= 0x40020);
 -              priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
 -                                        Gold cards from the others? */
 -              priv->has_mwo = (firmver >= 0x60000);
 -              priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 -              priv->ibss_port = 1;
 -              priv->has_hostscan = (firmver >= 0x8000a);
 -              priv->do_fw_download = 1;
 -              priv->broken_monitor = (firmver >= 0x80000);
 -              priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
 -              priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
 -              priv->has_wpa = (firmver >= 0x9002a);
 -              /* Tested with Agere firmware :
 -               *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
 -               * Tested CableTron firmware : 4.32 => Anton */
 -              break;
 -      case FIRMWARE_TYPE_SYMBOL:
 -              /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
 -              /* Intel MAC : 00:02:B3:* */
 -              /* 3Com MAC : 00:50:DA:* */
 -              memset(tmp, 0, sizeof(tmp));
 -              /* Get the Symbol firmware version */
 -              err = hermes_read_ltv(hw, USER_BAP,
 -                                    HERMES_RID_SECONDARYVERSION_SYMBOL,
 -                                    SYMBOL_MAX_VER_LEN, NULL, &tmp);
 -              if (err) {
 -                      printk(KERN_WARNING
 -                             "%s: Error %d reading Symbol firmware info. "
 -                             "Wildly guessing capabilities...\n",
 -                             dev->name, err);
 -                      firmver = 0;
 -                      tmp[0] = '\0';
 -              } else {
 -                      /* The firmware revision is a string, the format is
 -                       * something like : "V2.20-01".
 -                       * Quick and dirty parsing... - Jean II
 -                       */
 -                      firmver = ((tmp[1] - '0') << 16)
 -                              | ((tmp[3] - '0') << 12)
 -                              | ((tmp[4] - '0') << 8)
 -                              | ((tmp[6] - '0') << 4)
 -                              | (tmp[7] - '0');
 -
 -                      tmp[SYMBOL_MAX_VER_LEN] = '\0';
 -              }
 -
 -              snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
 -                       "Symbol %s", tmp);
 -
 -              priv->has_ibss = (firmver >= 0x20000);
 -              priv->has_wep = (firmver >= 0x15012);
 -              priv->has_big_wep = (firmver >= 0x20000);
 -              priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
 -                             (firmver >= 0x29000 && firmver < 0x30000) ||
 -                             firmver >= 0x31000;
 -              priv->has_preamble = (firmver >= 0x20000);
 -              priv->ibss_port = 4;
 -
 -              /* Symbol firmware is found on various cards, but
 -               * there has been no attempt to check firmware
 -               * download on non-spectrum_cs based cards.
 -               *
 -               * Given that the Agere firmware download works
 -               * differently, we should avoid doing a firmware
 -               * download with the Symbol algorithm on non-spectrum
 -               * cards.
 -               *
 -               * For now we can identify a spectrum_cs based card
 -               * because it has a firmware reset function.
 -               */
 -              priv->do_fw_download = (priv->stop_fw != NULL);
 -
 -              priv->broken_disableport = (firmver == 0x25013) ||
 -                              (firmver >= 0x30000 && firmver <= 0x31000);
 -              priv->has_hostscan = (firmver >= 0x31001) ||
 -                                   (firmver >= 0x29057 && firmver < 0x30000);
 -              /* Tested with Intel firmware : 0x20015 => Jean II */
 -              /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 -              break;
 -      case FIRMWARE_TYPE_INTERSIL:
 -              /* D-Link, Linksys, Adtron, ZoomAir, and many others...
 -               * Samsung, Compaq 100/200 and Proxim are slightly
 -               * different and less well tested */
 -              /* D-Link MAC : 00:40:05:* */
 -              /* Addtron MAC : 00:90:D1:* */
 -              snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
 -                       "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
 -                       sta_id.variant);
 -
 -              firmver = ((unsigned long)sta_id.major << 16) |
 -                      ((unsigned long)sta_id.minor << 8) | sta_id.variant;
 -
 -              priv->has_ibss = (firmver >= 0x000700); /* FIXME */
 -              priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
 -              priv->has_pm = (firmver >= 0x000700);
 -              priv->has_hostscan = (firmver >= 0x010301);
 -
 -              if (firmver >= 0x000800)
 -                      priv->ibss_port = 0;
 -              else {
 -                      printk(KERN_NOTICE "%s: Intersil firmware earlier "
 -                             "than v0.8.x - several features not supported\n",
 -                             dev->name);
 -                      priv->ibss_port = 1;
 -              }
 -              break;
 -      }
 -      printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
 -             priv->fw_name);
 -
 -      return 0;
 -}
 -
 -static int orinoco_init(struct net_device *dev)
 +int orinoco_init(struct orinoco_private *priv)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct device *dev = priv->dev;
 +      struct wiphy *wiphy = priv_to_wiphy(priv);
        hermes_t *hw = &priv->hw;
        int err = 0;
 -      struct hermes_idstring nickbuf;
 -      u16 reclen;
 -      int len;
  
        /* No need to lock, the hw_unavailable flag is already set in
         * alloc_orinocodev() */
        /* Initialize the firmware */
        err = hermes_init(hw);
        if (err != 0) {
 -              printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
 -                     dev->name, err);
 +              dev_err(dev, "Failed to initialize firmware (err = %d)\n",
 +                      err);
                goto out;
        }
  
 -      err = determine_firmware(dev);
 +      err = determine_fw_capabilities(priv);
        if (err != 0) {
 -              printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
 -                     dev->name);
 +              dev_err(dev, "Incompatible firmware, aborting\n");
                goto out;
        }
  
                        priv->do_fw_download = 0;
  
                /* Check firmware version again */
 -              err = determine_firmware(dev);
 +              err = determine_fw_capabilities(priv);
                if (err != 0) {
 -                      printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
 -                             dev->name);
 +                      dev_err(dev, "Incompatible firmware, aborting\n");
                        goto out;
                }
        }
  
        if (priv->has_port3)
 -              printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
 -                     dev->name);
 +              dev_info(dev, "Ad-hoc demo mode supported\n");
        if (priv->has_ibss)
 -              printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
 -                     dev->name);
 -      if (priv->has_wep) {
 -              printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
 -                     priv->has_big_wep ? "104" : "40");
 -      }
 +              dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
 +      if (priv->has_wep)
 +              dev_info(dev, "WEP supported, %s-bit key\n",
 +                       priv->has_big_wep ? "104" : "40");
        if (priv->has_wpa) {
 -              printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
 +              dev_info(dev, "WPA-PSK supported\n");
                if (orinoco_mic_init(priv)) {
 -                      printk(KERN_ERR "%s: Failed to setup MIC crypto "
 -                             "algorithm. Disabling WPA support\n", dev->name);
 +                      dev_err(dev, "Failed to setup MIC crypto algorithm. "
 +                              "Disabling WPA support\n");
                        priv->has_wpa = 0;
                }
        }
  
 -      /* Now we have the firmware capabilities, allocate appropiate
 -       * sized scan buffers */
 -      if (orinoco_bss_data_allocate(priv))
 -              goto out;
 -      orinoco_bss_data_init(priv);
 -
 -      /* Get the MAC address */
 -      err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
 -                            ETH_ALEN, NULL, dev->dev_addr);
 -      if (err) {
 -              printk(KERN_WARNING "%s: failed to read MAC address!\n",
 -                     dev->name);
 -              goto out;
 -      }
 -
 -      printk(KERN_DEBUG "%s: MAC address %pM\n",
 -             dev->name, dev->dev_addr);
 -
 -      /* Get the station name */
 -      err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
 -                            sizeof(nickbuf), &reclen, &nickbuf);
 -      if (err) {
 -              printk(KERN_ERR "%s: failed to read station name\n",
 -                     dev->name);
 -              goto out;
 -      }
 -      if (nickbuf.len)
 -              len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
 -      else
 -              len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
 -      memcpy(priv->nick, &nickbuf.val, len);
 -      priv->nick[len] = '\0';
 -
 -      printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
 -
 -      err = orinoco_allocate_fid(dev);
 -      if (err) {
 -              printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
 -                     dev->name);
 -              goto out;
 -      }
 -
 -      /* Get allowed channels */
 -      err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
 -                                &priv->channel_mask);
 -      if (err) {
 -              printk(KERN_ERR "%s: failed to read channel list!\n",
 -                     dev->name);
 -              goto out;
 -      }
 -
 -      /* Get initial AP density */
 -      err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
 -                                &priv->ap_density);
 -      if (err || priv->ap_density < 1 || priv->ap_density > 3)
 -              priv->has_sensitivity = 0;
 -
 -      /* Get initial RTS threshold */
 -      err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
 -                                &priv->rts_thresh);
 -      if (err) {
 -              printk(KERN_ERR "%s: failed to read RTS threshold!\n",
 -                     dev->name);
 +      err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
 +      if (err)
                goto out;
 -      }
  
 -      /* Get initial fragmentation settings */
 -      if (priv->has_mwo)
 -              err = hermes_read_wordrec(hw, USER_BAP,
 -                                        HERMES_RID_CNFMWOROBUST_AGERE,
 -                                        &priv->mwo_robust);
 -      else
 -              err = hermes_read_wordrec(hw, USER_BAP,
 -                                        HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 -                                        &priv->frag_thresh);
 +      err = orinoco_hw_allocate_fid(priv);
        if (err) {
 -              printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
 -                     dev->name);
 +              dev_err(dev, "Failed to allocate NIC buffer!\n");
                goto out;
        }
  
 -      /* Power management setup */
 -      if (priv->has_pm) {
 -              priv->pm_on = 0;
 -              priv->pm_mcast = 1;
 -              err = hermes_read_wordrec(hw, USER_BAP,
 -                                        HERMES_RID_CNFMAXSLEEPDURATION,
 -                                        &priv->pm_period);
 -              if (err) {
 -                      printk(KERN_ERR "%s: failed to read power management period!\n",
 -                             dev->name);
 -                      goto out;
 -              }
 -              err = hermes_read_wordrec(hw, USER_BAP,
 -                                        HERMES_RID_CNFPMHOLDOVERDURATION,
 -                                        &priv->pm_timeout);
 -              if (err) {
 -                      printk(KERN_ERR "%s: failed to read power management timeout!\n",
 -                             dev->name);
 -                      goto out;
 -              }
 -      }
 -
 -      /* Preamble setup */
 -      if (priv->has_preamble) {
 -              err = hermes_read_wordrec(hw, USER_BAP,
 -                                        HERMES_RID_CNFPREAMBLE_SYMBOL,
 -                                        &priv->preamble);
 -              if (err)
 -                      goto out;
 -      }
 -
        /* Set up the default configuration */
 -      priv->iw_mode = IW_MODE_INFRA;
 +      priv->iw_mode = NL80211_IFTYPE_STATION;
        /* By default use IEEE/IBSS ad-hoc mode if we have it */
        priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
        set_port_type(priv);
        priv->wpa_ie_len = 0;
        priv->wpa_ie = NULL;
  
 +      if (orinoco_wiphy_register(wiphy)) {
 +              err = -ENODEV;
 +              goto out;
 +      }
 +
        /* Make the hardware available, as long as it hasn't been
         * removed elsewhere (e.g. by PCMCIA hot unplug) */
        spin_lock_irq(&priv->lock);
        priv->hw_unavailable--;
        spin_unlock_irq(&priv->lock);
  
 -      printk(KERN_DEBUG "%s: ready\n", dev->name);
 +      dev_dbg(dev, "Ready\n");
  
   out:
        return err;
  }
 +EXPORT_SYMBOL(orinoco_init);
  
  static const struct net_device_ops orinoco_netdev_ops = {
 -      .ndo_init               = orinoco_init,
        .ndo_open               = orinoco_open,
        .ndo_stop               = orinoco_stop,
        .ndo_start_xmit         = orinoco_xmit,
        .ndo_set_multicast_list = orinoco_set_multicast_list,
        .ndo_change_mtu         = orinoco_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = orinoco_tx_timeout,
        .ndo_get_stats          = orinoco_get_stats,
  };
  
 -struct net_device
 +/* Allocate private data.
 + *
 + * This driver has a number of structures associated with it
 + *  netdev - Net device structure for each network interface
 + *  wiphy - structure associated with wireless phy
 + *  wireless_dev (wdev) - structure for each wireless interface
 + *  hw - structure for hermes chip info
 + *  card - card specific structure for use by the card driver
 + *         (airport, orinoco_cs)
 + *  priv - orinoco private data
 + *  device - generic linux device structure
 + *
 + *  +---------+    +---------+
 + *  |  wiphy  |    | netdev  |
 + *  | +-------+    | +-------+
 + *  | | priv  |    | | wdev  |
 + *  | | +-----+    +-+-------+
 + *  | | | hw  |
 + *  | +-+-----+
 + *  | | card  |
 + *  +-+-------+
 + *
 + * priv has a link to netdev and device
 + * wdev has a link to wiphy
 + */
 +struct orinoco_private
  *alloc_orinocodev(int sizeof_card,
                  struct device *device,
                  int (*hard_reset)(struct orinoco_private *),
                  int (*stop_fw)(struct orinoco_private *, int))
  {
 -      struct net_device *dev;
        struct orinoco_private *priv;
 +      struct wiphy *wiphy;
  
 -      dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
 -      if (!dev)
 +      /* allocate wiphy
 +       * NOTE: We only support a single virtual interface
 +       *       but this may change when monitor mode is added
 +       */
 +      wiphy = wiphy_new(&orinoco_cfg_ops,
 +                        sizeof(struct orinoco_private) + sizeof_card);
 +      if (!wiphy)
                return NULL;
 -      priv = netdev_priv(dev);
 -      priv->ndev = dev;
 +
 +      priv = wiphy_priv(wiphy);
 +      priv->dev = device;
 +
        if (sizeof_card)
                priv->card = (void *)((unsigned long)priv
                                      + sizeof(struct orinoco_private));
        else
                priv->card = NULL;
 -      priv->dev = device;
  
 -      /* Setup / override net_device fields */
 -      dev->netdev_ops = &orinoco_netdev_ops;
 -      dev->watchdog_timeo = HZ; /* 1 second timeout */
 -      dev->ethtool_ops = &orinoco_ethtool_ops;
 -      dev->wireless_handlers = &orinoco_handler_def;
 +      orinoco_wiphy_init(wiphy);
 +
  #ifdef WIRELESS_SPY
        priv->wireless_data.spy_data = &priv->spy_data;
 -      dev->wireless_data = &priv->wireless_data;
  #endif
  
 -      /* Reserve space in skb for the SNAP header */
 -      dev->hard_header_len += ENCAPS_OVERHEAD;
 -
        /* Set up default callbacks */
        priv->hard_reset = hard_reset;
        priv->stop_fw = stop_fw;
  
        INIT_LIST_HEAD(&priv->rx_list);
        tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
 -                   (unsigned long) dev);
 +                   (unsigned long) priv);
 +
 +      spin_lock_init(&priv->scan_lock);
 +      INIT_LIST_HEAD(&priv->scan_list);
 +      INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
  
 -      netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
  
  #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
        /* Register PM notifiers */
        orinoco_register_pm_notifier(priv);
  
 -      return dev;
 +      return priv;
  }
  EXPORT_SYMBOL(alloc_orinocodev);
  
 -void free_orinocodev(struct net_device *dev)
 +/* We can only support a single interface. We provide a separate
 + * function to set it up to distinguish between hardware
 + * initialisation and interface setup.
 + *
 + * The base_addr and irq parameters are passed on to netdev for use
 + * with SIOCGIFMAP.
 + */
 +int orinoco_if_add(struct orinoco_private *priv,
 +                 unsigned long base_addr,
 +                 unsigned int irq)
 +{
 +      struct wiphy *wiphy = priv_to_wiphy(priv);
 +      struct wireless_dev *wdev;
 +      struct net_device *dev;
 +      int ret;
 +
 +      dev = alloc_etherdev(sizeof(struct wireless_dev));
 +
 +      if (!dev)
 +              return -ENOMEM;
 +
 +      /* Initialise wireless_dev */
 +      wdev = netdev_priv(dev);
 +      wdev->wiphy = wiphy;
 +      wdev->iftype = NL80211_IFTYPE_STATION;
 +
 +      /* Setup / override net_device fields */
 +      dev->ieee80211_ptr = wdev;
 +      dev->netdev_ops = &orinoco_netdev_ops;
 +      dev->watchdog_timeo = HZ; /* 1 second timeout */
 +      dev->ethtool_ops = &orinoco_ethtool_ops;
 +      dev->wireless_handlers = &orinoco_handler_def;
 +#ifdef WIRELESS_SPY
 +      dev->wireless_data = &priv->wireless_data;
 +#endif
 +      /* we use the default eth_mac_addr for setting the MAC addr */
 +
 +      /* Reserve space in skb for the SNAP header */
 +      dev->hard_header_len += ENCAPS_OVERHEAD;
 +
 +      netif_carrier_off(dev);
 +
 +      memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
 +
 +      dev->base_addr = base_addr;
 +      dev->irq = irq;
 +
 +      SET_NETDEV_DEV(dev, priv->dev);
 +      ret = register_netdev(dev);
 +      if (ret)
 +              goto fail;
 +
 +      priv->ndev = dev;
 +
 +      /* Report what we've done */
 +      dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
 +
 +      return 0;
 +
 + fail:
 +      free_netdev(dev);
 +      return ret;
 +}
 +EXPORT_SYMBOL(orinoco_if_add);
 +
 +void orinoco_if_del(struct orinoco_private *priv)
 +{
 +      struct net_device *dev = priv->ndev;
 +
 +      unregister_netdev(dev);
 +      free_netdev(dev);
 +}
 +EXPORT_SYMBOL(orinoco_if_del);
 +
 +void free_orinocodev(struct orinoco_private *priv)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct wiphy *wiphy = priv_to_wiphy(priv);
        struct orinoco_rx_data *rx_data, *temp;
 +      struct orinoco_scan_data *sd, *sdtemp;
 +
 +      wiphy_unregister(wiphy);
  
        /* If the tasklet is scheduled when we call tasklet_kill it
         * will run one final time. However the tasklet will only
                kfree(rx_data);
        }
  
 +      cancel_work_sync(&priv->process_scan);
 +      /* Explicitly drain priv->scan_list */
 +      list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
 +              list_del(&sd->list);
 +
 +              if ((sd->len > 0) && sd->buf)
 +                      kfree(sd->buf);
 +              kfree(sd);
 +      }
 +
        orinoco_unregister_pm_notifier(priv);
        orinoco_uncache_fw(priv);
  
        priv->wpa_ie_len = 0;
        kfree(priv->wpa_ie);
        orinoco_mic_free(priv);
 -      orinoco_bss_data_free(priv);
 -      free_netdev(dev);
 +      wiphy_free(wiphy);
  }
  EXPORT_SYMBOL(free_orinocodev);
  
 +int orinoco_up(struct orinoco_private *priv)
 +{
 +      struct net_device *dev = priv->ndev;
 +      unsigned long flags;
 +      int err;
 +
 +      spin_lock_irqsave(&priv->lock, flags);
 +
 +      err = orinoco_reinit_firmware(priv);
 +      if (err) {
 +              printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
 +                     dev->name, err);
 +              goto exit;
 +      }
 +
 +      netif_device_attach(dev);
 +      priv->hw_unavailable--;
 +
 +      if (priv->open && !priv->hw_unavailable) {
 +              err = __orinoco_up(priv);
 +              if (err)
 +                      printk(KERN_ERR "%s: Error %d restarting card\n",
 +                             dev->name, err);
 +      }
 +
 +exit:
 +      spin_unlock_irqrestore(&priv->lock, flags);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL(orinoco_up);
 +
 +void orinoco_down(struct orinoco_private *priv)
 +{
 +      struct net_device *dev = priv->ndev;
 +      unsigned long flags;
 +      int err;
 +
 +      spin_lock_irqsave(&priv->lock, flags);
 +      err = __orinoco_down(priv);
 +      if (err)
 +              printk(KERN_WARNING "%s: Error %d downing interface\n",
 +                     dev->name, err);
 +
 +      netif_device_detach(dev);
 +      priv->hw_unavailable++;
 +      spin_unlock_irqrestore(&priv->lock, flags);
 +}
 +EXPORT_SYMBOL(orinoco_down);
 +
  static void orinoco_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
  {
 -      struct orinoco_private *priv = netdev_priv(dev);
 +      struct orinoco_private *priv = ndev_priv(dev);
  
        strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
        strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
diff --combined net/ipv4/ip_gre.c
@@@ -735,10 -735,10 +735,10 @@@ static int ipgre_tunnel_xmit(struct sk_
        }
  
        tos = tiph->tos;
-       if (tos&1) {
+       if (tos == 1) {
+               tos = 0;
                if (skb->protocol == htons(ETH_P_IP))
                        tos = old_iph->tos;
-               tos &= ~1;
        }
  
        {
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
 -                      return 0;
 +                      return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
  
        IPTUNNEL_XMIT();
        tunnel->recursion--;
 -      return 0;
 +      return NETDEV_TX_OK;
  
  tx_error_icmp:
        dst_link_failure(skb);
@@@ -898,7 -898,7 +898,7 @@@ tx_error
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static int ipgre_tunnel_bind_dev(struct net_device *dev)
diff --combined net/ipv6/ip6_output.c
  
  static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
  
 -static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
 -{
 -      static u32 ipv6_fragmentation_id = 1;
 -      static DEFINE_SPINLOCK(ip6_id_lock);
 -
 -      spin_lock_bh(&ip6_id_lock);
 -      fhdr->identification = htonl(ipv6_fragmentation_id);
 -      if (++ipv6_fragmentation_id == 0)
 -              ipv6_fragmentation_id = 1;
 -      spin_unlock_bh(&ip6_id_lock);
 -}
 -
  int __ip6_local_out(struct sk_buff *skb)
  {
        int len;
@@@ -694,7 -706,7 +694,7 @@@ static int ip6_fragment(struct sk_buff 
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
  
 -              ipv6_select_ident(skb, fh);
 +              ipv6_select_ident(fh);
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                fh->frag_off = htons(IP6_MF);
@@@ -832,7 -844,7 +832,7 @@@ slow_path
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                if (!frag_id) {
 -                      ipv6_select_ident(skb, fh);
 +                      ipv6_select_ident(fh);
                        frag_id = fh->identification;
                } else
                        fh->identification = frag_id;
@@@ -1075,13 -1087,11 +1075,13 @@@ static inline int ip6_ufo_append_data(s
        if (!err) {
                struct frag_hdr fhdr;
  
 -              /* specify the length of each IP datagram fragment*/
 -              skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
 -                                          sizeof(struct frag_hdr);
 +              /* Specify the length of each IPv6 datagram fragment.
 +               * It has to be a multiple of 8.
 +               */
 +              skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
 +                                           sizeof(struct frag_hdr)) & ~7;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
 -              ipv6_select_ident(skb, &fhdr);
 +              ipv6_select_ident(&fhdr);
                skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);
  
@@@ -1474,7 -1484,6 +1474,6 @@@ int ip6_push_pending_frames(struct soc
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
diff --combined net/ipv6/sit.c
@@@ -753,7 -753,7 +753,7 @@@ static int ipip6_tunnel_xmit(struct sk_
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
 -                      return 0;
 +                      return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
  
        IPTUNNEL_XMIT();
        tunnel->recursion--;
 -      return 0;
 +      return NETDEV_TX_OK;
  
  tx_error_icmp:
        dst_link_failure(skb);
@@@ -802,7 -802,7 +802,7 @@@ tx_error
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  static void ipip6_tunnel_bind_dev(struct net_device *dev)
@@@ -1018,6 -1018,7 +1018,7 @@@ static void ipip6_tunnel_setup(struct n
        dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
+       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;