Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 17 Jan 2014 19:43:17 +0000 (14:43 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 17 Jan 2014 19:43:17 +0000 (14:43 -0500)
1  2 
drivers/net/wireless/adm8211.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/ti/wl1251/main.c
include/net/nfc/nci_core.h
net/mac80211/tx.c
net/nfc/core.c
net/wireless/nl80211.c

@@@ -1313,7 -1313,7 +1313,7 @@@ static void adm8211_bss_info_changed(st
        if (!(changes & BSS_CHANGED_BSSID))
                return;
  
 -      if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
 +      if (!ether_addr_equal(conf->bssid, priv->bssid)) {
                adm8211_set_bssid(dev, conf->bssid);
                memcpy(priv->bssid, conf->bssid, ETH_ALEN);
        }
@@@ -1865,7 -1865,6 +1865,6 @@@ static int adm8211_probe(struct pci_de
        dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
        dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
  
-       dev->channel_change_time = 1000;
        dev->max_signal = 100;    /* FIXME: find better value */
  
        dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
@@@ -163,6 -163,11 +163,11 @@@ static const struct ieee80211_regdomai
        }
  };
  
+ static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = {
+       &hwsim_world_regdom_custom_01,
+       &hwsim_world_regdom_custom_02,
+ };
  struct hwsim_vif_priv {
        u32 magic;
        u8 bssid[ETH_ALEN];
@@@ -321,8 -326,52 +326,52 @@@ static const struct ieee80211_rate hwsi
        { .bitrate = 540 }
  };
  
+ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
+       { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
+       { .max = 2048,  .types = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ #ifdef CONFIG_MAC80211_MESH
+                                BIT(NL80211_IFTYPE_MESH_POINT) |
+ #endif
+                                BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_P2P_GO) },
+       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
+ };
+ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
+       { .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
+ };
+ static const struct ieee80211_iface_combination hwsim_if_comb[] = {
+       {
+               .limits = hwsim_if_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_limits),
+               .max_interfaces = 2048,
+               .num_different_channels = 1,
+       },
+       {
+               .limits = hwsim_if_dfs_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                      BIT(NL80211_CHAN_WIDTH_20) |
+                                      BIT(NL80211_CHAN_WIDTH_40) |
+                                      BIT(NL80211_CHAN_WIDTH_80) |
+                                      BIT(NL80211_CHAN_WIDTH_160),
+       }
+ };
  static spinlock_t hwsim_radio_lock;
  static struct list_head hwsim_radios;
+ static int hwsim_radio_idx;
+ static struct platform_driver mac80211_hwsim_driver = {
+       .driver = {
+               .name = "mac80211_hwsim",
+               .owner = THIS_MODULE,
+       },
+ };
  
  struct mac80211_hwsim_data {
        struct list_head list;
        struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)];
        struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
        struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
+       struct ieee80211_iface_combination if_combination;
  
        struct mac_address addresses[2];
+       int channels, idx;
  
        struct ieee80211_channel *tmp_chan;
        struct delayed_work roc_done;
@@@ -401,21 -452,179 +452,179 @@@ static struct genl_family hwsim_genl_fa
  /* MAC80211_HWSIM netlink policy */
  
  static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
-       [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC,
-                                      .len = 6*sizeof(u8) },
-       [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC,
-                                         .len = 6*sizeof(u8) },
+       [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
+       [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY,
                               .len = IEEE80211_MAX_DATA_LEN },
        [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 },
        [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 },
        [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 },
        [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC,
-                                .len = IEEE80211_TX_MAX_RATES*sizeof(
-                                       struct hwsim_tx_rate)},
+                                .len = IEEE80211_TX_MAX_RATES *
+                                       sizeof(struct hwsim_tx_rate)},
        [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 },
+       [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 },
+       [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
+       [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 },
+       [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
+       [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
  };
  
+ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
+                                   struct sk_buff *skb,
+                                   struct ieee80211_channel *chan);
+ /* sysfs attributes */
+ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+       struct sk_buff *skb;
+       struct ieee80211_pspoll *pspoll;
+       if (!vp->assoc)
+               return;
+       wiphy_debug(data->hw->wiphy,
+                   "%s: send PS-Poll to %pM for aid %d\n",
+                   __func__, vp->bssid, vp->aid);
+       skb = dev_alloc_skb(sizeof(*pspoll));
+       if (!skb)
+               return;
+       pspoll = (void *) skb_put(skb, sizeof(*pspoll));
+       pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                           IEEE80211_STYPE_PSPOLL |
+                                           IEEE80211_FCTL_PM);
+       pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
+       memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
+       memcpy(pspoll->ta, mac, ETH_ALEN);
+       rcu_read_lock();
+       mac80211_hwsim_tx_frame(data->hw, skb,
+                               rcu_dereference(vif->chanctx_conf)->def.chan);
+       rcu_read_unlock();
+ }
+ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
+                               struct ieee80211_vif *vif, int ps)
+ {
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       if (!vp->assoc)
+               return;
+       wiphy_debug(data->hw->wiphy,
+                   "%s: send data::nullfunc to %pM ps=%d\n",
+                   __func__, vp->bssid, ps);
+       skb = dev_alloc_skb(sizeof(*hdr));
+       if (!skb)
+               return;
+       hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                        IEEE80211_STYPE_NULLFUNC |
+                                        (ps ? IEEE80211_FCTL_PM : 0));
+       hdr->duration_id = cpu_to_le16(0);
+       memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
+       memcpy(hdr->addr2, mac, ETH_ALEN);
+       memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+       rcu_read_lock();
+       mac80211_hwsim_tx_frame(data->hw, skb,
+                               rcu_dereference(vif->chanctx_conf)->def.chan);
+       rcu_read_unlock();
+ }
+ static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
+                                  struct ieee80211_vif *vif)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       hwsim_send_nullfunc(data, mac, vif, 1);
+ }
+ static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
+                                     struct ieee80211_vif *vif)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       hwsim_send_nullfunc(data, mac, vif, 0);
+ }
+ static int hwsim_fops_ps_read(void *dat, u64 *val)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       *val = data->ps;
+       return 0;
+ }
+ static int hwsim_fops_ps_write(void *dat, u64 val)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       enum ps_mode old_ps;
+       if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
+           val != PS_MANUAL_POLL)
+               return -EINVAL;
+       old_ps = data->ps;
+       data->ps = val;
+       if (val == PS_MANUAL_POLL) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
+                                                   hwsim_send_ps_poll, data);
+               data->ps_poll_pending = true;
+       } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
+                                                   hwsim_send_nullfunc_ps,
+                                                   data);
+       } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
+                                                   hwsim_send_nullfunc_no_ps,
+                                                   data);
+       }
+       return 0;
+ }
+ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
+                       "%llu\n");
+ static int hwsim_write_simulate_radar(void *dat, u64 val)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       ieee80211_radar_detected(data->hw);
+       return 0;
+ }
+ DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
+                       hwsim_write_simulate_radar, "%llu\n");
+ static int hwsim_fops_group_read(void *dat, u64 *val)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       *val = data->group;
+       return 0;
+ }
+ static int hwsim_fops_group_write(void *dat, u64 val)
+ {
+       struct mac80211_hwsim_data *data = dat;
+       data->group = val;
+       return 0;
+ }
+ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group,
+                       hwsim_fops_group_read, hwsim_fops_group_write,
+                       "%llx\n");
  static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
                                        struct net_device *dev)
  {
@@@ -639,7 -848,7 +848,7 @@@ static void mac80211_hwsim_tx_frame_nl(
        }
  
        if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
-                   sizeof(struct mac_address), data->addresses[1].addr))
+                   ETH_ALEN, data->addresses[1].addr))
                goto nla_put_failure;
  
        /* We get the skb->data */
@@@ -878,7 -1087,7 +1087,7 @@@ static void mac80211_hwsim_tx(struct ie
                return;
        }
  
-       if (channels == 1) {
+       if (data->channels == 1) {
                channel = data->channel;
        } else if (txi->hw_queue == 4) {
                channel = data->tmp_chan;
        if (control->sta)
                hwsim_check_sta_magic(control->sta);
  
-       if (rctbl)
+       if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
                ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
                                       txi->control.rates,
                                       ARRAY_SIZE(txi->control.rates));
@@@ -1013,7 -1222,7 +1222,7 @@@ static void mac80211_hwsim_tx_frame(str
  {
        u32 _pid = ACCESS_ONCE(wmediumd_portid);
  
-       if (rctbl) {
+       if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) {
                struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
                ieee80211_get_tx_rates(txi->control.vif, NULL, skb,
                                       txi->control.rates,
@@@ -1050,7 -1259,7 +1259,7 @@@ static void mac80211_hwsim_beacon_tx(vo
        if (skb == NULL)
                return;
        info = IEEE80211_SKB_CB(skb);
-       if (rctbl)
+       if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
                ieee80211_get_tx_rates(vif, NULL, skb,
                                       info->control.rates,
                                       ARRAY_SIZE(info->control.rates));
@@@ -1141,7 -1350,7 +1350,7 @@@ static int mac80211_hwsim_config(struc
  
        data->channel = conf->chandef.chan;
  
-       WARN_ON(data->channel && channels > 1);
+       WARN_ON(data->channel && data->channels > 1);
  
        data->power_level = conf->power_level;
        if (!data->started || !data->beacon_int)
@@@ -1388,8 -1597,6 +1597,6 @@@ static const struct nla_policy hwsim_te
        [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
  };
  
- static int hwsim_fops_ps_write(void *dat, u64 val);
  static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       void *data, int len)
@@@ -1700,8 -1907,7 +1907,7 @@@ static void mac80211_hwsim_unassign_vif
        hwsim_check_chanctx_magic(ctx);
  }
  
- static struct ieee80211_ops mac80211_hwsim_ops =
- {
+ static const struct ieee80211_ops mac80211_hwsim_ops = {
        .tx = mac80211_hwsim_tx,
        .start = mac80211_hwsim_start,
        .stop = mac80211_hwsim_stop,
        .set_tsf = mac80211_hwsim_set_tsf,
  };
  
+ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
  
- static void mac80211_hwsim_free(void)
+ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
+                                      const struct ieee80211_regdomain *regd,
+                                      bool reg_strict)
  {
-       struct list_head tmplist, *i, *tmp;
-       struct mac80211_hwsim_data *data, *tmpdata;
-       INIT_LIST_HEAD(&tmplist);
+       int err;
+       u8 addr[ETH_ALEN];
+       struct mac80211_hwsim_data *data;
+       struct ieee80211_hw *hw;
+       enum ieee80211_band band;
+       const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
+       int idx;
  
        spin_lock_bh(&hwsim_radio_lock);
-       list_for_each_safe(i, tmp, &hwsim_radios)
-               list_move(i, &tmplist);
+       idx = hwsim_radio_idx++;
        spin_unlock_bh(&hwsim_radio_lock);
  
-       list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
-               debugfs_remove_recursive(data->debugfs);
-               ieee80211_unregister_hw(data->hw);
-               device_release_driver(data->dev);
-               device_unregister(data->dev);
-               ieee80211_free_hw(data->hw);
+       if (channels > 1)
+               ops = &mac80211_hwsim_mchan_ops;
+       hw = ieee80211_alloc_hw(sizeof(*data), ops);
+       if (!hw) {
+               printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
+               err = -ENOMEM;
+               goto failed;
+       }
+       data = hw->priv;
+       data->hw = hw;
+       data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx);
+       if (IS_ERR(data->dev)) {
+               printk(KERN_DEBUG
+                      "mac80211_hwsim: device_create failed (%ld)\n",
+                      PTR_ERR(data->dev));
+               err = -ENOMEM;
+               goto failed_drvdata;
+       }
+       data->dev->driver = &mac80211_hwsim_driver.driver;
+       err = device_bind_driver(data->dev);
+       if (err != 0) {
+               printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n",
+                      err);
+               goto failed_hw;
        }
-       class_destroy(hwsim_class);
- }
  
- static struct platform_driver mac80211_hwsim_driver = {
-       .driver = {
-               .name = "mac80211_hwsim",
-               .owner = THIS_MODULE,
-       },
- };
+       skb_queue_head_init(&data->pending);
  
- static const struct net_device_ops hwsim_netdev_ops = {
-       .ndo_start_xmit         = hwsim_mon_xmit,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
- };
+       SET_IEEE80211_DEV(hw, data->dev);
+       memset(addr, 0, ETH_ALEN);
+       addr[0] = 0x02;
+       addr[3] = idx >> 8;
+       addr[4] = idx;
+       memcpy(data->addresses[0].addr, addr, ETH_ALEN);
+       memcpy(data->addresses[1].addr, addr, ETH_ALEN);
+       data->addresses[1].addr[0] |= 0x40;
+       hw->wiphy->n_addresses = 2;
+       hw->wiphy->addresses = data->addresses;
+       data->channels = channels;
+       data->idx = idx;
+       if (data->channels > 1) {
+               hw->wiphy->max_scan_ssids = 255;
+               hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+               hw->wiphy->max_remain_on_channel_duration = 1000;
+               /* For channels > 1 DFS is not allowed */
+               hw->wiphy->n_iface_combinations = 1;
+               hw->wiphy->iface_combinations = &data->if_combination;
+               data->if_combination = hwsim_if_comb[0];
+               data->if_combination.num_different_channels = data->channels;
+       } else {
+               hw->wiphy->iface_combinations = hwsim_if_comb;
+               hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
+       }
  
- static void hwsim_mon_setup(struct net_device *dev)
- {
-       dev->netdev_ops = &hwsim_netdev_ops;
-       dev->destructor = free_netdev;
-       ether_setup(dev);
-       dev->tx_queue_len = 0;
-       dev->type = ARPHRD_IEEE80211_RADIOTAP;
-       memset(dev->dev_addr, 0, ETH_ALEN);
-       dev->dev_addr[0] = 0x12;
- }
+       INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
+       INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
+       hw->queues = 5;
+       hw->offchannel_tx_hw_queue = 4;
+       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                    BIT(NL80211_IFTYPE_AP) |
+                                    BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                    BIT(NL80211_IFTYPE_P2P_GO) |
+                                    BIT(NL80211_IFTYPE_ADHOC) |
+                                    BIT(NL80211_IFTYPE_MESH_POINT) |
+                                    BIT(NL80211_IFTYPE_P2P_DEVICE);
+       hw->flags = IEEE80211_HW_MFP_CAPABLE |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_SUPPORTS_STATIC_SMPS |
+                   IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                   IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_WANT_MONITOR_VIF |
+                   IEEE80211_HW_QUEUE_CONTROL |
+                   IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+       if (rctbl)
+               hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
+                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                           WIPHY_FLAG_AP_UAPSD;
+       hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+       /* ask mac80211 to reserve space for magic */
+       hw->vif_data_size = sizeof(struct hwsim_vif_priv);
+       hw->sta_data_size = sizeof(struct hwsim_sta_priv);
+       hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv);
+       memcpy(data->channels_2ghz, hwsim_channels_2ghz,
+               sizeof(hwsim_channels_2ghz));
+       memcpy(data->channels_5ghz, hwsim_channels_5ghz,
+               sizeof(hwsim_channels_5ghz));
+       memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
+       for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
+               struct ieee80211_supported_band *sband = &data->bands[band];
+               switch (band) {
+               case IEEE80211_BAND_2GHZ:
+                       sband->channels = data->channels_2ghz;
+                       sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz);
+                       sband->bitrates = data->rates;
+                       sband->n_bitrates = ARRAY_SIZE(hwsim_rates);
+                       break;
+               case IEEE80211_BAND_5GHZ:
+                       sband->channels = data->channels_5ghz;
+                       sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
+                       sband->bitrates = data->rates + 4;
+                       sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
+                       break;
+               default:
+                       continue;
+               }
  
+               sband->ht_cap.ht_supported = true;
+               sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                                   IEEE80211_HT_CAP_GRN_FLD |
+                                   IEEE80211_HT_CAP_SGI_40 |
+                                   IEEE80211_HT_CAP_DSSSCCK40;
+               sband->ht_cap.ampdu_factor = 0x3;
+               sband->ht_cap.ampdu_density = 0x6;
+               memset(&sband->ht_cap.mcs, 0,
+                      sizeof(sband->ht_cap.mcs));
+               sband->ht_cap.mcs.rx_mask[0] = 0xff;
+               sband->ht_cap.mcs.rx_mask[1] = 0xff;
+               sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+               hw->wiphy->bands[band] = sband;
+               sband->vht_cap.vht_supported = true;
+               sband->vht_cap.cap =
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+                       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+                       IEEE80211_VHT_CAP_RXLDPC |
+                       IEEE80211_VHT_CAP_SHORT_GI_80 |
+                       IEEE80211_VHT_CAP_SHORT_GI_160 |
+                       IEEE80211_VHT_CAP_TXSTBC |
+                       IEEE80211_VHT_CAP_RXSTBC_1 |
+                       IEEE80211_VHT_CAP_RXSTBC_2 |
+                       IEEE80211_VHT_CAP_RXSTBC_3 |
+                       IEEE80211_VHT_CAP_RXSTBC_4 |
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+               sband->vht_cap.vht_mcs.rx_mcs_map =
+                       cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
+               sband->vht_cap.vht_mcs.tx_mcs_map =
+                       sband->vht_cap.vht_mcs.rx_mcs_map;
+       }
  
- static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
- {
-       struct mac80211_hwsim_data *data = dat;
-       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-       struct sk_buff *skb;
-       struct ieee80211_pspoll *pspoll;
+       /* By default all radios belong to the first group */
+       data->group = 1;
+       mutex_init(&data->mutex);
  
-       if (!vp->assoc)
-               return;
-       wiphy_debug(data->hw->wiphy,
-                   "%s: send PS-Poll to %pM for aid %d\n",
-                   __func__, vp->bssid, vp->aid);
-       skb = dev_alloc_skb(sizeof(*pspoll));
-       if (!skb)
-               return;
-       pspoll = (void *) skb_put(skb, sizeof(*pspoll));
-       pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
-                                           IEEE80211_STYPE_PSPOLL |
-                                           IEEE80211_FCTL_PM);
-       pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
-       memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
-       memcpy(pspoll->ta, mac, ETH_ALEN);
-       rcu_read_lock();
-       mac80211_hwsim_tx_frame(data->hw, skb,
-                               rcu_dereference(vif->chanctx_conf)->def.chan);
-       rcu_read_unlock();
- }
+       /* Enable frame retransmissions for lossy channels */
+       hw->max_rates = 4;
+       hw->max_rate_tries = 11;
  
- static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
-                               struct ieee80211_vif *vif, int ps)
- {
-       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-       struct sk_buff *skb;
-       struct ieee80211_hdr *hdr;
+       if (reg_strict)
+               hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
+       if (regd) {
+               hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+               wiphy_apply_custom_regulatory(hw->wiphy, regd);
+               /* give the regulatory workqueue a chance to run */
+               schedule_timeout_interruptible(1);
+       }
  
-       if (!vp->assoc)
-               return;
+       err = ieee80211_register_hw(hw);
+       if (err < 0) {
+               printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
+                      err);
+               goto failed_hw;
+       }
  
-       wiphy_debug(data->hw->wiphy,
-                   "%s: send data::nullfunc to %pM ps=%d\n",
-                   __func__, vp->bssid, ps);
+       wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
  
-       skb = dev_alloc_skb(sizeof(*hdr));
-       if (!skb)
-               return;
-       hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
-       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
-                                        IEEE80211_STYPE_NULLFUNC |
-                                        (ps ? IEEE80211_FCTL_PM : 0));
-       hdr->duration_id = cpu_to_le16(0);
-       memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
-       memcpy(hdr->addr2, mac, ETH_ALEN);
-       memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+       if (reg_alpha2)
+               regulatory_hint(hw->wiphy, reg_alpha2);
  
-       rcu_read_lock();
-       mac80211_hwsim_tx_frame(data->hw, skb,
-                               rcu_dereference(vif->chanctx_conf)->def.chan);
-       rcu_read_unlock();
- }
+       data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
+       debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
+       debugfs_create_file("group", 0666, data->debugfs, data,
+                           &hwsim_fops_group);
+       if (data->channels == 1)
+               debugfs_create_file("dfs_simulate_radar", 0222,
+                                   data->debugfs,
+                                   data, &hwsim_simulate_radar);
  
+       tasklet_hrtimer_init(&data->beacon_timer,
+                            mac80211_hwsim_beacon,
+                            CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
  
- static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
-                                  struct ieee80211_vif *vif)
- {
-       struct mac80211_hwsim_data *data = dat;
-       hwsim_send_nullfunc(data, mac, vif, 1);
- }
+       spin_lock_bh(&hwsim_radio_lock);
+       list_add_tail(&data->list, &hwsim_radios);
+       spin_unlock_bh(&hwsim_radio_lock);
  
+       return idx;
  
- static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
-                                     struct ieee80211_vif *vif)
- {
-       struct mac80211_hwsim_data *data = dat;
-       hwsim_send_nullfunc(data, mac, vif, 0);
+ failed_hw:
+       device_unregister(data->dev);
+ failed_drvdata:
+       ieee80211_free_hw(hw);
+ failed:
+       return err;
  }
  
- static int hwsim_fops_ps_read(void *dat, u64 *val)
+ static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
  {
-       struct mac80211_hwsim_data *data = dat;
-       *val = data->ps;
-       return 0;
+       debugfs_remove_recursive(data->debugfs);
+       ieee80211_unregister_hw(data->hw);
+       device_release_driver(data->dev);
+       device_unregister(data->dev);
+       ieee80211_free_hw(data->hw);
  }
  
- static int hwsim_fops_ps_write(void *dat, u64 val)
+ static void mac80211_hwsim_free(void)
  {
-       struct mac80211_hwsim_data *data = dat;
-       enum ps_mode old_ps;
-       if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
-           val != PS_MANUAL_POLL)
-               return -EINVAL;
-       old_ps = data->ps;
-       data->ps = val;
+       struct mac80211_hwsim_data *data;
  
-       if (val == PS_MANUAL_POLL) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_ps_poll, data);
-               data->ps_poll_pending = true;
-       } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_nullfunc_ps,
-                                                   data);
-       } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_nullfunc_no_ps,
-                                                   data);
+       spin_lock_bh(&hwsim_radio_lock);
+       while ((data = list_first_entry_or_null(&hwsim_radios,
+                                               struct mac80211_hwsim_data,
+                                               list))) {
+               list_del(&data->list);
+               spin_unlock_bh(&hwsim_radio_lock);
+               mac80211_hwsim_destroy_radio(data);
+               spin_lock_bh(&hwsim_radio_lock);
        }
-       return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
-                       "%llu\n");
- static int hwsim_write_simulate_radar(void *dat, u64 val)
- {
-       struct mac80211_hwsim_data *data = dat;
-       ieee80211_radar_detected(data->hw);
-       return 0;
+       spin_unlock_bh(&hwsim_radio_lock);
+       class_destroy(hwsim_class);
  }
  
- DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
-                       hwsim_write_simulate_radar, "%llu\n");
- static int hwsim_fops_group_read(void *dat, u64 *val)
- {
-       struct mac80211_hwsim_data *data = dat;
-       *val = data->group;
-       return 0;
- }
+ static const struct net_device_ops hwsim_netdev_ops = {
+       .ndo_start_xmit         = hwsim_mon_xmit,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+ };
  
- static int hwsim_fops_group_write(void *dat, u64 val)
+ static void hwsim_mon_setup(struct net_device *dev)
  {
-       struct mac80211_hwsim_data *data = dat;
-       data->group = val;
-       return 0;
+       dev->netdev_ops = &hwsim_netdev_ops;
+       dev->destructor = free_netdev;
+       ether_setup(dev);
+       dev->tx_queue_len = 0;
+       dev->type = ARPHRD_IEEE80211_RADIOTAP;
+       memset(dev->dev_addr, 0, ETH_ALEN);
+       dev->dev_addr[0] = 0x12;
  }
  
- DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group,
-                       hwsim_fops_group_read, hwsim_fops_group_write,
-                       "%llx\n");
- static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(
-                            struct mac_address *addr)
+ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
  {
        struct mac80211_hwsim_data *data;
        bool _found = false;
  
        spin_lock_bh(&hwsim_radio_lock);
        list_for_each_entry(data, &hwsim_radios, list) {
-               if (memcmp(data->addresses[1].addr, addr,
-                         sizeof(struct mac_address)) == 0) {
+               if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
                        _found = true;
                        break;
                }
@@@ -1959,27 -2238,26 +2238,26 @@@ static int hwsim_tx_info_frame_received
        struct hwsim_tx_rate *tx_attempts;
        unsigned long ret_skb_ptr;
        struct sk_buff *skb, *tmp;
-       struct mac_address *src;
+       const u8 *src;
        unsigned int hwsim_flags;
        int i;
        bool found = false;
  
+       if (info->snd_portid != wmediumd_portid)
+               return -EINVAL;
        if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
-          !info->attrs[HWSIM_ATTR_FLAGS] ||
-          !info->attrs[HWSIM_ATTR_COOKIE] ||
-          !info->attrs[HWSIM_ATTR_TX_INFO])
+           !info->attrs[HWSIM_ATTR_FLAGS] ||
+           !info->attrs[HWSIM_ATTR_COOKIE] ||
+           !info->attrs[HWSIM_ATTR_TX_INFO])
                goto out;
  
-       src = (struct mac_address *)nla_data(
-                                  info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
+       src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
        hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
        ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
  
        data2 = get_hwsim_data_ref_from_addr(src);
-       if (data2 == NULL)
+       if (!data2)
                goto out;
  
        /* look for the skb matching the cookie passed back from user */
           (hwsim_flags & HWSIM_TX_STAT_ACK)) {
                if (skb->len >= 16) {
                        hdr = (struct ieee80211_hdr *) skb->data;
 -                      mac80211_hwsim_monitor_ack(txi->rate_driver_data[0],
 +                      mac80211_hwsim_monitor_ack(data2->channel,
                                                   hdr->addr2);
                }
                txi->flags |= IEEE80211_TX_STAT_ACK;
@@@ -2036,38 -2314,37 +2314,37 @@@ static int hwsim_cloned_frame_received_
  
        struct mac80211_hwsim_data *data2;
        struct ieee80211_rx_status rx_status;
-       struct mac_address *dst;
+       const u8 *dst;
        int frame_data_len;
-       char *frame_data;
+       void *frame_data;
        struct sk_buff *skb = NULL;
  
+       if (info->snd_portid != wmediumd_portid)
+               return -EINVAL;
        if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
            !info->attrs[HWSIM_ATTR_FRAME] ||
            !info->attrs[HWSIM_ATTR_RX_RATE] ||
            !info->attrs[HWSIM_ATTR_SIGNAL])
                goto out;
  
-       dst = (struct mac_address *)nla_data(
-                                  info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
+       dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
        frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
-       frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
+       frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
  
        /* Allocate new skb here */
        skb = alloc_skb(frame_data_len, GFP_KERNEL);
        if (skb == NULL)
                goto err;
  
-       if (frame_data_len <= IEEE80211_MAX_DATA_LEN) {
-               /* Copy the data */
-               memcpy(skb_put(skb, frame_data_len), frame_data,
-                      frame_data_len);
-       } else
+       if (frame_data_len > IEEE80211_MAX_DATA_LEN)
                goto err;
  
-       data2 = get_hwsim_data_ref_from_addr(dst);
+       /* Copy the data */
+       memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
  
-       if (data2 == NULL)
+       data2 = get_hwsim_data_ref_from_addr(dst);
+       if (!data2)
                goto out;
  
        /* check if radio is configured properly */
        if (data2->idle || !data2->started)
                goto out;
  
-       /*A frame is received from user space*/
+       /* A frame is received from user space */
        memset(&rx_status, 0, sizeof(rx_status));
        rx_status.freq = data2->channel->center_freq;
        rx_status.band = data2->channel->band;
  static int hwsim_register_received_nl(struct sk_buff *skb_2,
                                      struct genl_info *info)
  {
-       if (info == NULL)
-               goto out;
+       struct mac80211_hwsim_data *data;
+       int chans = 1;
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry(data, &hwsim_radios, list)
+               chans = max(chans, data->channels);
+       spin_unlock_bh(&hwsim_radio_lock);
+       /* In the future we should revise the userspace API and allow it
+        * to set a flag that it does support multi-channel, then we can
+        * let this pass conditionally on the flag.
+        * For current userspace, prohibit it since it won't work right.
+        */
+       if (chans > 1)
+               return -EOPNOTSUPP;
+       if (wmediumd_portid)
+               return -EBUSY;
  
        wmediumd_portid = info->snd_portid;
  
               "switching to wmediumd mode with pid %d\n", info->snd_portid);
  
        return 0;
- out:
-       printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
-       return -EINVAL;
+ }
+ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
+ {
+       unsigned int chans = channels;
+       const char *alpha2 = NULL;
+       const struct ieee80211_regdomain *regd = NULL;
+       bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+       if (info->attrs[HWSIM_ATTR_CHANNELS])
+               chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+       if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
+               alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
+       if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
+               u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
+               if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
+                       return -EINVAL;
+               regd = hwsim_world_regdom_custom[idx];
+       }
+       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict);
+ }
+ static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+ {
+       struct mac80211_hwsim_data *data;
+       int idx;
+       if (!info->attrs[HWSIM_ATTR_RADIO_ID])
+               return -EINVAL;
+       idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry(data, &hwsim_radios, list) {
+               if (data->idx != idx)
+                       continue;
+               list_del(&data->list);
+               spin_unlock_bh(&hwsim_radio_lock);
+               mac80211_hwsim_destroy_radio(data);
+               return 0;
+       }
+       spin_unlock_bh(&hwsim_radio_lock);
+       return -ENODEV;
  }
  
  /* Generic Netlink operations array */
@@@ -2129,6 -2466,18 +2466,18 @@@ static const struct genl_ops hwsim_ops[
                .policy = hwsim_genl_policy,
                .doit = hwsim_tx_info_frame_received_nl,
        },
+       {
+               .cmd = HWSIM_CMD_CREATE_RADIO,
+               .policy = hwsim_genl_policy,
+               .doit = hwsim_create_radio_nl,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = HWSIM_CMD_DESTROY_RADIO,
+               .policy = hwsim_genl_policy,
+               .doit = hwsim_destroy_radio_nl,
+               .flags = GENL_ADMIN_PERM,
+       },
  };
  
  static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
@@@ -2157,10 -2506,6 +2506,6 @@@ static int hwsim_init_netlink(void
  {
        int rc;
  
-       /* userspace test API hasn't been adjusted for multi-channel */
-       if (channels > 1)
-               return 0;
        printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
  
        rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
@@@ -2180,94 -2525,36 +2525,36 @@@ failure
  
  static void hwsim_exit_netlink(void)
  {
-       int ret;
-       /* userspace test API hasn't been adjusted for multi-channel */
-       if (channels > 1)
-               return;
-       printk(KERN_INFO "mac80211_hwsim: closing netlink\n");
        /* unregister the notifier */
        netlink_unregister_notifier(&hwsim_netlink_notifier);
        /* unregister the family */
-       ret = genl_unregister_family(&hwsim_genl_family);
-       if (ret)
-               printk(KERN_DEBUG "mac80211_hwsim: "
-                      "unregister family %i\n", ret);
+       genl_unregister_family(&hwsim_genl_family);
  }
  
- static const struct ieee80211_iface_limit hwsim_if_limits[] = {
-       { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
-       { .max = 2048,  .types = BIT(NL80211_IFTYPE_STATION) |
-                                BIT(NL80211_IFTYPE_P2P_CLIENT) |
- #ifdef CONFIG_MAC80211_MESH
-                                BIT(NL80211_IFTYPE_MESH_POINT) |
- #endif
-                                BIT(NL80211_IFTYPE_AP) |
-                                BIT(NL80211_IFTYPE_P2P_GO) },
-       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
- };
- static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
-       { .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
- };
- static struct ieee80211_iface_combination hwsim_if_comb[] = {
-       {
-               .limits = hwsim_if_limits,
-               .n_limits = ARRAY_SIZE(hwsim_if_limits),
-               .max_interfaces = 2048,
-               .num_different_channels = 1,
-       },
-       {
-               .limits = hwsim_if_dfs_limits,
-               .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
-               .max_interfaces = 8,
-               .num_different_channels = 1,
-               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-                                      BIT(NL80211_CHAN_WIDTH_20) |
-                                      BIT(NL80211_CHAN_WIDTH_40) |
-                                      BIT(NL80211_CHAN_WIDTH_80) |
-                                      BIT(NL80211_CHAN_WIDTH_160),
-       }
- };
  static int __init init_mac80211_hwsim(void)
  {
-       int i, err = 0;
-       u8 addr[ETH_ALEN];
-       struct mac80211_hwsim_data *data;
-       struct ieee80211_hw *hw;
-       enum ieee80211_band band;
+       int i, err;
  
-       if (radios < 1 || radios > 100)
+       if (radios < 0 || radios > 100)
                return -EINVAL;
  
        if (channels < 1)
                return -EINVAL;
  
-       if (channels > 1) {
-               hwsim_if_comb[0].num_different_channels = channels;
-               mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
-               mac80211_hwsim_ops.cancel_hw_scan =
-                       mac80211_hwsim_cancel_hw_scan;
-               mac80211_hwsim_ops.sw_scan_start = NULL;
-               mac80211_hwsim_ops.sw_scan_complete = NULL;
-               mac80211_hwsim_ops.remain_on_channel =
-                       mac80211_hwsim_roc;
-               mac80211_hwsim_ops.cancel_remain_on_channel =
-                       mac80211_hwsim_croc;
-               mac80211_hwsim_ops.add_chanctx =
-                       mac80211_hwsim_add_chanctx;
-               mac80211_hwsim_ops.remove_chanctx =
-                       mac80211_hwsim_remove_chanctx;
-               mac80211_hwsim_ops.change_chanctx =
-                       mac80211_hwsim_change_chanctx;
-               mac80211_hwsim_ops.assign_vif_chanctx =
-                       mac80211_hwsim_assign_vif_chanctx;
-               mac80211_hwsim_ops.unassign_vif_chanctx =
-                       mac80211_hwsim_unassign_vif_chanctx;
-       }
+       mac80211_hwsim_mchan_ops = mac80211_hwsim_ops;
+       mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan;
+       mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan;
+       mac80211_hwsim_mchan_ops.sw_scan_start = NULL;
+       mac80211_hwsim_mchan_ops.sw_scan_complete = NULL;
+       mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc;
+       mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc;
+       mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx;
+       mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx;
+       mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx;
+       mac80211_hwsim_mchan_ops.assign_vif_chanctx =
+               mac80211_hwsim_assign_vif_chanctx;
+       mac80211_hwsim_mchan_ops.unassign_vif_chanctx =
+               mac80211_hwsim_unassign_vif_chanctx;
  
        spin_lock_init(&hwsim_radio_lock);
        INIT_LIST_HEAD(&hwsim_radios);
        hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
        if (IS_ERR(hwsim_class)) {
                err = PTR_ERR(hwsim_class);
-               goto failed_unregister_driver;
+               goto out_unregister_driver;
        }
  
-       memset(addr, 0, ETH_ALEN);
-       addr[0] = 0x02;
        for (i = 0; i < radios; i++) {
-               printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n",
-                      i);
-               hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops);
-               if (!hw) {
-                       printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw "
-                              "failed\n");
-                       err = -ENOMEM;
-                       goto failed;
-               }
-               data = hw->priv;
-               data->hw = hw;
-               data->dev = device_create(hwsim_class, NULL, 0, hw,
-                                         "hwsim%d", i);
-               if (IS_ERR(data->dev)) {
-                       printk(KERN_DEBUG
-                              "mac80211_hwsim: device_create failed (%ld)\n",
-                              PTR_ERR(data->dev));
-                       err = -ENOMEM;
-                       goto failed_drvdata;
-               }
-               data->dev->driver = &mac80211_hwsim_driver.driver;
-               err = device_bind_driver(data->dev);
-               if (err != 0) {
-                       printk(KERN_DEBUG
-                              "mac80211_hwsim: device_bind_driver failed (%d)\n",
-                              err);
-                       goto failed_hw;
-               }
-               skb_queue_head_init(&data->pending);
-               SET_IEEE80211_DEV(hw, data->dev);
-               addr[3] = i >> 8;
-               addr[4] = i;
-               memcpy(data->addresses[0].addr, addr, ETH_ALEN);
-               memcpy(data->addresses[1].addr, addr, ETH_ALEN);
-               data->addresses[1].addr[0] |= 0x40;
-               hw->wiphy->n_addresses = 2;
-               hw->wiphy->addresses = data->addresses;
-               hw->wiphy->iface_combinations = hwsim_if_comb;
-               hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
-               if (channels > 1) {
-                       hw->wiphy->max_scan_ssids = 255;
-                       hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
-                       hw->wiphy->max_remain_on_channel_duration = 1000;
-                       /* For channels > 1 DFS is not allowed */
-                       hw->wiphy->n_iface_combinations = 1;
-               }
-               INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
-               INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
-               hw->channel_change_time = 1;
-               hw->queues = 5;
-               hw->offchannel_tx_hw_queue = 4;
-               hw->wiphy->interface_modes =
-                       BIT(NL80211_IFTYPE_STATION) |
-                       BIT(NL80211_IFTYPE_AP) |
-                       BIT(NL80211_IFTYPE_P2P_CLIENT) |
-                       BIT(NL80211_IFTYPE_P2P_GO) |
-                       BIT(NL80211_IFTYPE_ADHOC) |
-                       BIT(NL80211_IFTYPE_MESH_POINT) |
-                       BIT(NL80211_IFTYPE_P2P_DEVICE);
-               hw->flags = IEEE80211_HW_MFP_CAPABLE |
-                           IEEE80211_HW_SIGNAL_DBM |
-                           IEEE80211_HW_SUPPORTS_STATIC_SMPS |
-                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                           IEEE80211_HW_AMPDU_AGGREGATION |
-                           IEEE80211_HW_WANT_MONITOR_VIF |
-                           IEEE80211_HW_QUEUE_CONTROL |
-                           IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
-               if (rctbl)
-                       hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
-               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
-                                   WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-                                   WIPHY_FLAG_AP_UAPSD;
-               hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
-               /* ask mac80211 to reserve space for magic */
-               hw->vif_data_size = sizeof(struct hwsim_vif_priv);
-               hw->sta_data_size = sizeof(struct hwsim_sta_priv);
-               hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv);
-               memcpy(data->channels_2ghz, hwsim_channels_2ghz,
-                       sizeof(hwsim_channels_2ghz));
-               memcpy(data->channels_5ghz, hwsim_channels_5ghz,
-                       sizeof(hwsim_channels_5ghz));
-               memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
-               for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
-                       struct ieee80211_supported_band *sband = &data->bands[band];
-                       switch (band) {
-                       case IEEE80211_BAND_2GHZ:
-                               sband->channels = data->channels_2ghz;
-                               sband->n_channels =
-                                       ARRAY_SIZE(hwsim_channels_2ghz);
-                               sband->bitrates = data->rates;
-                               sband->n_bitrates = ARRAY_SIZE(hwsim_rates);
-                               break;
-                       case IEEE80211_BAND_5GHZ:
-                               sband->channels = data->channels_5ghz;
-                               sband->n_channels =
-                                       ARRAY_SIZE(hwsim_channels_5ghz);
-                               sband->bitrates = data->rates + 4;
-                               sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
-                               break;
-                       default:
-                               continue;
-                       }
-                       sband->ht_cap.ht_supported = true;
-                       sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                               IEEE80211_HT_CAP_GRN_FLD |
-                               IEEE80211_HT_CAP_SGI_40 |
-                               IEEE80211_HT_CAP_DSSSCCK40;
-                       sband->ht_cap.ampdu_factor = 0x3;
-                       sband->ht_cap.ampdu_density = 0x6;
-                       memset(&sband->ht_cap.mcs, 0,
-                              sizeof(sband->ht_cap.mcs));
-                       sband->ht_cap.mcs.rx_mask[0] = 0xff;
-                       sband->ht_cap.mcs.rx_mask[1] = 0xff;
-                       sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-                       hw->wiphy->bands[band] = sband;
-                       sband->vht_cap.vht_supported = true;
-                       sband->vht_cap.cap =
-                               IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
-                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
-                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
-                               IEEE80211_VHT_CAP_RXLDPC |
-                               IEEE80211_VHT_CAP_SHORT_GI_80 |
-                               IEEE80211_VHT_CAP_SHORT_GI_160 |
-                               IEEE80211_VHT_CAP_TXSTBC |
-                               IEEE80211_VHT_CAP_RXSTBC_1 |
-                               IEEE80211_VHT_CAP_RXSTBC_2 |
-                               IEEE80211_VHT_CAP_RXSTBC_3 |
-                               IEEE80211_VHT_CAP_RXSTBC_4 |
-                               IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
-                       sband->vht_cap.vht_mcs.rx_mcs_map =
-                               cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
-                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
-                       sband->vht_cap.vht_mcs.tx_mcs_map =
-                               sband->vht_cap.vht_mcs.rx_mcs_map;
-               }
-               /* By default all radios are belonging to the first group */
-               data->group = 1;
-               mutex_init(&data->mutex);
+               const char *reg_alpha2 = NULL;
+               const struct ieee80211_regdomain *regd = NULL;
+               bool reg_strict = false;
  
-               /* Enable frame retransmissions for lossy channels */
-               hw->max_rates = 4;
-               hw->max_rate_tries = 11;
-               /* Work to be done prior to ieee80211_register_hw() */
                switch (regtest) {
-               case HWSIM_REGTEST_DISABLED:
-               case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
-               case HWSIM_REGTEST_DRIVER_REG_ALL:
                case HWSIM_REGTEST_DIFF_COUNTRY:
-                       /*
-                        * Nothing to be done for driver regulatory domain
-                        * hints prior to ieee80211_register_hw()
-                        */
-                       break;
-               case HWSIM_REGTEST_WORLD_ROAM:
-                       if (i == 0) {
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_CUSTOM_REG;
-                               wiphy_apply_custom_regulatory(hw->wiphy,
-                                       &hwsim_world_regdom_custom_01);
-                       }
-                       break;
-               case HWSIM_REGTEST_CUSTOM_WORLD:
-                       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
-                       wiphy_apply_custom_regulatory(hw->wiphy,
-                               &hwsim_world_regdom_custom_01);
-                       break;
-               case HWSIM_REGTEST_CUSTOM_WORLD_2:
-                       if (i == 0) {
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_CUSTOM_REG;
-                               wiphy_apply_custom_regulatory(hw->wiphy,
-                                       &hwsim_world_regdom_custom_01);
-                       } else if (i == 1) {
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_CUSTOM_REG;
-                               wiphy_apply_custom_regulatory(hw->wiphy,
-                                       &hwsim_world_regdom_custom_02);
-                       }
-                       break;
-               case HWSIM_REGTEST_STRICT_ALL:
-                       hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
-                       break;
-               case HWSIM_REGTEST_STRICT_FOLLOW:
-               case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
-                       if (i == 0)
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_STRICT_REG;
-                       break;
-               case HWSIM_REGTEST_ALL:
-                       if (i == 0) {
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_CUSTOM_REG;
-                               wiphy_apply_custom_regulatory(hw->wiphy,
-                                       &hwsim_world_regdom_custom_01);
-                       } else if (i == 1) {
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_CUSTOM_REG;
-                               wiphy_apply_custom_regulatory(hw->wiphy,
-                                       &hwsim_world_regdom_custom_02);
-                       } else if (i == 4)
-                               hw->wiphy->regulatory_flags |=
-                                       REGULATORY_STRICT_REG;
-                       break;
-               default:
-                       break;
-               }
-               /* give the regulatory workqueue a chance to run */
-               if (regtest)
-                       schedule_timeout_interruptible(1);
-               err = ieee80211_register_hw(hw);
-               if (err < 0) {
-                       printk(KERN_DEBUG "mac80211_hwsim: "
-                              "ieee80211_register_hw failed (%d)\n", err);
-                       goto failed_hw;
-               }
-               /* Work to be done after to ieee80211_register_hw() */
-               switch (regtest) {
-               case HWSIM_REGTEST_WORLD_ROAM:
-               case HWSIM_REGTEST_DISABLED:
+                       if (i < ARRAY_SIZE(hwsim_alpha2s))
+                               reg_alpha2 = hwsim_alpha2s[i];
                        break;
                case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
                        if (!i)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                               reg_alpha2 = hwsim_alpha2s[0];
                        break;
-               case HWSIM_REGTEST_DRIVER_REG_ALL:
                case HWSIM_REGTEST_STRICT_ALL:
-                       regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       reg_strict = true;
+               case HWSIM_REGTEST_DRIVER_REG_ALL:
+                       reg_alpha2 = hwsim_alpha2s[0];
                        break;
-               case HWSIM_REGTEST_DIFF_COUNTRY:
-                       if (i < ARRAY_SIZE(hwsim_alpha2s))
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[i]);
+               case HWSIM_REGTEST_WORLD_ROAM:
+                       if (i == 0)
+                               regd = &hwsim_world_regdom_custom_01;
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD:
+                       regd = &hwsim_world_regdom_custom_01;
+                       break;
                case HWSIM_REGTEST_CUSTOM_WORLD_2:
-                       /*
-                        * Nothing to be done for custom world regulatory
-                        * domains after to ieee80211_register_hw
-                        */
+                       if (i == 0)
+                               regd = &hwsim_world_regdom_custom_01;
+                       else if (i == 1)
+                               regd = &hwsim_world_regdom_custom_02;
                        break;
                case HWSIM_REGTEST_STRICT_FOLLOW:
-                       if (i == 0)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       if (i == 0) {
+                               reg_strict = true;
+                               reg_alpha2 = hwsim_alpha2s[0];
+                       }
                        break;
                case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
-                       if (i == 0)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
-                       else if (i == 1)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[1]);
+                       if (i == 0) {
+                               reg_strict = true;
+                               reg_alpha2 = hwsim_alpha2s[0];
+                       } else if (i == 1) {
+                               reg_alpha2 = hwsim_alpha2s[1];
+                       }
                        break;
                case HWSIM_REGTEST_ALL:
-                       if (i == 2)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
-                       else if (i == 3)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[1]);
-                       else if (i == 4)
-                               regulatory_hint(hw->wiphy, hwsim_alpha2s[2]);
+                       switch (i) {
+                       case 0:
+                               regd = &hwsim_world_regdom_custom_01;
+                               break;
+                       case 1:
+                               regd = &hwsim_world_regdom_custom_02;
+                               break;
+                       case 2:
+                               reg_alpha2 = hwsim_alpha2s[0];
+                               break;
+                       case 3:
+                               reg_alpha2 = hwsim_alpha2s[1];
+                               break;
+                       case 4:
+                               reg_strict = true;
+                               reg_alpha2 = hwsim_alpha2s[2];
+                               break;
+                       }
                        break;
                default:
                        break;
                }
  
-               wiphy_debug(hw->wiphy, "hwaddr %pm registered\n",
-                           hw->wiphy->perm_addr);
-               data->debugfs = debugfs_create_dir("hwsim",
-                                                  hw->wiphy->debugfsdir);
-               debugfs_create_file("ps", 0666, data->debugfs, data,
-                                   &hwsim_fops_ps);
-               debugfs_create_file("group", 0666, data->debugfs, data,
-                                   &hwsim_fops_group);
-               if (channels == 1)
-                       debugfs_create_file("dfs_simulate_radar", 0222,
-                                           data->debugfs,
-                                           data, &hwsim_simulate_radar);
-               tasklet_hrtimer_init(&data->beacon_timer,
-                                    mac80211_hwsim_beacon,
-                                    CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
-               list_add_tail(&data->list, &hwsim_radios);
+               err = mac80211_hwsim_create_radio(channels, reg_alpha2,
+                                                 regd, reg_strict);
+               if (err < 0)
+                       goto out_free_radios;
        }
  
        hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup);
        if (hwsim_mon == NULL) {
                err = -ENOMEM;
-               goto failed;
+               goto out_free_radios;
        }
  
        rtnl_lock();
        err = dev_alloc_name(hwsim_mon, hwsim_mon->name);
-       if (err < 0)
-               goto failed_mon;
+       if (err < 0) {
+               rtnl_unlock();
+               goto out_free_radios;
+       }
  
        err = register_netdevice(hwsim_mon);
-       if (err < 0)
-               goto failed_mon;
+       if (err < 0) {
+               rtnl_unlock();
+               goto out_free_mon;
+       }
        rtnl_unlock();
  
        err = hwsim_init_netlink();
        if (err < 0)
-               goto failed_nl;
+               goto out_free_mon;
  
        return 0;
  
- failed_nl:
-       printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n");
-       return err;
- failed_mon:
-       rtnl_unlock();
+ out_free_mon:
        free_netdev(hwsim_mon);
+ out_free_radios:
        mac80211_hwsim_free();
-       return err;
- failed_hw:
-       device_unregister(data->dev);
- failed_drvdata:
-       ieee80211_free_hw(hw);
- failed:
-       mac80211_hwsim_free();
- failed_unregister_driver:
+ out_unregister_driver:
        platform_driver_unregister(&mac80211_hwsim_driver);
        return err;
  }
@@@ -525,7 -525,7 +525,7 @@@ static int wl1251_op_add_interface(stru
                goto out;
        }
  
 -      if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
 +      if (!ether_addr_equal_unaligned(wl->mac_addr, vif->addr)) {
                memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
                SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
                ret = wl1251_acx_station_id(wl);
@@@ -1468,7 -1468,6 +1468,6 @@@ int wl1251_init_ieee80211(struct wl125
  
        /* unit us */
        /* FIXME: find a proper value */
-       wl->hw->channel_change_time = 10000;
  
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_SUPPORTS_PS |
@@@ -21,7 -21,8 +21,7 @@@
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
 - *  along with this program; if not, write to the Free Software
 - *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
   *
   */
  
@@@ -67,6 -68,7 +67,7 @@@ struct nci_ops 
        int (*open)(struct nci_dev *ndev);
        int (*close)(struct nci_dev *ndev);
        int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
+       int (*setup)(struct nci_dev *ndev);
  };
  
  #define NCI_MAX_SUPPORTED_RF_INTERFACES               4
@@@ -153,6 -155,7 +154,7 @@@ void nci_free_device(struct nci_dev *nd
  int nci_register_device(struct nci_dev *ndev);
  void nci_unregister_device(struct nci_dev *ndev);
  int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
+ int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val);
  
  static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev,
                                            unsigned int len,
diff --combined net/mac80211/tx.c
@@@ -464,6 -464,7 +464,6 @@@ ieee80211_tx_h_unicast_ps_buf(struct ie
  {
        struct sta_info *sta = tx->sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 -      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
  
        if (unlikely(!sta))
                     !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
                int ac = skb_get_queue_mapping(tx->skb);
  
 -              /* only deauth, disassoc and action are bufferable MMPDUs */
 -              if (ieee80211_is_mgmt(hdr->frame_control) &&
 -                  !ieee80211_is_deauth(hdr->frame_control) &&
 -                  !ieee80211_is_disassoc(hdr->frame_control) &&
 -                  !ieee80211_is_action(hdr->frame_control)) {
 -                      info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
 -                      return TX_CONTINUE;
 -              }
 -
                ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                info->control.jiffies = jiffies;
                info->control.vif = &tx->sdata->vif;
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+               info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
                skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
  
                if (!timer_pending(&local->sta_cleanup))
  static ieee80211_tx_result debug_noinline
  ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
  {
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 +      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 +
        if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
                return TX_CONTINUE;
  
 +      /* only deauth, disassoc and action are bufferable MMPDUs */
 +      if (ieee80211_is_mgmt(hdr->frame_control) &&
 +          !ieee80211_is_deauth(hdr->frame_control) &&
 +          !ieee80211_is_disassoc(hdr->frame_control) &&
 +          !ieee80211_is_action(hdr->frame_control)) {
 +              if (tx->flags & IEEE80211_TX_UNICAST)
 +                      info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
 +              return TX_CONTINUE;
 +      }
 +
        if (tx->flags & IEEE80211_TX_UNICAST)
                return ieee80211_tx_h_unicast_ps_buf(tx);
        else
@@@ -1076,6 -1074,7 +1077,7 @@@ static bool ieee80211_tx_prep_agg(struc
                        queued = true;
                        info->control.vif = &tx->sdata->vif;
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+                       info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
                        __skb_queue_tail(&tid_tx->pending, skb);
                        if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
                                purge_skb = __skb_dequeue(&tid_tx->pending);
diff --combined net/nfc/core.c
@@@ -133,11 -133,8 +133,8 @@@ int nfc_dev_up(struct nfc_dev *dev
                dev->dev_up = true;
  
        /* We have to enable the device before discovering SEs */
-       if (dev->ops->discover_se) {
-               rc = dev->ops->discover_se(dev);
-               if (rc)
-                       pr_warn("SE discovery failed\n");
-       }
+       if (dev->ops->discover_se && dev->ops->discover_se(dev))
+               pr_err("SE discovery failed\n");
  
  error:
        device_unlock(&dev->dev);
@@@ -382,7 -379,7 +379,7 @@@ int nfc_dep_link_is_up(struct nfc_dev *
  {
        dev->dep_link_up = true;
  
 -      if (!dev->active_target) {
 +      if (!dev->active_target && rf_mode == NFC_RF_INITIATOR) {
                struct nfc_target *target;
  
                target = nfc_find_target(dev, target_idx);
diff --combined net/wireless/nl80211.c
@@@ -165,7 -165,7 +165,7 @@@ __cfg80211_rdev_from_attrs(struct net *
  
        if (attrs[NL80211_ATTR_IFINDEX]) {
                int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
 -              netdev = dev_get_by_index(netns, ifindex);
 +              netdev = __dev_get_by_index(netns, ifindex);
                if (netdev) {
                        if (netdev->ieee80211_ptr)
                                tmp = wiphy_to_dev(
                        else
                                tmp = NULL;
  
 -                      dev_put(netdev);
 -
                        /* not wireless device -- return error */
                        if (!tmp)
                                return ERR_PTR(-EINVAL);
@@@ -1654,7 -1656,7 +1654,7 @@@ static int nl80211_dump_wiphy_parse(str
                struct cfg80211_registered_device *rdev;
                int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
  
 -              netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
 +              netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
                if (!netdev)
                        return -ENODEV;
                if (netdev->ieee80211_ptr) {
                                netdev->ieee80211_ptr->wiphy);
                        state->filter_wiphy = rdev->wiphy_idx;
                }
 -              dev_put(netdev);
        }
  
        return 0;
@@@ -1984,7 -1987,7 +1984,7 @@@ static int nl80211_set_wiphy(struct sk_
        if (info->attrs[NL80211_ATTR_IFINDEX]) {
                int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
  
 -              netdev = dev_get_by_index(genl_info_net(info), ifindex);
 +              netdev = __dev_get_by_index(genl_info_net(info), ifindex);
                if (netdev && netdev->ieee80211_ptr)
                        rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
                else
                        rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
  
        if (result)
 -              goto bad_res;
 +              return result;
  
        if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
                struct ieee80211_txq_params txq_params;
                struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
  
 -              if (!rdev->ops->set_txq_params) {
 -                      result = -EOPNOTSUPP;
 -                      goto bad_res;
 -              }
 +              if (!rdev->ops->set_txq_params)
 +                      return -EOPNOTSUPP;
  
 -              if (!netdev) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +              if (!netdev)
 +                      return -EINVAL;
  
                if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 -                  netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +                  netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
 +                      return -EINVAL;
  
 -              if (!netif_running(netdev)) {
 -                      result = -ENETDOWN;
 -                      goto bad_res;
 -              }
 +              if (!netif_running(netdev))
 +                      return -ENETDOWN;
  
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                  txq_params_policy);
                        result = parse_txq_params(tb, &txq_params);
                        if (result)
 -                              goto bad_res;
 +                              return result;
  
                        result = rdev_set_txq_params(rdev, netdev,
                                                     &txq_params);
                        if (result)
 -                              goto bad_res;
 +                              return result;
                }
        }
  
                                nl80211_can_set_dev_channel(wdev) ? wdev : NULL,
                                info);
                if (result)
 -                      goto bad_res;
 +                      return result;
        }
  
        if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
                if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
                        txp_wdev = NULL;
  
 -              if (!rdev->ops->set_tx_power) {
 -                      result = -EOPNOTSUPP;
 -                      goto bad_res;
 -              }
 +              if (!rdev->ops->set_tx_power)
 +                      return -EOPNOTSUPP;
  
                idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
                type = nla_get_u32(info->attrs[idx]);
  
                if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
 -                  (type != NL80211_TX_POWER_AUTOMATIC)) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +                  (type != NL80211_TX_POWER_AUTOMATIC))
 +                      return -EINVAL;
  
                if (type != NL80211_TX_POWER_AUTOMATIC) {
                        idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
  
                result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
                if (result)
 -                      goto bad_res;
 +                      return result;
        }
  
        if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
                u32 tx_ant, rx_ant;
                if ((!rdev->wiphy.available_antennas_tx &&
                     !rdev->wiphy.available_antennas_rx) ||
 -                  !rdev->ops->set_antenna) {
 -                      result = -EOPNOTSUPP;
 -                      goto bad_res;
 -              }
 +                  !rdev->ops->set_antenna)
 +                      return -EOPNOTSUPP;
  
                tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
                rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
                /* reject antenna configurations which don't match the
                 * available antenna masks, except for the "all" mask */
                if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
 -                  (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +                  (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
 +                      return -EINVAL;
  
                tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
                rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
  
                result = rdev_set_antenna(rdev, tx_ant, rx_ant);
                if (result)
 -                      goto bad_res;
 +                      return result;
        }
  
        changed = 0;
        if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
                retry_short = nla_get_u8(
                        info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
 -              if (retry_short == 0) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +              if (retry_short == 0)
 +                      return -EINVAL;
 +
                changed |= WIPHY_PARAM_RETRY_SHORT;
        }
  
        if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
                retry_long = nla_get_u8(
                        info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
 -              if (retry_long == 0) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +              if (retry_long == 0)
 +                      return -EINVAL;
 +
                changed |= WIPHY_PARAM_RETRY_LONG;
        }
  
        if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
                frag_threshold = nla_get_u32(
                        info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
 -              if (frag_threshold < 256) {
 -                      result = -EINVAL;
 -                      goto bad_res;
 -              }
 +              if (frag_threshold < 256)
 +                      return -EINVAL;
 +
                if (frag_threshold != (u32) -1) {
                        /*
                         * Fragments (apart from the last one) are required to
                u32 old_frag_threshold, old_rts_threshold;
                u8 old_coverage_class;
  
 -              if (!rdev->ops->set_wiphy_params) {
 -                      result = -EOPNOTSUPP;
 -                      goto bad_res;
 -              }
 +              if (!rdev->ops->set_wiphy_params)
 +                      return -EOPNOTSUPP;
  
                old_retry_short = rdev->wiphy.retry_short;
                old_retry_long = rdev->wiphy.retry_long;
                        rdev->wiphy.coverage_class = old_coverage_class;
                }
        }
 -
 - bad_res:
 -      if (netdev)
 -              dev_put(netdev);
 -      return result;
 +      return 0;
  }
  
  static inline u64 wdev_id(struct wireless_dev *wdev)
@@@ -5257,12 -5285,7 +5257,7 @@@ static int nl80211_trigger_scan(struct 
                        goto unlock;
                }
        } else {
-               enum ieee80211_band band;
-               n_channels = 0;
-               for (band = 0; band < IEEE80211_NUM_BANDS; band++)
-                       if (wiphy->bands[band])
-                               n_channels += wiphy->bands[band]->n_channels;
+               n_channels = ieee80211_get_num_supported_channels(wiphy);
        }
  
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
@@@ -5470,11 -5493,7 +5465,7 @@@ static int nl80211_start_sched_scan(str
                if (!n_channels)
                        return -EINVAL;
        } else {
-               n_channels = 0;
-               for (band = 0; band < IEEE80211_NUM_BANDS; band++)
-                       if (wiphy->bands[band])
-                               n_channels += wiphy->bands[band]->n_channels;
+               n_channels = ieee80211_get_num_supported_channels(wiphy);
        }
  
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
@@@ -6767,6 -6786,55 +6758,55 @@@ __cfg80211_alloc_vendor_skb(struct cfg8
        return NULL;
  }
  
+ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int vendor_event_idx,
+                                          int approxlen, gfp_t gfp)
+ {
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       const struct nl80211_vendor_cmd_info *info;
+       switch (cmd) {
+       case NL80211_CMD_TESTMODE:
+               if (WARN_ON(vendor_event_idx != -1))
+                       return NULL;
+               info = NULL;
+               break;
+       case NL80211_CMD_VENDOR:
+               if (WARN_ON(vendor_event_idx < 0 ||
+                           vendor_event_idx >= wiphy->n_vendor_events))
+                       return NULL;
+               info = &wiphy->vendor_events[vendor_event_idx];
+               break;
+       default:
+               WARN_ON(1);
+               return NULL;
+       }
+       return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+                                          cmd, attr, info, gfp);
+ }
+ EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
+ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
+ {
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+       void *hdr = ((void **)skb->cb)[1];
+       struct nlattr *data = ((void **)skb->cb)[2];
+       enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
+       nla_nest_end(skb, data);
+       genlmsg_end(skb, hdr);
+       if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
+               mcgrp = NL80211_MCGRP_VENDOR;
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
+                               mcgrp, gfp);
+ }
+ EXPORT_SYMBOL(__cfg80211_send_event_skb);
  #ifdef CONFIG_NL80211_TESTMODE
  static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
  {
@@@ -6893,55 -6961,6 +6933,6 @@@ static int nl80211_testmode_dump(struc
        rtnl_unlock();
        return err;
  }
- struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
-                                          enum nl80211_commands cmd,
-                                          enum nl80211_attrs attr,
-                                          int vendor_event_idx,
-                                          int approxlen, gfp_t gfp)
- {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       const struct nl80211_vendor_cmd_info *info;
-       switch (cmd) {
-       case NL80211_CMD_TESTMODE:
-               if (WARN_ON(vendor_event_idx != -1))
-                       return NULL;
-               info = NULL;
-               break;
-       case NL80211_CMD_VENDOR:
-               if (WARN_ON(vendor_event_idx < 0 ||
-                           vendor_event_idx >= wiphy->n_vendor_events))
-                       return NULL;
-               info = &wiphy->vendor_events[vendor_event_idx];
-               break;
-       default:
-               WARN_ON(1);
-               return NULL;
-       }
-       return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
-                                          cmd, attr, info, gfp);
- }
- EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
- void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
- {
-       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
-       void *hdr = ((void **)skb->cb)[1];
-       struct nlattr *data = ((void **)skb->cb)[2];
-       enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
-       nla_nest_end(skb, data);
-       genlmsg_end(skb, hdr);
-       if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
-               mcgrp = NL80211_MCGRP_VENDOR;
-       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
-                               mcgrp, gfp);
- }
- EXPORT_SYMBOL(__cfg80211_send_event_skb);
  #endif
  
  static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)