aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
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/mlme.c
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/mlme.c')
-rw-r--r--net/mac80211/mlme.c52
1 files changed, 40 insertions, 12 deletions
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;