aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/mlme.c52
-rw-r--r--net/mac80211/util.c23
3 files changed, 66 insertions, 14 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b1d18d967d8c..38c980612518 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -308,6 +308,8 @@ struct ieee80211_if_managed {
308 int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ 308 int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
309 int auth_transaction; 309 int auth_transaction;
310 310
311 u32 beacon_crc;
312
311 enum { 313 enum {
312 IEEE80211_MFP_DISABLED, 314 IEEE80211_MFP_DISABLED,
313 IEEE80211_MFP_OPTIONAL, 315 IEEE80211_MFP_OPTIONAL,
@@ -1085,6 +1087,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
1085 int encrypt); 1087 int encrypt);
1086void ieee802_11_parse_elems(u8 *start, size_t len, 1088void ieee802_11_parse_elems(u8 *start, size_t len,
1087 struct ieee802_11_elems *elems); 1089 struct ieee802_11_elems *elems);
1090u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
1091 struct ieee802_11_elems *elems,
1092 u64 filter, u32 crc);
1088int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); 1093int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
1089u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 1094u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
1090 enum ieee80211_band band); 1095 enum ieee80211_band band);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c39a214e7ad0..7a8d4c494246 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -18,6 +18,7 @@
18#include <linux/etherdevice.h> 18#include <linux/etherdevice.h>
19#include <linux/rtnetlink.h> 19#include <linux/rtnetlink.h>
20#include <linux/pm_qos_params.h> 20#include <linux/pm_qos_params.h>
21#include <linux/crc32.h>
21#include <net/mac80211.h> 22#include <net/mac80211.h>
22#include <asm/unaligned.h> 23#include <asm/unaligned.h>
23 24
@@ -1752,46 +1753,73 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
1752 ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; 1753 ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
1753} 1754}
1754 1755
1756/*
1757 * This is the canonical list of information elements we care about,
1758 * the filter code also gives us all changes to the Microsoft OUI
1759 * (00:50:F2) vendor IE which is used for WMM which we need to track.
1760 *
1761 * We implement beacon filtering in software since that means we can
1762 * avoid processing the frame here and in cfg80211, and userspace
1763 * will not be able to tell whether the hardware supports it or not.
1764 *
1765 * XXX: This list needs to be dynamic -- userspace needs to be able to
1766 * add items it requires. It also needs to be able to tell us to
1767 * look out for other vendor IEs.
1768 */
1769static const u64 care_about_ies =
1770 BIT(WLAN_EID_COUNTRY) |
1771 BIT(WLAN_EID_ERP_INFO) |
1772 BIT(WLAN_EID_CHANNEL_SWITCH) |
1773 BIT(WLAN_EID_PWR_CONSTRAINT) |
1774 BIT(WLAN_EID_HT_CAPABILITY) |
1775 BIT(WLAN_EID_HT_INFORMATION);
1776
1755static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, 1777static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1756 struct ieee80211_mgmt *mgmt, 1778 struct ieee80211_mgmt *mgmt,
1757 size_t len, 1779 size_t len,
1758 struct ieee80211_rx_status *rx_status) 1780 struct ieee80211_rx_status *rx_status)
1759{ 1781{
1760 struct ieee80211_if_managed *ifmgd; 1782 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1761 size_t baselen; 1783 size_t baselen;
1762 struct ieee802_11_elems elems; 1784 struct ieee802_11_elems elems;
1763 struct ieee80211_local *local = sdata->local; 1785 struct ieee80211_local *local = sdata->local;
1764 u32 changed = 0; 1786 u32 changed = 0;
1765 bool erp_valid, directed_tim; 1787 bool erp_valid, directed_tim = false;
1766 u8 erp_value = 0; 1788 u8 erp_value = 0;
1789 u32 ncrc;
1767 1790
1768 /* Process beacon from the current BSS */ 1791 /* Process beacon from the current BSS */
1769 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; 1792 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
1770 if (baselen > len) 1793 if (baselen > len)
1771 return; 1794 return;
1772 1795
1773 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); 1796 if (rx_status->freq != local->hw.conf.channel->center_freq)
1774
1775 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
1776
1777 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1778 return; 1797 return;
1779 1798
1780 ifmgd = &sdata->u.mgd;
1781
1782 if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || 1799 if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
1783 memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) 1800 memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
1784 return; 1801 return;
1785 1802
1786 if (rx_status->freq != local->hw.conf.channel->center_freq) 1803 ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
1804 ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
1805 len - baselen, &elems,
1806 care_about_ies, ncrc);
1807
1808 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
1809 directed_tim = ieee80211_check_tim(&elems, ifmgd->aid);
1810
1811 ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim));
1812
1813 if (ncrc == ifmgd->beacon_crc)
1787 return; 1814 return;
1815 ifmgd->beacon_crc = ncrc;
1816
1817 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
1788 1818
1789 ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, 1819 ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
1790 elems.wmm_param_len); 1820 elems.wmm_param_len);
1791 1821
1792 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { 1822 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
1793 directed_tim = ieee80211_check_tim(&elems, ifmgd->aid);
1794
1795 if (directed_tim) { 1823 if (directed_tim) {
1796 if (local->hw.conf.dynamic_ps_timeout > 0) { 1824 if (local->hw.conf.dynamic_ps_timeout > 0) {
1797 local->hw.conf.flags &= ~IEEE80211_CONF_PS; 1825 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b361e2acfce9..3dd490fa4b68 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>
@@ -537,8 +538,16 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
537void ieee802_11_parse_elems(u8 *start, size_t len, 538void ieee802_11_parse_elems(u8 *start, size_t len,
538 struct ieee802_11_elems *elems) 539 struct ieee802_11_elems *elems)
539{ 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{
540 size_t left = len; 548 size_t left = len;
541 u8 *pos = start; 549 u8 *pos = start;
550 bool calc_crc = filter != 0;
542 551
543 memset(elems, 0, sizeof(*elems)); 552 memset(elems, 0, sizeof(*elems));
544 elems->ie_start = start; 553 elems->ie_start = start;
@@ -552,7 +561,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
552 left -= 2; 561 left -= 2;
553 562
554 if (elen > left) 563 if (elen > left)
555 return; 564 break;
565
566 if (calc_crc && id < 64 && (filter & BIT(id)))
567 crc = crc32_be(crc, pos - 2, elen + 2);
556 568
557 switch (id) { 569 switch (id) {
558 case WLAN_EID_SSID: 570 case WLAN_EID_SSID:
@@ -587,15 +599,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
587 elems->challenge = pos; 599 elems->challenge = pos;
588 elems->challenge_len = elen; 600 elems->challenge_len = elen;
589 break; 601 break;
590 case WLAN_EID_WPA: 602 case WLAN_EID_VENDOR_SPECIFIC:
591 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 603 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
592 pos[2] == 0xf2) { 604 pos[2] == 0xf2) {
593 /* Microsoft OUI (00:50:F2) */ 605 /* Microsoft OUI (00:50:F2) */
606
607 if (calc_crc)
608 crc = crc32_be(crc, pos - 2, elen + 2);
609
594 if (pos[3] == 1) { 610 if (pos[3] == 1) {
595 /* OUI Type 1 - WPA IE */ 611 /* OUI Type 1 - WPA IE */
596 elems->wpa = pos; 612 elems->wpa = pos;
597 elems->wpa_len = elen; 613 elems->wpa_len = elen;
598 } else if (elen >= 5 && pos[3] == 2) { 614 } else if (elen >= 5 && pos[3] == 2) {
615 /* OUI Type 2 - WMM IE */
599 if (pos[4] == 0) { 616 if (pos[4] == 0) {
600 elems->wmm_info = pos; 617 elems->wmm_info = pos;
601 elems->wmm_info_len = elen; 618 elems->wmm_info_len = elen;
@@ -680,6 +697,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
680 left -= elen; 697 left -= elen;
681 pos += elen; 698 pos += elen;
682 } 699 }
700
701 return crc;
683} 702}
684 703
685void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 704void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)