]> Pileus Git - ~andy/linux/commitdiff
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
authorJohannes Berg <johannes.berg@intel.com>
Mon, 16 Dec 2013 10:23:45 +0000 (11:23 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 16 Dec 2013 10:23:45 +0000 (11:23 +0100)
1  2 
drivers/net/wireless/mwifiex/cfg80211.c
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/trace.h
net/mac80211/util.c
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c

index 6f5e49b32e794a5c0d37a47069dabec264df6627,4d23647faef0451ef227804dbe1464bbd2442161..3ff28c2149ceb6c5b88502c830c6670e9fdd1b2f
@@@ -222,6 -222,7 +222,7 @@@ mwifiex_cfg80211_mgmt_tx(struct wiphy *
        tx_info = MWIFIEX_SKB_TXCB(skb);
        tx_info->bss_num = priv->bss_num;
        tx_info->bss_type = priv->bss_type;
+       tx_info->pkt_len = pkt_len;
  
        mwifiex_form_mgmt_frame(skb, buf, len);
        mwifiex_queue_tx_pkt(priv, skb);
@@@ -1170,10 -1171,10 +1171,10 @@@ static int mwifiex_cfg80211_set_bitrate
        else
                bitmap_rates[1] = mask->control[band].legacy;
  
 -      /* Fill MCS rates */
 -      bitmap_rates[2] = mask->control[band].mcs[0];
 +      /* Fill HT MCS rates */
 +      bitmap_rates[2] = mask->control[band].ht_mcs[0];
        if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2)
 -              bitmap_rates[2] |= mask->control[band].mcs[1] << 8;
 +              bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
  
        return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
                                     HostCmd_ACT_GEN_SET, 0, bitmap_rates);
@@@ -2210,8 -2211,10 +2211,10 @@@ struct wireless_dev *mwifiex_add_virtua
                priv->bss_started = 0;
                priv->bss_num = 0;
  
-               if (mwifiex_cfg80211_init_p2p_client(priv))
-                       return ERR_PTR(-EFAULT);
+               if (mwifiex_cfg80211_init_p2p_client(priv)) {
+                       wdev = ERR_PTR(-EFAULT);
+                       goto done;
+               }
  
                break;
        default:
        if (!dev) {
                wiphy_err(wiphy, "no memory available for netdevice\n");
                priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
-               return ERR_PTR(-ENOMEM);
+               wdev = ERR_PTR(-ENOMEM);
+               goto done;
        }
  
        mwifiex_init_priv_params(priv, dev);
                wiphy_err(wiphy, "cannot register virtual network device\n");
                free_netdev(dev);
                priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
-               return ERR_PTR(-EFAULT);
+               priv->netdev = NULL;
+               wdev = ERR_PTR(-EFAULT);
+               goto done;
        }
  
        sema_init(&priv->async_sem, 1);
  #ifdef CONFIG_DEBUG_FS
        mwifiex_dev_debugfs_init(priv);
  #endif
+ done:
+       if (IS_ERR(wdev)) {
+               kfree(priv->wdev);
+               priv->wdev = NULL;
+       }
        return wdev;
  }
  EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
@@@ -2298,7 -2311,10 +2311,10 @@@ int mwifiex_del_virtual_intf(struct wip
                unregister_netdevice(wdev->netdev);
  
        /* Clear the priv in adapter */
+       priv->netdev->ieee80211_ptr = NULL;
        priv->netdev = NULL;
+       kfree(wdev);
+       priv->wdev = NULL;
  
        priv->media_connected = false;
  
diff --combined net/mac80211/cfg.c
index a74d61d520b07f6b69adf8cd0dfc37db13029cd2,f80e8c4c6bcd303762781ed8a2aa613ff763f5fa..8b790e7b221eacfa9239d0d1da1285184b1354cd
@@@ -1394,7 -1394,7 +1394,7 @@@ static int sta_apply_parameters(struct 
                        changed |=
                              ieee80211_mps_set_sta_local_pm(sta,
                                                             params->local_pm);
-               ieee80211_bss_info_change_notify(sdata, changed);
+               ieee80211_mbss_info_change_notify(sdata, changed);
  #endif
        }
  
@@@ -2514,8 -2514,7 +2514,7 @@@ static int ieee80211_set_power_mgmt(str
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
  
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EOPNOTSUPP;
  
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
@@@ -2588,8 -2587,8 +2587,8 @@@ static int ieee80211_set_bitrate_mask(s
                int j;
  
                sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
 -              memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
 -                     sizeof(mask->control[i].mcs));
 +              memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs,
 +                     sizeof(mask->control[i].ht_mcs));
  
                sdata->rc_has_mcs_mask[i] = false;
                if (!sband)
@@@ -3156,9 -3155,17 +3155,17 @@@ static int ieee80211_channel_switch(str
                    params->chandef.chan->band)
                        return -EINVAL;
  
+               ifmsh->chsw_init = true;
+               if (!ifmsh->pre_value)
+                       ifmsh->pre_value = 1;
+               else
+                       ifmsh->pre_value++;
                err = ieee80211_mesh_csa_beacon(sdata, params, true);
-               if (err < 0)
+               if (err < 0) {
+                       ifmsh->chsw_init = false;
                        return err;
+               }
                break;
  #endif
        default:
diff --combined net/mac80211/ibss.c
index df21e4f79df86f299a759de415e197d7c317a513,2eda7b13124abb7469a8b7b86503de07c0155623..e97fa7fac96e07676f632fb3aa14e78e4000662e
@@@ -534,8 -534,7 +534,8 @@@ int ieee80211_ibss_finish_csa(struct ie
        int err;
        u16 capability;
  
 -      sdata_lock(sdata);
 +      sdata_assert_lock(sdata);
 +
        /* update cfg80211 bss information with the new channel */
        if (!is_zero_ether_addr(ifibss->bssid)) {
                capability = WLAN_CAPABILITY_IBSS;
  
        /* generate the beacon */
        err = ieee80211_ibss_csa_beacon(sdata, NULL);
 -      sdata_unlock(sdata);
        if (err < 0)
                return err;
  
@@@ -823,6 -823,10 +823,10 @@@ ieee80211_ibss_process_chanswitch(struc
        if (err)
                return false;
  
+       /* channel switch is not supported, disconnect */
+       if (!(sdata->local->hw.wiphy->flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
+               goto disconnect;
        params.count = csa_ie.count;
        params.chandef = csa_ie.chandef;
  
diff --combined net/mac80211/iface.c
index 3e5c89a295b9697a3901bbbf7a23a6e683f0a47f,7aa9f9dea9df0af487c25c36d52004179d76b72c..1fe5d5810fc9c2ee4d46bb7e6b70c8427bce23e3
@@@ -1018,6 -1018,17 +1018,6 @@@ static void ieee80211_set_multicast_lis
                        atomic_dec(&local->iff_promiscs);
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
 -
 -      /*
 -       * TODO: If somebody needs this on AP interfaces,
 -       *       it can be enabled easily but multicast
 -       *       addresses from VLANs need to be synced.
 -       */
 -      if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
 -          sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 -          sdata->vif.type != NL80211_IFTYPE_AP)
 -              drv_set_multicast_list(local, sdata, &dev->mc);
 -
        spin_lock_bh(&local->filter_lock);
        __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
@@@ -1316,7 -1327,6 +1316,6 @@@ static void ieee80211_setup_sdata(struc
                sdata->vif.bss_conf.bssid = NULL;
                break;
        case NL80211_IFTYPE_AP_VLAN:
-               break;
        case NL80211_IFTYPE_P2P_DEVICE:
                sdata->vif.bss_conf.bssid = sdata->vif.addr;
                break;
diff --combined net/mac80211/rx.c
index 1892f883bd7fdb1fe56da84abe1d457ca601e758,2dfa755227339533d2c105313ba8ab4ea3ba67b5..5a2afe9583a806d5f9059c390e0cc70ae7799e22
@@@ -924,7 -924,8 +924,8 @@@ static void ieee80211_rx_reorder_ampdu(
        u16 sc;
        u8 tid, ack_policy;
  
-       if (!ieee80211_is_data_qos(hdr->frame_control))
+       if (!ieee80211_is_data_qos(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1))
                goto dont_reorder;
  
        /*
@@@ -1962,17 -1963,20 +1963,17 @@@ ieee80211_deliver_skb(struct ieee80211_
                }
        }
  
 -      if (skb) {
 -              int align __maybe_unused;
 -
  #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 -              /*
 -               * 'align' will only take the values 0 or 2 here
 -               * since all frames are required to be aligned
 -               * to 2-byte boundaries when being passed to
 -               * mac80211; the code here works just as well if
 -               * that isn't true, but mac80211 assumes it can
 -               * access fields as 2-byte aligned (e.g. for
 -               * compare_ether_addr)
 +      if (skb) {
 +              /* 'align' will only take the values 0 or 2 here since all
 +               * frames are required to be aligned to 2-byte boundaries
 +               * when being passed to mac80211; the code here works just
 +               * as well if that isn't true, but mac80211 assumes it can
 +               * access fields as 2-byte aligned (e.g. for ether_addr_equal)
                 */
 -              align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
 +              int align;
 +
 +              align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3;
                if (align) {
                        if (WARN_ON(skb_headroom(skb) < 3)) {
                                dev_kfree_skb(skb);
                                skb_set_tail_pointer(skb, len);
                        }
                }
 +      }
  #endif
  
 -              if (skb) {
 -                      /* deliver to local stack */
 -                      skb->protocol = eth_type_trans(skb, dev);
 -                      memset(skb->cb, 0, sizeof(skb->cb));
 -                      netif_receive_skb(skb);
 -              }
 +      if (skb) {
 +              /* deliver to local stack */
 +              skb->protocol = eth_type_trans(skb, dev);
 +              memset(skb->cb, 0, sizeof(skb->cb));
 +              netif_receive_skb(skb);
        }
  
        if (xmit_skb) {
diff --combined net/mac80211/scan.c
index 3ccb5841d50eb4419722ddc773ee99d51aca5e82,4d73c46df86262a385ad5fb9a5912c6a8168831e..ee6c8515f97b139620bb3dd1b4dbe85ae77b78ba
@@@ -271,11 -271,10 +271,11 @@@ static bool ieee80211_prep_hw_scan(stru
        return true;
  }
  
 -static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
 -                                     bool was_hw_scan)
 +static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
  {
        struct ieee80211_local *local = hw_to_local(hw);
 +      bool hw_scan = local->ops->hw_scan;
 +      bool was_scanning = local->scanning;
  
        lockdep_assert_held(&local->mtx);
  
        if (WARN_ON(!local->scan_req))
                return;
  
 -      if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
 +      if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
                int rc;
  
                rc = drv_hw_scan(local,
        /* Set power back to normal operating levels. */
        ieee80211_hw_config(local, 0);
  
 -      if (!was_hw_scan) {
 +      if (!hw_scan) {
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
                ieee80211_offchannel_return(local);
        ieee80211_mlme_notify_scan_completed(local);
        ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
 -      ieee80211_start_next_roc(local);
 +      if (was_scanning)
 +              ieee80211_start_next_roc(local);
  }
  
  void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@@ -749,7 -747,7 +749,7 @@@ void ieee80211_scan_work(struct work_st
                container_of(work, struct ieee80211_local, scan_work.work);
        struct ieee80211_sub_if_data *sdata;
        unsigned long next_delay = 0;
 -      bool aborted, hw_scan;
 +      bool aborted;
  
        mutex_lock(&local->mtx);
  
                        goto out;
        }
  
 -      /*
 -       * Avoid re-scheduling when the sdata is going away.
 -       */
 -      if (!ieee80211_sdata_running(sdata)) {
 -              aborted = true;
 -              goto out_complete;
 -      }
 -
        /*
         * as long as no delay is required advance immediately
         * without scheduling a new work
        goto out;
  
  out_complete:
 -      hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
 -      __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
 +      __ieee80211_scan_completed(&local->hw, aborted);
  out:
        mutex_unlock(&local->mtx);
  }
@@@ -966,7 -973,7 +966,7 @@@ void ieee80211_scan_cancel(struct ieee8
         */
        cancel_delayed_work(&local->scan_work);
        /* and clean up */
 -      __ieee80211_scan_completed(&local->hw, true, false);
 +      __ieee80211_scan_completed(&local->hw, true);
  out:
        mutex_unlock(&local->mtx);
  }
@@@ -1081,6 -1088,6 +1081,6 @@@ void ieee80211_sched_scan_stopped(struc
  
        trace_api_sched_scan_stopped(local);
  
-       ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
+       schedule_work(&local->sched_scan_stopped_work);
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
diff --combined net/mac80211/trace.h
index 9d213e82326e6144af94400b16d1466fc71ec1b0,e9ccf22f6dd972c8b0517c5d35a345085eb45ec6..854bc59431272b03b5772bc841559f90940a7668
@@@ -94,13 -94,13 +94,13 @@@ DECLARE_EVENT_CLASS(local_sdata_addr_ev
        TP_STRUCT__entry(
                LOCAL_ENTRY
                VIF_ENTRY
-               __array(char, addr, 6)
+               __array(char, addr, ETH_ALEN)
        ),
  
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               memcpy(__entry->addr, sdata->vif.addr, 6);
+               memcpy(__entry->addr, sdata->vif.addr, ETH_ALEN);
        ),
  
        TP_printk(
@@@ -443,6 -443,30 +443,6 @@@ TRACE_EVENT(drv_prepare_multicast
        )
  );
  
 -TRACE_EVENT(drv_set_multicast_list,
 -      TP_PROTO(struct ieee80211_local *local,
 -               struct ieee80211_sub_if_data *sdata, int mc_count),
 -
 -      TP_ARGS(local, sdata, mc_count),
 -
 -      TP_STRUCT__entry(
 -              LOCAL_ENTRY
 -              __field(bool, allmulti)
 -              __field(int, mc_count)
 -      ),
 -
 -      TP_fast_assign(
 -              LOCAL_ASSIGN;
 -              __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
 -              __entry->mc_count = mc_count;
 -      ),
 -
 -      TP_printk(
 -              LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d",
 -              LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti
 -      )
 -);
 -
  TRACE_EVENT(drv_configure_filter,
        TP_PROTO(struct ieee80211_local *local,
                 unsigned int changed_flags,
diff --combined net/mac80211/util.c
index 4a376a724153169655e48839d2ab3e489238e53c,875e172c001c697a72f85941fd0db8ef1b28b86a..adf81f02368195eb62ca1f2ccb2d9ef947f6189d
@@@ -642,17 -642,6 +642,17 @@@ void ieee80211_iterate_active_interface
  }
  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
  
 +struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
 +{
 +      struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 +
 +      if (!ieee80211_sdata_running(sdata) ||
 +          !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
 +              return NULL;
 +      return &sdata->vif;
 +}
 +EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
 +
  /*
   * Nothing should have been stuffed into the workqueue during
   * the suspend->resume cycle. If this WARN is seen then there
@@@ -2312,17 -2301,15 +2312,15 @@@ void ieee80211_dfs_radar_detected_work(
  {
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, radar_detected_work);
-       struct cfg80211_chan_def chandef;
+       struct cfg80211_chan_def chandef = local->hw.conf.chandef;
  
        ieee80211_dfs_cac_cancel(local);
  
        if (local->use_chanctx)
                /* currently not handled */
                WARN_ON(1);
-       else {
-               chandef = local->hw.conf.chandef;
+       else
                cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
-       }
  }
  
  void ieee80211_radar_detected(struct ieee80211_hw *hw)
@@@ -2492,13 -2479,8 +2490,8 @@@ int ieee80211_send_action_csa(struct ie
                          WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
                put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
                pos += 2;
-               if (!ifmsh->pre_value)
-                       ifmsh->pre_value = 1;
-               else
-                       ifmsh->pre_value++;
                put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
                pos += 2;
-               ifmsh->chsw_init = true;
        }
  
        ieee80211_tx_skb(sdata, skb);
diff --combined net/wireless/core.c
index 1a92c6a0731fe3c3fe5ba301d0ea1995d9a00dfc,06db6eb5258aefc332fb4fb09ed165562ea8cd7d..d89dee2259b5994b9237100425aae0a3f21b20af
@@@ -203,8 -203,17 +203,8 @@@ void cfg80211_stop_p2p_device(struct cf
  
        rdev->opencount--;
  
 -      if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
 -              /*
 -               * If the scan request wasn't notified as done, set it
 -               * to aborted and leak it after a warning. The driver
 -               * should have notified us that it ended at the latest
 -               * during rdev_stop_p2p_device().
 -               */
 -              if (WARN_ON(!rdev->scan_req->notified))
 -                      rdev->scan_req->aborted = true;
 -              ___cfg80211_scan_done(rdev, !rdev->scan_req->notified);
 -      }
 +      WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
 +              !rdev->scan_req->notified);
  }
  
  static int cfg80211_rfkill_set_block(void *data, bool blocked)
@@@ -440,6 -449,15 +440,15 @@@ int wiphy_register(struct wiphy *wiphy
        int i;
        u16 ifmodes = wiphy->interface_modes;
  
+       /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
+       wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+       /*
+        * There are major locking problems in nl80211/mac80211 for CSA,
+        * disable for all drivers until this has been reworked.
+        */
+       wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH;
  #ifdef CONFIG_PM
        if (WARN_ON(wiphy->wowlan &&
                    (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
@@@ -747,16 -765,13 +756,16 @@@ void cfg80211_leave(struct cfg80211_reg
  {
        struct net_device *dev = wdev->netdev;
  
 +      ASSERT_RTNL();
 +
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
                cfg80211_leave_ibss(rdev, dev, true);
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
 -              __cfg80211_stop_sched_scan(rdev, false);
 +              if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
 +                      __cfg80211_stop_sched_scan(rdev, false);
  
                wdev_lock(wdev);
  #ifdef CONFIG_CFG80211_WEXT
@@@ -850,8 -865,11 +859,8 @@@ static int cfg80211_netdev_notifier_cal
                break;
        case NETDEV_DOWN:
                cfg80211_update_iface_num(rdev, wdev->iftype, -1);
 -              if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
 -                      if (WARN_ON(!rdev->scan_req->notified))
 -                              rdev->scan_req->aborted = true;
 -                      ___cfg80211_scan_done(rdev, true);
 -              }
 +              WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
 +                      !rdev->scan_req->notified);
  
                if (WARN_ON(rdev->sched_scan_req &&
                            rdev->sched_scan_req->dev == wdev->netdev)) {
diff --combined net/wireless/core.h
index 453c6ed880f194cbeb3119f1efec3512a0c49ea2,0a277c33bb027a879d854492ddde295be2c663a0..37ec16d7bb1ab6bf6e4948259aad19eb6e5a58cf
@@@ -67,7 -67,9 +67,7 @@@ struct cfg80211_registered_device 
        struct work_struct scan_done_wk;
        struct work_struct sched_scan_results_wk;
  
 -#ifdef CONFIG_NL80211_TESTMODE
 -      struct genl_info *testmode_info;
 -#endif
 +      struct genl_info *cur_cmd_info;
  
        struct work_struct conn_work;
        struct work_struct event_work;
@@@ -232,10 -234,10 +232,10 @@@ struct cfg80211_beacon_registration 
  };
  
  /* free object */
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
+ void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
  
extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
-                              char *newname);
+ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
+                       char *newname);
  
  void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
  
@@@ -361,7 -363,7 +361,7 @@@ int cfg80211_validate_key_settings(stru
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr);
  void __cfg80211_scan_done(struct work_struct *wk);
 -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
 +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
  void __cfg80211_sched_scan_results(struct work_struct *wk);
  int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
                               bool driver_initiated);
diff --combined net/wireless/nl80211.c
index 801e57da88b466f9515b07dbd4961d1234dd71b8,a693f86e59704016e9c8419eb82a8c43185d9642..2d0c19c6133b3586d2f512fcb487396a349bf091
@@@ -30,9 -30,9 +30,9 @@@ static int nl80211_crypto_settings(stru
                                   struct cfg80211_crypto_settings *settings,
                                   int cipher_limit);
  
- static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
                            struct genl_info *info);
- static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
                              struct genl_info *info);
  
  /* the netlink family */
@@@ -47,6 -47,25 +47,25 @@@ static struct genl_family nl80211_fam 
        .post_doit = nl80211_post_doit,
  };
  
+ /* multicast groups */
+ enum nl80211_multicast_groups {
+       NL80211_MCGRP_CONFIG,
+       NL80211_MCGRP_SCAN,
+       NL80211_MCGRP_REGULATORY,
+       NL80211_MCGRP_MLME,
+       NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
+ };
+ static const struct genl_multicast_group nl80211_mcgrps[] = {
+       [NL80211_MCGRP_CONFIG] = { .name = "config", },
+       [NL80211_MCGRP_SCAN] = { .name = "scan", },
+       [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
+       [NL80211_MCGRP_MLME] = { .name = "mlme", },
+ #ifdef CONFIG_NL80211_TESTMODE
+       [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
+ #endif
+ };
  /* returns ERR_PTR values */
  static struct wireless_dev *
  __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
@@@ -357,10 -376,6 +376,10 @@@ static const struct nla_policy nl80211_
        [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
        [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
        [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
 +      [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
 +      [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
 +      [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
 +      [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
  };
  
  /* policy for the key attributes */
@@@ -1169,7 -1184,6 +1188,7 @@@ static int nl80211_send_wiphy(struct cf
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_cmds;
 +      struct nlattr *nl_vendor_cmds;
        enum ieee80211_band band;
        struct ieee80211_channel *chan;
        int i;
                    (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
                     nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
                        goto nla_put_failure;
 +              state->split_start++;
 +              break;
 +      case 11:
 +              nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
 +              if (!nl_vendor_cmds)
 +                      goto nla_put_failure;
 +
 +              for (i = 0; i < dev->wiphy.n_vendor_commands; i++)
 +                      if (nla_put(msg, i + 1,
 +                                  sizeof(struct nl80211_vendor_cmd_info),
 +                                  &dev->wiphy.vendor_commands[i].info))
 +                              goto nla_put_failure;
 +              nla_nest_end(msg, nl_vendor_cmds);
  
                /* done */
                state->split_start = 0;
@@@ -2687,7 -2688,7 +2706,7 @@@ static int nl80211_get_key(struct sk_bu
        hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
                             NL80211_CMD_NEW_KEY);
        if (!hdr)
-               return -ENOBUFS;
+               goto nla_put_failure;
  
        cookie.msg = msg;
        cookie.idx = key_idx;
@@@ -4150,12 -4151,6 +4169,12 @@@ static int nl80211_new_station(struct s
                params.vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
  
 +      if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
 +              params.opmode_notif_used = true;
 +              params.opmode_notif =
 +                      nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
 +      }
 +
        if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
                params.plink_action =
                        nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
@@@ -5370,6 -5365,10 +5389,10 @@@ static int nl80211_trigger_scan(struct 
                                err = -EINVAL;
                                goto out_free;
                        }
+                       if (!wiphy->bands[band])
+                               continue;
                        err = ieee80211_get_ratemask(wiphy->bands[band],
                                                     nla_data(attr),
                                                     nla_len(attr),
@@@ -5668,13 -5667,8 +5691,13 @@@ static int nl80211_start_radar_detectio
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_chan_def chandef;
 +      enum nl80211_dfs_regions dfs_region;
        int err;
  
 +      dfs_region = reg_get_dfs_region(wdev->wiphy);
 +      if (dfs_region == NL80211_DFS_UNSET)
 +              return -EINVAL;
 +
        err = nl80211_parse_chandef(rdev, info, &chandef);
        if (err)
                return err;
@@@ -6699,46 -6693,8 +6722,42 @@@ static int nl80211_set_mcast_rate(struc
        return err;
  }
  
 +static struct sk_buff *
 +__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
 +                          int approxlen, u32 portid, u32 seq,
 +                          enum nl80211_commands cmd,
 +                          enum nl80211_attrs attr, gfp_t gfp)
 +{
 +      struct sk_buff *skb;
 +      void *hdr;
 +      struct nlattr *data;
 +
 +      skb = nlmsg_new(approxlen + 100, gfp);
 +      if (!skb)
 +              return NULL;
 +
 +      hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
 +      if (!hdr) {
 +              kfree_skb(skb);
 +              return NULL;
 +      }
 +
 +      if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
 +              goto nla_put_failure;
 +      data = nla_nest_start(skb, attr);
 +
 +      ((void **)skb->cb)[0] = rdev;
 +      ((void **)skb->cb)[1] = hdr;
 +      ((void **)skb->cb)[2] = data;
 +
 +      return skb;
 +
 + nla_put_failure:
 +      kfree_skb(skb);
 +      return NULL;
 +}
  
  #ifdef CONFIG_NL80211_TESTMODE
- static struct genl_multicast_group nl80211_testmode_mcgrp = {
-       .name = "testmode",
- };
  static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
  {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        if (!info->attrs[NL80211_ATTR_TESTDATA])
                return -EINVAL;
  
 -      rdev->testmode_info = info;
 +      rdev->cur_cmd_info = info;
        err = rdev_testmode_cmd(rdev, wdev,
                                nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
                                nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
 -      rdev->testmode_info = NULL;
 +      rdev->cur_cmd_info = NULL;
  
        return err;
  }
@@@ -6865,14 -6821,77 +6884,14 @@@ static int nl80211_testmode_dump(struc
        return err;
  }
  
 -static struct sk_buff *
 -__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
 -                            int approxlen, u32 portid, u32 seq, gfp_t gfp)
 -{
 -      struct sk_buff *skb;
 -      void *hdr;
 -      struct nlattr *data;
 -
 -      skb = nlmsg_new(approxlen + 100, gfp);
 -      if (!skb)
 -              return NULL;
 -
 -      hdr = nl80211hdr_put(skb, portid, seq, 0, NL80211_CMD_TESTMODE);
 -      if (!hdr) {
 -              kfree_skb(skb);
 -              return NULL;
 -      }
 -
 -      if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
 -              goto nla_put_failure;
 -      data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
 -
 -      ((void **)skb->cb)[0] = rdev;
 -      ((void **)skb->cb)[1] = hdr;
 -      ((void **)skb->cb)[2] = data;
 -
 -      return skb;
 -
 - nla_put_failure:
 -      kfree_skb(skb);
 -      return NULL;
 -}
 -
 -struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
 -                                                int approxlen)
 -{
 -      struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 -
 -      if (WARN_ON(!rdev->testmode_info))
 -              return NULL;
 -
 -      return __cfg80211_testmode_alloc_skb(rdev, approxlen,
 -                              rdev->testmode_info->snd_portid,
 -                              rdev->testmode_info->snd_seq,
 -                              GFP_KERNEL);
 -}
 -EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
 -
 -int cfg80211_testmode_reply(struct sk_buff *skb)
 -{
 -      struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
 -      void *hdr = ((void **)skb->cb)[1];
 -      struct nlattr *data = ((void **)skb->cb)[2];
 -
 -      if (WARN_ON(!rdev->testmode_info)) {
 -              kfree_skb(skb);
 -              return -EINVAL;
 -      }
 -
 -      nla_nest_end(skb, data);
 -      genlmsg_end(skb, hdr);
 -      return genlmsg_reply(skb, rdev->testmode_info);
 -}
 -EXPORT_SYMBOL(cfg80211_testmode_reply);
 -
  struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
                                                  int approxlen, gfp_t gfp)
  {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  
 -      return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
 +      return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
 +                                         NL80211_CMD_TESTMODE,
 +                                         NL80211_ATTR_TESTDATA, gfp);
  }
  EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
  
@@@ -6884,8 -6903,8 +6903,8 @@@ void cfg80211_testmode_event(struct sk_
  
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
-                               nl80211_testmode_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
+                               NL80211_MCGRP_TESTMODE, gfp);
  }
  EXPORT_SYMBOL(cfg80211_testmode_event);
  #endif
@@@ -7312,8 -7331,8 +7331,8 @@@ static bool ht_rateset_to_mask(struct i
  static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
        [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
                                    .len = NL80211_MAX_SUPP_RATES },
 -      [NL80211_TXRATE_MCS] = { .type = NLA_BINARY,
 -                               .len = NL80211_MAX_SUPP_HT_RATES },
 +      [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
 +                              .len = NL80211_MAX_SUPP_HT_RATES },
  };
  
  static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        struct nlattr *tx_rates;
        struct ieee80211_supported_band *sband;
  
 -      if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
 -              return -EINVAL;
 -
        if (!rdev->ops->set_bitrate_mask)
                return -EOPNOTSUPP;
  
        /* Default to all rates enabled */
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                sband = rdev->wiphy.bands[i];
 -              mask.control[i].legacy =
 -                      sband ? (1 << sband->n_bitrates) - 1 : 0;
 -              if (sband)
 -                      memcpy(mask.control[i].mcs,
 -                             sband->ht_cap.mcs.rx_mask,
 -                             sizeof(mask.control[i].mcs));
 -              else
 -                      memset(mask.control[i].mcs, 0,
 -                             sizeof(mask.control[i].mcs));
 +
 +              if (!sband)
 +                      continue;
 +
 +              mask.control[i].legacy = (1 << sband->n_bitrates) - 1;
 +              memcpy(mask.control[i].ht_mcs,
 +                     sband->ht_cap.mcs.rx_mask,
 +                     sizeof(mask.control[i].ht_mcs));
        }
  
 +      /* if no rates are given set it back to the defaults */
 +      if (!info->attrs[NL80211_ATTR_TX_RATES])
 +              goto out;
 +
        /*
         * The nested attribute uses enum nl80211_band as the index. This maps
         * directly to the enum ieee80211_band values used in cfg80211.
                            nla_len(tb[NL80211_TXRATE_LEGACY]))
                                return -EINVAL;
                }
 -              if (tb[NL80211_TXRATE_MCS]) {
 +              if (tb[NL80211_TXRATE_HT]) {
                        if (!ht_rateset_to_mask(
                                        sband,
 -                                      nla_data(tb[NL80211_TXRATE_MCS]),
 -                                      nla_len(tb[NL80211_TXRATE_MCS]),
 -                                      mask.control[band].mcs))
 +                                      nla_data(tb[NL80211_TXRATE_HT]),
 +                                      nla_len(tb[NL80211_TXRATE_HT]),
 +                                      mask.control[band].ht_mcs))
                                return -EINVAL;
                }
  
                                return -EINVAL;
  
                        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
 -                              if (mask.control[band].mcs[i])
 +                              if (mask.control[band].ht_mcs[i])
                                        break;
  
                        /* legacy and mcs rates may not be both empty */
                }
        }
  
 +out:
        return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
  }
  
@@@ -8857,111 -8875,6 +8876,111 @@@ static int nl80211_crit_protocol_stop(s
        return 0;
  }
  
 +static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +      struct wireless_dev *wdev =
 +              __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
 +      int i, err;
 +      u32 vid, subcmd;
 +
 +      if (!rdev->wiphy.vendor_commands)
 +              return -EOPNOTSUPP;
 +
 +      if (IS_ERR(wdev)) {
 +              err = PTR_ERR(wdev);
 +              if (err != -EINVAL)
 +                      return err;
 +              wdev = NULL;
 +      } else if (wdev->wiphy != &rdev->wiphy) {
 +              return -EINVAL;
 +      }
 +
 +      if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
 +          !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
 +              return -EINVAL;
 +
 +      vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
 +      subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
 +      for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
 +              const struct wiphy_vendor_command *vcmd;
 +              void *data = NULL;
 +              int len = 0;
 +
 +              vcmd = &rdev->wiphy.vendor_commands[i];
 +
 +              if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
 +                      continue;
 +
 +              if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
 +                                 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
 +                      if (!wdev)
 +                              return -EINVAL;
 +                      if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
 +                          !wdev->netdev)
 +                              return -EINVAL;
 +
 +                      if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
 +                              if (wdev->netdev &&
 +                                  !netif_running(wdev->netdev))
 +                                      return -ENETDOWN;
 +                              if (!wdev->netdev && !wdev->p2p_started)
 +                                      return -ENETDOWN;
 +                      }
 +              } else {
 +                      wdev = NULL;
 +              }
 +
 +              if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
 +                      data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
 +                      len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
 +              }
 +
 +              rdev->cur_cmd_info = info;
 +              err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
 +                                                        data, len);
 +              rdev->cur_cmd_info = NULL;
 +              return err;
 +      }
 +
 +      return -EOPNOTSUPP;
 +}
 +
 +struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
 +                                         enum nl80211_commands cmd,
 +                                         enum nl80211_attrs attr,
 +                                         int approxlen)
 +{
 +      struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 +
 +      if (WARN_ON(!rdev->cur_cmd_info))
 +              return NULL;
 +
 +      return __cfg80211_alloc_vendor_skb(rdev, approxlen,
 +                                         rdev->cur_cmd_info->snd_portid,
 +                                         rdev->cur_cmd_info->snd_seq,
 +                                         cmd, attr, GFP_KERNEL);
 +}
 +EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
 +
 +int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
 +{
 +      struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
 +      void *hdr = ((void **)skb->cb)[1];
 +      struct nlattr *data = ((void **)skb->cb)[2];
 +
 +      if (WARN_ON(!rdev->cur_cmd_info)) {
 +              kfree_skb(skb);
 +              return -EINVAL;
 +      }
 +
 +      nla_nest_end(skb, data);
 +      genlmsg_end(skb, hdr);
 +      return genlmsg_reply(skb, rdev->cur_cmd_info);
 +}
 +EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
 +
 +
  #define NL80211_FLAG_NEED_WIPHY               0x01
  #define NL80211_FLAG_NEED_NETDEV      0x02
  #define NL80211_FLAG_NEED_RTNL                0x04
  #define NL80211_FLAG_NEED_WDEV_UP     (NL80211_FLAG_NEED_WDEV |\
                                         NL80211_FLAG_CHECK_NETDEV_UP)
  
- static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
                            struct genl_info *info)
  {
        struct cfg80211_registered_device *rdev;
        return 0;
  }
  
- static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
                              struct genl_info *info)
  {
        if (info->user_ptr[1]) {
                rtnl_unlock();
  }
  
- static struct genl_ops nl80211_ops[] = {
+ static const struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
                .doit = nl80211_get_wiphy,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
 +      {
 +              .cmd = NL80211_CMD_VENDOR,
 +              .doit = nl80211_vendor_cmd,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_WIPHY |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
  };
  
- static struct genl_multicast_group nl80211_mlme_mcgrp = {
-       .name = "mlme",
- };
- /* 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 */
  
  void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_config_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_CONFIG, GFP_KERNEL);
  }
  
  static int nl80211_add_scan_req(struct sk_buff *msg,
            nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
                goto nla_put_failure;
  
-       if (req->flags)
-               nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
+       if (req->flags &&
+           nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
+               goto nla_put_failure;
  
        return 0;
   nla_put_failure:
@@@ -9837,8 -9728,8 +9842,8 @@@ void nl80211_send_scan_start(struct cfg
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_scan_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_SCAN, GFP_KERNEL);
  }
  
  void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_scan_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_SCAN, GFP_KERNEL);
  }
  
  void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_scan_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_SCAN, GFP_KERNEL);
  }
  
  void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_scan_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_SCAN, GFP_KERNEL);
  }
  
  void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_scan_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_SCAN, GFP_KERNEL);
  }
  
  /*
@@@ -9967,8 -9858,8 +9972,8 @@@ void nl80211_send_reg_change_event(stru
        genlmsg_end(msg, hdr);
  
        rcu_read_lock();
-       genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
-                               GFP_ATOMIC);
+       genlmsg_multicast_allns(&nl80211_fam, msg, 0,
+                               NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
        rcu_read_unlock();
  
        return;
@@@ -10003,8 -9894,8 +10008,8 @@@ static void nl80211_send_mlme_event(str
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10091,8 -9982,8 +10096,8 @@@ static void nl80211_send_mlme_timeout(s
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10147,8 -10038,8 +10152,8 @@@ void nl80211_send_connect_result(struc
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10186,8 -10077,8 +10191,8 @@@ void nl80211_send_roamed(struct cfg8021
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10224,8 -10115,8 +10229,8 @@@ void nl80211_send_disconnected(struct c
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, GFP_KERNEL);
        return;
  
   nla_put_failure:
@@@ -10258,8 -10149,8 +10263,8 @@@ void nl80211_send_ibss_bssid(struct cfg
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10299,8 -10190,8 +10304,8 @@@ void cfg80211_notify_new_peer_candidate
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10338,8 -10229,8 +10343,8 @@@ void nl80211_michael_mic_failure(struc
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10391,8 -10282,8 +10396,8 @@@ void nl80211_send_beacon_hint_event(str
        genlmsg_end(msg, hdr);
  
        rcu_read_lock();
-       genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
-                               GFP_ATOMIC);
+       genlmsg_multicast_allns(&nl80211_fam, msg, 0,
+                               NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
        rcu_read_unlock();
  
        return;
@@@ -10437,8 -10328,8 +10442,8 @@@ static void nl80211_send_remain_on_chan
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10492,8 -10383,8 +10497,8 @@@ void cfg80211_new_sta(struct net_devic
                return;
        }
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
  }
  EXPORT_SYMBOL(cfg80211_new_sta);
  
@@@ -10522,8 -10413,8 +10527,8 @@@ void cfg80211_del_sta(struct net_devic
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10558,8 -10449,8 +10563,8 @@@ void cfg80211_conn_failed(struct net_de
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10720,8 -10611,8 +10725,8 @@@ void cfg80211_mgmt_tx_status(struct wir
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10769,8 -10660,8 +10774,8 @@@ void cfg80211_cqm_rssi_notify(struct ne
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10814,8 -10705,8 +10819,8 @@@ static void nl80211_gtk_rekey_notify(st
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10872,8 -10763,8 +10877,8 @@@ nl80211_pmksa_candidate_notify(struct c
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10919,8 -10810,8 +10924,8 @@@ static void nl80211_ch_switch_notify(st
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -10993,8 -10884,8 +10998,8 @@@ void cfg80211_cqm_txe_notify(struct net
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -11042,8 -10933,8 +11047,8 @@@ nl80211_radar_notify(struct cfg80211_re
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -11089,8 -10980,8 +11094,8 @@@ void cfg80211_cqm_pktloss_notify(struc
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -11129,8 -11020,8 +11134,8 @@@ void cfg80211_probe_status(struct net_d
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -11220,6 -11111,8 +11225,8 @@@ void cfg80211_report_wowlan_wakeup(stru
                struct nlattr *reasons;
  
                reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
+               if (!reasons)
+                       goto free_msg;
  
                if (wakeup->disconnect &&
                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
                                wakeup->pattern_idx))
                        goto free_msg;
  
-               if (wakeup->tcp_match)
-                       nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH);
+               if (wakeup->tcp_match &&
+                   nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
+                       goto free_msg;
  
-               if (wakeup->tcp_connlost)
-                       nla_put_flag(msg,
-                                    NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST);
+               if (wakeup->tcp_connlost &&
+                   nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
+                       goto free_msg;
  
-               if (wakeup->tcp_nomoretokens)
-                       nla_put_flag(msg,
-                               NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS);
+               if (wakeup->tcp_nomoretokens &&
+                   nla_put_flag(msg,
+                                NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
+                       goto free_msg;
  
                if (wakeup->packet) {
                        u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   free_msg:
@@@ -11323,8 -11218,8 +11332,8 @@@ void cfg80211_tdls_oper_request(struct 
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, gfp);
        return;
  
   nla_put_failure:
@@@ -11390,24 -11285,29 +11399,29 @@@ void cfg80211_ft_event(struct net_devic
                return;
  
        hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
-       if (!hdr) {
-               nlmsg_free(msg);
-               return;
-       }
+       if (!hdr)
+               goto out;
  
-       nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
-       nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
-       nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap);
-       if (ft_event->ies)
-               nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies);
-       if (ft_event->ric_ies)
-               nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
-                       ft_event->ric_ies);
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
+               goto out;
+       if (ft_event->ies &&
+           nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
+               goto out;
+       if (ft_event->ric_ies &&
+           nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
+                   ft_event->ric_ies))
+               goto out;
  
        genlmsg_end(msg, hdr);
  
-       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-                               nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, GFP_KERNEL);
+       return;
+  out:
+       nlmsg_free(msg);
  }
  EXPORT_SYMBOL(cfg80211_ft_event);
  
@@@ -11456,33 -11356,11 +11470,11 @@@ int nl80211_init(void
  {
        int err;
  
-       err = genl_register_family_with_ops(&nl80211_fam,
-               nl80211_ops, ARRAY_SIZE(nl80211_ops));
+       err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops,
+                                                  nl80211_mcgrps);
        if (err)
                return err;
  
-       err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
-       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;
-       err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp);
-       if (err)
-               goto err_out;
- #ifdef CONFIG_NL80211_TESTMODE
-       err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp);
-       if (err)
-               goto err_out;
- #endif
        err = netlink_register_notifier(&nl80211_netlink_notifier);
        if (err)
                goto err_out;