diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-02-10 15:25:55 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:45:49 -0500 |
commit | 2a5193119269062608582418deba7af82844159a (patch) | |
tree | 1f2fe8cffbeb7530dce7fa708310f6fb29ab0dd8 /net/mac80211 | |
parent | 849b7967818995a32c3017542e33eb3155944368 (diff) |
cfg80211/nl80211: scanning (and mac80211 update to use it)
This patch adds basic scan capability to cfg80211/nl80211 and
changes mac80211 to use it. The BSS list that cfg80211 maintains
is made driver-accessible with a private area in each BSS struct,
but mac80211 doesn't yet use it. That's another large project.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 20 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 18 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/main.c | 32 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 37 | ||||
-rw-r--r-- | net/mac80211/scan.c | 356 | ||||
-rw-r--r-- | net/mac80211/wext.c | 59 |
7 files changed, 151 insertions, 373 deletions
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 | ||
1280 | static 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 | |||
1280 | struct cfg80211_ops mac80211_config_ops = { | 1299 | struct 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 */ |
931 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 930 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
932 | u8 *ssid, size_t ssid_len); | 931 | struct cfg80211_scan_request *req); |
933 | int ieee80211_scan_results(struct ieee80211_local *local, | 932 | int 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 | ||
945 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 944 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
946 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 945 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, |
947 | u8 *ssid, size_t ssid_len); | 946 | struct cfg80211_scan_request *req); |
948 | struct ieee80211_bss * | 947 | struct ieee80211_bss * |
949 | ieee80211_bss_info_update(struct ieee80211_local *local, | 948 | ieee80211_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); | ||
955 | struct ieee80211_bss * | 955 | struct ieee80211_bss * |
956 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | 956 | ieee80211_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 | ||
953 | fail_wep: | 976 | fail_wep: |
@@ -966,6 +989,8 @@ fail_workqueue: | |||
966 | free_netdev(local->mdev); | 989 | free_netdev(local->mdev); |
967 | fail_mdev_alloc: | 990 | fail_mdev_alloc: |
968 | wiphy_unregister(local->hw.wiphy); | 991 | wiphy_unregister(local->hw.wiphy); |
992 | fail_wiphy_register: | ||
993 | kfree(local->int_scan_req.channels); | ||
969 | return result; | 994 | return result; |
970 | } | 995 | } |
971 | EXPORT_SYMBOL(ieee80211_register_hw); | 996 | EXPORT_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 | } |
1015 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 1041 | EXPORT_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 | ||
442 | void ieee80211_scan_completed(struct ieee80211_hw *hw) | 461 | void 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 | ||
612 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 601 | int 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 | ||
708 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 697 | int 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 | |||
741 | static 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 | |||
782 | static char * | ||
783 | ieee80211_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, ¤t_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 | |||
948 | int 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 | ||
418 | static 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 | |||
447 | static 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 | |||
470 | static int ieee80211_ioctl_siwrate(struct net_device *dev, | 419 | static 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 */ |