diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-02-10 15:26:03 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:46:03 -0500 |
commit | fe3d2c3fe32dd4d0a421ba39caba1cf87402314e (patch) | |
tree | 6cb7ed72356cd24852c63fb3a10c3ce4a1d68f6e /net/mac80211/mlme.c | |
parent | a71800f3e3de15583c5d336aafa2853786be18a2 (diff) |
mac80211: split managed/ibss code a little more
It appears that you can completely mess up mac80211 in IBSS
mode by sending it a disassoc or deauth: it'll stop queues
and do a lot more but not ever do anything again. Fix this
by not handling all those frames in IBSS mode,
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.c | 254 |
1 files changed, 146 insertions, 108 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 332397415890..fbb766afe599 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -808,9 +808,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
808 | bss_info_changed |= BSS_CHANGED_ASSOC; | 808 | bss_info_changed |= BSS_CHANGED_ASSOC; |
809 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 809 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; |
810 | 810 | ||
811 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
812 | return; | ||
813 | |||
814 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 811 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
815 | conf->channel->center_freq, | 812 | conf->channel->center_freq, |
816 | ifsta->ssid, ifsta->ssid_len); | 813 | ifsta->ssid, ifsta->ssid_len); |
@@ -1169,6 +1166,30 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1169 | elems.challenge_len + 2, 1); | 1166 | elems.challenge_len + 2, 1); |
1170 | } | 1167 | } |
1171 | 1168 | ||
1169 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | ||
1170 | struct ieee80211_if_sta *ifsta, | ||
1171 | struct ieee80211_mgmt *mgmt, | ||
1172 | size_t len) | ||
1173 | { | ||
1174 | u16 auth_alg, auth_transaction, status_code; | ||
1175 | |||
1176 | if (len < 24 + 6) | ||
1177 | return; | ||
1178 | |||
1179 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1180 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1181 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1182 | |||
1183 | /* | ||
1184 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1185 | * networks and most implementations do not seem to use it. | ||
1186 | * However, try to reply to authentication attempts if someone | ||
1187 | * has actually implemented this. | ||
1188 | */ | ||
1189 | if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) | ||
1190 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1191 | } | ||
1192 | |||
1172 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1193 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1173 | struct ieee80211_if_sta *ifsta, | 1194 | struct ieee80211_if_sta *ifsta, |
1174 | struct ieee80211_mgmt *mgmt, | 1195 | struct ieee80211_mgmt *mgmt, |
@@ -1176,38 +1197,22 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1176 | { | 1197 | { |
1177 | u16 auth_alg, auth_transaction, status_code; | 1198 | u16 auth_alg, auth_transaction, status_code; |
1178 | 1199 | ||
1179 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1200 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE) |
1180 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1181 | return; | 1201 | return; |
1182 | 1202 | ||
1183 | if (len < 24 + 6) | 1203 | if (len < 24 + 6) |
1184 | return; | 1204 | return; |
1185 | 1205 | ||
1186 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1206 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) |
1187 | memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1188 | return; | 1207 | return; |
1189 | 1208 | ||
1190 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1209 | if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1191 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1192 | return; | 1210 | return; |
1193 | 1211 | ||
1194 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1212 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1195 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1213 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1196 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1214 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1197 | 1215 | ||
1198 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
1199 | /* | ||
1200 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1201 | * networks and most implementations do not seem to use it. | ||
1202 | * However, try to reply to authentication attempts if someone | ||
1203 | * has actually implemented this. | ||
1204 | */ | ||
1205 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
1206 | return; | ||
1207 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1208 | return; | ||
1209 | } | ||
1210 | |||
1211 | if (auth_alg != ifsta->auth_alg || | 1216 | if (auth_alg != ifsta->auth_alg || |
1212 | auth_transaction != ifsta->auth_transaction) | 1217 | auth_transaction != ifsta->auth_transaction) |
1213 | return; | 1218 | return; |
@@ -1762,74 +1767,85 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1762 | /* was just updated in ieee80211_bss_info_update */ | 1767 | /* was just updated in ieee80211_bss_info_update */ |
1763 | beacon_timestamp = bss->cbss.tsf; | 1768 | beacon_timestamp = bss->cbss.tsf; |
1764 | 1769 | ||
1765 | /* | 1770 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1766 | * In STA mode, the remaining parameters should not be overridden | 1771 | goto put_bss; |
1767 | * by beacons because they're not necessarily accurate there. | ||
1768 | */ | ||
1769 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
1770 | bss->last_probe_resp && beacon) { | ||
1771 | ieee80211_rx_bss_put(local, bss); | ||
1772 | return; | ||
1773 | } | ||
1774 | 1772 | ||
1775 | /* check if we need to merge IBSS */ | 1773 | /* check if we need to merge IBSS */ |
1776 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && | 1774 | |
1777 | (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) && | 1775 | /* merge only on beacons (???) */ |
1778 | bss->cbss.capability & WLAN_CAPABILITY_IBSS && | 1776 | if (!beacon) |
1779 | bss->cbss.channel == local->oper_channel && | 1777 | goto put_bss; |
1780 | elems->ssid_len == sdata->u.sta.ssid_len && | 1778 | |
1779 | /* we use a fixed BSSID */ | ||
1780 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) | ||
1781 | goto put_bss; | ||
1782 | |||
1783 | /* not an IBSS */ | ||
1784 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||
1785 | goto put_bss; | ||
1786 | |||
1787 | /* different channel */ | ||
1788 | if (bss->cbss.channel != local->oper_channel) | ||
1789 | goto put_bss; | ||
1790 | |||
1791 | /* different SSID */ | ||
1792 | if (elems->ssid_len != sdata->u.sta.ssid_len || | ||
1781 | memcmp(elems->ssid, sdata->u.sta.ssid, | 1793 | memcmp(elems->ssid, sdata->u.sta.ssid, |
1782 | sdata->u.sta.ssid_len) == 0) { | 1794 | sdata->u.sta.ssid_len)) |
1783 | if (rx_status->flag & RX_FLAG_TSFT) { | 1795 | goto put_bss; |
1784 | /* in order for correct IBSS merging we need mactime | 1796 | |
1785 | * | 1797 | if (rx_status->flag & RX_FLAG_TSFT) { |
1786 | * since mactime is defined as the time the first data | 1798 | /* |
1787 | * symbol of the frame hits the PHY, and the timestamp | 1799 | * For correct IBSS merging we need mactime; since mactime is |
1788 | * of the beacon is defined as "the time that the data | 1800 | * defined as the time the first data symbol of the frame hits |
1789 | * symbol containing the first bit of the timestamp is | 1801 | * the PHY, and the timestamp of the beacon is defined as "the |
1790 | * transmitted to the PHY plus the transmitting STA’s | 1802 | * time that the data symbol containing the first bit of the |
1791 | * delays through its local PHY from the MAC-PHY | 1803 | * timestamp is transmitted to the PHY plus the transmitting |
1792 | * interface to its interface with the WM" | 1804 | * STA's delays through its local PHY from the MAC-PHY |
1793 | * (802.11 11.1.2) - equals the time this bit arrives at | 1805 | * interface to its interface with the WM" (802.11 11.1.2) |
1794 | * the receiver - we have to take into account the | 1806 | * - equals the time this bit arrives at the receiver - we have |
1795 | * offset between the two. | 1807 | * to take into account the offset between the two. |
1796 | * e.g: at 1 MBit that means mactime is 192 usec earlier | 1808 | * |
1797 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | 1809 | * E.g. at 1 MBit that means mactime is 192 usec earlier |
1798 | */ | 1810 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. |
1799 | int rate; | 1811 | */ |
1800 | if (rx_status->flag & RX_FLAG_HT) { | 1812 | int rate; |
1801 | rate = 65; /* TODO: HT rates */ | 1813 | |
1802 | } else { | 1814 | if (rx_status->flag & RX_FLAG_HT) |
1803 | rate = local->hw.wiphy->bands[band]-> | 1815 | rate = 65; /* TODO: HT rates */ |
1804 | bitrates[rx_status->rate_idx].bitrate; | ||
1805 | } | ||
1806 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1807 | } else if (local && local->ops && local->ops->get_tsf) | ||
1808 | /* second best option: get current TSF */ | ||
1809 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1810 | else | 1816 | else |
1811 | /* can't merge without knowing the TSF */ | 1817 | rate = local->hw.wiphy->bands[band]-> |
1812 | rx_timestamp = -1LLU; | 1818 | bitrates[rx_status->rate_idx].bitrate; |
1819 | |||
1820 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1821 | } else if (local && local->ops && local->ops->get_tsf) | ||
1822 | /* second best option: get current TSF */ | ||
1823 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1824 | else | ||
1825 | /* can't merge without knowing the TSF */ | ||
1826 | rx_timestamp = -1LLU; | ||
1827 | |||
1813 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1828 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1814 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | 1829 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" |
1815 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | 1830 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", |
1816 | mgmt->sa, mgmt->bssid, | 1831 | mgmt->sa, mgmt->bssid, |
1817 | (unsigned long long)rx_timestamp, | 1832 | (unsigned long long)rx_timestamp, |
1818 | (unsigned long long)beacon_timestamp, | 1833 | (unsigned long long)beacon_timestamp, |
1819 | (unsigned long long)(rx_timestamp - beacon_timestamp), | 1834 | (unsigned long long)(rx_timestamp - beacon_timestamp), |
1820 | jiffies); | 1835 | jiffies); |
1821 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1836 | #endif |
1822 | if (beacon_timestamp > rx_timestamp) { | 1837 | |
1838 | if (beacon_timestamp > rx_timestamp) { | ||
1823 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1839 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1824 | printk(KERN_DEBUG "%s: beacon TSF higher than " | 1840 | printk(KERN_DEBUG "%s: beacon TSF higher than " |
1825 | "local TSF - IBSS merge with BSSID %pM\n", | 1841 | "local TSF - IBSS merge with BSSID %pM\n", |
1826 | sdata->dev->name, mgmt->bssid); | 1842 | sdata->dev->name, mgmt->bssid); |
1827 | #endif | 1843 | #endif |
1828 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | 1844 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); |
1829 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 1845 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); |
1830 | } | ||
1831 | } | 1846 | } |
1832 | 1847 | ||
1848 | put_bss: | ||
1833 | ieee80211_rx_bss_put(local, bss); | 1849 | ieee80211_rx_bss_put(local, bss); |
1834 | } | 1850 | } |
1835 | 1851 | ||
@@ -1993,8 +2009,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1993 | struct ieee80211_mgmt *resp; | 2009 | struct ieee80211_mgmt *resp; |
1994 | u8 *pos, *end; | 2010 | u8 *pos, *end; |
1995 | 2011 | ||
1996 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC || | 2012 | if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || |
1997 | ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | ||
1998 | len < 24 + 2 || !ifsta->probe_resp) | 2013 | len < 24 + 2 || !ifsta->probe_resp) |
1999 | return; | 2014 | return; |
2000 | 2015 | ||
@@ -2098,31 +2113,54 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2098 | mgmt = (struct ieee80211_mgmt *) skb->data; | 2113 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2099 | fc = le16_to_cpu(mgmt->frame_control); | 2114 | fc = le16_to_cpu(mgmt->frame_control); |
2100 | 2115 | ||
2101 | switch (fc & IEEE80211_FCTL_STYPE) { | 2116 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2102 | case IEEE80211_STYPE_PROBE_REQ: | 2117 | switch (fc & IEEE80211_FCTL_STYPE) { |
2103 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len); | 2118 | case IEEE80211_STYPE_PROBE_REQ: |
2104 | break; | 2119 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, |
2105 | case IEEE80211_STYPE_PROBE_RESP: | 2120 | skb->len); |
2106 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | 2121 | break; |
2107 | break; | 2122 | case IEEE80211_STYPE_PROBE_RESP: |
2108 | case IEEE80211_STYPE_BEACON: | 2123 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2109 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 2124 | rx_status); |
2110 | break; | 2125 | break; |
2111 | case IEEE80211_STYPE_AUTH: | 2126 | case IEEE80211_STYPE_BEACON: |
2112 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | 2127 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
2113 | break; | 2128 | rx_status); |
2114 | case IEEE80211_STYPE_ASSOC_RESP: | 2129 | break; |
2115 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); | 2130 | case IEEE80211_STYPE_AUTH: |
2116 | break; | 2131 | ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt, |
2117 | case IEEE80211_STYPE_REASSOC_RESP: | 2132 | skb->len); |
2118 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); | 2133 | break; |
2119 | break; | 2134 | } |
2120 | case IEEE80211_STYPE_DEAUTH: | 2135 | } else { /* NL80211_IFTYPE_STATION */ |
2121 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | 2136 | switch (fc & IEEE80211_FCTL_STYPE) { |
2122 | break; | 2137 | case IEEE80211_STYPE_PROBE_RESP: |
2123 | case IEEE80211_STYPE_DISASSOC: | 2138 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2124 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len); | 2139 | rx_status); |
2125 | break; | 2140 | break; |
2141 | case IEEE80211_STYPE_BEACON: | ||
2142 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | ||
2143 | rx_status); | ||
2144 | break; | ||
2145 | case IEEE80211_STYPE_AUTH: | ||
2146 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | ||
2147 | break; | ||
2148 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2149 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2150 | skb->len, 0); | ||
2151 | break; | ||
2152 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2153 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2154 | skb->len, 1); | ||
2155 | break; | ||
2156 | case IEEE80211_STYPE_DEAUTH: | ||
2157 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | ||
2158 | break; | ||
2159 | case IEEE80211_STYPE_DISASSOC: | ||
2160 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, | ||
2161 | skb->len); | ||
2162 | break; | ||
2163 | } | ||
2126 | } | 2164 | } |
2127 | 2165 | ||
2128 | kfree_skb(skb); | 2166 | kfree_skb(skb); |