diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-04-01 05:58:36 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-04-22 16:54:39 -0400 |
commit | de95a54b1aebe5592cae971ca5e5d9ec6a381a17 (patch) | |
tree | 55a622d1e61e73cd6426c5e0643ac9fd117a9fe8 | |
parent | 18a8365992a8041aa178ae9ad5f0d951d0457230 (diff) |
mac80211: pass all probe request IEs to driver
Instead of just passing the cfg80211-requested IEs, pass
the locally generated ones as well.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | include/net/cfg80211.h | 2 | ||||
-rw-r--r-- | include/net/mac80211.h | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 9 | ||||
-rw-r--r-- | net/mac80211/main.c | 49 | ||||
-rw-r--r-- | net/mac80211/scan.c | 24 | ||||
-rw-r--r-- | net/mac80211/util.c | 79 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 3 |
7 files changed, 123 insertions, 56 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2b1f6c69773c..d303c269a693 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -503,7 +503,7 @@ struct cfg80211_scan_request { | |||
503 | int n_ssids; | 503 | int n_ssids; |
504 | struct ieee80211_channel **channels; | 504 | struct ieee80211_channel **channels; |
505 | u32 n_channels; | 505 | u32 n_channels; |
506 | u8 *ie; | 506 | const u8 *ie; |
507 | size_t ie_len; | 507 | size_t ie_len; |
508 | 508 | ||
509 | /* internal */ | 509 | /* internal */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3b83a80e3fe0..2c6f976831b5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1330,11 +1330,14 @@ enum ieee80211_ampdu_mlme_action { | |||
1330 | * the scan state machine in stack. The scan must honour the channel | 1330 | * the scan state machine in stack. The scan must honour the channel |
1331 | * configuration done by the regulatory agent in the wiphy's | 1331 | * configuration done by the regulatory agent in the wiphy's |
1332 | * registered bands. The hardware (or the driver) needs to make sure | 1332 | * registered bands. The hardware (or the driver) needs to make sure |
1333 | * that power save is disabled. When the scan finishes, | 1333 | * that power save is disabled. |
1334 | * ieee80211_scan_completed() must be called; note that it also must | 1334 | * The @req ie/ie_len members are rewritten by mac80211 to contain the |
1335 | * be called when the scan cannot finish because the hardware is | 1335 | * entire IEs after the SSID, so that drivers need not look at these |
1336 | * turned off! Anything else is a bug! Returns a negative error code | 1336 | * at all but just send them after the SSID -- mac80211 includes the |
1337 | * which will be seen in userspace. | 1337 | * (extended) supported rates and HT information (where applicable). |
1338 | * When the scan finishes, ieee80211_scan_completed() must be called; | ||
1339 | * note that it also must be called when the scan cannot finish due to | ||
1340 | * any error unless this callback returned a negative error code. | ||
1338 | * | 1341 | * |
1339 | * @sw_scan_start: Notifier function that is called just before a software scan | 1342 | * @sw_scan_start: Notifier function that is called just before a software scan |
1340 | * is started. Can be NULL, if the driver doesn't need this notification. | 1343 | * is started. Can be NULL, if the driver doesn't need this notification. |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 73d9f894ed5d..cb80a80504e6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -671,7 +671,10 @@ struct ieee80211_local { | |||
671 | struct cfg80211_scan_request int_scan_req; | 671 | struct cfg80211_scan_request int_scan_req; |
672 | struct cfg80211_scan_request *scan_req; | 672 | struct cfg80211_scan_request *scan_req; |
673 | struct ieee80211_channel *scan_channel; | 673 | struct ieee80211_channel *scan_channel; |
674 | const u8 *orig_ies; | ||
675 | int orig_ies_len; | ||
674 | int scan_channel_idx; | 676 | int scan_channel_idx; |
677 | int scan_ies_len; | ||
675 | 678 | ||
676 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; | 679 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; |
677 | unsigned long last_scan_completed; | 680 | unsigned long last_scan_completed; |
@@ -1090,9 +1093,11 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1090 | u16 transaction, u16 auth_alg, | 1093 | u16 transaction, u16 auth_alg, |
1091 | u8 *extra, size_t extra_len, | 1094 | u8 *extra, size_t extra_len, |
1092 | const u8 *bssid, int encrypt); | 1095 | const u8 *bssid, int encrypt); |
1096 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
1097 | const u8 *ie, size_t ie_len); | ||
1093 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1098 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1094 | u8 *ssid, size_t ssid_len, | 1099 | const u8 *ssid, size_t ssid_len, |
1095 | u8 *ie, size_t ie_len); | 1100 | const u8 *ie, size_t ie_len); |
1096 | 1101 | ||
1097 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 1102 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
1098 | const size_t supp_rates_len, | 1103 | const size_t supp_rates_len, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ee58a7873699..b3bbe78821d9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -729,22 +729,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
729 | 729 | ||
730 | wiphy->privid = mac80211_wiphy_privid; | 730 | wiphy->privid = mac80211_wiphy_privid; |
731 | 731 | ||
732 | if (!ops->hw_scan) { | ||
733 | /* For hw_scan, driver needs to set these up. */ | ||
734 | wiphy->max_scan_ssids = 4; | ||
735 | |||
736 | /* we support a maximum of 32 rates in cfg80211 */ | ||
737 | wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN | ||
738 | - 2 - 32 /* SSID */ | ||
739 | - 4 - 32 /* (ext) supp rates */; | ||
740 | |||
741 | } | ||
742 | |||
743 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 732 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ |
744 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | 733 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - |
745 | sizeof(struct cfg80211_bss); | 734 | sizeof(struct cfg80211_bss); |
746 | 735 | ||
747 | local = wiphy_priv(wiphy); | 736 | local = wiphy_priv(wiphy); |
737 | |||
748 | local->hw.wiphy = wiphy; | 738 | local->hw.wiphy = wiphy; |
749 | 739 | ||
750 | local->hw.priv = (char *)local + | 740 | local->hw.priv = (char *)local + |
@@ -831,7 +821,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
831 | enum ieee80211_band band; | 821 | enum ieee80211_band band; |
832 | struct net_device *mdev; | 822 | struct net_device *mdev; |
833 | struct ieee80211_master_priv *mpriv; | 823 | struct ieee80211_master_priv *mpriv; |
834 | int channels, i, j; | 824 | int channels, i, j, max_bitrates; |
835 | 825 | ||
836 | /* | 826 | /* |
837 | * generic code guarantees at least one band, | 827 | * generic code guarantees at least one band, |
@@ -839,18 +829,23 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
839 | * that hw.conf.channel is assigned | 829 | * that hw.conf.channel is assigned |
840 | */ | 830 | */ |
841 | channels = 0; | 831 | channels = 0; |
832 | max_bitrates = 0; | ||
842 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 833 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
843 | struct ieee80211_supported_band *sband; | 834 | struct ieee80211_supported_band *sband; |
844 | 835 | ||
845 | sband = local->hw.wiphy->bands[band]; | 836 | sband = local->hw.wiphy->bands[band]; |
846 | if (sband && !local->oper_channel) { | 837 | if (!sband) |
838 | continue; | ||
839 | if (!local->oper_channel) { | ||
847 | /* init channel we're on */ | 840 | /* init channel we're on */ |
848 | local->hw.conf.channel = | 841 | local->hw.conf.channel = |
849 | local->oper_channel = | 842 | local->oper_channel = |
850 | local->scan_channel = &sband->channels[0]; | 843 | local->scan_channel = &sband->channels[0]; |
851 | } | 844 | } |
852 | if (sband) | 845 | channels += sband->n_channels; |
853 | channels += sband->n_channels; | 846 | |
847 | if (max_bitrates < sband->n_bitrates) | ||
848 | max_bitrates = sband->n_bitrates; | ||
854 | } | 849 | } |
855 | 850 | ||
856 | local->int_scan_req.n_channels = channels; | 851 | local->int_scan_req.n_channels = channels; |
@@ -870,6 +865,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
870 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 865 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
871 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 866 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
872 | 867 | ||
868 | /* | ||
869 | * Calculate scan IE length -- we need this to alloc | ||
870 | * memory and to subtract from the driver limit. It | ||
871 | * includes the (extended) supported rates and HT | ||
872 | * information -- SSID is the driver's responsibility. | ||
873 | */ | ||
874 | local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ | ||
875 | |||
876 | if (!local->ops->hw_scan) { | ||
877 | /* For hw_scan, driver needs to set these up. */ | ||
878 | local->hw.wiphy->max_scan_ssids = 4; | ||
879 | local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
880 | } | ||
881 | |||
882 | /* | ||
883 | * If the driver supports any scan IEs, then assume the | ||
884 | * limit includes the IEs mac80211 will add, otherwise | ||
885 | * leave it at zero and let the driver sort it out; we | ||
886 | * still pass our IEs to the driver but userspace will | ||
887 | * not be allowed to in that case. | ||
888 | */ | ||
889 | if (local->hw.wiphy->max_scan_ie_len) | ||
890 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | ||
891 | |||
873 | result = wiphy_register(local->hw.wiphy); | 892 | result = wiphy_register(local->hw.wiphy); |
874 | if (result < 0) | 893 | if (result < 0) |
875 | goto fail_wiphy_register; | 894 | goto fail_wiphy_register; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 3bf9839f5916..4ec1bfc7f6a9 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -285,6 +285,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
285 | if (WARN_ON(!local->scan_req)) | 285 | if (WARN_ON(!local->scan_req)) |
286 | return; | 286 | return; |
287 | 287 | ||
288 | if (local->hw_scanning) { | ||
289 | kfree(local->scan_req->ie); | ||
290 | local->scan_req->ie = local->orig_ies; | ||
291 | local->scan_req->ie_len = local->orig_ies_len; | ||
292 | } | ||
293 | |||
288 | if (local->scan_req != &local->int_scan_req) | 294 | if (local->scan_req != &local->int_scan_req) |
289 | cfg80211_scan_done(local->scan_req, aborted); | 295 | cfg80211_scan_done(local->scan_req, aborted); |
290 | local->scan_req = NULL; | 296 | local->scan_req = NULL; |
@@ -457,12 +463,28 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
457 | } | 463 | } |
458 | 464 | ||
459 | if (local->ops->hw_scan) { | 465 | if (local->ops->hw_scan) { |
460 | int rc; | 466 | u8 *ies; |
467 | int rc, ielen; | ||
468 | |||
469 | ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + | ||
470 | local->scan_ies_len + req->ie_len, GFP_KERNEL); | ||
471 | if (!ies) | ||
472 | return -ENOMEM; | ||
473 | |||
474 | ielen = ieee80211_build_preq_ies(local, ies, | ||
475 | req->ie, req->ie_len); | ||
476 | local->orig_ies = req->ie; | ||
477 | local->orig_ies_len = req->ie_len; | ||
478 | req->ie = ies; | ||
479 | req->ie_len = ielen; | ||
461 | 480 | ||
462 | local->hw_scanning = true; | 481 | local->hw_scanning = true; |
463 | rc = local->ops->hw_scan(local_to_hw(local), req); | 482 | rc = local->ops->hw_scan(local_to_hw(local), req); |
464 | if (rc) { | 483 | if (rc) { |
465 | local->hw_scanning = false; | 484 | local->hw_scanning = false; |
485 | kfree(ies); | ||
486 | req->ie_len = local->orig_ies_len; | ||
487 | req->ie = local->orig_ies; | ||
466 | return rc; | 488 | return rc; |
467 | } | 489 | } |
468 | local->scan_sdata = scan_sdata; | 490 | local->scan_sdata = scan_sdata; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 05caf34f31da..72b091317a7c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -831,16 +831,57 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
831 | ieee80211_tx_skb(sdata, skb, encrypt); | 831 | ieee80211_tx_skb(sdata, skb, encrypt); |
832 | } | 832 | } |
833 | 833 | ||
834 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
835 | const u8 *ie, size_t ie_len) | ||
836 | { | ||
837 | struct ieee80211_supported_band *sband; | ||
838 | u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | ||
839 | int i; | ||
840 | |||
841 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
842 | |||
843 | pos = buffer; | ||
844 | |||
845 | *pos++ = WLAN_EID_SUPP_RATES; | ||
846 | supp_rates_len = pos; | ||
847 | *pos++ = 0; | ||
848 | |||
849 | for (i = 0; i < sband->n_bitrates; i++) { | ||
850 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
851 | |||
852 | if (esupp_rates_len) { | ||
853 | *esupp_rates_len += 1; | ||
854 | } else if (*supp_rates_len == 8) { | ||
855 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
856 | esupp_rates_len = pos; | ||
857 | *pos++ = 1; | ||
858 | } else | ||
859 | *supp_rates_len += 1; | ||
860 | |||
861 | *pos++ = rate->bitrate / 5; | ||
862 | } | ||
863 | |||
864 | /* | ||
865 | * If adding more here, adjust code in main.c | ||
866 | * that calculates local->scan_ies_len. | ||
867 | */ | ||
868 | |||
869 | if (ie) { | ||
870 | memcpy(pos, ie, ie_len); | ||
871 | pos += ie_len; | ||
872 | } | ||
873 | |||
874 | return pos - buffer; | ||
875 | } | ||
876 | |||
834 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 877 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
835 | u8 *ssid, size_t ssid_len, | 878 | const u8 *ssid, size_t ssid_len, |
836 | u8 *ie, size_t ie_len) | 879 | const u8 *ie, size_t ie_len) |
837 | { | 880 | { |
838 | struct ieee80211_local *local = sdata->local; | 881 | struct ieee80211_local *local = sdata->local; |
839 | struct ieee80211_supported_band *sband; | ||
840 | struct sk_buff *skb; | 882 | struct sk_buff *skb; |
841 | struct ieee80211_mgmt *mgmt; | 883 | struct ieee80211_mgmt *mgmt; |
842 | u8 *pos, *supp_rates, *esupp_rates = NULL; | 884 | u8 *pos; |
843 | int i; | ||
844 | 885 | ||
845 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 886 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + |
846 | ie_len); | 887 | ie_len); |
@@ -867,33 +908,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
867 | *pos++ = WLAN_EID_SSID; | 908 | *pos++ = WLAN_EID_SSID; |
868 | *pos++ = ssid_len; | 909 | *pos++ = ssid_len; |
869 | memcpy(pos, ssid, ssid_len); | 910 | memcpy(pos, ssid, ssid_len); |
911 | pos += ssid_len; | ||
870 | 912 | ||
871 | supp_rates = skb_put(skb, 2); | 913 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); |
872 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
873 | supp_rates[1] = 0; | ||
874 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
875 | |||
876 | for (i = 0; i < sband->n_bitrates; i++) { | ||
877 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
878 | if (esupp_rates) { | ||
879 | pos = skb_put(skb, 1); | ||
880 | esupp_rates[1]++; | ||
881 | } else if (supp_rates[1] == 8) { | ||
882 | esupp_rates = skb_put(skb, 3); | ||
883 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
884 | esupp_rates[1] = 1; | ||
885 | pos = &esupp_rates[2]; | ||
886 | } else { | ||
887 | pos = skb_put(skb, 1); | ||
888 | supp_rates[1]++; | ||
889 | } | ||
890 | *pos = rate->bitrate / 5; | ||
891 | } | ||
892 | |||
893 | /* if adding more here, adjust max_scan_ie_len */ | ||
894 | |||
895 | if (ie) | ||
896 | memcpy(skb_put(skb, ie_len), ie, ie_len); | ||
897 | 914 | ||
898 | ieee80211_tx_skb(sdata, skb, 0); | 915 | ieee80211_tx_skb(sdata, skb, 0); |
899 | } | 916 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 447fa1790b4e..68c51022e9dd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -2597,7 +2597,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2597 | 2597 | ||
2598 | if (info->attrs[NL80211_ATTR_IE]) { | 2598 | if (info->attrs[NL80211_ATTR_IE]) { |
2599 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2599 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2600 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | 2600 | memcpy((void *)request->ie, |
2601 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2601 | request->ie_len); | 2602 | request->ie_len); |
2602 | } | 2603 | } |
2603 | 2604 | ||