aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c17
-rw-r--r--include/linux/nl80211.h65
-rw-r--r--include/net/cfg80211.h131
-rw-r--r--include/net/mac80211.h6
-rw-r--r--include/net/wireless.h3
-rw-r--r--net/mac80211/cfg.c20
-rw-r--r--net/mac80211/ieee80211_i.h18
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/main.c32
-rw-r--r--net/mac80211/mlme.c37
-rw-r--r--net/mac80211/scan.c356
-rw-r--r--net/mac80211/wext.c59
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c8
-rw-r--r--net/wireless/core.h20
-rw-r--r--net/wireless/nl80211.c323
-rw-r--r--net/wireless/nl80211.h8
-rw-r--r--net/wireless/scan.c807
21 files changed, 1546 insertions, 383 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c196abc6db7a..539960da7e13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2678,11 +2678,19 @@ static void iwl_bss_info_changed(struct ieee80211_hw *hw,
2678 2678
2679} 2679}
2680 2680
2681static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) 2681static int iwl_mac_hw_scan(struct ieee80211_hw *hw,
2682 struct cfg80211_scan_request *req)
2682{ 2683{
2683 unsigned long flags; 2684 unsigned long flags;
2684 struct iwl_priv *priv = hw->priv; 2685 struct iwl_priv *priv = hw->priv;
2685 int ret; 2686 int ret;
2687 u8 *ssid = NULL;
2688 size_t ssid_len = 0;
2689
2690 if (req->n_ssids) {
2691 ssid = req->ssids[0].ssid;
2692 ssid_len = req->ssids[0].ssid_len;
2693 }
2686 2694
2687 IWL_DEBUG_MAC80211(priv, "enter\n"); 2695 IWL_DEBUG_MAC80211(priv, "enter\n");
2688 2696
@@ -2718,7 +2726,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
2718 2726
2719 if (ssid_len) { 2727 if (ssid_len) {
2720 priv->one_direct_scan = 1; 2728 priv->one_direct_scan = 1;
2721 priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); 2729 priv->direct_ssid_len = ssid_len;
2722 memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); 2730 memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
2723 } else { 2731 } else {
2724 priv->one_direct_scan = 0; 2732 priv->one_direct_scan = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index e18c3f326f71..260bf903cb71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1271,6 +1271,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
1271 BIT(NL80211_IFTYPE_ADHOC); 1271 BIT(NL80211_IFTYPE_ADHOC);
1272 1272
1273 hw->wiphy->custom_regulatory = true; 1273 hw->wiphy->custom_regulatory = true;
1274 hw->wiphy->max_scan_ssids = 1;
1274 1275
1275 /* Default value; 4 EDCA QOS priorities */ 1276 /* Default value; 4 EDCA QOS priorities */
1276 hw->queues = 4; 1277 hw->queues = 4;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 22bad3ce7d6a..1ec2b20eb37c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -860,7 +860,7 @@ void iwl_bg_scan_completed(struct work_struct *work)
860 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 860 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
861 return; 861 return;
862 862
863 ieee80211_scan_completed(priv->hw); 863 ieee80211_scan_completed(priv->hw, false);
864 864
865 /* Since setting the TXPOWER may have been deferred while 865 /* Since setting the TXPOWER may have been deferred while
866 * performing the scan, fire one off */ 866 * performing the scan, fire one off */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 42cc2884971c..0cd8cb96a5ef 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4442,15 +4442,23 @@ static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
4442 4442
4443} 4443}
4444 4444
4445static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) 4445static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw,
4446 struct cfg80211_scan_request *req)
4446{ 4447{
4447 int rc = 0; 4448 int rc = 0;
4448 unsigned long flags; 4449 unsigned long flags;
4449 struct iwl_priv *priv = hw->priv; 4450 struct iwl_priv *priv = hw->priv;
4451 size_t len = 0;
4452 u8 *ssid = NULL;
4450 DECLARE_SSID_BUF(ssid_buf); 4453 DECLARE_SSID_BUF(ssid_buf);
4451 4454
4452 IWL_DEBUG_MAC80211(priv, "enter\n"); 4455 IWL_DEBUG_MAC80211(priv, "enter\n");
4453 4456
4457 if (req->n_ssids) {
4458 ssid = req->ssids[0].ssid;
4459 len = req->ssids[0].ssid_len;
4460 }
4461
4454 mutex_lock(&priv->mutex); 4462 mutex_lock(&priv->mutex);
4455 spin_lock_irqsave(&priv->lock, flags); 4463 spin_lock_irqsave(&priv->lock, flags);
4456 4464
@@ -4478,9 +4486,8 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
4478 print_ssid(ssid_buf, ssid, len), len); 4486 print_ssid(ssid_buf, ssid, len), len);
4479 4487
4480 priv->one_direct_scan = 1; 4488 priv->one_direct_scan = 1;
4481 priv->direct_ssid_len = (u8) 4489 priv->direct_ssid_len = len;
4482 min((u8) len, (u8) IW_ESSID_MAX_SIZE); 4490 memcpy(priv->direct_ssid, ssid, len);
4483 memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
4484 } else 4491 } else
4485 priv->one_direct_scan = 0; 4492 priv->one_direct_scan = 0;
4486 4493
@@ -5412,6 +5419,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
5412 5419
5413 hw->wiphy->custom_regulatory = true; 5420 hw->wiphy->custom_regulatory = true;
5414 5421
5422 hw->wiphy->max_scan_ssids = 1;
5423
5415 /* 4 EDCA QOS priorities */ 5424 /* 4 EDCA QOS priorities */
5416 hw->queues = 4; 5425 hw->queues = 4;
5417 5426
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 4bc27049f4e5..8802d1bda382 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -143,6 +143,13 @@
143 * added to all specified management frames generated by 143 * added to all specified management frames generated by
144 * kernel/firmware/driver. 144 * kernel/firmware/driver.
145 * 145 *
146 * @NL80211_CMD_GET_SCAN: get scan results
147 * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
148 * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
149 * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
150 * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
151 * partial scan results may be available
152 *
146 * @NL80211_CMD_MAX: highest used command number 153 * @NL80211_CMD_MAX: highest used command number
147 * @__NL80211_CMD_AFTER_LAST: internal use 154 * @__NL80211_CMD_AFTER_LAST: internal use
148 */ 155 */
@@ -192,6 +199,11 @@ enum nl80211_commands {
192 199
193 NL80211_CMD_GET_REG, 200 NL80211_CMD_GET_REG,
194 201
202 NL80211_CMD_GET_SCAN,
203 NL80211_CMD_TRIGGER_SCAN,
204 NL80211_CMD_NEW_SCAN_RESULTS,
205 NL80211_CMD_SCAN_ABORTED,
206
195 /* add new commands above here */ 207 /* add new commands above here */
196 208
197 /* used to define NL80211_CMD_MAX below */ 209 /* used to define NL80211_CMD_MAX below */
@@ -305,6 +317,18 @@ enum nl80211_commands {
305 * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with 317 * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
306 * %NL80211_CMD_SET_MGMT_EXTRA_IE). 318 * %NL80211_CMD_SET_MGMT_EXTRA_IE).
307 * 319 *
320 * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
321 * a single scan request, a wiphy attribute.
322 *
323 * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
324 * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
325 * scanning and include a zero-length SSID (wildcard) for wildcard scan
326 * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
327 * scan result list changes (BSS expired or added) so that applications
328 * can verify that they got a single, consistent snapshot (when all dump
329 * messages carried the same generation number)
330 * @NL80211_ATTR_BSS: scan result BSS
331 *
308 * @NL80211_ATTR_MAX: highest attribute number currently defined 332 * @NL80211_ATTR_MAX: highest attribute number currently defined
309 * @__NL80211_ATTR_AFTER_LAST: internal use 333 * @__NL80211_ATTR_AFTER_LAST: internal use
310 */ 334 */
@@ -372,6 +396,13 @@ enum nl80211_attrs {
372 NL80211_ATTR_MGMT_SUBTYPE, 396 NL80211_ATTR_MGMT_SUBTYPE,
373 NL80211_ATTR_IE, 397 NL80211_ATTR_IE,
374 398
399 NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
400
401 NL80211_ATTR_SCAN_FREQUENCIES,
402 NL80211_ATTR_SCAN_SSIDS,
403 NL80211_ATTR_SCAN_GENERATION,
404 NL80211_ATTR_BSS,
405
375 /* add attributes here, update the policy in nl80211.c */ 406 /* add attributes here, update the policy in nl80211.c */
376 407
377 __NL80211_ATTR_AFTER_LAST, 408 __NL80211_ATTR_AFTER_LAST,
@@ -841,4 +872,38 @@ enum nl80211_channel_type {
841 NL80211_CHAN_HT40MINUS, 872 NL80211_CHAN_HT40MINUS,
842 NL80211_CHAN_HT40PLUS 873 NL80211_CHAN_HT40PLUS
843}; 874};
875
876/**
877 * enum nl80211_bss - netlink attributes for a BSS
878 *
879 * @__NL80211_BSS_INVALID: invalid
880 * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
881 * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
882 * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
883 * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
884 * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
885 * raw information elements from the probe response/beacon (bin)
886 * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
887 * in mBm (100 * dBm) (s32)
888 * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
889 * in unspecified units, scaled to 0..100 (u8)
890 * @__NL80211_BSS_AFTER_LAST: internal
891 * @NL80211_BSS_MAX: highest BSS attribute
892 */
893enum nl80211_bss {
894 __NL80211_BSS_INVALID,
895 NL80211_BSS_BSSID,
896 NL80211_BSS_FREQUENCY,
897 NL80211_BSS_TSF,
898 NL80211_BSS_BEACON_INTERVAL,
899 NL80211_BSS_CAPABILITY,
900 NL80211_BSS_INFORMATION_ELEMENTS,
901 NL80211_BSS_SIGNAL_MBM,
902 NL80211_BSS_SIGNAL_UNSPEC,
903
904 /* keep last */
905 __NL80211_BSS_AFTER_LAST,
906 NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
907};
908
844#endif /* __LINUX_NL80211_H */ 909#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dd1fd51638fc..09a0b268e5cf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4,6 +4,10 @@
4#include <linux/netlink.h> 4#include <linux/netlink.h>
5#include <linux/skbuff.h> 5#include <linux/skbuff.h>
6#include <linux/nl80211.h> 6#include <linux/nl80211.h>
7#include <linux/if_ether.h>
8#include <linux/ieee80211.h>
9#include <linux/wireless.h>
10#include <net/iw_handler.h>
7#include <net/genetlink.h> 11#include <net/genetlink.h>
8/* remove once we remove the wext stuff */ 12/* remove once we remove the wext stuff */
9#include <net/iw_handler.h> 13#include <net/iw_handler.h>
@@ -505,6 +509,83 @@ struct wiphy;
505struct ieee80211_channel; 509struct ieee80211_channel;
506 510
507/** 511/**
512 * struct cfg80211_ssid - SSID description
513 * @ssid: the SSID
514 * @ssid_len: length of the ssid
515 */
516struct cfg80211_ssid {
517 u8 ssid[IEEE80211_MAX_SSID_LEN];
518 u8 ssid_len;
519};
520
521/**
522 * struct cfg80211_scan_request - scan request description
523 *
524 * @ssids: SSIDs to scan for (active scan only)
525 * @n_ssids: number of SSIDs
526 * @channels: channels to scan on.
527 * @n_channels: number of channels for each band
528 * @wiphy: the wiphy this was for
529 * @ifidx: the interface index
530 */
531struct cfg80211_scan_request {
532 struct cfg80211_ssid *ssids;
533 int n_ssids;
534 struct ieee80211_channel **channels;
535 u32 n_channels;
536
537 /* internal */
538 struct wiphy *wiphy;
539 int ifidx;
540};
541
542/**
543 * enum cfg80211_signal_type - signal type
544 *
545 * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
546 * @CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm)
547 * @CFG80211_SIGNAL_TYPE_UNSPEC: signal strength, increasing from 0 through 100
548 */
549enum cfg80211_signal_type {
550 CFG80211_SIGNAL_TYPE_NONE,
551 CFG80211_SIGNAL_TYPE_MBM,
552 CFG80211_SIGNAL_TYPE_UNSPEC,
553};
554
555/**
556 * struct cfg80211_bss - BSS description
557 *
558 * This structure describes a BSS (which may also be a mesh network)
559 * for use in scan results and similar.
560 *
561 * @bssid: BSSID of the BSS
562 * @tsf: timestamp of last received update
563 * @beacon_interval: the beacon interval as from the frame
564 * @capability: the capability field in host byte order
565 * @information_elements: the information elements (Note that there
566 * is no guarantee that these are well-formed!)
567 * @len_information_elements: total length of the information elements
568 * @signal: signal strength value
569 * @signal_type: signal type
570 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
571 */
572struct cfg80211_bss {
573 struct ieee80211_channel *channel;
574
575 u8 bssid[ETH_ALEN];
576 u64 tsf;
577 u16 beacon_interval;
578 u16 capability;
579 u8 *information_elements;
580 size_t len_information_elements;
581
582 s32 signal;
583 enum cfg80211_signal_type signal_type;
584
585 u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
586};
587
588/**
508 * struct cfg80211_ops - backend description for wireless configuration 589 * struct cfg80211_ops - backend description for wireless configuration
509 * 590 *
510 * This struct is registered by fullmac card drivers and/or wireless stacks 591 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -571,6 +652,11 @@ struct ieee80211_channel;
571 * @set_channel: Set channel 652 * @set_channel: Set channel
572 * 653 *
573 * @set_mgmt_extra_ie: Set extra IE data for management frames 654 * @set_mgmt_extra_ie: Set extra IE data for management frames
655 *
656 * @scan: Request to do a scan. If returning zero, the scan request is given
657 * the driver, and will be valid until passed to cfg80211_scan_done().
658 * For scan results, call cfg80211_inform_bss(); you can call this outside
659 * the scan/scan_done bracket too.
574 */ 660 */
575struct cfg80211_ops { 661struct cfg80211_ops {
576 int (*suspend)(struct wiphy *wiphy); 662 int (*suspend)(struct wiphy *wiphy);
@@ -648,6 +734,9 @@ struct cfg80211_ops {
648 int (*set_mgmt_extra_ie)(struct wiphy *wiphy, 734 int (*set_mgmt_extra_ie)(struct wiphy *wiphy,
649 struct net_device *dev, 735 struct net_device *dev,
650 struct mgmt_extra_ie_params *params); 736 struct mgmt_extra_ie_params *params);
737
738 int (*scan)(struct wiphy *wiphy, struct net_device *dev,
739 struct cfg80211_scan_request *request);
651}; 740};
652 741
653/* temporary wext handlers */ 742/* temporary wext handlers */
@@ -658,5 +747,47 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
658 u32 *mode, char *extra); 747 u32 *mode, char *extra);
659int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, 748int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
660 u32 *mode, char *extra); 749 u32 *mode, char *extra);
750int cfg80211_wext_siwscan(struct net_device *dev,
751 struct iw_request_info *info,
752 union iwreq_data *wrqu, char *extra);
753int cfg80211_wext_giwscan(struct net_device *dev,
754 struct iw_request_info *info,
755 struct iw_point *data, char *extra);
756
757/**
758 * cfg80211_scan_done - notify that scan finished
759 *
760 * @request: the corresponding scan request
761 * @aborted: set to true if the scan was aborted for any reason,
762 * userspace will be notified of that
763 */
764void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
765
766/**
767 * cfg80211_inform_bss - inform cfg80211 of a new BSS
768 *
769 * @wiphy: the wiphy reporting the BSS
770 * @bss: the found BSS
771 * @gfp: context flags
772 *
773 * This informs cfg80211 that BSS information was found and
774 * the BSS should be updated/added.
775 */
776struct cfg80211_bss*
777cfg80211_inform_bss_frame(struct wiphy *wiphy,
778 struct ieee80211_channel *channel,
779 struct ieee80211_mgmt *mgmt, size_t len,
780 s32 signal, enum cfg80211_signal_type sigtype,
781 gfp_t gfp);
782
783struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
784 struct ieee80211_channel *channel,
785 const u8 *bssid,
786 const u8 *ssid, size_t ssid_len);
787struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
788 struct ieee80211_channel *channel,
789 const u8 *meshid, size_t meshidlen,
790 const u8 *meshcfg);
791void cfg80211_put_bss(struct cfg80211_bss *bss);
661 792
662#endif /* __NET_CFG80211_H */ 793#endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 341f3e595ebd..88fa3e03e3e9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1406,7 +1406,8 @@ struct ieee80211_ops {
1406 void (*update_tkip_key)(struct ieee80211_hw *hw, 1406 void (*update_tkip_key)(struct ieee80211_hw *hw,
1407 struct ieee80211_key_conf *conf, const u8 *address, 1407 struct ieee80211_key_conf *conf, const u8 *address,
1408 u32 iv32, u16 *phase1key); 1408 u32 iv32, u16 *phase1key);
1409 int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); 1409 int (*hw_scan)(struct ieee80211_hw *hw,
1410 struct cfg80211_scan_request *req);
1410 int (*get_stats)(struct ieee80211_hw *hw, 1411 int (*get_stats)(struct ieee80211_hw *hw,
1411 struct ieee80211_low_level_stats *stats); 1412 struct ieee80211_low_level_stats *stats);
1412 void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, 1413 void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
@@ -1844,8 +1845,9 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
1844 * mac80211 that the scan finished. 1845 * mac80211 that the scan finished.
1845 * 1846 *
1846 * @hw: the hardware that finished the scan 1847 * @hw: the hardware that finished the scan
1848 * @aborted: set to true if scan was aborted
1847 */ 1849 */
1848void ieee80211_scan_completed(struct ieee80211_hw *hw); 1850void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
1849 1851
1850/** 1852/**
1851 * ieee80211_iterate_active_interfaces - iterate active interfaces 1853 * ieee80211_iterate_active_interfaces - iterate active interfaces
diff --git a/include/net/wireless.h b/include/net/wireless.h
index a42c1562d52b..1c6285eb1666 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -213,6 +213,9 @@ struct wiphy {
213 bool custom_regulatory; 213 bool custom_regulatory;
214 bool strict_regulatory; 214 bool strict_regulatory;
215 215
216 int bss_priv_size;
217 u8 max_scan_ssids;
218
216 /* If multiple wiphys are registered and you're handed e.g. 219 /* If multiple wiphys are registered and you're handed e.g.
217 * a regular netdev with assigned ieee80211_ptr, you won't 220 * a regular netdev with assigned ieee80211_ptr, you won't
218 * know whether it points to a wiphy your driver has registered 221 * know whether it points to a wiphy your driver has registered
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 42d692fd9bec..c8d969be440b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1277,6 +1277,25 @@ static int ieee80211_resume(struct wiphy *wiphy)
1277#define ieee80211_resume NULL 1277#define ieee80211_resume NULL
1278#endif 1278#endif
1279 1279
1280static int ieee80211_scan(struct wiphy *wiphy,
1281 struct net_device *dev,
1282 struct cfg80211_scan_request *req)
1283{
1284 struct ieee80211_sub_if_data *sdata;
1285
1286 if (!netif_running(dev))
1287 return -ENETDOWN;
1288
1289 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1290
1291 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
1292 sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1293 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
1294 return -EOPNOTSUPP;
1295
1296 return ieee80211_request_scan(sdata, req);
1297}
1298
1280struct cfg80211_ops mac80211_config_ops = { 1299struct cfg80211_ops mac80211_config_ops = {
1281 .add_virtual_intf = ieee80211_add_iface, 1300 .add_virtual_intf = ieee80211_add_iface,
1282 .del_virtual_intf = ieee80211_del_iface, 1301 .del_virtual_intf = ieee80211_del_iface,
@@ -1309,4 +1328,5 @@ struct cfg80211_ops mac80211_config_ops = {
1309 .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, 1328 .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
1310 .suspend = ieee80211_suspend, 1329 .suspend = ieee80211_suspend,
1311 .resume = ieee80211_resume, 1330 .resume = ieee80211_resume,
1331 .scan = ieee80211_scan,
1312}; 1332};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9122416fd6af..cbc0b7d647f9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -294,8 +294,6 @@ struct ieee80211_if_sta {
294 u8 ssid[IEEE80211_MAX_SSID_LEN]; 294 u8 ssid[IEEE80211_MAX_SSID_LEN];
295 enum ieee80211_sta_mlme_state state; 295 enum ieee80211_sta_mlme_state state;
296 size_t ssid_len; 296 size_t ssid_len;
297 u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
298 size_t scan_ssid_len;
299 u16 aid; 297 u16 aid;
300 u16 ap_capab, capab; 298 u16 ap_capab, capab;
301 u8 *extra_ie; /* to be added to the end of AssocReq */ 299 u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -658,17 +656,18 @@ struct ieee80211_local {
658 656
659 /* Scanning and BSS list */ 657 /* Scanning and BSS list */
660 bool sw_scanning, hw_scanning; 658 bool sw_scanning, hw_scanning;
659 struct cfg80211_ssid scan_ssid;
660 struct cfg80211_scan_request int_scan_req;
661 struct cfg80211_scan_request *scan_req;
662 struct ieee80211_channel *scan_channel;
661 int scan_channel_idx; 663 int scan_channel_idx;
662 enum ieee80211_band scan_band;
663 664
664 enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; 665 enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
665 unsigned long last_scan_completed; 666 unsigned long last_scan_completed;
666 struct delayed_work scan_work; 667 struct delayed_work scan_work;
667 struct ieee80211_sub_if_data *scan_sdata; 668 struct ieee80211_sub_if_data *scan_sdata;
668 struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel;
669 enum nl80211_channel_type oper_channel_type; 669 enum nl80211_channel_type oper_channel_type;
670 u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; 670 struct ieee80211_channel *oper_channel, *csa_channel;
671 size_t scan_ssid_len;
672 struct list_head bss_list; 671 struct list_head bss_list;
673 struct ieee80211_bss *bss_hash[STA_HASH_SIZE]; 672 struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
674 spinlock_t bss_lock; 673 spinlock_t bss_lock;
@@ -929,7 +928,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
929 928
930/* scan/BSS handling */ 929/* scan/BSS handling */
931int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 930int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
932 u8 *ssid, size_t ssid_len); 931 struct cfg80211_scan_request *req);
933int ieee80211_scan_results(struct ieee80211_local *local, 932int ieee80211_scan_results(struct ieee80211_local *local,
934 struct iw_request_info *info, 933 struct iw_request_info *info,
935 char *buf, size_t len); 934 char *buf, size_t len);
@@ -944,14 +943,15 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
944 943
945void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); 944void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
946int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, 945int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
947 u8 *ssid, size_t ssid_len); 946 struct cfg80211_scan_request *req);
948struct ieee80211_bss * 947struct ieee80211_bss *
949ieee80211_bss_info_update(struct ieee80211_local *local, 948ieee80211_bss_info_update(struct ieee80211_local *local,
950 struct ieee80211_rx_status *rx_status, 949 struct ieee80211_rx_status *rx_status,
951 struct ieee80211_mgmt *mgmt, 950 struct ieee80211_mgmt *mgmt,
952 size_t len, 951 size_t len,
953 struct ieee802_11_elems *elems, 952 struct ieee802_11_elems *elems,
954 int freq, bool beacon); 953 struct ieee80211_channel *channel,
954 bool beacon);
955struct ieee80211_bss * 955struct ieee80211_bss *
956ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, 956ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
957 u8 *ssid, u8 ssid_len); 957 u8 *ssid, u8 ssid_len);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1c17fb8e4058..df94b9365264 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -522,7 +522,7 @@ static int ieee80211_stop(struct net_device *dev)
522 * scan event to userspace -- the scan is incomplete. 522 * scan event to userspace -- the scan is incomplete.
523 */ 523 */
524 if (local->sw_scanning) 524 if (local->sw_scanning)
525 ieee80211_scan_completed(&local->hw); 525 ieee80211_scan_completed(&local->hw, true);
526 } 526 }
527 527
528 conf.vif = &sdata->vif; 528 conf.vif = &sdata->vif;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 956afea4214d..954edfbb6b6f 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -733,6 +733,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
733 return NULL; 733 return NULL;
734 734
735 wiphy->privid = mac80211_wiphy_privid; 735 wiphy->privid = mac80211_wiphy_privid;
736 wiphy->max_scan_ssids = 4;
736 737
737 local = wiphy_priv(wiphy); 738 local = wiphy_priv(wiphy);
738 local->hw.wiphy = wiphy; 739 local->hw.wiphy = wiphy;
@@ -817,25 +818,33 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
817 enum ieee80211_band band; 818 enum ieee80211_band band;
818 struct net_device *mdev; 819 struct net_device *mdev;
819 struct ieee80211_master_priv *mpriv; 820 struct ieee80211_master_priv *mpriv;
821 int channels, i, j;
820 822
821 /* 823 /*
822 * generic code guarantees at least one band, 824 * generic code guarantees at least one band,
823 * set this very early because much code assumes 825 * set this very early because much code assumes
824 * that hw.conf.channel is assigned 826 * that hw.conf.channel is assigned
825 */ 827 */
828 channels = 0;
826 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 829 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
827 struct ieee80211_supported_band *sband; 830 struct ieee80211_supported_band *sband;
828 831
829 sband = local->hw.wiphy->bands[band]; 832 sband = local->hw.wiphy->bands[band];
830 if (sband) { 833 if (sband && !local->oper_channel) {
831 /* init channel we're on */ 834 /* init channel we're on */
832 local->hw.conf.channel = 835 local->hw.conf.channel =
833 local->oper_channel = 836 local->oper_channel =
834 local->scan_channel = &sband->channels[0]; 837 local->scan_channel = &sband->channels[0];
835 break;
836 } 838 }
839 if (sband)
840 channels += sband->n_channels;
837 } 841 }
838 842
843 local->int_scan_req.n_channels = channels;
844 local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
845 if (!local->int_scan_req.channels)
846 return -ENOMEM;
847
839 /* if low-level driver supports AP, we also support VLAN */ 848 /* if low-level driver supports AP, we also support VLAN */
840 if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) 849 if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
841 local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); 850 local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
@@ -845,7 +854,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
845 854
846 result = wiphy_register(local->hw.wiphy); 855 result = wiphy_register(local->hw.wiphy);
847 if (result < 0) 856 if (result < 0)
848 return result; 857 goto fail_wiphy_register;
849 858
850 /* 859 /*
851 * We use the number of queues for feature tests (QoS, HT) internally 860 * We use the number of queues for feature tests (QoS, HT) internally
@@ -948,6 +957,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
948 957
949 ieee80211_led_init(local); 958 ieee80211_led_init(local);
950 959
960 /* alloc internal scan request */
961 i = 0;
962 local->int_scan_req.ssids = &local->scan_ssid;
963 local->int_scan_req.n_ssids = 1;
964 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
965 if (!hw->wiphy->bands[band])
966 continue;
967 for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
968 local->int_scan_req.channels[i] =
969 &hw->wiphy->bands[band]->channels[j];
970 i++;
971 }
972 }
973
951 return 0; 974 return 0;
952 975
953fail_wep: 976fail_wep:
@@ -966,6 +989,8 @@ fail_workqueue:
966 free_netdev(local->mdev); 989 free_netdev(local->mdev);
967fail_mdev_alloc: 990fail_mdev_alloc:
968 wiphy_unregister(local->hw.wiphy); 991 wiphy_unregister(local->hw.wiphy);
992fail_wiphy_register:
993 kfree(local->int_scan_req.channels);
969 return result; 994 return result;
970} 995}
971EXPORT_SYMBOL(ieee80211_register_hw); 996EXPORT_SYMBOL(ieee80211_register_hw);
@@ -1011,6 +1036,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
1011 ieee80211_wep_free(local); 1036 ieee80211_wep_free(local);
1012 ieee80211_led_exit(local); 1037 ieee80211_led_exit(local);
1013 free_netdev(local->mdev); 1038 free_netdev(local->mdev);
1039 kfree(local->int_scan_req.channels);
1014} 1040}
1015EXPORT_SYMBOL(ieee80211_unregister_hw); 1041EXPORT_SYMBOL(ieee80211_unregister_hw);
1016 1042
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bfc47b330687..46b4817cdea9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1743,7 +1743,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1743 } 1743 }
1744 1744
1745 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, 1745 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
1746 freq, beacon); 1746 channel, beacon);
1747 if (!bss) 1747 if (!bss)
1748 return; 1748 return;
1749 1749
@@ -2162,7 +2162,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
2162 2162
2163 printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " 2163 printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
2164 "IBSS networks with same SSID (merge)\n", sdata->dev->name); 2164 "IBSS networks with same SSID (merge)\n", sdata->dev->name);
2165 ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); 2165
2166 /* XXX maybe racy? */
2167 if (sdata->local->scan_req)
2168 return;
2169
2170 memcpy(sdata->local->int_scan_req.ssids[0].ssid,
2171 ifsta->ssid, IEEE80211_MAX_SSID_LEN);
2172 sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
2173 ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
2166} 2174}
2167 2175
2168 2176
@@ -2378,8 +2386,15 @@ dont_join:
2378 IEEE80211_SCAN_INTERVAL)) { 2386 IEEE80211_SCAN_INTERVAL)) {
2379 printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " 2387 printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
2380 "join\n", sdata->dev->name); 2388 "join\n", sdata->dev->name);
2381 return ieee80211_request_scan(sdata, ifsta->ssid, 2389
2382 ifsta->ssid_len); 2390 /* XXX maybe racy? */
2391 if (local->scan_req)
2392 return -EBUSY;
2393
2394 memcpy(local->int_scan_req.ssids[0].ssid,
2395 ifsta->ssid, IEEE80211_MAX_SSID_LEN);
2396 local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
2397 return ieee80211_request_scan(sdata, &local->int_scan_req);
2383 } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { 2398 } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
2384 int interval = IEEE80211_SCAN_INTERVAL; 2399 int interval = IEEE80211_SCAN_INTERVAL;
2385 2400
@@ -2478,11 +2493,16 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
2478 } else { 2493 } else {
2479 if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { 2494 if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
2480 ifsta->assoc_scan_tries++; 2495 ifsta->assoc_scan_tries++;
2496 /* XXX maybe racy? */
2497 if (local->scan_req)
2498 return -1;
2499 memcpy(local->int_scan_req.ssids[0].ssid,
2500 ifsta->ssid, IEEE80211_MAX_SSID_LEN);
2481 if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) 2501 if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
2482 ieee80211_start_scan(sdata, NULL, 0); 2502 local->int_scan_req.ssids[0].ssid_len = 0;
2483 else 2503 else
2484 ieee80211_start_scan(sdata, ifsta->ssid, 2504 local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
2485 ifsta->ssid_len); 2505 ieee80211_start_scan(sdata, &local->int_scan_req);
2486 ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; 2506 ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
2487 set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); 2507 set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
2488 } else { 2508 } else {
@@ -2520,8 +2540,7 @@ static void ieee80211_sta_work(struct work_struct *work)
2520 ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && 2540 ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
2521 ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && 2541 ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
2522 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { 2542 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
2523 ieee80211_start_scan(sdata, ifsta->scan_ssid, 2543 ieee80211_start_scan(sdata, local->scan_req);
2524 ifsta->scan_ssid_len);
2525 return; 2544 return;
2526 } 2545 }
2527 2546
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index eddca4e1e13c..c6b275b10cf9 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -13,6 +13,9 @@
13 */ 13 */
14 14
15/* TODO: 15/* TODO:
16 * figure out how to avoid that the "current BSS" expires
17 * clean up IBSS code (in MLME), see why it adds a BSS to the list
18 * use cfg80211's BSS handling (depends on IBSS TODO above)
16 * order BSS list by RSSI(?) ("quality of AP") 19 * order BSS list by RSSI(?) ("quality of AP")
17 * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, 20 * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
18 * SSID) 21 * SSID)
@@ -225,10 +228,26 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
225 struct ieee80211_mgmt *mgmt, 228 struct ieee80211_mgmt *mgmt,
226 size_t len, 229 size_t len,
227 struct ieee802_11_elems *elems, 230 struct ieee802_11_elems *elems,
228 int freq, bool beacon) 231 struct ieee80211_channel *channel,
232 bool beacon)
229{ 233{
230 struct ieee80211_bss *bss; 234 struct ieee80211_bss *bss;
231 int clen; 235 int clen, freq = channel->center_freq;
236 enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
237 s32 signal = 0;
238
239 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
240 sigtype = CFG80211_SIGNAL_TYPE_MBM;
241 signal = rx_status->signal * 100;
242 } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
243 sigtype = CFG80211_SIGNAL_TYPE_UNSPEC;
244 signal = (rx_status->signal * 100) / local->hw.max_signal;
245 }
246
247 cfg80211_put_bss(
248 cfg80211_inform_bss_frame(local->hw.wiphy, channel,
249 mgmt, len, signal, sigtype,
250 GFP_ATOMIC));
232 251
233#ifdef CONFIG_MAC80211_MESH 252#ifdef CONFIG_MAC80211_MESH
234 if (elems->mesh_config) 253 if (elems->mesh_config)
@@ -401,7 +420,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
401 420
402 bss = ieee80211_bss_info_update(sdata->local, rx_status, 421 bss = ieee80211_bss_info_update(sdata->local, rx_status,
403 mgmt, skb->len, &elems, 422 mgmt, skb->len, &elems,
404 freq, beacon); 423 channel, beacon);
405 if (bss) 424 if (bss)
406 ieee80211_rx_bss_put(sdata->local, bss); 425 ieee80211_rx_bss_put(sdata->local, bss);
407 426
@@ -439,26 +458,22 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
439 ieee80211_tx_skb(sdata, skb, 0); 458 ieee80211_tx_skb(sdata, skb, 0);
440} 459}
441 460
442void ieee80211_scan_completed(struct ieee80211_hw *hw) 461void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
443{ 462{
444 struct ieee80211_local *local = hw_to_local(hw); 463 struct ieee80211_local *local = hw_to_local(hw);
445 struct ieee80211_sub_if_data *sdata; 464 struct ieee80211_sub_if_data *sdata;
446 union iwreq_data wrqu;
447 465
448 if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) 466 if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
449 return; 467 return;
450 468
451 local->last_scan_completed = jiffies; 469 if (WARN_ON(!local->scan_req))
452 memset(&wrqu, 0, sizeof(wrqu)); 470 return;
453 471
454 /* 472 if (local->scan_req != &local->int_scan_req)
455 * local->scan_sdata could have been NULLed by the interface 473 cfg80211_scan_done(local->scan_req, aborted);
456 * down code in case we were scanning on an interface that is 474 local->scan_req = NULL;
457 * being taken down. 475
458 */ 476 local->last_scan_completed = jiffies;
459 sdata = local->scan_sdata;
460 if (sdata)
461 wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
462 477
463 if (local->hw_scanning) { 478 if (local->hw_scanning) {
464 local->hw_scanning = false; 479 local->hw_scanning = false;
@@ -520,9 +535,8 @@ void ieee80211_scan_work(struct work_struct *work)
520 struct ieee80211_local *local = 535 struct ieee80211_local *local =
521 container_of(work, struct ieee80211_local, scan_work.work); 536 container_of(work, struct ieee80211_local, scan_work.work);
522 struct ieee80211_sub_if_data *sdata = local->scan_sdata; 537 struct ieee80211_sub_if_data *sdata = local->scan_sdata;
523 struct ieee80211_supported_band *sband;
524 struct ieee80211_channel *chan; 538 struct ieee80211_channel *chan;
525 int skip; 539 int skip, i;
526 unsigned long next_delay = 0; 540 unsigned long next_delay = 0;
527 541
528 /* 542 /*
@@ -533,33 +547,13 @@ void ieee80211_scan_work(struct work_struct *work)
533 547
534 switch (local->scan_state) { 548 switch (local->scan_state) {
535 case SCAN_SET_CHANNEL: 549 case SCAN_SET_CHANNEL:
536 /*
537 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
538 * after we successfully scanned the last channel of the last
539 * band (and the last band is supported by the hw)
540 */
541 if (local->scan_band < IEEE80211_NUM_BANDS)
542 sband = local->hw.wiphy->bands[local->scan_band];
543 else
544 sband = NULL;
545
546 /*
547 * If we are at an unsupported band and have more bands
548 * left to scan, advance to the next supported one.
549 */
550 while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
551 local->scan_band++;
552 sband = local->hw.wiphy->bands[local->scan_band];
553 local->scan_channel_idx = 0;
554 }
555
556 /* if no more bands/channels left, complete scan */ 550 /* if no more bands/channels left, complete scan */
557 if (!sband || local->scan_channel_idx >= sband->n_channels) { 551 if (local->scan_channel_idx >= local->scan_req->n_channels) {
558 ieee80211_scan_completed(local_to_hw(local)); 552 ieee80211_scan_completed(local_to_hw(local), false);
559 return; 553 return;
560 } 554 }
561 skip = 0; 555 skip = 0;
562 chan = &sband->channels[local->scan_channel_idx]; 556 chan = local->scan_req->channels[local->scan_channel_idx];
563 557
564 if (chan->flags & IEEE80211_CHAN_DISABLED || 558 if (chan->flags & IEEE80211_CHAN_DISABLED ||
565 (sdata->vif.type == NL80211_IFTYPE_ADHOC && 559 (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
@@ -575,15 +569,6 @@ void ieee80211_scan_work(struct work_struct *work)
575 569
576 /* advance state machine to next channel/band */ 570 /* advance state machine to next channel/band */
577 local->scan_channel_idx++; 571 local->scan_channel_idx++;
578 if (local->scan_channel_idx >= sband->n_channels) {
579 /*
580 * scan_band may end up == IEEE80211_NUM_BANDS, but
581 * we'll catch that case above and complete the scan
582 * if that is the case.
583 */
584 local->scan_band++;
585 local->scan_channel_idx = 0;
586 }
587 572
588 if (skip) 573 if (skip)
589 break; 574 break;
@@ -596,10 +581,14 @@ void ieee80211_scan_work(struct work_struct *work)
596 next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; 581 next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
597 local->scan_state = SCAN_SET_CHANNEL; 582 local->scan_state = SCAN_SET_CHANNEL;
598 583
599 if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) 584 if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
585 !local->scan_req->n_ssids)
600 break; 586 break;
601 ieee80211_send_probe_req(sdata, NULL, local->scan_ssid, 587 for (i = 0; i < local->scan_req->n_ssids; i++)
602 local->scan_ssid_len); 588 ieee80211_send_probe_req(
589 sdata, NULL,
590 local->scan_req->ssids[i].ssid,
591 local->scan_req->ssids[i].ssid_len);
603 next_delay = IEEE80211_CHANNEL_TIME; 592 next_delay = IEEE80211_CHANNEL_TIME;
604 break; 593 break;
605 } 594 }
@@ -610,14 +599,19 @@ void ieee80211_scan_work(struct work_struct *work)
610 599
611 600
612int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, 601int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
613 u8 *ssid, size_t ssid_len) 602 struct cfg80211_scan_request *req)
614{ 603{
615 struct ieee80211_local *local = scan_sdata->local; 604 struct ieee80211_local *local = scan_sdata->local;
616 struct ieee80211_sub_if_data *sdata; 605 struct ieee80211_sub_if_data *sdata;
617 606
618 if (ssid_len > IEEE80211_MAX_SSID_LEN) 607 if (!req)
619 return -EINVAL; 608 return -EINVAL;
620 609
610 if (local->scan_req && local->scan_req != req)
611 return -EBUSY;
612
613 local->scan_req = req;
614
621 /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) 615 /* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
622 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS 616 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
623 * BSSID: MACAddress 617 * BSSID: MACAddress
@@ -645,7 +639,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
645 int rc; 639 int rc;
646 640
647 local->hw_scanning = true; 641 local->hw_scanning = true;
648 rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len); 642 rc = local->ops->hw_scan(local_to_hw(local), req);
649 if (rc) { 643 if (rc) {
650 local->hw_scanning = false; 644 local->hw_scanning = false;
651 return rc; 645 return rc;
@@ -678,15 +672,10 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
678 } 672 }
679 mutex_unlock(&local->iflist_mtx); 673 mutex_unlock(&local->iflist_mtx);
680 674
681 if (ssid) {
682 local->scan_ssid_len = ssid_len;
683 memcpy(local->scan_ssid, ssid, ssid_len);
684 } else
685 local->scan_ssid_len = 0;
686 local->scan_state = SCAN_SET_CHANNEL; 675 local->scan_state = SCAN_SET_CHANNEL;
687 local->scan_channel_idx = 0; 676 local->scan_channel_idx = 0;
688 local->scan_band = IEEE80211_BAND_2GHZ;
689 local->scan_sdata = scan_sdata; 677 local->scan_sdata = scan_sdata;
678 local->scan_req = req;
690 679
691 netif_addr_lock_bh(local->mdev); 680 netif_addr_lock_bh(local->mdev);
692 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; 681 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
@@ -706,13 +695,21 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
706 695
707 696
708int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 697int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
709 u8 *ssid, size_t ssid_len) 698 struct cfg80211_scan_request *req)
710{ 699{
711 struct ieee80211_local *local = sdata->local; 700 struct ieee80211_local *local = sdata->local;
712 struct ieee80211_if_sta *ifsta; 701 struct ieee80211_if_sta *ifsta;
713 702
703 if (!req)
704 return -EINVAL;
705
706 if (local->scan_req && local->scan_req != req)
707 return -EBUSY;
708
709 local->scan_req = req;
710
714 if (sdata->vif.type != NL80211_IFTYPE_STATION) 711 if (sdata->vif.type != NL80211_IFTYPE_STATION)
715 return ieee80211_start_scan(sdata, ssid, ssid_len); 712 return ieee80211_start_scan(sdata, req);
716 713
717 /* 714 /*
718 * STA has a state machine that might need to defer scanning 715 * STA has a state machine that might need to defer scanning
@@ -727,241 +724,8 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
727 } 724 }
728 725
729 ifsta = &sdata->u.sta; 726 ifsta = &sdata->u.sta;
730
731 ifsta->scan_ssid_len = ssid_len;
732 if (ssid_len)
733 memcpy(ifsta->scan_ssid, ssid, ssid_len);
734 set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); 727 set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
735 queue_work(local->hw.workqueue, &ifsta->work); 728 queue_work(local->hw.workqueue, &ifsta->work);
736 729
737 return 0; 730 return 0;
738} 731}
739
740
741static void ieee80211_scan_add_ies(struct iw_request_info *info,
742 struct ieee80211_bss *bss,
743 char **current_ev, char *end_buf)
744{
745 u8 *pos, *end, *next;
746 struct iw_event iwe;
747
748 if (bss == NULL || bss->ies == NULL)
749 return;
750
751 /*
752 * If needed, fragment the IEs buffer (at IE boundaries) into short
753 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
754 */
755 pos = bss->ies;
756 end = pos + bss->ies_len;
757
758 while (end - pos > IW_GENERIC_IE_MAX) {
759 next = pos + 2 + pos[1];
760 while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
761 next = next + 2 + next[1];
762
763 memset(&iwe, 0, sizeof(iwe));
764 iwe.cmd = IWEVGENIE;
765 iwe.u.data.length = next - pos;
766 *current_ev = iwe_stream_add_point(info, *current_ev,
767 end_buf, &iwe, pos);
768
769 pos = next;
770 }
771
772 if (end > pos) {
773 memset(&iwe, 0, sizeof(iwe));
774 iwe.cmd = IWEVGENIE;
775 iwe.u.data.length = end - pos;
776 *current_ev = iwe_stream_add_point(info, *current_ev,
777 end_buf, &iwe, pos);
778 }
779}
780
781
782static char *
783ieee80211_scan_result(struct ieee80211_local *local,
784 struct iw_request_info *info,
785 struct ieee80211_bss *bss,
786 char *current_ev, char *end_buf)
787{
788 struct iw_event iwe;
789 char *buf;
790
791 if (time_after(jiffies,
792 bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
793 return current_ev;
794
795 memset(&iwe, 0, sizeof(iwe));
796 iwe.cmd = SIOCGIWAP;
797 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
798 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
799 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
800 IW_EV_ADDR_LEN);
801
802 memset(&iwe, 0, sizeof(iwe));
803 iwe.cmd = SIOCGIWESSID;
804 if (bss_mesh_cfg(bss)) {
805 iwe.u.data.length = bss_mesh_id_len(bss);
806 iwe.u.data.flags = 1;
807 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
808 &iwe, bss_mesh_id(bss));
809 } else {
810 iwe.u.data.length = bss->ssid_len;
811 iwe.u.data.flags = 1;
812 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
813 &iwe, bss->ssid);
814 }
815
816 if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
817 || bss_mesh_cfg(bss)) {
818 memset(&iwe, 0, sizeof(iwe));
819 iwe.cmd = SIOCGIWMODE;
820 if (bss_mesh_cfg(bss))
821 iwe.u.mode = IW_MODE_MESH;
822 else if (bss->capability & WLAN_CAPABILITY_ESS)
823 iwe.u.mode = IW_MODE_MASTER;
824 else
825 iwe.u.mode = IW_MODE_ADHOC;
826 current_ev = iwe_stream_add_event(info, current_ev, end_buf,
827 &iwe, IW_EV_UINT_LEN);
828 }
829
830 memset(&iwe, 0, sizeof(iwe));
831 iwe.cmd = SIOCGIWFREQ;
832 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
833 iwe.u.freq.e = 0;
834 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
835 IW_EV_FREQ_LEN);
836
837 memset(&iwe, 0, sizeof(iwe));
838 iwe.cmd = SIOCGIWFREQ;
839 iwe.u.freq.m = bss->freq;
840 iwe.u.freq.e = 6;
841 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
842 IW_EV_FREQ_LEN);
843 memset(&iwe, 0, sizeof(iwe));
844 iwe.cmd = IWEVQUAL;
845 iwe.u.qual.qual = bss->qual;
846 iwe.u.qual.level = bss->signal;
847 iwe.u.qual.noise = bss->noise;
848 iwe.u.qual.updated = local->wstats_flags;
849 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
850 IW_EV_QUAL_LEN);
851
852 memset(&iwe, 0, sizeof(iwe));
853 iwe.cmd = SIOCGIWENCODE;
854 if (bss->capability & WLAN_CAPABILITY_PRIVACY)
855 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
856 else
857 iwe.u.data.flags = IW_ENCODE_DISABLED;
858 iwe.u.data.length = 0;
859 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
860 &iwe, "");
861
862 ieee80211_scan_add_ies(info, bss, &current_ev, end_buf);
863
864 if (bss->supp_rates_len > 0) {
865 /* display all supported rates in readable format */
866 char *p = current_ev + iwe_stream_lcp_len(info);
867 int i;
868
869 memset(&iwe, 0, sizeof(iwe));
870 iwe.cmd = SIOCGIWRATE;
871 /* Those two flags are ignored... */
872 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
873
874 for (i = 0; i < bss->supp_rates_len; i++) {
875 iwe.u.bitrate.value = ((bss->supp_rates[i] &
876 0x7f) * 500000);
877 p = iwe_stream_add_value(info, current_ev, p,
878 end_buf, &iwe, IW_EV_PARAM_LEN);
879 }
880 current_ev = p;
881 }
882
883 buf = kmalloc(30, GFP_ATOMIC);
884 if (buf) {
885 memset(&iwe, 0, sizeof(iwe));
886 iwe.cmd = IWEVCUSTOM;
887 sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
888 iwe.u.data.length = strlen(buf);
889 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
890 &iwe, buf);
891 memset(&iwe, 0, sizeof(iwe));
892 iwe.cmd = IWEVCUSTOM;
893 sprintf(buf, " Last beacon: %dms ago",
894 jiffies_to_msecs(jiffies - bss->last_update));
895 iwe.u.data.length = strlen(buf);
896 current_ev = iwe_stream_add_point(info, current_ev,
897 end_buf, &iwe, buf);
898 kfree(buf);
899 }
900
901 if (bss_mesh_cfg(bss)) {
902 u8 *cfg = bss_mesh_cfg(bss);
903 buf = kmalloc(50, GFP_ATOMIC);
904 if (buf) {
905 memset(&iwe, 0, sizeof(iwe));
906 iwe.cmd = IWEVCUSTOM;
907 sprintf(buf, "Mesh network (version %d)", cfg[0]);
908 iwe.u.data.length = strlen(buf);
909 current_ev = iwe_stream_add_point(info, current_ev,
910 end_buf,
911 &iwe, buf);
912 sprintf(buf, "Path Selection Protocol ID: "
913 "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
914 cfg[4]);
915 iwe.u.data.length = strlen(buf);
916 current_ev = iwe_stream_add_point(info, current_ev,
917 end_buf,
918 &iwe, buf);
919 sprintf(buf, "Path Selection Metric ID: "
920 "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
921 cfg[8]);
922 iwe.u.data.length = strlen(buf);
923 current_ev = iwe_stream_add_point(info, current_ev,
924 end_buf,
925 &iwe, buf);
926 sprintf(buf, "Congestion Control Mode ID: "
927 "0x%02X%02X%02X%02X", cfg[9], cfg[10],
928 cfg[11], cfg[12]);
929 iwe.u.data.length = strlen(buf);
930 current_ev = iwe_stream_add_point(info, current_ev,
931 end_buf,
932 &iwe, buf);
933 sprintf(buf, "Channel Precedence: "
934 "0x%02X%02X%02X%02X", cfg[13], cfg[14],
935 cfg[15], cfg[16]);
936 iwe.u.data.length = strlen(buf);
937 current_ev = iwe_stream_add_point(info, current_ev,
938 end_buf,
939 &iwe, buf);
940 kfree(buf);
941 }
942 }
943
944 return current_ev;
945}
946
947
948int ieee80211_scan_results(struct ieee80211_local *local,
949 struct iw_request_info *info,
950 char *buf, size_t len)
951{
952 char *current_ev = buf;
953 char *end_buf = buf + len;
954 struct ieee80211_bss *bss;
955
956 spin_lock_bh(&local->bss_lock);
957 list_for_each_entry(bss, &local->bss_list, list) {
958 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
959 spin_unlock_bh(&local->bss_lock);
960 return -E2BIG;
961 }
962 current_ev = ieee80211_scan_result(local, info, bss,
963 current_ev, end_buf);
964 }
965 spin_unlock_bh(&local->bss_lock);
966 return current_ev - buf;
967}
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index acd5808b87f4..b337d7d5edb3 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -173,8 +173,9 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
173 range->num_encoding_sizes = 2; 173 range->num_encoding_sizes = 2;
174 range->max_encoding_tokens = NUM_DEFAULT_KEYS; 174 range->max_encoding_tokens = NUM_DEFAULT_KEYS;
175 175
176 /* cfg80211 requires this, and enforces 0..100 */
176 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) 177 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
177 range->max_qual.level = local->hw.max_signal; 178 range->max_qual.level = 100;
178 else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) 179 else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
179 range->max_qual.level = -110; 180 range->max_qual.level = -110;
180 else 181 else
@@ -415,58 +416,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
415} 416}
416 417
417 418
418static int ieee80211_ioctl_siwscan(struct net_device *dev,
419 struct iw_request_info *info,
420 union iwreq_data *wrqu, char *extra)
421{
422 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
423 struct iw_scan_req *req = NULL;
424 u8 *ssid = NULL;
425 size_t ssid_len = 0;
426
427 if (!netif_running(dev))
428 return -ENETDOWN;
429
430 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
431 sdata->vif.type != NL80211_IFTYPE_ADHOC &&
432 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
433 return -EOPNOTSUPP;
434
435 /* if SSID was specified explicitly then use that */
436 if (wrqu->data.length == sizeof(struct iw_scan_req) &&
437 wrqu->data.flags & IW_SCAN_THIS_ESSID) {
438 req = (struct iw_scan_req *)extra;
439 ssid = req->essid;
440 ssid_len = req->essid_len;
441 }
442
443 return ieee80211_request_scan(sdata, ssid, ssid_len);
444}
445
446
447static int ieee80211_ioctl_giwscan(struct net_device *dev,
448 struct iw_request_info *info,
449 struct iw_point *data, char *extra)
450{
451 int res;
452 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
453 struct ieee80211_sub_if_data *sdata;
454
455 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
456
457 if (local->sw_scanning || local->hw_scanning)
458 return -EAGAIN;
459
460 res = ieee80211_scan_results(local, info, extra, data->length);
461 if (res >= 0) {
462 data->length = res;
463 return 0;
464 }
465 data->length = 0;
466 return res;
467}
468
469
470static int ieee80211_ioctl_siwrate(struct net_device *dev, 419static int ieee80211_ioctl_siwrate(struct net_device *dev,
471 struct iw_request_info *info, 420 struct iw_request_info *info,
472 struct iw_param *rate, char *extra) 421 struct iw_param *rate, char *extra)
@@ -1165,8 +1114,8 @@ static const iw_handler ieee80211_handler[] =
1165 (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ 1114 (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
1166 (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ 1115 (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
1167 (iw_handler) NULL, /* SIOCGIWAPLIST */ 1116 (iw_handler) NULL, /* SIOCGIWAPLIST */
1168 (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */ 1117 (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
1169 (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */ 1118 (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
1170 (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ 1119 (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
1171 (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ 1120 (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
1172 (iw_handler) NULL, /* SIOCSIWNICKN */ 1121 (iw_handler) NULL, /* SIOCSIWNICKN */
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 938a334c8dbc..dad43c24f695 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o
9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
10cfg80211-$(CONFIG_NL80211) += nl80211.o 10cfg80211-$(CONFIG_NL80211) += nl80211.o
11 11
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 125226476089..3cccd1390cea 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -240,6 +240,8 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
240 mutex_init(&drv->mtx); 240 mutex_init(&drv->mtx);
241 mutex_init(&drv->devlist_mtx); 241 mutex_init(&drv->devlist_mtx);
242 INIT_LIST_HEAD(&drv->netdev_list); 242 INIT_LIST_HEAD(&drv->netdev_list);
243 spin_lock_init(&drv->bss_lock);
244 INIT_LIST_HEAD(&drv->bss_list);
243 245
244 device_initialize(&drv->wiphy.dev); 246 device_initialize(&drv->wiphy.dev);
245 drv->wiphy.dev.class = &ieee80211_class; 247 drv->wiphy.dev.class = &ieee80211_class;
@@ -259,6 +261,9 @@ int wiphy_register(struct wiphy *wiphy)
259 int i; 261 int i;
260 u16 ifmodes = wiphy->interface_modes; 262 u16 ifmodes = wiphy->interface_modes;
261 263
264 if (WARN_ON(wiphy->max_scan_ssids < 1))
265 return -EINVAL;
266
262 /* sanity check ifmodes */ 267 /* sanity check ifmodes */
263 WARN_ON(!ifmodes); 268 WARN_ON(!ifmodes);
264 ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; 269 ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -367,8 +372,11 @@ EXPORT_SYMBOL(wiphy_unregister);
367 372
368void cfg80211_dev_free(struct cfg80211_registered_device *drv) 373void cfg80211_dev_free(struct cfg80211_registered_device *drv)
369{ 374{
375 struct cfg80211_internal_bss *scan, *tmp;
370 mutex_destroy(&drv->mtx); 376 mutex_destroy(&drv->mtx);
371 mutex_destroy(&drv->devlist_mtx); 377 mutex_destroy(&drv->devlist_mtx);
378 list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
379 kfree(scan);
372 kfree(drv); 380 kfree(drv);
373} 381}
374 382
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f7fb9f413028..e29ad4cd464f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -8,6 +8,8 @@
8#include <linux/mutex.h> 8#include <linux/mutex.h>
9#include <linux/list.h> 9#include <linux/list.h>
10#include <linux/netdevice.h> 10#include <linux/netdevice.h>
11#include <linux/kref.h>
12#include <linux/rbtree.h>
11#include <net/genetlink.h> 13#include <net/genetlink.h>
12#include <net/wireless.h> 14#include <net/wireless.h>
13#include <net/cfg80211.h> 15#include <net/cfg80211.h>
@@ -41,6 +43,13 @@ struct cfg80211_registered_device {
41 struct mutex devlist_mtx; 43 struct mutex devlist_mtx;
42 struct list_head netdev_list; 44 struct list_head netdev_list;
43 45
46 /* BSSes/scanning */
47 spinlock_t bss_lock;
48 struct list_head bss_list;
49 struct rb_root bss_tree;
50 u32 bss_generation;
51 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
52
44 /* must be last because of the way we do wiphy_priv(), 53 /* must be last because of the way we do wiphy_priv(),
45 * and it should at least be aligned to NETDEV_ALIGN */ 54 * and it should at least be aligned to NETDEV_ALIGN */
46 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); 55 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -56,6 +65,15 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
56extern struct mutex cfg80211_drv_mutex; 65extern struct mutex cfg80211_drv_mutex;
57extern struct list_head cfg80211_drv_list; 66extern struct list_head cfg80211_drv_list;
58 67
68struct cfg80211_internal_bss {
69 struct list_head list;
70 struct rb_node rbn;
71 unsigned long ts;
72 struct kref ref;
73 /* must be last because of priv member */
74 struct cfg80211_bss pub;
75};
76
59/* 77/*
60 * This function returns a pointer to the driver 78 * This function returns a pointer to the driver
61 * that the genl_info item that is passed refers to. 79 * that the genl_info item that is passed refers to.
@@ -94,4 +112,6 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
94void ieee80211_set_bitrate_flags(struct wiphy *wiphy); 112void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
95void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); 113void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
96 114
115void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
116
97#endif /* __NET_WIRELESS_CORE_H */ 117#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d452396006ee..298a4de59948 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -14,6 +14,7 @@
14#include <linux/nl80211.h> 14#include <linux/nl80211.h>
15#include <linux/rtnetlink.h> 15#include <linux/rtnetlink.h>
16#include <linux/netlink.h> 16#include <linux/netlink.h>
17#include <linux/etherdevice.h>
17#include <net/genetlink.h> 18#include <net/genetlink.h>
18#include <net/cfg80211.h> 19#include <net/cfg80211.h>
19#include "core.h" 20#include "core.h"
@@ -109,6 +110,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
109 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, 110 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
110 [NL80211_ATTR_IE] = { .type = NLA_BINARY, 111 [NL80211_ATTR_IE] = { .type = NLA_BINARY,
111 .len = IEEE80211_MAX_DATA_LEN }, 112 .len = IEEE80211_MAX_DATA_LEN },
113 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
114 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
112}; 115};
113 116
114/* message building helper */ 117/* message building helper */
@@ -141,6 +144,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
141 144
142 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); 145 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
143 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); 146 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
147 NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
148 dev->wiphy.max_scan_ssids);
144 149
145 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); 150 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
146 if (!nl_modes) 151 if (!nl_modes)
@@ -2270,6 +2275,246 @@ static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
2270 return err; 2275 return err;
2271} 2276}
2272 2277
2278static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2279{
2280 struct cfg80211_registered_device *drv;
2281 struct net_device *dev;
2282 struct cfg80211_scan_request *request;
2283 struct cfg80211_ssid *ssid;
2284 struct ieee80211_channel *channel;
2285 struct nlattr *attr;
2286 struct wiphy *wiphy;
2287 int err, tmp, n_ssids = 0, n_channels = 0, i;
2288 enum ieee80211_band band;
2289
2290 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2291 if (err)
2292 return err;
2293
2294 wiphy = &drv->wiphy;
2295
2296 if (!drv->ops->scan) {
2297 err = -EOPNOTSUPP;
2298 goto out;
2299 }
2300
2301 rtnl_lock();
2302
2303 if (drv->scan_req) {
2304 err = -EBUSY;
2305 goto out_unlock;
2306 }
2307
2308 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
2309 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
2310 n_channels++;
2311 if (!n_channels) {
2312 err = -EINVAL;
2313 goto out_unlock;
2314 }
2315 } else {
2316 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
2317 if (wiphy->bands[band])
2318 n_channels += wiphy->bands[band]->n_channels;
2319 }
2320
2321 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
2322 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
2323 n_ssids++;
2324
2325 if (n_ssids > wiphy->max_scan_ssids) {
2326 err = -EINVAL;
2327 goto out_unlock;
2328 }
2329
2330 request = kzalloc(sizeof(*request)
2331 + sizeof(*ssid) * n_ssids
2332 + sizeof(channel) * n_channels, GFP_KERNEL);
2333 if (!request) {
2334 err = -ENOMEM;
2335 goto out_unlock;
2336 }
2337
2338 request->channels = (void *)((char *)request + sizeof(*request));
2339 request->n_channels = n_channels;
2340 if (n_ssids)
2341 request->ssids = (void *)(request->channels + n_channels);
2342 request->n_ssids = n_ssids;
2343
2344 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
2345 /* user specified, bail out if channel not found */
2346 request->n_channels = n_channels;
2347 i = 0;
2348 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
2349 request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr));
2350 if (!request->channels[i]) {
2351 err = -EINVAL;
2352 goto out_free;
2353 }
2354 i++;
2355 }
2356 } else {
2357 /* all channels */
2358 i = 0;
2359 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
2360 int j;
2361 if (!wiphy->bands[band])
2362 continue;
2363 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
2364 request->channels[i] = &wiphy->bands[band]->channels[j];
2365 i++;
2366 }
2367 }
2368 }
2369
2370 i = 0;
2371 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
2372 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
2373 if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
2374 err = -EINVAL;
2375 goto out_free;
2376 }
2377 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
2378 request->ssids[i].ssid_len = nla_len(attr);
2379 i++;
2380 }
2381 }
2382
2383 request->ifidx = dev->ifindex;
2384 request->wiphy = &drv->wiphy;
2385
2386 drv->scan_req = request;
2387 err = drv->ops->scan(&drv->wiphy, dev, request);
2388
2389 out_free:
2390 if (err) {
2391 drv->scan_req = NULL;
2392 kfree(request);
2393 }
2394 out_unlock:
2395 rtnl_unlock();
2396 out:
2397 cfg80211_put_dev(drv);
2398 dev_put(dev);
2399 return err;
2400}
2401
2402static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
2403 struct cfg80211_registered_device *rdev,
2404 struct net_device *dev,
2405 struct cfg80211_bss *res)
2406{
2407 void *hdr;
2408 struct nlattr *bss;
2409
2410 hdr = nl80211hdr_put(msg, pid, seq, flags,
2411 NL80211_CMD_NEW_SCAN_RESULTS);
2412 if (!hdr)
2413 return -1;
2414
2415 NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
2416 rdev->bss_generation);
2417 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
2418
2419 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
2420 if (!bss)
2421 goto nla_put_failure;
2422 if (!is_zero_ether_addr(res->bssid))
2423 NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid);
2424 if (res->information_elements && res->len_information_elements)
2425 NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
2426 res->len_information_elements,
2427 res->information_elements);
2428 if (res->tsf)
2429 NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
2430 if (res->beacon_interval)
2431 NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
2432 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
2433 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
2434
2435 switch (res->signal_type) {
2436 case CFG80211_SIGNAL_TYPE_MBM:
2437 NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
2438 break;
2439 case CFG80211_SIGNAL_TYPE_UNSPEC:
2440 NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal);
2441 break;
2442 default:
2443 break;
2444 }
2445
2446 nla_nest_end(msg, bss);
2447
2448 return genlmsg_end(msg, hdr);
2449
2450 nla_put_failure:
2451 genlmsg_cancel(msg, hdr);
2452 return -EMSGSIZE;
2453}
2454
2455static int nl80211_dump_scan(struct sk_buff *skb,
2456 struct netlink_callback *cb)
2457{
2458 struct cfg80211_registered_device *dev;
2459 struct net_device *netdev;
2460 struct cfg80211_internal_bss *scan;
2461 int ifidx = cb->args[0];
2462 int start = cb->args[1], idx = 0;
2463 int err;
2464
2465 if (!ifidx) {
2466 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
2467 nl80211_fam.attrbuf, nl80211_fam.maxattr,
2468 nl80211_policy);
2469 if (err)
2470 return err;
2471
2472 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
2473 return -EINVAL;
2474
2475 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
2476 if (!ifidx)
2477 return -EINVAL;
2478 cb->args[0] = ifidx;
2479 }
2480
2481 netdev = dev_get_by_index(&init_net, ifidx);
2482 if (!netdev)
2483 return -ENODEV;
2484
2485 dev = cfg80211_get_dev_from_ifindex(ifidx);
2486 if (IS_ERR(dev)) {
2487 err = PTR_ERR(dev);
2488 goto out_put_netdev;
2489 }
2490
2491 spin_lock_bh(&dev->bss_lock);
2492 cfg80211_bss_expire(dev);
2493
2494 list_for_each_entry(scan, &dev->bss_list, list) {
2495 if (++idx <= start)
2496 continue;
2497 if (nl80211_send_bss(skb,
2498 NETLINK_CB(cb->skb).pid,
2499 cb->nlh->nlmsg_seq, NLM_F_MULTI,
2500 dev, netdev, &scan->pub) < 0) {
2501 idx--;
2502 goto out;
2503 }
2504 }
2505
2506 out:
2507 spin_unlock_bh(&dev->bss_lock);
2508
2509 cb->args[1] = idx;
2510 err = skb->len;
2511 cfg80211_put_dev(dev);
2512 out_put_netdev:
2513 dev_put(netdev);
2514
2515 return err;
2516}
2517
2273static struct genl_ops nl80211_ops[] = { 2518static struct genl_ops nl80211_ops[] = {
2274 { 2519 {
2275 .cmd = NL80211_CMD_GET_WIPHY, 2520 .cmd = NL80211_CMD_GET_WIPHY,
@@ -2443,12 +2688,26 @@ static struct genl_ops nl80211_ops[] = {
2443 .policy = nl80211_policy, 2688 .policy = nl80211_policy,
2444 .flags = GENL_ADMIN_PERM, 2689 .flags = GENL_ADMIN_PERM,
2445 }, 2690 },
2691 {
2692 .cmd = NL80211_CMD_TRIGGER_SCAN,
2693 .doit = nl80211_trigger_scan,
2694 .policy = nl80211_policy,
2695 .flags = GENL_ADMIN_PERM,
2696 },
2697 {
2698 .cmd = NL80211_CMD_GET_SCAN,
2699 .policy = nl80211_policy,
2700 .dumpit = nl80211_dump_scan,
2701 },
2446}; 2702};
2447 2703
2448/* multicast groups */ 2704/* multicast groups */
2449static struct genl_multicast_group nl80211_config_mcgrp = { 2705static struct genl_multicast_group nl80211_config_mcgrp = {
2450 .name = "config", 2706 .name = "config",
2451}; 2707};
2708static struct genl_multicast_group nl80211_scan_mcgrp = {
2709 .name = "scan",
2710};
2452 2711
2453/* notification functions */ 2712/* notification functions */
2454 2713
@@ -2468,6 +2727,66 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
2468 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); 2727 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
2469} 2728}
2470 2729
2730static int nl80211_send_scan_donemsg(struct sk_buff *msg,
2731 struct cfg80211_registered_device *rdev,
2732 struct net_device *netdev,
2733 u32 pid, u32 seq, int flags,
2734 u32 cmd)
2735{
2736 void *hdr;
2737
2738 hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
2739 if (!hdr)
2740 return -1;
2741
2742 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
2743 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
2744
2745 /* XXX: we should probably bounce back the request? */
2746
2747 return genlmsg_end(msg, hdr);
2748
2749 nla_put_failure:
2750 genlmsg_cancel(msg, hdr);
2751 return -EMSGSIZE;
2752}
2753
2754void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
2755 struct net_device *netdev)
2756{
2757 struct sk_buff *msg;
2758
2759 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2760 if (!msg)
2761 return;
2762
2763 if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
2764 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
2765 nlmsg_free(msg);
2766 return;
2767 }
2768
2769 genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
2770}
2771
2772void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
2773 struct net_device *netdev)
2774{
2775 struct sk_buff *msg;
2776
2777 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2778 if (!msg)
2779 return;
2780
2781 if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
2782 NL80211_CMD_SCAN_ABORTED) < 0) {
2783 nlmsg_free(msg);
2784 return;
2785 }
2786
2787 genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
2788}
2789
2471/* initialisation/exit functions */ 2790/* initialisation/exit functions */
2472 2791
2473int nl80211_init(void) 2792int nl80211_init(void)
@@ -2488,6 +2807,10 @@ int nl80211_init(void)
2488 if (err) 2807 if (err)
2489 goto err_out; 2808 goto err_out;
2490 2809
2810 err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp);
2811 if (err)
2812 goto err_out;
2813
2491 return 0; 2814 return 0;
2492 err_out: 2815 err_out:
2493 genl_unregister_family(&nl80211_fam); 2816 genl_unregister_family(&nl80211_fam);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f3ea5c029aee..b565a5f84e97 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -7,6 +7,10 @@
7extern int nl80211_init(void); 7extern int nl80211_init(void);
8extern void nl80211_exit(void); 8extern void nl80211_exit(void);
9extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); 9extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
10extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
11 struct net_device *netdev);
12extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
13 struct net_device *netdev);
10#else 14#else
11static inline int nl80211_init(void) 15static inline int nl80211_init(void)
12{ 16{
@@ -19,6 +23,10 @@ static inline void nl80211_notify_dev_rename(
19 struct cfg80211_registered_device *rdev) 23 struct cfg80211_registered_device *rdev)
20{ 24{
21} 25}
26static inline void
27nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
28 struct net_device *netdev)
29{}
22#endif /* CONFIG_NL80211 */ 30#endif /* CONFIG_NL80211 */
23 31
24#endif /* __NET_WIRELESS_NL80211_H */ 32#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
new file mode 100644
index 000000000000..009d12810c55
--- /dev/null
+++ b/net/wireless/scan.c
@@ -0,0 +1,807 @@
1/*
2 * cfg80211 scan result handling
3 *
4 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
5 */
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/netdevice.h>
9#include <linux/wireless.h>
10#include <linux/nl80211.h>
11#include <linux/etherdevice.h>
12#include <net/arp.h>
13#include <net/cfg80211.h>
14#include <net/iw_handler.h>
15#include "core.h"
16#include "nl80211.h"
17
18#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
19
20void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
21{
22 struct net_device *dev;
23#ifdef CONFIG_WIRELESS_EXT
24 union iwreq_data wrqu;
25#endif
26
27 dev = dev_get_by_index(&init_net, request->ifidx);
28 if (!dev)
29 goto out;
30
31 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
32 wiphy_to_dev(request->wiphy)->scan_req = NULL;
33
34 if (aborted)
35 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
36 else
37 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
38
39#ifdef CONFIG_WIRELESS_EXT
40 if (!aborted) {
41 memset(&wrqu, 0, sizeof(wrqu));
42
43 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
44 }
45#endif
46
47 dev_put(dev);
48
49 out:
50 kfree(request);
51}
52EXPORT_SYMBOL(cfg80211_scan_done);
53
54static void bss_release(struct kref *ref)
55{
56 struct cfg80211_internal_bss *bss;
57
58 bss = container_of(ref, struct cfg80211_internal_bss, ref);
59 kfree(bss);
60}
61
62/* must hold dev->bss_lock! */
63void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
64{
65 struct cfg80211_internal_bss *bss, *tmp;
66 bool expired = false;
67
68 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
69 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
70 continue;
71 list_del(&bss->list);
72 rb_erase(&bss->rbn, &dev->bss_tree);
73 kref_put(&bss->ref, bss_release);
74 expired = true;
75 }
76
77 if (expired)
78 dev->bss_generation++;
79}
80
81static u8 *find_ie(u8 num, u8 *ies, size_t len)
82{
83 while (len > 2 && ies[0] != num) {
84 len -= ies[1] + 2;
85 ies += ies[1] + 2;
86 }
87 if (len < 2)
88 return NULL;
89 if (len < 2 + ies[1])
90 return NULL;
91 return ies;
92}
93
94static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
95{
96 const u8 *ie1 = find_ie(num, ies1, len1);
97 const u8 *ie2 = find_ie(num, ies2, len2);
98 int r;
99
100 if (!ie1 && !ie2)
101 return 0;
102 if (!ie1)
103 return -1;
104
105 r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
106 if (r == 0 && ie1[1] != ie2[1])
107 return ie2[1] - ie1[1];
108 return r;
109}
110
111static bool is_bss(struct cfg80211_bss *a,
112 const u8 *bssid,
113 const u8 *ssid, size_t ssid_len)
114{
115 const u8 *ssidie;
116
117 if (compare_ether_addr(a->bssid, bssid))
118 return false;
119
120 ssidie = find_ie(WLAN_EID_SSID,
121 a->information_elements,
122 a->len_information_elements);
123 if (!ssidie)
124 return false;
125 if (ssidie[1] != ssid_len)
126 return false;
127 return memcmp(ssidie + 2, ssid, ssid_len) == 0;
128}
129
130static bool is_mesh(struct cfg80211_bss *a,
131 const u8 *meshid, size_t meshidlen,
132 const u8 *meshcfg)
133{
134 const u8 *ie;
135
136 if (!is_zero_ether_addr(a->bssid))
137 return false;
138
139 ie = find_ie(WLAN_EID_MESH_ID,
140 a->information_elements,
141 a->len_information_elements);
142 if (!ie)
143 return false;
144 if (ie[1] != meshidlen)
145 return false;
146 if (memcmp(ie + 2, meshid, meshidlen))
147 return false;
148
149 ie = find_ie(WLAN_EID_MESH_CONFIG,
150 a->information_elements,
151 a->len_information_elements);
152 if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
153 return false;
154
155 /*
156 * Ignore mesh capability (last two bytes of the IE) when
157 * comparing since that may differ between stations taking
158 * part in the same mesh.
159 */
160 return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
161}
162
163static int cmp_bss(struct cfg80211_bss *a,
164 struct cfg80211_bss *b)
165{
166 int r;
167
168 if (a->channel != b->channel)
169 return b->channel->center_freq - a->channel->center_freq;
170
171 r = memcmp(a->bssid, b->bssid, ETH_ALEN);
172 if (r)
173 return r;
174
175 if (is_zero_ether_addr(a->bssid)) {
176 r = cmp_ies(WLAN_EID_MESH_ID,
177 a->information_elements,
178 a->len_information_elements,
179 b->information_elements,
180 b->len_information_elements);
181 if (r)
182 return r;
183 return cmp_ies(WLAN_EID_MESH_CONFIG,
184 a->information_elements,
185 a->len_information_elements,
186 b->information_elements,
187 b->len_information_elements);
188 }
189
190 return cmp_ies(WLAN_EID_SSID,
191 a->information_elements,
192 a->len_information_elements,
193 b->information_elements,
194 b->len_information_elements);
195}
196
197struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
198 struct ieee80211_channel *channel,
199 const u8 *bssid,
200 const u8 *ssid, size_t ssid_len)
201{
202 struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
203 struct cfg80211_internal_bss *bss, *res = NULL;
204
205 spin_lock_bh(&dev->bss_lock);
206
207 list_for_each_entry(bss, &dev->bss_list, list) {
208 if (channel && bss->pub.channel != channel)
209 continue;
210 if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
211 res = bss;
212 kref_get(&res->ref);
213 break;
214 }
215 }
216
217 spin_unlock_bh(&dev->bss_lock);
218 if (!res)
219 return NULL;
220 return &res->pub;
221}
222EXPORT_SYMBOL(cfg80211_get_bss);
223
224struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
225 struct ieee80211_channel *channel,
226 const u8 *meshid, size_t meshidlen,
227 const u8 *meshcfg)
228{
229 struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
230 struct cfg80211_internal_bss *bss, *res = NULL;
231
232 spin_lock_bh(&dev->bss_lock);
233
234 list_for_each_entry(bss, &dev->bss_list, list) {
235 if (channel && bss->pub.channel != channel)
236 continue;
237 if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
238 res = bss;
239 kref_get(&res->ref);
240 break;
241 }
242 }
243
244 spin_unlock_bh(&dev->bss_lock);
245 if (!res)
246 return NULL;
247 return &res->pub;
248}
249EXPORT_SYMBOL(cfg80211_get_mesh);
250
251
252static void rb_insert_bss(struct cfg80211_registered_device *dev,
253 struct cfg80211_internal_bss *bss)
254{
255 struct rb_node **p = &dev->bss_tree.rb_node;
256 struct rb_node *parent = NULL;
257 struct cfg80211_internal_bss *tbss;
258 int cmp;
259
260 while (*p) {
261 parent = *p;
262 tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
263
264 cmp = cmp_bss(&bss->pub, &tbss->pub);
265
266 if (WARN_ON(!cmp)) {
267 /* will sort of leak this BSS */
268 return;
269 }
270
271 if (cmp < 0)
272 p = &(*p)->rb_left;
273 else
274 p = &(*p)->rb_right;
275 }
276
277 rb_link_node(&bss->rbn, parent, p);
278 rb_insert_color(&bss->rbn, &dev->bss_tree);
279}
280
281static struct cfg80211_internal_bss *
282rb_find_bss(struct cfg80211_registered_device *dev,
283 struct cfg80211_internal_bss *res)
284{
285 struct rb_node *n = dev->bss_tree.rb_node;
286 struct cfg80211_internal_bss *bss;
287 int r;
288
289 while (n) {
290 bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
291 r = cmp_bss(&res->pub, &bss->pub);
292
293 if (r == 0)
294 return bss;
295 else if (r < 0)
296 n = n->rb_left;
297 else
298 n = n->rb_right;
299 }
300
301 return NULL;
302}
303
304static struct cfg80211_internal_bss *
305cfg80211_bss_update(struct cfg80211_registered_device *dev,
306 struct cfg80211_internal_bss *res,
307 bool overwrite)
308{
309 struct cfg80211_internal_bss *found = NULL;
310 const u8 *meshid, *meshcfg;
311
312 /*
313 * The reference to "res" is donated to this function.
314 */
315
316 if (WARN_ON(!res->pub.channel)) {
317 kref_put(&res->ref, bss_release);
318 return NULL;
319 }
320
321 res->ts = jiffies;
322
323 if (is_zero_ether_addr(res->pub.bssid)) {
324 /* must be mesh, verify */
325 meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
326 res->pub.len_information_elements);
327 meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
328 res->pub.information_elements,
329 res->pub.len_information_elements);
330 if (!meshid || !meshcfg ||
331 meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
332 /* bogus mesh */
333 kref_put(&res->ref, bss_release);
334 return NULL;
335 }
336 }
337
338 spin_lock_bh(&dev->bss_lock);
339
340 found = rb_find_bss(dev, res);
341
342 if (found && overwrite) {
343 list_replace(&found->list, &res->list);
344 rb_replace_node(&found->rbn, &res->rbn,
345 &dev->bss_tree);
346 kref_put(&found->ref, bss_release);
347 found = res;
348 } else if (found) {
349 kref_get(&found->ref);
350 found->pub.beacon_interval = res->pub.beacon_interval;
351 found->pub.tsf = res->pub.tsf;
352 found->pub.signal = res->pub.signal;
353 found->pub.signal_type = res->pub.signal_type;
354 found->pub.capability = res->pub.capability;
355 found->ts = res->ts;
356 kref_put(&res->ref, bss_release);
357 } else {
358 /* this "consumes" the reference */
359 list_add_tail(&res->list, &dev->bss_list);
360 rb_insert_bss(dev, res);
361 found = res;
362 }
363
364 dev->bss_generation++;
365 spin_unlock_bh(&dev->bss_lock);
366
367 kref_get(&found->ref);
368 return found;
369}
370
371struct cfg80211_bss *
372cfg80211_inform_bss_frame(struct wiphy *wiphy,
373 struct ieee80211_channel *channel,
374 struct ieee80211_mgmt *mgmt, size_t len,
375 s32 signal, enum cfg80211_signal_type sigtype,
376 gfp_t gfp)
377{
378 struct cfg80211_internal_bss *res;
379 size_t ielen = len - offsetof(struct ieee80211_mgmt,
380 u.probe_resp.variable);
381 bool overwrite;
382 size_t privsz = wiphy->bss_priv_size;
383
384 if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&
385 (signal < 0 || signal > 100)))
386 return NULL;
387
388 if (WARN_ON(!mgmt || !wiphy ||
389 len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
390 return NULL;
391
392 res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
393 if (!res)
394 return NULL;
395
396 memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
397 res->pub.channel = channel;
398 res->pub.signal_type = sigtype;
399 res->pub.signal = signal;
400 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
401 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
402 res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
403 /* point to after the private area */
404 res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
405 memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
406 res->pub.len_information_elements = ielen;
407
408 kref_init(&res->ref);
409
410 overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
411
412 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
413 if (!res)
414 return NULL;
415
416 /* cfg80211_bss_update gives us a referenced result */
417 return &res->pub;
418}
419EXPORT_SYMBOL(cfg80211_inform_bss_frame);
420
421void cfg80211_put_bss(struct cfg80211_bss *pub)
422{
423 struct cfg80211_internal_bss *bss;
424
425 if (!pub)
426 return;
427
428 bss = container_of(pub, struct cfg80211_internal_bss, pub);
429 kref_put(&bss->ref, bss_release);
430}
431EXPORT_SYMBOL(cfg80211_put_bss);
432
433#ifdef CONFIG_WIRELESS_EXT
434int cfg80211_wext_siwscan(struct net_device *dev,
435 struct iw_request_info *info,
436 union iwreq_data *wrqu, char *extra)
437{
438 struct cfg80211_registered_device *rdev;
439 struct wiphy *wiphy;
440 struct iw_scan_req *wreq = NULL;
441 struct cfg80211_scan_request *creq;
442 int i, err, n_channels = 0;
443 enum ieee80211_band band;
444
445 if (!netif_running(dev))
446 return -ENETDOWN;
447
448 rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
449
450 if (IS_ERR(rdev))
451 return PTR_ERR(rdev);
452
453 if (rdev->scan_req) {
454 err = -EBUSY;
455 goto out;
456 }
457
458 wiphy = &rdev->wiphy;
459
460 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
461 if (wiphy->bands[band])
462 n_channels += wiphy->bands[band]->n_channels;
463
464 creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
465 n_channels * sizeof(void *),
466 GFP_ATOMIC);
467 if (!creq) {
468 err = -ENOMEM;
469 goto out;
470 }
471
472 creq->wiphy = wiphy;
473 creq->ifidx = dev->ifindex;
474 creq->ssids = (void *)(creq + 1);
475 creq->channels = (void *)(creq->ssids + 1);
476 creq->n_channels = n_channels;
477 creq->n_ssids = 1;
478
479 /* all channels */
480 i = 0;
481 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
482 int j;
483 if (!wiphy->bands[band])
484 continue;
485 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
486 creq->channels[i] = &wiphy->bands[band]->channels[j];
487 i++;
488 }
489 }
490
491 /* translate scan request */
492 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
493 wreq = (struct iw_scan_req *)extra;
494
495 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
496 if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
497 return -EINVAL;
498 memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
499 creq->ssids[0].ssid_len = wreq->essid_len;
500 }
501 if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
502 creq->n_ssids = 0;
503 }
504
505 rdev->scan_req = creq;
506 err = rdev->ops->scan(wiphy, dev, creq);
507 if (err) {
508 rdev->scan_req = NULL;
509 kfree(creq);
510 }
511 out:
512 cfg80211_put_dev(rdev);
513 return err;
514}
515EXPORT_SYMBOL(cfg80211_wext_siwscan);
516
517static void ieee80211_scan_add_ies(struct iw_request_info *info,
518 struct cfg80211_bss *bss,
519 char **current_ev, char *end_buf)
520{
521 u8 *pos, *end, *next;
522 struct iw_event iwe;
523
524 if (!bss->information_elements ||
525 !bss->len_information_elements)
526 return;
527
528 /*
529 * If needed, fragment the IEs buffer (at IE boundaries) into short
530 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
531 */
532 pos = bss->information_elements;
533 end = pos + bss->len_information_elements;
534
535 while (end - pos > IW_GENERIC_IE_MAX) {
536 next = pos + 2 + pos[1];
537 while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
538 next = next + 2 + next[1];
539
540 memset(&iwe, 0, sizeof(iwe));
541 iwe.cmd = IWEVGENIE;
542 iwe.u.data.length = next - pos;
543 *current_ev = iwe_stream_add_point(info, *current_ev,
544 end_buf, &iwe, pos);
545
546 pos = next;
547 }
548
549 if (end > pos) {
550 memset(&iwe, 0, sizeof(iwe));
551 iwe.cmd = IWEVGENIE;
552 iwe.u.data.length = end - pos;
553 *current_ev = iwe_stream_add_point(info, *current_ev,
554 end_buf, &iwe, pos);
555 }
556}
557
558
559static char *
560ieee80211_bss(struct iw_request_info *info,
561 struct cfg80211_internal_bss *bss,
562 char *current_ev, char *end_buf)
563{
564 struct iw_event iwe;
565 u8 *buf, *cfg, *p;
566 u8 *ie = bss->pub.information_elements;
567 int rem = bss->pub.len_information_elements, i;
568 bool ismesh = false;
569
570 memset(&iwe, 0, sizeof(iwe));
571 iwe.cmd = SIOCGIWAP;
572 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
573 memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
574 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
575 IW_EV_ADDR_LEN);
576
577 memset(&iwe, 0, sizeof(iwe));
578 iwe.cmd = SIOCGIWFREQ;
579 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
580 iwe.u.freq.e = 0;
581 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
582 IW_EV_FREQ_LEN);
583
584 memset(&iwe, 0, sizeof(iwe));
585 iwe.cmd = SIOCGIWFREQ;
586 iwe.u.freq.m = bss->pub.channel->center_freq;
587 iwe.u.freq.e = 6;
588 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
589 IW_EV_FREQ_LEN);
590
591 if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {
592 memset(&iwe, 0, sizeof(iwe));
593 iwe.cmd = IWEVQUAL;
594 iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
595 IW_QUAL_NOISE_INVALID |
596 IW_QUAL_QUAL_INVALID;
597 switch (bss->pub.signal_type) {
598 case CFG80211_SIGNAL_TYPE_MBM:
599 iwe.u.qual.level = bss->pub.signal / 100;
600 iwe.u.qual.updated |= IW_QUAL_DBM;
601 break;
602 case CFG80211_SIGNAL_TYPE_UNSPEC:
603 iwe.u.qual.level = bss->pub.signal;
604 break;
605 default:
606 /* not reached */
607 break;
608 }
609 current_ev = iwe_stream_add_event(info, current_ev, end_buf,
610 &iwe, IW_EV_QUAL_LEN);
611 }
612
613 memset(&iwe, 0, sizeof(iwe));
614 iwe.cmd = SIOCGIWENCODE;
615 if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
616 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
617 else
618 iwe.u.data.flags = IW_ENCODE_DISABLED;
619 iwe.u.data.length = 0;
620 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
621 &iwe, "");
622
623 while (rem >= 2) {
624 /* invalid data */
625 if (ie[1] > rem - 2)
626 break;
627
628 switch (ie[0]) {
629 case WLAN_EID_SSID:
630 memset(&iwe, 0, sizeof(iwe));
631 iwe.cmd = SIOCGIWESSID;
632 iwe.u.data.length = ie[1];
633 iwe.u.data.flags = 1;
634 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
635 &iwe, ie + 2);
636 break;
637 case WLAN_EID_MESH_ID:
638 memset(&iwe, 0, sizeof(iwe));
639 iwe.cmd = SIOCGIWESSID;
640 iwe.u.data.length = ie[1];
641 iwe.u.data.flags = 1;
642 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
643 &iwe, ie + 2);
644 break;
645 case WLAN_EID_MESH_CONFIG:
646 ismesh = true;
647 if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
648 break;
649 buf = kmalloc(50, GFP_ATOMIC);
650 if (!buf)
651 break;
652 cfg = ie + 2;
653 memset(&iwe, 0, sizeof(iwe));
654 iwe.cmd = IWEVCUSTOM;
655 sprintf(buf, "Mesh network (version %d)", cfg[0]);
656 iwe.u.data.length = strlen(buf);
657 current_ev = iwe_stream_add_point(info, current_ev,
658 end_buf,
659 &iwe, buf);
660 sprintf(buf, "Path Selection Protocol ID: "
661 "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
662 cfg[4]);
663 iwe.u.data.length = strlen(buf);
664 current_ev = iwe_stream_add_point(info, current_ev,
665 end_buf,
666 &iwe, buf);
667 sprintf(buf, "Path Selection Metric ID: "
668 "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
669 cfg[8]);
670 iwe.u.data.length = strlen(buf);
671 current_ev = iwe_stream_add_point(info, current_ev,
672 end_buf,
673 &iwe, buf);
674 sprintf(buf, "Congestion Control Mode ID: "
675 "0x%02X%02X%02X%02X", cfg[9], cfg[10],
676 cfg[11], cfg[12]);
677 iwe.u.data.length = strlen(buf);
678 current_ev = iwe_stream_add_point(info, current_ev,
679 end_buf,
680 &iwe, buf);
681 sprintf(buf, "Channel Precedence: "
682 "0x%02X%02X%02X%02X", cfg[13], cfg[14],
683 cfg[15], cfg[16]);
684 iwe.u.data.length = strlen(buf);
685 current_ev = iwe_stream_add_point(info, current_ev,
686 end_buf,
687 &iwe, buf);
688 kfree(buf);
689 break;
690 case WLAN_EID_SUPP_RATES:
691 case WLAN_EID_EXT_SUPP_RATES:
692 /* display all supported rates in readable format */
693 p = current_ev + iwe_stream_lcp_len(info);
694
695 memset(&iwe, 0, sizeof(iwe));
696 iwe.cmd = SIOCGIWRATE;
697 /* Those two flags are ignored... */
698 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
699
700 for (i = 0; i < ie[1]; i++) {
701 iwe.u.bitrate.value =
702 ((ie[i + 2] & 0x7f) * 500000);
703 p = iwe_stream_add_value(info, current_ev, p,
704 end_buf, &iwe, IW_EV_PARAM_LEN);
705 }
706 current_ev = p;
707 break;
708 }
709 rem -= ie[1] + 2;
710 ie += ie[1] + 2;
711 }
712
713 if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
714 || ismesh) {
715 memset(&iwe, 0, sizeof(iwe));
716 iwe.cmd = SIOCGIWMODE;
717 if (ismesh)
718 iwe.u.mode = IW_MODE_MESH;
719 else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
720 iwe.u.mode = IW_MODE_MASTER;
721 else
722 iwe.u.mode = IW_MODE_ADHOC;
723 current_ev = iwe_stream_add_event(info, current_ev, end_buf,
724 &iwe, IW_EV_UINT_LEN);
725 }
726
727 buf = kmalloc(30, GFP_ATOMIC);
728 if (buf) {
729 memset(&iwe, 0, sizeof(iwe));
730 iwe.cmd = IWEVCUSTOM;
731 sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
732 iwe.u.data.length = strlen(buf);
733 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
734 &iwe, buf);
735 memset(&iwe, 0, sizeof(iwe));
736 iwe.cmd = IWEVCUSTOM;
737 sprintf(buf, " Last beacon: %dms ago",
738 jiffies_to_msecs(jiffies - bss->ts));
739 iwe.u.data.length = strlen(buf);
740 current_ev = iwe_stream_add_point(info, current_ev,
741 end_buf, &iwe, buf);
742 kfree(buf);
743 }
744
745 ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf);
746
747 return current_ev;
748}
749
750
751static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
752 struct iw_request_info *info,
753 char *buf, size_t len)
754{
755 char *current_ev = buf;
756 char *end_buf = buf + len;
757 struct cfg80211_internal_bss *bss;
758
759 spin_lock_bh(&dev->bss_lock);
760 cfg80211_bss_expire(dev);
761
762 list_for_each_entry(bss, &dev->bss_list, list) {
763 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
764 spin_unlock_bh(&dev->bss_lock);
765 return -E2BIG;
766 }
767 current_ev = ieee80211_bss(info, bss,
768 current_ev, end_buf);
769 }
770 spin_unlock_bh(&dev->bss_lock);
771 return current_ev - buf;
772}
773
774
775int cfg80211_wext_giwscan(struct net_device *dev,
776 struct iw_request_info *info,
777 struct iw_point *data, char *extra)
778{
779 struct cfg80211_registered_device *rdev;
780 int res;
781
782 if (!netif_running(dev))
783 return -ENETDOWN;
784
785 rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
786
787 if (IS_ERR(rdev))
788 return PTR_ERR(rdev);
789
790 if (rdev->scan_req) {
791 res = -EAGAIN;
792 goto out;
793 }
794
795 res = ieee80211_scan_results(rdev, info, extra, data->length);
796 data->length = 0;
797 if (res >= 0) {
798 data->length = res;
799 res = 0;
800 }
801
802 out:
803 cfg80211_put_dev(rdev);
804 return res;
805}
806EXPORT_SYMBOL(cfg80211_wext_giwscan);
807#endif