aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-16 07:17:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:57:16 -0400
commitd91f36db51661018f6d54ff5966e283bcec4c545 (patch)
treecde91cde0e6478c3c8cb256786eb61f3c48842c4 /net/mac80211
parent10f644a47b76d3e61b98f2d02ce9690b94c51ee5 (diff)
mac80211: implement beacon filtering in software
Regardless of whether the hardware implements beacon filtering, there's no need to process all beacons in software all the time throughout the stack (mac80211 does a lot, then cfg80211, then in the future possibly userspace). This patch implements the "best possible" beacon filtering in mac80211. "Best possible" means that it can look for changes in all requested information elements, and distinguish vendor IEs by their OUI. In the future, we will add nl80211 API for userspace to request information elements and vendor IE OUIs to watch -- drivers can then implement the best they can do while software implements it fully. It is unclear whether or not this actually saves CPU time, but the data is all in the cache already so it should be fairly cheap. The additional _testing_, however, has great benefit; Without this, and on hardware that doesn't implement beacon filtering, wrong assumptions about, for example, scan result updates could quickly creep into code. 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/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 b1d18d967d8..38c98061251 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 c39a214e7ad..7a8d4c49424 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 b361e2acfce..3dd490fa4b6 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)