aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/main.c49
-rw-r--r--net/mac80211/scan.c24
-rw-r--r--net/mac80211/util.c79
-rw-r--r--net/wireless/nl80211.c3
5 files changed, 114 insertions, 50 deletions
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);
1096int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1097 const u8 *ie, size_t ie_len);
1093void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1098void 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
1097void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 1102void 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
834int 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
834void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 877void 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