diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 52 | ||||
-rw-r--r-- | net/mac80211/util.c | 23 |
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); |
1086 | void ieee802_11_parse_elems(u8 *start, size_t len, | 1088 | void ieee802_11_parse_elems(u8 *start, size_t len, |
1087 | struct ieee802_11_elems *elems); | 1089 | struct ieee802_11_elems *elems); |
1090 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | ||
1091 | struct ieee802_11_elems *elems, | ||
1092 | u64 filter, u32 crc); | ||
1088 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); | 1093 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); |
1089 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | 1094 | u32 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 | */ | ||
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; |
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); | |||
537 | void ieee802_11_parse_elems(u8 *start, size_t len, | 538 | void 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 | |||
544 | u32 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 | ||
685 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | 704 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) |