diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 52 |
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 | */ | ||
1769 | static 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 | |||
1755 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1777 | static 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; |