aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/ap.c4
-rw-r--r--net/wireless/chan.c5
-rw-r--r--net/wireless/core.c67
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/ibss.c2
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/nl80211.c140
-rw-r--r--net/wireless/rdev-ops.h2
-rw-r--r--net/wireless/reg.c3
-rw-r--r--net/wireless/scan.c12
-rw-r--r--net/wireless/sme.c8
-rw-r--r--net/wireless/trace.h37
-rw-r--r--net/wireless/util.c38
13 files changed, 252 insertions, 77 deletions
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 3e02ade508d8..bdad1f951561 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -6,8 +6,8 @@
6#include "rdev-ops.h" 6#include "rdev-ops.h"
7 7
8 8
9static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, 9int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
10 struct net_device *dev, bool notify) 10 struct net_device *dev, bool notify)
11{ 11{
12 struct wireless_dev *wdev = dev->ieee80211_ptr; 12 struct wireless_dev *wdev = dev->ieee80211_ptr;
13 int err; 13 int err;
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 84d686e2dbd0..992b34070bcb 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -370,8 +370,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
370 case NL80211_IFTYPE_AP_VLAN: 370 case NL80211_IFTYPE_AP_VLAN:
371 case NL80211_IFTYPE_WDS: 371 case NL80211_IFTYPE_WDS:
372 case NL80211_IFTYPE_P2P_DEVICE: 372 case NL80211_IFTYPE_P2P_DEVICE:
373 case NL80211_IFTYPE_UNSPECIFIED:
374 break; 373 break;
374 case NL80211_IFTYPE_UNSPECIFIED:
375 case NUM_NL80211_IFTYPES: 375 case NUM_NL80211_IFTYPES:
376 WARN_ON(1); 376 WARN_ON(1);
377 } 377 }
@@ -796,8 +796,7 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
796 !cfg80211_go_permissive_chan(rdev, chandef->chan)) 796 !cfg80211_go_permissive_chan(rdev, chandef->chan))
797 prohibited_flags |= IEEE80211_CHAN_NO_IR; 797 prohibited_flags |= IEEE80211_CHAN_NO_IR;
798 798
799 if (cfg80211_chandef_dfs_required(wiphy, chandef, 799 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
800 NL80211_IFTYPE_UNSPECIFIED) > 0 &&
801 cfg80211_chandef_dfs_available(wiphy, chandef)) { 800 cfg80211_chandef_dfs_available(wiphy, chandef)) {
802 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ 801 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
803 prohibited_flags = IEEE80211_CHAN_DISABLED; 802 prohibited_flags = IEEE80211_CHAN_DISABLED;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index b3ff3697239a..d03d8bdb29ca 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -210,15 +210,12 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
210 } 210 }
211} 211}
212 212
213static int cfg80211_rfkill_set_block(void *data, bool blocked) 213void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
214{ 214{
215 struct cfg80211_registered_device *rdev = data; 215 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
216 struct wireless_dev *wdev; 216 struct wireless_dev *wdev;
217 217
218 if (!blocked) 218 ASSERT_RTNL();
219 return 0;
220
221 rtnl_lock();
222 219
223 list_for_each_entry(wdev, &rdev->wdev_list, list) { 220 list_for_each_entry(wdev, &rdev->wdev_list, list) {
224 if (wdev->netdev) { 221 if (wdev->netdev) {
@@ -234,7 +231,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
234 break; 231 break;
235 } 232 }
236 } 233 }
234}
235EXPORT_SYMBOL_GPL(cfg80211_shutdown_all_interfaces);
237 236
237static int cfg80211_rfkill_set_block(void *data, bool blocked)
238{
239 struct cfg80211_registered_device *rdev = data;
240
241 if (!blocked)
242 return 0;
243
244 rtnl_lock();
245 cfg80211_shutdown_all_interfaces(&rdev->wiphy);
238 rtnl_unlock(); 246 rtnl_unlock();
239 247
240 return 0; 248 return 0;
@@ -394,6 +402,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
394 rdev->wiphy.rts_threshold = (u32) -1; 402 rdev->wiphy.rts_threshold = (u32) -1;
395 rdev->wiphy.coverage_class = 0; 403 rdev->wiphy.coverage_class = 0;
396 404
405 rdev->wiphy.max_num_csa_counters = 1;
406
397 return &rdev->wiphy; 407 return &rdev->wiphy;
398} 408}
399EXPORT_SYMBOL(wiphy_new); 409EXPORT_SYMBOL(wiphy_new);
@@ -690,7 +700,7 @@ void wiphy_unregister(struct wiphy *wiphy)
690 rtnl_lock(); 700 rtnl_lock();
691 rdev->wiphy.registered = false; 701 rdev->wiphy.registered = false;
692 702
693 BUG_ON(!list_empty(&rdev->wdev_list)); 703 WARN_ON(!list_empty(&rdev->wdev_list));
694 704
695 /* 705 /*
696 * First remove the hardware from everywhere, this makes 706 * First remove the hardware from everywhere, this makes
@@ -792,23 +802,23 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
792 rdev->num_running_monitor_ifaces += num; 802 rdev->num_running_monitor_ifaces += num;
793} 803}
794 804
795void cfg80211_leave(struct cfg80211_registered_device *rdev, 805void __cfg80211_leave(struct cfg80211_registered_device *rdev,
796 struct wireless_dev *wdev) 806 struct wireless_dev *wdev)
797{ 807{
798 struct net_device *dev = wdev->netdev; 808 struct net_device *dev = wdev->netdev;
799 809
800 ASSERT_RTNL(); 810 ASSERT_RTNL();
811 ASSERT_WDEV_LOCK(wdev);
801 812
802 switch (wdev->iftype) { 813 switch (wdev->iftype) {
803 case NL80211_IFTYPE_ADHOC: 814 case NL80211_IFTYPE_ADHOC:
804 cfg80211_leave_ibss(rdev, dev, true); 815 __cfg80211_leave_ibss(rdev, dev, true);
805 break; 816 break;
806 case NL80211_IFTYPE_P2P_CLIENT: 817 case NL80211_IFTYPE_P2P_CLIENT:
807 case NL80211_IFTYPE_STATION: 818 case NL80211_IFTYPE_STATION:
808 if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) 819 if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
809 __cfg80211_stop_sched_scan(rdev, false); 820 __cfg80211_stop_sched_scan(rdev, false);
810 821
811 wdev_lock(wdev);
812#ifdef CONFIG_CFG80211_WEXT 822#ifdef CONFIG_CFG80211_WEXT
813 kfree(wdev->wext.ie); 823 kfree(wdev->wext.ie);
814 wdev->wext.ie = NULL; 824 wdev->wext.ie = NULL;
@@ -817,20 +827,49 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
817#endif 827#endif
818 cfg80211_disconnect(rdev, dev, 828 cfg80211_disconnect(rdev, dev,
819 WLAN_REASON_DEAUTH_LEAVING, true); 829 WLAN_REASON_DEAUTH_LEAVING, true);
820 wdev_unlock(wdev);
821 break; 830 break;
822 case NL80211_IFTYPE_MESH_POINT: 831 case NL80211_IFTYPE_MESH_POINT:
823 cfg80211_leave_mesh(rdev, dev); 832 __cfg80211_leave_mesh(rdev, dev);
824 break; 833 break;
825 case NL80211_IFTYPE_AP: 834 case NL80211_IFTYPE_AP:
826 case NL80211_IFTYPE_P2P_GO: 835 case NL80211_IFTYPE_P2P_GO:
827 cfg80211_stop_ap(rdev, dev, true); 836 __cfg80211_stop_ap(rdev, dev, true);
828 break; 837 break;
829 default: 838 default:
830 break; 839 break;
831 } 840 }
832} 841}
833 842
843void cfg80211_leave(struct cfg80211_registered_device *rdev,
844 struct wireless_dev *wdev)
845{
846 wdev_lock(wdev);
847 __cfg80211_leave(rdev, wdev);
848 wdev_unlock(wdev);
849}
850
851void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
852 gfp_t gfp)
853{
854 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
855 struct cfg80211_event *ev;
856 unsigned long flags;
857
858 trace_cfg80211_stop_iface(wiphy, wdev);
859
860 ev = kzalloc(sizeof(*ev), gfp);
861 if (!ev)
862 return;
863
864 ev->type = EVENT_STOPPED;
865
866 spin_lock_irqsave(&wdev->event_lock, flags);
867 list_add_tail(&ev->list, &wdev->event_list);
868 spin_unlock_irqrestore(&wdev->event_lock, flags);
869 queue_work(cfg80211_wq, &rdev->event_work);
870}
871EXPORT_SYMBOL(cfg80211_stop_iface);
872
834static int cfg80211_netdev_notifier_call(struct notifier_block *nb, 873static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
835 unsigned long state, void *ptr) 874 unsigned long state, void *ptr)
836{ 875{
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 681b8fa4355b..e9afbf10e756 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -185,6 +185,7 @@ enum cfg80211_event_type {
185 EVENT_ROAMED, 185 EVENT_ROAMED,
186 EVENT_DISCONNECTED, 186 EVENT_DISCONNECTED,
187 EVENT_IBSS_JOINED, 187 EVENT_IBSS_JOINED,
188 EVENT_STOPPED,
188}; 189};
189 190
190struct cfg80211_event { 191struct cfg80211_event {
@@ -281,6 +282,8 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
281 struct net_device *dev, 282 struct net_device *dev,
282 struct mesh_setup *setup, 283 struct mesh_setup *setup,
283 const struct mesh_config *conf); 284 const struct mesh_config *conf);
285int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
286 struct net_device *dev);
284int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 287int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
285 struct net_device *dev); 288 struct net_device *dev);
286int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, 289int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
@@ -288,6 +291,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
288 struct cfg80211_chan_def *chandef); 291 struct cfg80211_chan_def *chandef);
289 292
290/* AP */ 293/* AP */
294int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
295 struct net_device *dev, bool notify);
291int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, 296int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
292 struct net_device *dev, bool notify); 297 struct net_device *dev, bool notify);
293 298
@@ -441,6 +446,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
441void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 446void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
442 enum nl80211_iftype iftype, int num); 447 enum nl80211_iftype iftype, int num);
443 448
449void __cfg80211_leave(struct cfg80211_registered_device *rdev,
450 struct wireless_dev *wdev);
444void cfg80211_leave(struct cfg80211_registered_device *rdev, 451void cfg80211_leave(struct cfg80211_registered_device *rdev,
445 struct wireless_dev *wdev); 452 struct wireless_dev *wdev);
446 453
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 6b50588b709f..8f345da3ea5f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -420,8 +420,8 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
420 if (len > 0 && ssid[len - 1] == '\0') 420 if (len > 0 && ssid[len - 1] == '\0')
421 len--; 421 len--;
422 422
423 memcpy(wdev->ssid, ssid, len);
423 wdev->wext.ibss.ssid = wdev->ssid; 424 wdev->wext.ibss.ssid = wdev->ssid;
424 memcpy(wdev->wext.ibss.ssid, ssid, len);
425 wdev->wext.ibss.ssid_len = len; 425 wdev->wext.ibss.ssid_len = len;
426 426
427 wdev_lock(wdev); 427 wdev_lock(wdev);
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 3ddfb7cd335e..092300b30c37 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -238,8 +238,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
238 return 0; 238 return 0;
239} 239}
240 240
241static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 241int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
242 struct net_device *dev) 242 struct net_device *dev)
243{ 243{
244 struct wireless_dev *wdev = dev->ieee80211_ptr; 244 struct wireless_dev *wdev = dev->ieee80211_ptr;
245 int err; 245 int err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0f1b18f209d6..62bdb1adaa4d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -371,8 +371,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
371 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, 371 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
372 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, 372 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
373 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, 373 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
374 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 }, 374 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
375 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, 375 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
376 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, 376 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
377 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, 377 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
378 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, 378 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
@@ -386,6 +386,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
386 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, 386 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
387 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, 387 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
388 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, 388 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
389 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
389}; 390};
390 391
391/* policy for the key attributes */ 392/* policy for the key attributes */
@@ -970,8 +971,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
970 c->max_interfaces)) 971 c->max_interfaces))
971 goto nla_put_failure; 972 goto nla_put_failure;
972 if (large && 973 if (large &&
973 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, 974 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
974 c->radar_detect_widths)) 975 c->radar_detect_widths) ||
976 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
977 c->radar_detect_regions)))
975 goto nla_put_failure; 978 goto nla_put_failure;
976 979
977 nla_nest_end(msg, nl_combi); 980 nla_nest_end(msg, nl_combi);
@@ -1667,6 +1670,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
1667 } 1670 }
1668 nla_nest_end(msg, nested); 1671 nla_nest_end(msg, nested);
1669 } 1672 }
1673 state->split_start++;
1674 break;
1675 case 12:
1676 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1677 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1678 rdev->wiphy.max_num_csa_counters))
1679 goto nla_put_failure;
1670 1680
1671 /* done */ 1681 /* done */
1672 state->split_start = 0; 1682 state->split_start = 0;
@@ -3640,6 +3650,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
3640 nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, 3650 nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
3641 sinfo->tx_failed)) 3651 sinfo->tx_failed))
3642 goto nla_put_failure; 3652 goto nla_put_failure;
3653 if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) &&
3654 nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT,
3655 sinfo->expected_throughput))
3656 goto nla_put_failure;
3643 if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && 3657 if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
3644 nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, 3658 nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
3645 sinfo->beacon_loss_count)) 3659 sinfo->beacon_loss_count))
@@ -5820,7 +5834,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
5820 return -EBUSY; 5834 return -EBUSY;
5821 5835
5822 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, 5836 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
5823 NL80211_IFTYPE_UNSPECIFIED); 5837 wdev->iftype);
5824 if (err < 0) 5838 if (err < 0)
5825 return err; 5839 return err;
5826 5840
@@ -5861,6 +5875,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
5861 u8 radar_detect_width = 0; 5875 u8 radar_detect_width = 0;
5862 int err; 5876 int err;
5863 bool need_new_beacon = false; 5877 bool need_new_beacon = false;
5878 int len, i;
5864 5879
5865 if (!rdev->ops->channel_switch || 5880 if (!rdev->ops->channel_switch ||
5866 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) 5881 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
@@ -5919,26 +5934,55 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
5919 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) 5934 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
5920 return -EINVAL; 5935 return -EINVAL;
5921 5936
5922 params.counter_offset_beacon = 5937 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
5923 nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]); 5938 if (!len || (len % sizeof(u16)))
5924 if (params.counter_offset_beacon >= params.beacon_csa.tail_len)
5925 return -EINVAL; 5939 return -EINVAL;
5926 5940
5927 /* sanity check - counters should be the same */ 5941 params.n_counter_offsets_beacon = len / sizeof(u16);
5928 if (params.beacon_csa.tail[params.counter_offset_beacon] != 5942 if (rdev->wiphy.max_num_csa_counters &&
5929 params.count) 5943 (params.n_counter_offsets_beacon >
5944 rdev->wiphy.max_num_csa_counters))
5930 return -EINVAL; 5945 return -EINVAL;
5931 5946
5947 params.counter_offsets_beacon =
5948 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
5949
5950 /* sanity checks - counters should fit and be the same */
5951 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
5952 u16 offset = params.counter_offsets_beacon[i];
5953
5954 if (offset >= params.beacon_csa.tail_len)
5955 return -EINVAL;
5956
5957 if (params.beacon_csa.tail[offset] != params.count)
5958 return -EINVAL;
5959 }
5960
5932 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) { 5961 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
5933 params.counter_offset_presp = 5962 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
5934 nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]); 5963 if (!len || (len % sizeof(u16)))
5935 if (params.counter_offset_presp >=
5936 params.beacon_csa.probe_resp_len)
5937 return -EINVAL; 5964 return -EINVAL;
5938 5965
5939 if (params.beacon_csa.probe_resp[params.counter_offset_presp] != 5966 params.n_counter_offsets_presp = len / sizeof(u16);
5940 params.count) 5967 if (rdev->wiphy.max_num_csa_counters &&
5968 (params.n_counter_offsets_beacon >
5969 rdev->wiphy.max_num_csa_counters))
5941 return -EINVAL; 5970 return -EINVAL;
5971
5972 params.counter_offsets_presp =
5973 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
5974
5975 /* sanity checks - counters should fit and be the same */
5976 for (i = 0; i < params.n_counter_offsets_presp; i++) {
5977 u16 offset = params.counter_offsets_presp[i];
5978
5979 if (offset >= params.beacon_csa.probe_resp_len)
5980 return -EINVAL;
5981
5982 if (params.beacon_csa.probe_resp[offset] !=
5983 params.count)
5984 return -EINVAL;
5985 }
5942 } 5986 }
5943 5987
5944skip_beacons: 5988skip_beacons:
@@ -7784,6 +7828,27 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
7784 if (!chandef.chan && params.offchan) 7828 if (!chandef.chan && params.offchan)
7785 return -EINVAL; 7829 return -EINVAL;
7786 7830
7831 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
7832 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
7833
7834 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
7835 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
7836 int i;
7837
7838 if (len % sizeof(u16))
7839 return -EINVAL;
7840
7841 params.n_csa_offsets = len / sizeof(u16);
7842 params.csa_offsets =
7843 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
7844
7845 /* check that all the offsets fit the frame */
7846 for (i = 0; i < params.n_csa_offsets; i++) {
7847 if (params.csa_offsets[i] >= params.len)
7848 return -EINVAL;
7849 }
7850 }
7851
7787 if (!params.dont_wait_for_ack) { 7852 if (!params.dont_wait_for_ack) {
7788 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 7853 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7789 if (!msg) 7854 if (!msg)
@@ -7797,8 +7862,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
7797 } 7862 }
7798 } 7863 }
7799 7864
7800 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
7801 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
7802 params.chan = chandef.chan; 7865 params.chan = chandef.chan;
7803 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie); 7866 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
7804 if (err) 7867 if (err)
@@ -8495,6 +8558,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
8495 8558
8496 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], 8559 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
8497 rem) { 8560 rem) {
8561 u8 *mask_pat;
8562
8498 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), 8563 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
8499 nla_len(pat), NULL); 8564 nla_len(pat), NULL);
8500 err = -EINVAL; 8565 err = -EINVAL;
@@ -8518,19 +8583,18 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
8518 goto error; 8583 goto error;
8519 new_triggers.patterns[i].pkt_offset = pkt_offset; 8584 new_triggers.patterns[i].pkt_offset = pkt_offset;
8520 8585
8521 new_triggers.patterns[i].mask = 8586 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
8522 kmalloc(mask_len + pat_len, GFP_KERNEL); 8587 if (!mask_pat) {
8523 if (!new_triggers.patterns[i].mask) {
8524 err = -ENOMEM; 8588 err = -ENOMEM;
8525 goto error; 8589 goto error;
8526 } 8590 }
8527 new_triggers.patterns[i].pattern = 8591 new_triggers.patterns[i].mask = mask_pat;
8528 new_triggers.patterns[i].mask + mask_len; 8592 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
8529 memcpy(new_triggers.patterns[i].mask,
8530 nla_data(pat_tb[NL80211_PKTPAT_MASK]),
8531 mask_len); 8593 mask_len);
8594 mask_pat += mask_len;
8595 new_triggers.patterns[i].pattern = mask_pat;
8532 new_triggers.patterns[i].pattern_len = pat_len; 8596 new_triggers.patterns[i].pattern_len = pat_len;
8533 memcpy(new_triggers.patterns[i].pattern, 8597 memcpy(mask_pat,
8534 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), 8598 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
8535 pat_len); 8599 pat_len);
8536 i++; 8600 i++;
@@ -8722,6 +8786,8 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
8722 8786
8723 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], 8787 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
8724 rem) { 8788 rem) {
8789 u8 *mask_pat;
8790
8725 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), 8791 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
8726 nla_len(pat), NULL); 8792 nla_len(pat), NULL);
8727 if (!pat_tb[NL80211_PKTPAT_MASK] || 8793 if (!pat_tb[NL80211_PKTPAT_MASK] ||
@@ -8743,17 +8809,19 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
8743 return -EINVAL; 8809 return -EINVAL;
8744 new_rule->patterns[i].pkt_offset = pkt_offset; 8810 new_rule->patterns[i].pkt_offset = pkt_offset;
8745 8811
8746 new_rule->patterns[i].mask = 8812 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
8747 kmalloc(mask_len + pat_len, GFP_KERNEL); 8813 if (!mask_pat)
8748 if (!new_rule->patterns[i].mask)
8749 return -ENOMEM; 8814 return -ENOMEM;
8750 new_rule->patterns[i].pattern = 8815
8751 new_rule->patterns[i].mask + mask_len; 8816 new_rule->patterns[i].mask = mask_pat;
8752 memcpy(new_rule->patterns[i].mask, 8817 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
8753 nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len); 8818 mask_len);
8819
8820 mask_pat += mask_len;
8821 new_rule->patterns[i].pattern = mask_pat;
8754 new_rule->patterns[i].pattern_len = pat_len; 8822 new_rule->patterns[i].pattern_len = pat_len;
8755 memcpy(new_rule->patterns[i].pattern, 8823 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
8756 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len); 8824 pat_len);
8757 i++; 8825 i++;
8758 } 8826 }
8759 8827
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 00cdf73ba6c4..d95bbe348138 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -199,7 +199,7 @@ static inline int rdev_change_station(struct cfg80211_registered_device *rdev,
199} 199}
200 200
201static inline int rdev_get_station(struct cfg80211_registered_device *rdev, 201static inline int rdev_get_station(struct cfg80211_registered_device *rdev,
202 struct net_device *dev, u8 *mac, 202 struct net_device *dev, const u8 *mac,
203 struct station_info *sinfo) 203 struct station_info *sinfo)
204{ 204{
205 int ret; 205 int ret;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e78f532aaa5b..558b0e3a02d8 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1876,7 +1876,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
1876 case NL80211_REGDOM_SET_BY_USER: 1876 case NL80211_REGDOM_SET_BY_USER:
1877 treatment = reg_process_hint_user(reg_request); 1877 treatment = reg_process_hint_user(reg_request);
1878 if (treatment == REG_REQ_IGNORE || 1878 if (treatment == REG_REQ_IGNORE ||
1879 treatment == REG_REQ_ALREADY_SET) 1879 treatment == REG_REQ_ALREADY_SET ||
1880 treatment == REG_REQ_USER_HINT_HANDLED)
1880 return; 1881 return;
1881 queue_delayed_work(system_power_efficient_wq, 1882 queue_delayed_work(system_power_efficient_wq,
1882 &reg_timeout, msecs_to_jiffies(3142)); 1883 &reg_timeout, msecs_to_jiffies(3142));
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e7329bb6a323..0798c62e6085 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -891,6 +891,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
891 struct cfg80211_bss_ies *ies; 891 struct cfg80211_bss_ies *ies;
892 struct ieee80211_channel *channel; 892 struct ieee80211_channel *channel;
893 struct cfg80211_internal_bss tmp = {}, *res; 893 struct cfg80211_internal_bss tmp = {}, *res;
894 bool signal_valid;
894 895
895 if (WARN_ON(!wiphy)) 896 if (WARN_ON(!wiphy))
896 return NULL; 897 return NULL;
@@ -927,8 +928,9 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
927 rcu_assign_pointer(tmp.pub.beacon_ies, ies); 928 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
928 rcu_assign_pointer(tmp.pub.ies, ies); 929 rcu_assign_pointer(tmp.pub.ies, ies);
929 930
930 res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, 931 signal_valid = abs(rx_channel->center_freq - channel->center_freq) <=
931 rx_channel == channel); 932 wiphy->max_adj_channel_rssi_comp;
933 res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
932 if (!res) 934 if (!res)
933 return NULL; 935 return NULL;
934 936
@@ -952,6 +954,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
952 struct cfg80211_internal_bss tmp = {}, *res; 954 struct cfg80211_internal_bss tmp = {}, *res;
953 struct cfg80211_bss_ies *ies; 955 struct cfg80211_bss_ies *ies;
954 struct ieee80211_channel *channel; 956 struct ieee80211_channel *channel;
957 bool signal_valid;
955 size_t ielen = len - offsetof(struct ieee80211_mgmt, 958 size_t ielen = len - offsetof(struct ieee80211_mgmt,
956 u.probe_resp.variable); 959 u.probe_resp.variable);
957 960
@@ -999,8 +1002,9 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
999 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); 1002 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
1000 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); 1003 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
1001 1004
1002 res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, 1005 signal_valid = abs(rx_channel->center_freq - channel->center_freq) <=
1003 rx_channel == channel); 1006 wiphy->max_adj_channel_rssi_comp;
1007 res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
1004 if (!res) 1008 if (!res)
1005 return NULL; 1009 return NULL;
1006 1010
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 0c0844b585d1..8bbeeb302216 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -149,7 +149,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
149 case CFG80211_CONN_SCAN_AGAIN: 149 case CFG80211_CONN_SCAN_AGAIN:
150 return cfg80211_conn_scan(wdev); 150 return cfg80211_conn_scan(wdev);
151 case CFG80211_CONN_AUTHENTICATE_NEXT: 151 case CFG80211_CONN_AUTHENTICATE_NEXT:
152 BUG_ON(!rdev->ops->auth); 152 if (WARN_ON(!rdev->ops->auth))
153 return -EOPNOTSUPP;
153 wdev->conn->state = CFG80211_CONN_AUTHENTICATING; 154 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
154 return cfg80211_mlme_auth(rdev, wdev->netdev, 155 return cfg80211_mlme_auth(rdev, wdev->netdev,
155 params->channel, params->auth_type, 156 params->channel, params->auth_type,
@@ -161,7 +162,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
161 case CFG80211_CONN_AUTH_FAILED: 162 case CFG80211_CONN_AUTH_FAILED:
162 return -ENOTCONN; 163 return -ENOTCONN;
163 case CFG80211_CONN_ASSOCIATE_NEXT: 164 case CFG80211_CONN_ASSOCIATE_NEXT:
164 BUG_ON(!rdev->ops->assoc); 165 if (WARN_ON(!rdev->ops->assoc))
166 return -EOPNOTSUPP;
165 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 167 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
166 if (wdev->conn->prev_bssid_valid) 168 if (wdev->conn->prev_bssid_valid)
167 req.prev_bssid = wdev->conn->prev_bssid; 169 req.prev_bssid = wdev->conn->prev_bssid;
@@ -877,7 +879,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
877} 879}
878 880
879void cfg80211_disconnected(struct net_device *dev, u16 reason, 881void cfg80211_disconnected(struct net_device *dev, u16 reason,
880 u8 *ie, size_t ie_len, gfp_t gfp) 882 const u8 *ie, size_t ie_len, gfp_t gfp)
881{ 883{
882 struct wireless_dev *wdev = dev->ieee80211_ptr; 884 struct wireless_dev *wdev = dev->ieee80211_ptr;
883 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 885 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index f3c13ff4d04c..560ed77084e9 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1876,29 +1876,33 @@ TRACE_EVENT(rdev_channel_switch,
1876 WIPHY_ENTRY 1876 WIPHY_ENTRY
1877 NETDEV_ENTRY 1877 NETDEV_ENTRY
1878 CHAN_DEF_ENTRY 1878 CHAN_DEF_ENTRY
1879 __field(u16, counter_offset_beacon)
1880 __field(u16, counter_offset_presp)
1881 __field(bool, radar_required) 1879 __field(bool, radar_required)
1882 __field(bool, block_tx) 1880 __field(bool, block_tx)
1883 __field(u8, count) 1881 __field(u8, count)
1882 __dynamic_array(u16, bcn_ofs, params->n_counter_offsets_beacon)
1883 __dynamic_array(u16, pres_ofs, params->n_counter_offsets_presp)
1884 ), 1884 ),
1885 TP_fast_assign( 1885 TP_fast_assign(
1886 WIPHY_ASSIGN; 1886 WIPHY_ASSIGN;
1887 NETDEV_ASSIGN; 1887 NETDEV_ASSIGN;
1888 CHAN_DEF_ASSIGN(&params->chandef); 1888 CHAN_DEF_ASSIGN(&params->chandef);
1889 __entry->counter_offset_beacon = params->counter_offset_beacon;
1890 __entry->counter_offset_presp = params->counter_offset_presp;
1891 __entry->radar_required = params->radar_required; 1889 __entry->radar_required = params->radar_required;
1892 __entry->block_tx = params->block_tx; 1890 __entry->block_tx = params->block_tx;
1893 __entry->count = params->count; 1891 __entry->count = params->count;
1892 memcpy(__get_dynamic_array(bcn_ofs),
1893 params->counter_offsets_beacon,
1894 params->n_counter_offsets_beacon * sizeof(u16));
1895
1896 /* probe response offsets are optional */
1897 if (params->n_counter_offsets_presp)
1898 memcpy(__get_dynamic_array(pres_ofs),
1899 params->counter_offsets_presp,
1900 params->n_counter_offsets_presp * sizeof(u16));
1894 ), 1901 ),
1895 TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT 1902 TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
1896 ", block_tx: %d, count: %u, radar_required: %d" 1903 ", block_tx: %d, count: %u, radar_required: %d",
1897 ", counter offsets (beacon/presp): %u/%u",
1898 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, 1904 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
1899 __entry->block_tx, __entry->count, __entry->radar_required, 1905 __entry->block_tx, __entry->count, __entry->radar_required)
1900 __entry->counter_offset_beacon,
1901 __entry->counter_offset_presp)
1902); 1906);
1903 1907
1904TRACE_EVENT(rdev_set_qos_map, 1908TRACE_EVENT(rdev_set_qos_map,
@@ -2636,6 +2640,21 @@ TRACE_EVENT(cfg80211_ft_event,
2636 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) 2640 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
2637); 2641);
2638 2642
2643TRACE_EVENT(cfg80211_stop_iface,
2644 TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
2645 TP_ARGS(wiphy, wdev),
2646 TP_STRUCT__entry(
2647 WIPHY_ENTRY
2648 WDEV_ENTRY
2649 ),
2650 TP_fast_assign(
2651 WIPHY_ASSIGN;
2652 WDEV_ASSIGN;
2653 ),
2654 TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
2655 WIPHY_PR_ARG, WDEV_PR_ARG)
2656);
2657
2639#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ 2658#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
2640 2659
2641#undef TRACE_INCLUDE_PATH 2660#undef TRACE_INCLUDE_PATH
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 7c47fa07b276..728f1c0dc70d 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -476,7 +476,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
476EXPORT_SYMBOL(ieee80211_data_to_8023); 476EXPORT_SYMBOL(ieee80211_data_to_8023);
477 477
478int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, 478int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
479 enum nl80211_iftype iftype, u8 *bssid, bool qos) 479 enum nl80211_iftype iftype,
480 const u8 *bssid, bool qos)
480{ 481{
481 struct ieee80211_hdr hdr; 482 struct ieee80211_hdr hdr;
482 u16 hdrlen, ethertype; 483 u16 hdrlen, ethertype;
@@ -839,6 +840,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
839 __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, 840 __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
840 ev->ij.channel); 841 ev->ij.channel);
841 break; 842 break;
843 case EVENT_STOPPED:
844 __cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
845 break;
842 } 846 }
843 wdev_unlock(wdev); 847 wdev_unlock(wdev);
844 848
@@ -1271,10 +1275,20 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
1271 void *data), 1275 void *data),
1272 void *data) 1276 void *data)
1273{ 1277{
1278 const struct ieee80211_regdomain *regdom;
1279 enum nl80211_dfs_regions region = 0;
1274 int i, j, iftype; 1280 int i, j, iftype;
1275 int num_interfaces = 0; 1281 int num_interfaces = 0;
1276 u32 used_iftypes = 0; 1282 u32 used_iftypes = 0;
1277 1283
1284 if (radar_detect) {
1285 rcu_read_lock();
1286 regdom = rcu_dereference(cfg80211_regdomain);
1287 if (regdom)
1288 region = regdom->dfs_region;
1289 rcu_read_unlock();
1290 }
1291
1278 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { 1292 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
1279 num_interfaces += iftype_num[iftype]; 1293 num_interfaces += iftype_num[iftype];
1280 if (iftype_num[iftype] > 0 && 1294 if (iftype_num[iftype] > 0 &&
@@ -1315,6 +1329,10 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
1315 if (radar_detect != (c->radar_detect_widths & radar_detect)) 1329 if (radar_detect != (c->radar_detect_widths & radar_detect))
1316 goto cont; 1330 goto cont;
1317 1331
1332 if (radar_detect && c->radar_detect_regions &&
1333 !(c->radar_detect_regions & BIT(region)))
1334 goto cont;
1335
1318 /* Finally check that all iftypes that we're currently 1336 /* Finally check that all iftypes that we're currently
1319 * using are actually part of this combination. If they 1337 * using are actually part of this combination. If they
1320 * aren't then we can't use this combination and have 1338 * aren't then we can't use this combination and have
@@ -1528,6 +1546,24 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
1528} 1546}
1529EXPORT_SYMBOL(ieee80211_get_num_supported_channels); 1547EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
1530 1548
1549int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
1550 struct station_info *sinfo)
1551{
1552 struct cfg80211_registered_device *rdev;
1553 struct wireless_dev *wdev;
1554
1555 wdev = dev->ieee80211_ptr;
1556 if (!wdev)
1557 return -EOPNOTSUPP;
1558
1559 rdev = wiphy_to_rdev(wdev->wiphy);
1560 if (!rdev->ops->get_station)
1561 return -EOPNOTSUPP;
1562
1563 return rdev_get_station(rdev, dev, mac_addr, sinfo);
1564}
1565EXPORT_SYMBOL(cfg80211_get_station);
1566
1531/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ 1567/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
1532/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ 1568/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
1533const unsigned char rfc1042_header[] __aligned(2) = 1569const unsigned char rfc1042_header[] __aligned(2) =