aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c240
1 files changed, 207 insertions, 33 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index fdf432f14554..61876eb50b49 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -20,6 +20,7 @@
20#include <linux/if_arp.h> 20#include <linux/if_arp.h>
21#include <linux/wireless.h> 21#include <linux/wireless.h>
22#include <linux/bitmap.h> 22#include <linux/bitmap.h>
23#include <linux/crc32.h>
23#include <net/net_namespace.h> 24#include <net/net_namespace.h>
24#include <net/cfg80211.h> 25#include <net/cfg80211.h>
25#include <net/rtnetlink.h> 26#include <net/rtnetlink.h>
@@ -28,6 +29,7 @@
28#include "rate.h" 29#include "rate.h"
29#include "mesh.h" 30#include "mesh.h"
30#include "wme.h" 31#include "wme.h"
32#include "led.h"
31 33
32/* privid for wiphys to determine whether they belong to us or not */ 34/* privid for wiphys to determine whether they belong to us or not */
33void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 35void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -536,8 +538,16 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
536void ieee802_11_parse_elems(u8 *start, size_t len, 538void ieee802_11_parse_elems(u8 *start, size_t len,
537 struct ieee802_11_elems *elems) 539 struct ieee802_11_elems *elems)
538{ 540{
541 ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
542}
543
544u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
545 struct ieee802_11_elems *elems,
546 u64 filter, u32 crc)
547{
539 size_t left = len; 548 size_t left = len;
540 u8 *pos = start; 549 u8 *pos = start;
550 bool calc_crc = filter != 0;
541 551
542 memset(elems, 0, sizeof(*elems)); 552 memset(elems, 0, sizeof(*elems));
543 elems->ie_start = start; 553 elems->ie_start = start;
@@ -551,7 +561,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
551 left -= 2; 561 left -= 2;
552 562
553 if (elen > left) 563 if (elen > left)
554 return; 564 break;
565
566 if (calc_crc && id < 64 && (filter & BIT(id)))
567 crc = crc32_be(crc, pos - 2, elen + 2);
555 568
556 switch (id) { 569 switch (id) {
557 case WLAN_EID_SSID: 570 case WLAN_EID_SSID:
@@ -575,8 +588,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
575 elems->cf_params_len = elen; 588 elems->cf_params_len = elen;
576 break; 589 break;
577 case WLAN_EID_TIM: 590 case WLAN_EID_TIM:
578 elems->tim = pos; 591 if (elen >= sizeof(struct ieee80211_tim_ie)) {
579 elems->tim_len = elen; 592 elems->tim = (void *)pos;
593 elems->tim_len = elen;
594 }
580 break; 595 break;
581 case WLAN_EID_IBSS_PARAMS: 596 case WLAN_EID_IBSS_PARAMS:
582 elems->ibss_params = pos; 597 elems->ibss_params = pos;
@@ -586,15 +601,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
586 elems->challenge = pos; 601 elems->challenge = pos;
587 elems->challenge_len = elen; 602 elems->challenge_len = elen;
588 break; 603 break;
589 case WLAN_EID_WPA: 604 case WLAN_EID_VENDOR_SPECIFIC:
590 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 605 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
591 pos[2] == 0xf2) { 606 pos[2] == 0xf2) {
592 /* Microsoft OUI (00:50:F2) */ 607 /* Microsoft OUI (00:50:F2) */
608
609 if (calc_crc)
610 crc = crc32_be(crc, pos - 2, elen + 2);
611
593 if (pos[3] == 1) { 612 if (pos[3] == 1) {
594 /* OUI Type 1 - WPA IE */ 613 /* OUI Type 1 - WPA IE */
595 elems->wpa = pos; 614 elems->wpa = pos;
596 elems->wpa_len = elen; 615 elems->wpa_len = elen;
597 } else if (elen >= 5 && pos[3] == 2) { 616 } else if (elen >= 5 && pos[3] == 2) {
617 /* OUI Type 2 - WMM IE */
598 if (pos[4] == 0) { 618 if (pos[4] == 0) {
599 elems->wmm_info = pos; 619 elems->wmm_info = pos;
600 elems->wmm_info_len = elen; 620 elems->wmm_info_len = elen;
@@ -679,6 +699,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
679 left -= elen; 699 left -= elen;
680 pos += elen; 700 pos += elen;
681 } 701 }
702
703 return crc;
682} 704}
683 705
684void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 706void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
@@ -831,16 +853,73 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
831 ieee80211_tx_skb(sdata, skb, encrypt); 853 ieee80211_tx_skb(sdata, skb, encrypt);
832} 854}
833 855
856int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
857 const u8 *ie, size_t ie_len)
858{
859 struct ieee80211_supported_band *sband;
860 u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
861 int i;
862
863 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
864
865 pos = buffer;
866
867 *pos++ = WLAN_EID_SUPP_RATES;
868 supp_rates_len = pos;
869 *pos++ = 0;
870
871 for (i = 0; i < sband->n_bitrates; i++) {
872 struct ieee80211_rate *rate = &sband->bitrates[i];
873
874 if (esupp_rates_len) {
875 *esupp_rates_len += 1;
876 } else if (*supp_rates_len == 8) {
877 *pos++ = WLAN_EID_EXT_SUPP_RATES;
878 esupp_rates_len = pos;
879 *pos++ = 1;
880 } else
881 *supp_rates_len += 1;
882
883 *pos++ = rate->bitrate / 5;
884 }
885
886 if (sband->ht_cap.ht_supported) {
887 __le16 tmp = cpu_to_le16(sband->ht_cap.cap);
888
889 *pos++ = WLAN_EID_HT_CAPABILITY;
890 *pos++ = sizeof(struct ieee80211_ht_cap);
891 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
892 memcpy(pos, &tmp, sizeof(u16));
893 pos += sizeof(u16);
894 /* TODO: needs a define here for << 2 */
895 *pos++ = sband->ht_cap.ampdu_factor |
896 (sband->ht_cap.ampdu_density << 2);
897 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
898 pos += sizeof(sband->ht_cap.mcs);
899 pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
900 }
901
902 /*
903 * If adding more here, adjust code in main.c
904 * that calculates local->scan_ies_len.
905 */
906
907 if (ie) {
908 memcpy(pos, ie, ie_len);
909 pos += ie_len;
910 }
911
912 return pos - buffer;
913}
914
834void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 915void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
835 u8 *ssid, size_t ssid_len, 916 const u8 *ssid, size_t ssid_len,
836 u8 *ie, size_t ie_len) 917 const u8 *ie, size_t ie_len)
837{ 918{
838 struct ieee80211_local *local = sdata->local; 919 struct ieee80211_local *local = sdata->local;
839 struct ieee80211_supported_band *sband;
840 struct sk_buff *skb; 920 struct sk_buff *skb;
841 struct ieee80211_mgmt *mgmt; 921 struct ieee80211_mgmt *mgmt;
842 u8 *pos, *supp_rates, *esupp_rates = NULL; 922 u8 *pos;
843 int i;
844 923
845 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + 924 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
846 ie_len); 925 ie_len);
@@ -867,31 +946,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
867 *pos++ = WLAN_EID_SSID; 946 *pos++ = WLAN_EID_SSID;
868 *pos++ = ssid_len; 947 *pos++ = ssid_len;
869 memcpy(pos, ssid, ssid_len); 948 memcpy(pos, ssid, ssid_len);
949 pos += ssid_len;
870 950
871 supp_rates = skb_put(skb, 2); 951 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 (ie)
894 memcpy(skb_put(skb, ie_len), ie, ie_len);
895 952
896 ieee80211_tx_skb(sdata, skb, 0); 953 ieee80211_tx_skb(sdata, skb, 0);
897} 954}
@@ -931,3 +988,120 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
931 } 988 }
932 return supp_rates; 989 return supp_rates;
933} 990}
991
992int ieee80211_reconfig(struct ieee80211_local *local)
993{
994 struct ieee80211_hw *hw = &local->hw;
995 struct ieee80211_sub_if_data *sdata;
996 struct ieee80211_if_init_conf conf;
997 struct sta_info *sta;
998 unsigned long flags;
999 int res;
1000
1001 /* restart hardware */
1002 if (local->open_count) {
1003 res = local->ops->start(hw);
1004
1005 ieee80211_led_radio(local, hw->conf.radio_enabled);
1006 }
1007
1008 /* add interfaces */
1009 list_for_each_entry(sdata, &local->interfaces, list) {
1010 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1011 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1012 netif_running(sdata->dev)) {
1013 conf.vif = &sdata->vif;
1014 conf.type = sdata->vif.type;
1015 conf.mac_addr = sdata->dev->dev_addr;
1016 res = local->ops->add_interface(hw, &conf);
1017 }
1018 }
1019
1020 /* add STAs back */
1021 if (local->ops->sta_notify) {
1022 spin_lock_irqsave(&local->sta_lock, flags);
1023 list_for_each_entry(sta, &local->sta_list, list) {
1024 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1025 sdata = container_of(sdata->bss,
1026 struct ieee80211_sub_if_data,
1027 u.ap);
1028
1029 local->ops->sta_notify(hw, &sdata->vif,
1030 STA_NOTIFY_ADD, &sta->sta);
1031 }
1032 spin_unlock_irqrestore(&local->sta_lock, flags);
1033 }
1034
1035 /* Clear Suspend state so that ADDBA requests can be processed */
1036
1037 rcu_read_lock();
1038
1039 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1040 list_for_each_entry_rcu(sta, &local->sta_list, list) {
1041 clear_sta_flags(sta, WLAN_STA_SUSPEND);
1042 }
1043 }
1044
1045 rcu_read_unlock();
1046
1047 /* setup RTS threshold */
1048 if (local->ops->set_rts_threshold)
1049 local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold);
1050
1051 /* reconfigure hardware */
1052 ieee80211_hw_config(local, ~0);
1053
1054 netif_addr_lock_bh(local->mdev);
1055 ieee80211_configure_filter(local);
1056 netif_addr_unlock_bh(local->mdev);
1057
1058 /* Finally also reconfigure all the BSS information */
1059 list_for_each_entry(sdata, &local->interfaces, list) {
1060 u32 changed = ~0;
1061 if (!netif_running(sdata->dev))
1062 continue;
1063 switch (sdata->vif.type) {
1064 case NL80211_IFTYPE_STATION:
1065 /* disable beacon change bits */
1066 changed &= ~IEEE80211_IFCC_BEACON;
1067 /* fall through */
1068 case NL80211_IFTYPE_ADHOC:
1069 case NL80211_IFTYPE_AP:
1070 case NL80211_IFTYPE_MESH_POINT:
1071 /*
1072 * Driver's config_interface can fail if rfkill is
1073 * enabled. Accommodate this return code.
1074 * FIXME: When mac80211 has knowledge of rfkill
1075 * state the code below can change back to:
1076 * WARN(ieee80211_if_config(sdata, changed));
1077 * ieee80211_bss_info_change_notify(sdata, ~0);
1078 */
1079 if (ieee80211_if_config(sdata, changed))
1080 printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
1081 sdata->dev->name);
1082 else
1083 ieee80211_bss_info_change_notify(sdata, ~0);
1084 break;
1085 case NL80211_IFTYPE_WDS:
1086 break;
1087 case NL80211_IFTYPE_AP_VLAN:
1088 case NL80211_IFTYPE_MONITOR:
1089 /* ignore virtual */
1090 break;
1091 case NL80211_IFTYPE_UNSPECIFIED:
1092 case __NL80211_IFTYPE_AFTER_LAST:
1093 WARN_ON(1);
1094 break;
1095 }
1096 }
1097
1098 /* add back keys */
1099 list_for_each_entry(sdata, &local->interfaces, list)
1100 if (netif_running(sdata->dev))
1101 ieee80211_enable_keys(sdata);
1102
1103 ieee80211_wake_queues_by_reason(hw,
1104 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1105
1106 return 0;
1107}