Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Mon, 23 Mar 2009 20:35:04 +0000 (13:35 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 23 Mar 2009 20:35:04 +0000 (13:35 -0700)
Conflicts:
drivers/net/ucc_geth.c

1  2 
drivers/net/Kconfig
drivers/net/dnet.c
drivers/net/sungem.c
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
net/wireless/nl80211.c

diff --combined drivers/net/Kconfig
@@@ -26,15 -26,6 +26,15 @@@ menuconfig NETDEVICE
  # that for each of the symbols.
  if NETDEVICES
  
 +config COMPAT_NET_DEV_OPS
 +       default y
 +       bool "Enable older network device API compatiablity"
 +       ---help---
 +          This option enables kernel compatiability with older network devices
 +          that do not use net_device_ops interface.
 +
 +        If unsure, say Y.
 +
  config IFB
        tristate "Intermediate Functional Block support"
        depends on NET_CLS_ACT
@@@ -1051,7 -1042,7 +1051,7 @@@ config NI6
  
  config DNET
        tristate "Dave ethernet support (DNET)"
-       depends on NET_ETHERNET
+       depends on NET_ETHERNET && HAS_IOMEM
        select PHYLIB
        help
          The Dave ethernet interface (DNET) is found on Qong Board FPGA.
@@@ -1849,10 -1840,10 +1849,10 @@@ config 68360_ENE
  
  config FEC
        bool "FEC ethernet controller (of ColdFire CPUs)"
 -      depends on M523x || M527x || M5272 || M528x || M520x || M532x
 +      depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
 -        controller on some Motorola ColdFire processors.
 +        controller on some Motorola ColdFire and Freescale i.MX processors.
  
  config FEC2
        bool "Second FEC ethernet controller (on some ColdFire CPUs)"
@@@ -2039,6 -2030,15 +2039,6 @@@ config IG
           To compile this driver as a module, choose M here. The module
           will be called igb.
  
 -config IGB_LRO 
 -      bool "Use software LRO"
 -      depends on IGB && INET
 -      select INET_LRO
 -      ---help---
 -        Say Y here if you want to use large receive offload. 
 -
 -        If in doubt, say N.
 -
  config IGB_DCA
        bool "Direct Cache Access (DCA) Support"
        default y
@@@ -2284,17 -2284,9 +2284,17 @@@ config GELIC_WIRELESS_OLD_PSK_INTERFAC
  
            If unsure, say N.
  
 +config FSL_PQ_MDIO
 +      tristate "Freescale PQ MDIO"
 +      depends on FSL_SOC
 +      select PHYLIB
 +      help
 +        This driver supports the MDIO bus used by the gianfar and UCC drivers.
 +
  config GIANFAR
        tristate "Gianfar Ethernet"
        depends on FSL_SOC
 +      select FSL_PQ_MDIO
        select PHYLIB
        select CRC32
        help
  config UCC_GETH
        tristate "Freescale QE Gigabit Ethernet"
        depends on QUICC_ENGINE
 +      select FSL_PQ_MDIO
        select PHYLIB
        help
          This driver supports the Gigabit Ethernet mode of the QUICC Engine,
@@@ -2321,7 -2312,6 +2321,7 @@@ config UGETH_TX_ON_DEMAN
  config MV643XX_ETH
        tristate "Marvell Discovery (643XX) and Orion ethernet support"
        depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
 +      select INET_LRO
        select PHYLIB
        help
          This driver supports the gigabit ethernet MACs in the
@@@ -2440,6 -2430,7 +2440,6 @@@ config CHELSIO_T
        tristate "Chelsio Communications T3 10Gb Ethernet support"
        depends on CHELSIO_T3_DEPENDS
        select FW_LOADER
 -      select INET_LRO
        help
          This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
          adapters.
@@@ -2475,6 -2466,7 +2475,6 @@@ config ENI
  config IXGBE
        tristate "Intel(R) 10GbE PCI Express adapters support"
        depends on PCI && INET
 -      select INET_LRO
        ---help---
          This driver supports Intel(R) 10GbE PCI Express family of
          adapters.  For more information on how to identify your adapter, go
diff --combined drivers/net/dnet.c
@@@ -21,6 -21,7 +21,6 @@@
  #include <linux/dma-mapping.h>
  #include <linux/platform_device.h>
  #include <linux/phy.h>
 -#include <linux/platform_device.h>
  
  #include "dnet.h"
  
@@@ -279,11 -280,11 +279,11 @@@ static int dnet_mii_probe(struct net_de
  
        /* attach the mac to the phy */
        if (bp->capabilities & DNET_HAS_RMII) {
-               phydev = phy_connect(dev, phydev->dev.bus_id,
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
                                     &dnet_handle_link_change, 0,
                                     PHY_INTERFACE_MODE_RMII);
        } else {
-               phydev = phy_connect(dev, phydev->dev.bus_id,
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
                                     &dnet_handle_link_change, 0,
                                     PHY_INTERFACE_MODE_MII);
        }
@@@ -926,7 -927,7 +926,7 @@@ static int __devinit dnet_probe(struct 
        phydev = bp->phy_dev;
        dev_info(&pdev->dev, "attached PHY driver [%s] "
               "(mii_bus:phy_addr=%s, irq=%d)\n",
-              phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+              phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
  
        return 0;
  
diff --combined drivers/net/sungem.c
@@@ -921,7 -921,7 +921,7 @@@ static int gem_poll(struct napi_struct 
                gp->status = readl(gp->regs + GREG_STAT);
        } while (gp->status & GREG_STAT_NAPI);
  
 -      __netif_rx_complete(napi);
 +      __napi_complete(napi);
        gem_enable_ints(gp);
  
        spin_unlock_irqrestore(&gp->lock, flags);
@@@ -944,7 -944,7 +944,7 @@@ static irqreturn_t gem_interrupt(int ir
  
        spin_lock_irqsave(&gp->lock, flags);
  
 -      if (netif_rx_schedule_prep(&gp->napi)) {
 +      if (napi_schedule_prep(&gp->napi)) {
                u32 gem_status = readl(gp->regs + GREG_STAT);
  
                if (gem_status == 0) {
                }
                gp->status = gem_status;
                gem_disable_ints(gp);
 -              __netif_rx_schedule(&gp->napi);
 +              __napi_schedule(&gp->napi);
        }
  
        spin_unlock_irqrestore(&gp->lock, flags);
@@@ -2998,8 -2998,11 +2998,11 @@@ static const struct net_device_ops gem_
        .ndo_do_ioctl           = gem_ioctl,
        .ndo_tx_timeout         = gem_tx_timeout,
        .ndo_change_mtu         = gem_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = gem_set_mac_address,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = gem_poll_controller,
+ #endif
  };
  
  static int __devinit gem_init_one(struct pci_dev *pdev,
        dev->watchdog_timeo = 5 * HZ;
        dev->irq = pdev->irq;
        dev->dma = 0;
-       dev->set_mac_address = gem_set_mac_address;
- #ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = gem_poll_controller;
- #endif
  
        /* Set that now, in case PM kicks in now */
        pci_set_drvdata(pdev, dev);
diff --combined drivers/net/ucc_geth.c
@@@ -39,7 -39,7 +39,7 @@@
  #include <asm/ucc_fast.h>
  
  #include "ucc_geth.h"
 -#include "ucc_geth_mii.h"
 +#include "fsl_pq_mdio.h"
  
  #undef DEBUG
  
@@@ -1536,32 -1536,15 +1536,15 @@@ static void adjust_link(struct net_devi
  static int init_phy(struct net_device *dev)
  {
        struct ucc_geth_private *priv = netdev_priv(dev);
-       struct device_node *np = priv->node;
-       struct device_node *phy, *mdio;
-       const phandle *ph;
-       char bus_name[MII_BUS_ID_SIZE];
-       const unsigned int *id;
+       struct ucc_geth_info *ug_info = priv->ug_info;
        struct phy_device *phydev;
-       char phy_id[BUS_ID_SIZE];
  
        priv->oldlink = 0;
        priv->oldspeed = 0;
        priv->oldduplex = -1;
  
-       ph = of_get_property(np, "phy-handle", NULL);
-       phy = of_find_node_by_phandle(*ph);
-       mdio = of_get_parent(phy);
-       id = of_get_property(phy, "reg", NULL);
-       of_node_put(phy);
-       of_node_put(mdio);
-       fsl_pq_mdio_bus_name(bus_name, mdio);
-       snprintf(phy_id, sizeof(phy_id), "%s:%02x",
-                                 bus_name, *id);
-       phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
+       phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0,
+                            priv->phy_interface);
  
        if (IS_ERR(phydev)) {
                printk("%s: Could not attach to PHY\n", dev->name);
@@@ -3266,7 -3249,7 +3249,7 @@@ static int ucc_geth_poll(struct napi_st
                howmany += ucc_geth_rx(ugeth, i, budget - howmany);
  
        if (howmany < budget) {
 -              netif_rx_complete(napi);
 +              napi_complete(napi);
                setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS);
        }
  
@@@ -3297,10 -3280,10 +3280,10 @@@ static irqreturn_t ucc_geth_irq_handler
  
        /* check for receive events that require processing */
        if (ucce & UCCE_RX_EVENTS) {
 -              if (netif_rx_schedule_prep(&ugeth->napi)) {
 +              if (napi_schedule_prep(&ugeth->napi)) {
                        uccm &= ~UCCE_RX_EVENTS;
                        out_be32(uccf->p_uccm, uccm);
 -                      __netif_rx_schedule(&ugeth->napi);
 +                      __napi_schedule(&ugeth->napi);
                }
        }
  
@@@ -3629,10 -3612,12 +3612,12 @@@ static int ucc_geth_probe(struct of_dev
        ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
        fixed_link = of_get_property(np, "fixed-link", NULL);
        if (fixed_link) {
-               snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0");
-               ug_info->phy_address = fixed_link[0];
+               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
+                        PHY_ID_FMT, "0", fixed_link[0]);
                phy = NULL;
        } else {
+               char bus_name[MII_BUS_ID_SIZE];
                ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
  
                prop = of_get_property(phy, "reg", NULL);
                if (prop == NULL)
                        return -1;
-               ug_info->phy_address = *prop;
  
                /* Set the bus id */
                mdio = of_get_parent(phy);
                if (err)
                        return -1;
  
++<<<<<<< HEAD:drivers/net/ucc_geth.c
 +              snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x",
 +                              res.start&0xfffff);
++=======
+               uec_mdio_bus_name(bus_name, mdio);
+               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
+                       "%s:%02x", bus_name, *prop);
++>>>>>>> 61fa9dcf9329cb92c220f7b656410fbe5e72f933:drivers/net/ucc_geth.c
        }
  
        /* get the phy interface type, or default to MII */
@@@ -3804,6 -3789,11 +3794,6 @@@ static int __init ucc_geth_init(void
  {
        int i, ret;
  
 -      ret = uec_mdio_init();
 -
 -      if (ret)
 -              return ret;
 -
        if (netif_msg_drv(&debug))
                printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
        for (i = 0; i < 8; i++)
  
        ret = of_register_platform_driver(&ucc_geth_driver);
  
 -      if (ret)
 -              uec_mdio_exit();
 -
        return ret;
  }
  
  static void __exit ucc_geth_exit(void)
  {
        of_unregister_platform_driver(&ucc_geth_driver);
 -      uec_mdio_exit();
  }
  
  module_init(ucc_geth_init);
diff --combined drivers/net/ucc_geth.h
@@@ -28,6 -28,8 +28,6 @@@
  #include <asm/ucc.h>
  #include <asm/ucc_fast.h>
  
 -#include "ucc_geth_mii.h"
 -
  #define DRV_DESC "QE UCC Gigabit Ethernet Controller"
  #define DRV_NAME "ucc_geth"
  #define DRV_VERSION "1.1"
@@@ -182,18 -184,6 +182,18 @@@ struct ucc_geth 
  #define UCCE_RX_EVENTS  (UCCE_RXF | UCC_GETH_UCCE_BSY)
  #define UCCE_TX_EVENTS        (UCCE_TXB | UCC_GETH_UCCE_TXE)
  
 +/* TBI defines */
 +#define       ENET_TBI_MII_CR         0x00    /* Control */
 +#define       ENET_TBI_MII_SR         0x01    /* Status */
 +#define       ENET_TBI_MII_ANA        0x04    /* AN advertisement */
 +#define       ENET_TBI_MII_ANLPBPA    0x05    /* AN link partner base page ability */
 +#define       ENET_TBI_MII_ANEX       0x06    /* AN expansion */
 +#define       ENET_TBI_MII_ANNPT      0x07    /* AN next page transmit */
 +#define       ENET_TBI_MII_ANLPANP    0x08    /* AN link partner ability next page */
 +#define       ENET_TBI_MII_EXST       0x0F    /* Extended status */
 +#define       ENET_TBI_MII_JD         0x10    /* Jitter diagnostics */
 +#define       ENET_TBI_MII_TBICON     0x11    /* TBI control */
 +
  /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */
  #define MACCFG1_FLOW_RX                         0x00000020    /* Flow Control
                                                                   Rx */
@@@ -1101,8 -1091,7 +1101,7 @@@ struct ucc_geth_info 
        u32 eventRegMask;
        u16 pausePeriod;
        u16 extensionField;
-       u8 phy_address;
-       char mdio_bus[MII_BUS_ID_SIZE];
+       char phy_bus_id[BUS_ID_SIZE];
        u8 weightfactor[NUM_TX_QUEUES];
        u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
        u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
diff --combined net/wireless/nl80211.c
@@@ -7,13 -7,13 +7,13 @@@
  #include <linux/if.h>
  #include <linux/module.h>
  #include <linux/err.h>
 -#include <linux/mutex.h>
  #include <linux/list.h>
  #include <linux/if_ether.h>
  #include <linux/ieee80211.h>
  #include <linux/nl80211.h>
  #include <linux/rtnetlink.h>
  #include <linux/netlink.h>
 +#include <linux/etherdevice.h>
  #include <net/genetlink.h>
  #include <net/cfg80211.h>
  #include "core.h"
@@@ -105,12 -105,6 +105,12 @@@ static struct nla_policy nl80211_policy
  
        [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
                                         .len = NL80211_HT_CAPABILITY_LEN },
 +
 +      [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
 +      [NL80211_ATTR_IE] = { .type = NLA_BINARY,
 +                            .len = IEEE80211_MAX_DATA_LEN },
 +      [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
 +      [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
  };
  
  /* message building helper */
@@@ -141,10 -135,8 +141,10 @@@ static int nl80211_send_wiphy(struct sk
        if (!hdr)
                return -1;
  
 -      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);
        NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 +      NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
 +                 dev->wiphy.max_scan_ssids);
  
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
@@@ -255,7 -247,7 +255,7 @@@ static int nl80211_dump_wiphy(struct sk
        int start = cb->args[0];
        struct cfg80211_registered_device *dev;
  
 -      mutex_lock(&cfg80211_drv_mutex);
 +      mutex_lock(&cfg80211_mutex);
        list_for_each_entry(dev, &cfg80211_drv_list, list) {
                if (++idx <= start)
                        continue;
                        break;
                }
        }
 -      mutex_unlock(&cfg80211_drv_mutex);
 +      mutex_unlock(&cfg80211_mutex);
  
        cb->args[0] = idx;
  
@@@ -469,7 -461,7 +469,7 @@@ static int nl80211_dump_interface(struc
        struct cfg80211_registered_device *dev;
        struct wireless_dev *wdev;
  
 -      mutex_lock(&cfg80211_drv_mutex);
 +      mutex_lock(&cfg80211_mutex);
        list_for_each_entry(dev, &cfg80211_drv_list, list) {
                if (wp_idx < wp_start) {
                        wp_idx++;
                wp_idx++;
        }
   out:
 -      mutex_unlock(&cfg80211_drv_mutex);
 +      mutex_unlock(&cfg80211_mutex);
  
        cb->args[0] = wp_idx;
        cb->args[1] = if_idx;
@@@ -746,7 -738,7 +746,7 @@@ static int nl80211_get_key(struct sk_bu
        if (info->attrs[NL80211_ATTR_KEY_IDX])
                key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
  
 -      if (key_idx > 3)
 +      if (key_idx > 5)
                return -EINVAL;
  
        if (info->attrs[NL80211_ATTR_MAC])
@@@ -812,41 -804,30 +812,41 @@@ static int nl80211_set_key(struct sk_bu
        int err;
        struct net_device *dev;
        u8 key_idx;
 +      int (*func)(struct wiphy *wiphy, struct net_device *netdev,
 +                  u8 key_index);
  
        if (!info->attrs[NL80211_ATTR_KEY_IDX])
                return -EINVAL;
  
        key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
  
 -      if (key_idx > 3)
 +      if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
 +              if (key_idx < 4 || key_idx > 5)
 +                      return -EINVAL;
 +      } else if (key_idx > 3)
                return -EINVAL;
  
        /* currently only support setting default key */
 -      if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
 +      if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
 +          !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
                return -EINVAL;
  
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
  
 -      if (!drv->ops->set_default_key) {
 +      if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
 +              func = drv->ops->set_default_key;
 +      else
 +              func = drv->ops->set_default_mgmt_key;
 +
 +      if (!func) {
                err = -EOPNOTSUPP;
                goto out;
        }
  
        rtnl_lock();
 -      err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
 +      err = func(&drv->wiphy, dev, key_idx);
        rtnl_unlock();
  
   out:
@@@ -882,7 -863,7 +882,7 @@@ static int nl80211_new_key(struct sk_bu
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
  
 -      if (key_idx > 3)
 +      if (key_idx > 5)
                return -EINVAL;
  
        /*
                if (params.key_len != 13)
                        return -EINVAL;
                break;
 +      case WLAN_CIPHER_SUITE_AES_CMAC:
 +              if (params.key_len != 16)
 +                      return -EINVAL;
 +              break;
        default:
                return -EINVAL;
        }
@@@ -951,7 -928,7 +951,7 @@@ static int nl80211_del_key(struct sk_bu
        if (info->attrs[NL80211_ATTR_KEY_IDX])
                key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
  
 -      if (key_idx > 3)
 +      if (key_idx > 5)
                return -EINVAL;
  
        if (info->attrs[NL80211_ATTR_MAC])
@@@ -1205,12 -1182,6 +1205,12 @@@ static int nl80211_send_station(struct 
  
                nla_nest_end(msg, txrate);
        }
 +      if (sinfo->filled & STATION_INFO_RX_PACKETS)
 +              NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
 +                          sinfo->rx_packets);
 +      if (sinfo->filled & STATION_INFO_TX_PACKETS)
 +              NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
 +                          sinfo->tx_packets);
        nla_nest_end(msg, sinfoattr);
  
        return genlmsg_end(msg, hdr);
@@@ -1905,19 -1876,6 +1905,19 @@@ static int nl80211_req_set_reg(struct s
        int r;
        char *data = NULL;
  
 +      /*
 +       * You should only get this when cfg80211 hasn't yet initialized
 +       * completely when built-in to the kernel right between the time
 +       * window between nl80211_init() and regulatory_init(), if that is
 +       * even possible.
 +       */
 +      mutex_lock(&cfg80211_mutex);
 +      if (unlikely(!cfg80211_regdomain)) {
 +              mutex_unlock(&cfg80211_mutex);
 +              return -EINPROGRESS;
 +      }
 +      mutex_unlock(&cfg80211_mutex);
 +
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                return -EINVAL;
  
        if (is_world_regdom(data))
                return -EINVAL;
  #endif
 -      mutex_lock(&cfg80211_drv_mutex);
 -      r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
 -      mutex_unlock(&cfg80211_drv_mutex);
 +
 +      r = regulatory_hint_user(data);
 +
        return r;
  }
  
@@@ -1950,6 -1908,11 +1950,11 @@@ static int nl80211_get_mesh_params(stru
        if (err)
                return err;
  
+       if (!drv->ops->get_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
        /* Get the mesh params */
        rtnl_lock();
        err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
@@@ -2059,6 -2022,11 +2064,11 @@@ static int nl80211_set_mesh_params(stru
        if (err)
                return err;
  
+       if (!drv->ops->set_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
        /* This makes sure that there aren't more than 32 mesh config
         * parameters (otherwise our bitfield scheme would not work.) */
        BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
        err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
        rtnl_unlock();
  
+  out:
        /* cleanup */
        cfg80211_put_dev(drv);
        dev_put(dev);
  
  #undef FILL_IN_MESH_PARAM_IF_SET
  
 +static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct sk_buff *msg;
 +      void *hdr = NULL;
 +      struct nlattr *nl_reg_rules;
 +      unsigned int i;
 +      int err = -EINVAL;
 +
 +      mutex_lock(&cfg80211_mutex);
 +
 +      if (!cfg80211_regdomain)
 +              goto out;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 +      if (!msg) {
 +              err = -ENOBUFS;
 +              goto out;
 +      }
 +
 +      hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 +                           NL80211_CMD_GET_REG);
 +      if (!hdr)
 +              goto nla_put_failure;
 +
 +      NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2,
 +              cfg80211_regdomain->alpha2);
 +
 +      nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
 +      if (!nl_reg_rules)
 +              goto nla_put_failure;
 +
 +      for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
 +              struct nlattr *nl_reg_rule;
 +              const struct ieee80211_reg_rule *reg_rule;
 +              const struct ieee80211_freq_range *freq_range;
 +              const struct ieee80211_power_rule *power_rule;
 +
 +              reg_rule = &cfg80211_regdomain->reg_rules[i];
 +              freq_range = &reg_rule->freq_range;
 +              power_rule = &reg_rule->power_rule;
 +
 +              nl_reg_rule = nla_nest_start(msg, i);
 +              if (!nl_reg_rule)
 +                      goto nla_put_failure;
 +
 +              NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS,
 +                      reg_rule->flags);
 +              NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START,
 +                      freq_range->start_freq_khz);
 +              NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END,
 +                      freq_range->end_freq_khz);
 +              NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
 +                      freq_range->max_bandwidth_khz);
 +              NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
 +                      power_rule->max_antenna_gain);
 +              NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
 +                      power_rule->max_eirp);
 +
 +              nla_nest_end(msg, nl_reg_rule);
 +      }
 +
 +      nla_nest_end(msg, nl_reg_rules);
 +
 +      genlmsg_end(msg, hdr);
 +      err = genlmsg_unicast(msg, info->snd_pid);
 +      goto out;
 +
 +nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      err = -EMSGSIZE;
 +out:
 +      mutex_unlock(&cfg80211_mutex);
 +      return err;
 +}
 +
  static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
  {
        struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
  
        BUG_ON(rule_idx != num_rules);
  
 -      mutex_lock(&cfg80211_drv_mutex);
 +      mutex_lock(&cfg80211_mutex);
        r = set_regdom(rd);
 -      mutex_unlock(&cfg80211_drv_mutex);
 +      mutex_unlock(&cfg80211_mutex);
        return r;
  
   bad_reg:
        return -EINVAL;
  }
  
 +static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
 +                                   struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *drv;
 +      int err;
 +      struct net_device *dev;
 +      struct mgmt_extra_ie_params params;
 +
 +      memset(&params, 0, sizeof(params));
 +
 +      if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE])
 +              return -EINVAL;
 +      params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
 +      if (params.subtype > 15)
 +              return -EINVAL; /* FC Subtype field is 4 bits (0..15) */
 +
 +      if (info->attrs[NL80211_ATTR_IE]) {
 +              params.ies = nla_data(info->attrs[NL80211_ATTR_IE]);
 +              params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 +      }
 +
 +      err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
 +      if (err)
 +              return err;
 +
 +      if (drv->ops->set_mgmt_extra_ie) {
 +              rtnl_lock();
 +              err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
 +              rtnl_unlock();
 +      } else
 +              err = -EOPNOTSUPP;
 +
 +      cfg80211_put_dev(drv);
 +      dev_put(dev);
 +      return err;
 +}
 +
 +static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *drv;
 +      struct net_device *dev;
 +      struct cfg80211_scan_request *request;
 +      struct cfg80211_ssid *ssid;
 +      struct ieee80211_channel *channel;
 +      struct nlattr *attr;
 +      struct wiphy *wiphy;
 +      int err, tmp, n_ssids = 0, n_channels = 0, i;
 +      enum ieee80211_band band;
 +      size_t ie_len;
 +
 +      err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
 +      if (err)
 +              return err;
 +
 +      wiphy = &drv->wiphy;
 +
 +      if (!drv->ops->scan) {
 +              err = -EOPNOTSUPP;
 +              goto out;
 +      }
 +
 +      rtnl_lock();
 +
 +      if (drv->scan_req) {
 +              err = -EBUSY;
 +              goto out_unlock;
 +      }
 +
 +      if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
 +              nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
 +                      n_channels++;
 +              if (!n_channels) {
 +                      err = -EINVAL;
 +                      goto out_unlock;
 +              }
 +      } else {
 +              for (band = 0; band < IEEE80211_NUM_BANDS; band++)
 +                      if (wiphy->bands[band])
 +                              n_channels += wiphy->bands[band]->n_channels;
 +      }
 +
 +      if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
 +              nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
 +                      n_ssids++;
 +
 +      if (n_ssids > wiphy->max_scan_ssids) {
 +              err = -EINVAL;
 +              goto out_unlock;
 +      }
 +
 +      if (info->attrs[NL80211_ATTR_IE])
 +              ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 +      else
 +              ie_len = 0;
 +
 +      request = kzalloc(sizeof(*request)
 +                      + sizeof(*ssid) * n_ssids
 +                      + sizeof(channel) * n_channels
 +                      + ie_len, GFP_KERNEL);
 +      if (!request) {
 +              err = -ENOMEM;
 +              goto out_unlock;
 +      }
 +
 +      request->channels = (void *)((char *)request + sizeof(*request));
 +      request->n_channels = n_channels;
 +      if (n_ssids)
 +              request->ssids = (void *)(request->channels + n_channels);
 +      request->n_ssids = n_ssids;
 +      if (ie_len) {
 +              if (request->ssids)
 +                      request->ie = (void *)(request->ssids + n_ssids);
 +              else
 +                      request->ie = (void *)(request->channels + n_channels);
 +      }
 +
 +      if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
 +              /* user specified, bail out if channel not found */
 +              request->n_channels = n_channels;
 +              i = 0;
 +              nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
 +                      request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr));
 +                      if (!request->channels[i]) {
 +                              err = -EINVAL;
 +                              goto out_free;
 +                      }
 +                      i++;
 +              }
 +      } else {
 +              /* all channels */
 +              i = 0;
 +              for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 +                      int j;
 +                      if (!wiphy->bands[band])
 +                              continue;
 +                      for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
 +                              request->channels[i] = &wiphy->bands[band]->channels[j];
 +                              i++;
 +                      }
 +              }
 +      }
 +
 +      i = 0;
 +      if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
 +              nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
 +                      if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
 +                              err = -EINVAL;
 +                              goto out_free;
 +                      }
 +                      memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
 +                      request->ssids[i].ssid_len = nla_len(attr);
 +                      i++;
 +              }
 +      }
 +
 +      if (info->attrs[NL80211_ATTR_IE]) {
 +              request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 +              memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),
 +                     request->ie_len);
 +      }
 +
 +      request->ifidx = dev->ifindex;
 +      request->wiphy = &drv->wiphy;
 +
 +      drv->scan_req = request;
 +      err = drv->ops->scan(&drv->wiphy, dev, request);
 +
 + out_free:
 +      if (err) {
 +              drv->scan_req = NULL;
 +              kfree(request);
 +      }
 + out_unlock:
 +      rtnl_unlock();
 + out:
 +      cfg80211_put_dev(drv);
 +      dev_put(dev);
 +      return err;
 +}
 +
 +static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 +                          struct cfg80211_registered_device *rdev,
 +                          struct net_device *dev,
 +                          struct cfg80211_bss *res)
 +{
 +      void *hdr;
 +      struct nlattr *bss;
 +
 +      hdr = nl80211hdr_put(msg, pid, seq, flags,
 +                           NL80211_CMD_NEW_SCAN_RESULTS);
 +      if (!hdr)
 +              return -1;
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
 +                  rdev->bss_generation);
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 +
 +      bss = nla_nest_start(msg, NL80211_ATTR_BSS);
 +      if (!bss)
 +              goto nla_put_failure;
 +      if (!is_zero_ether_addr(res->bssid))
 +              NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid);
 +      if (res->information_elements && res->len_information_elements)
 +              NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
 +                      res->len_information_elements,
 +                      res->information_elements);
 +      if (res->tsf)
 +              NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
 +      if (res->beacon_interval)
 +              NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
 +      NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
 +      NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
 +
 +      switch (rdev->wiphy.signal_type) {
 +      case CFG80211_SIGNAL_TYPE_MBM:
 +              NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
 +              break;
 +      case CFG80211_SIGNAL_TYPE_UNSPEC:
 +              NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal);
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      nla_nest_end(msg, bss);
 +
 +      return genlmsg_end(msg, hdr);
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      return -EMSGSIZE;
 +}
 +
 +static int nl80211_dump_scan(struct sk_buff *skb,
 +                           struct netlink_callback *cb)
 +{
 +      struct cfg80211_registered_device *dev;
 +      struct net_device *netdev;
 +      struct cfg80211_internal_bss *scan;
 +      int ifidx = cb->args[0];
 +      int start = cb->args[1], idx = 0;
 +      int err;
 +
 +      if (!ifidx) {
 +              err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
 +                                nl80211_fam.attrbuf, nl80211_fam.maxattr,
 +                                nl80211_policy);
 +              if (err)
 +                      return err;
 +
 +              if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
 +                      return -EINVAL;
 +
 +              ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
 +              if (!ifidx)
 +                      return -EINVAL;
 +              cb->args[0] = ifidx;
 +      }
 +
 +      netdev = dev_get_by_index(&init_net, ifidx);
 +      if (!netdev)
 +              return -ENODEV;
 +
 +      dev = cfg80211_get_dev_from_ifindex(ifidx);
 +      if (IS_ERR(dev)) {
 +              err = PTR_ERR(dev);
 +              goto out_put_netdev;
 +      }
 +
 +      spin_lock_bh(&dev->bss_lock);
 +      cfg80211_bss_expire(dev);
 +
 +      list_for_each_entry(scan, &dev->bss_list, list) {
 +              if (++idx <= start)
 +                      continue;
 +              if (nl80211_send_bss(skb,
 +                              NETLINK_CB(cb->skb).pid,
 +                              cb->nlh->nlmsg_seq, NLM_F_MULTI,
 +                              dev, netdev, &scan->pub) < 0) {
 +                      idx--;
 +                      goto out;
 +              }
 +      }
 +
 + out:
 +      spin_unlock_bh(&dev->bss_lock);
 +
 +      cb->args[1] = idx;
 +      err = skb->len;
 +      cfg80211_put_dev(dev);
 + out_put_netdev:
 +      dev_put(netdev);
 +
 +      return err;
 +}
 +
  static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
                .doit = nl80211_get_station,
                .dumpit = nl80211_dump_station,
                .policy = nl80211_policy,
 -              .flags = GENL_ADMIN_PERM,
        },
        {
                .cmd = NL80211_CMD_SET_STATION,
                .flags = GENL_ADMIN_PERM,
        },
        {
 +              .cmd = NL80211_CMD_GET_REG,
 +              .doit = nl80211_get_reg,
 +              .policy = nl80211_policy,
 +              /* can be retrieved by unprivileged users */
 +      },
 +      {
                .cmd = NL80211_CMD_SET_REG,
                .doit = nl80211_set_reg,
                .policy = nl80211_policy,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
 +      {
 +              .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE,
 +              .doit = nl80211_set_mgmt_extra_ie,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +      },
 +      {
 +              .cmd = NL80211_CMD_TRIGGER_SCAN,
 +              .doit = nl80211_trigger_scan,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +      },
 +      {
 +              .cmd = NL80211_CMD_GET_SCAN,
 +              .policy = nl80211_policy,
 +              .dumpit = nl80211_dump_scan,
 +      },
  };
  
  /* multicast groups */
  static struct genl_multicast_group nl80211_config_mcgrp = {
        .name = "config",
  };
 +static struct genl_multicast_group nl80211_scan_mcgrp = {
 +      .name = "scan",
 +};
 +static struct genl_multicast_group nl80211_regulatory_mcgrp = {
 +      .name = "regulatory",
 +};
  
  /* notification functions */
  
@@@ -2761,121 -2331,6 +2772,121 @@@ void nl80211_notify_dev_rename(struct c
        genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
  }
  
 +static int nl80211_send_scan_donemsg(struct sk_buff *msg,
 +                                  struct cfg80211_registered_device *rdev,
 +                                  struct net_device *netdev,
 +                                  u32 pid, u32 seq, int flags,
 +                                  u32 cmd)
 +{
 +      void *hdr;
 +
 +      hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
 +      if (!hdr)
 +              return -1;
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 +
 +      /* XXX: we should probably bounce back the request? */
 +
 +      return genlmsg_end(msg, hdr);
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      return -EMSGSIZE;
 +}
 +
 +void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
 +                          struct net_device *netdev)
 +{
 +      struct sk_buff *msg;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 +      if (!msg)
 +              return;
 +
 +      if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
 +                                    NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 +}
 +
 +void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
 +                             struct net_device *netdev)
 +{
 +      struct sk_buff *msg;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 +      if (!msg)
 +              return;
 +
 +      if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
 +                                    NL80211_CMD_SCAN_ABORTED) < 0) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 +}
 +
 +/*
 + * This can happen on global regulatory changes or device specific settings
 + * based on custom world regulatory domains.
 + */
 +void nl80211_send_reg_change_event(struct regulatory_request *request)
 +{
 +      struct sk_buff *msg;
 +      void *hdr;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 +      if (!msg)
 +              return;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      /* Userspace can always count this one always being set */
 +      NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator);
 +
 +      if (request->alpha2[0] == '0' && request->alpha2[1] == '0')
 +              NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
 +                         NL80211_REGDOM_TYPE_WORLD);
 +      else if (request->alpha2[0] == '9' && request->alpha2[1] == '9')
 +              NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
 +                         NL80211_REGDOM_TYPE_CUSTOM_WORLD);
 +      else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
 +               request->intersect)
 +              NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
 +                         NL80211_REGDOM_TYPE_INTERSECTION);
 +      else {
 +              NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
 +                         NL80211_REGDOM_TYPE_COUNTRY);
 +              NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2);
 +      }
 +
 +      if (wiphy_idx_valid(request->wiphy_idx))
 +              NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
 +
 +      if (genlmsg_end(msg, hdr) < 0) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
 +
 +      return;
 +
 +nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +}
 +
  /* initialisation/exit functions */
  
  int nl80211_init(void)
        if (err)
                goto err_out;
  
 +      err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp);
 +      if (err)
 +              goto err_out;
 +
 +      err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp);
 +      if (err)
 +              goto err_out;
 +
        return 0;
   err_out:
        genl_unregister_family(&nl80211_fam);