diff options
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 110 |
1 files changed, 44 insertions, 66 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6b7644e818d8..40b71dfcc79d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -67,7 +67,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
67 | skb_reserve(skb, sdata->local->hw.extra_tx_headroom); | 67 | skb_reserve(skb, sdata->local->hw.extra_tx_headroom); |
68 | 68 | ||
69 | if (!ether_addr_equal(ifibss->bssid, bssid)) | 69 | if (!ether_addr_equal(ifibss->bssid, bssid)) |
70 | sta_info_flush(sdata->local, sdata); | 70 | sta_info_flush(sdata); |
71 | 71 | ||
72 | /* if merging, indicate to driver that we leave the old IBSS */ | 72 | /* if merging, indicate to driver that we leave the old IBSS */ |
73 | if (sdata->vif.bss_conf.ibss_joined) { | 73 | if (sdata->vif.bss_conf.ibss_joined) { |
@@ -191,6 +191,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
191 | 191 | ||
192 | rcu_assign_pointer(ifibss->presp, skb); | 192 | rcu_assign_pointer(ifibss->presp, skb); |
193 | 193 | ||
194 | sdata->vif.bss_conf.enable_beacon = true; | ||
194 | sdata->vif.bss_conf.beacon_int = beacon_int; | 195 | sdata->vif.bss_conf.beacon_int = beacon_int; |
195 | sdata->vif.bss_conf.basic_rates = basic_rates; | 196 | sdata->vif.bss_conf.basic_rates = basic_rates; |
196 | bss_change = BSS_CHANGED_BEACON_INT; | 197 | bss_change = BSS_CHANGED_BEACON_INT; |
@@ -227,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
227 | 228 | ||
228 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | 229 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, |
229 | mgmt, skb->len, 0, GFP_KERNEL); | 230 | mgmt, skb->len, 0, GFP_KERNEL); |
230 | cfg80211_put_bss(bss); | 231 | cfg80211_put_bss(local->hw.wiphy, bss); |
231 | netif_carrier_on(sdata->dev); | 232 | netif_carrier_on(sdata->dev); |
232 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 233 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
233 | } | 234 | } |
@@ -241,6 +242,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
241 | u32 basic_rates; | 242 | u32 basic_rates; |
242 | int i, j; | 243 | int i, j; |
243 | u16 beacon_int = cbss->beacon_interval; | 244 | u16 beacon_int = cbss->beacon_interval; |
245 | const struct cfg80211_bss_ies *ies; | ||
246 | u64 tsf; | ||
244 | 247 | ||
245 | lockdep_assert_held(&sdata->u.ibss.mtx); | 248 | lockdep_assert_held(&sdata->u.ibss.mtx); |
246 | 249 | ||
@@ -264,13 +267,17 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
264 | } | 267 | } |
265 | } | 268 | } |
266 | 269 | ||
270 | rcu_read_lock(); | ||
271 | ies = rcu_dereference(cbss->ies); | ||
272 | tsf = ies->tsf; | ||
273 | rcu_read_unlock(); | ||
274 | |||
267 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, | 275 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, |
268 | beacon_int, | 276 | beacon_int, |
269 | cbss->channel, | 277 | cbss->channel, |
270 | basic_rates, | 278 | basic_rates, |
271 | cbss->capability, | 279 | cbss->capability, |
272 | cbss->tsf, | 280 | tsf, false); |
273 | false); | ||
274 | } | 281 | } |
275 | 282 | ||
276 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | 283 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, |
@@ -301,7 +308,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
301 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | 308 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", |
302 | sdata->vif.addr, addr, sdata->u.ibss.bssid); | 309 | sdata->vif.addr, addr, sdata->u.ibss.bssid); |
303 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, | 310 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, |
304 | addr, sdata->u.ibss.bssid, NULL, 0, 0); | 311 | addr, sdata->u.ibss.bssid, NULL, 0, 0, 0); |
305 | } | 312 | } |
306 | return sta; | 313 | return sta; |
307 | } | 314 | } |
@@ -421,15 +428,13 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
421 | * has actually implemented this. | 428 | * has actually implemented this. |
422 | */ | 429 | */ |
423 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, | 430 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, |
424 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); | 431 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0); |
425 | } | 432 | } |
426 | 433 | ||
427 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 434 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
428 | struct ieee80211_mgmt *mgmt, | 435 | struct ieee80211_mgmt *mgmt, size_t len, |
429 | size_t len, | ||
430 | struct ieee80211_rx_status *rx_status, | 436 | struct ieee80211_rx_status *rx_status, |
431 | struct ieee802_11_elems *elems, | 437 | struct ieee802_11_elems *elems) |
432 | bool beacon) | ||
433 | { | 438 | { |
434 | struct ieee80211_local *local = sdata->local; | 439 | struct ieee80211_local *local = sdata->local; |
435 | int freq; | 440 | int freq; |
@@ -491,33 +496,26 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
491 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 496 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
492 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
493 | /* we both use HT */ | 498 | /* we both use HT */ |
494 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 499 | struct ieee80211_ht_cap htcap_ie; |
495 | struct cfg80211_chan_def chandef; | 500 | struct cfg80211_chan_def chandef; |
496 | 501 | ||
497 | ieee80211_ht_oper_to_chandef(channel, | 502 | ieee80211_ht_oper_to_chandef(channel, |
498 | elems->ht_operation, | 503 | elems->ht_operation, |
499 | &chandef); | 504 | &chandef); |
500 | 505 | ||
501 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 506 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
502 | elems->ht_cap_elem, | ||
503 | &sta_ht_cap_new); | ||
504 | 507 | ||
505 | /* | 508 | /* |
506 | * fall back to HT20 if we don't use or use | 509 | * fall back to HT20 if we don't use or use |
507 | * the other extension channel | 510 | * the other extension channel |
508 | */ | 511 | */ |
509 | if (chandef.width != NL80211_CHAN_WIDTH_40 || | 512 | if (cfg80211_get_chandef_type(&chandef) != |
510 | cfg80211_get_chandef_type(&chandef) != | ||
511 | sdata->u.ibss.channel_type) | 513 | sdata->u.ibss.channel_type) |
512 | sta_ht_cap_new.cap &= | 514 | htcap_ie.cap_info &= |
513 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 515 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
514 | 516 | ||
515 | if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new, | 517 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap( |
516 | sizeof(sta_ht_cap_new))) { | 518 | sdata, sband, &htcap_ie, sta); |
517 | memcpy(&sta->sta.ht_cap, &sta_ht_cap_new, | ||
518 | sizeof(sta_ht_cap_new)); | ||
519 | rates_updated = true; | ||
520 | } | ||
521 | } | 519 | } |
522 | 520 | ||
523 | if (sta && rates_updated) { | 521 | if (sta && rates_updated) { |
@@ -530,14 +528,14 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
530 | } | 528 | } |
531 | 529 | ||
532 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 530 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
533 | channel, beacon); | 531 | channel); |
534 | if (!bss) | 532 | if (!bss) |
535 | return; | 533 | return; |
536 | 534 | ||
537 | cbss = container_of((void *)bss, struct cfg80211_bss, priv); | 535 | cbss = container_of((void *)bss, struct cfg80211_bss, priv); |
538 | 536 | ||
539 | /* was just updated in ieee80211_bss_info_update */ | 537 | /* same for beacon and probe response */ |
540 | beacon_timestamp = cbss->tsf; | 538 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
541 | 539 | ||
542 | /* check if we need to merge IBSS */ | 540 | /* check if we need to merge IBSS */ |
543 | 541 | ||
@@ -877,14 +875,21 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
877 | ieee80211_tx_skb(sdata, skb); | 875 | ieee80211_tx_skb(sdata, skb); |
878 | } | 876 | } |
879 | 877 | ||
880 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 878 | static |
881 | struct ieee80211_mgmt *mgmt, | 879 | void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata, |
882 | size_t len, | 880 | struct ieee80211_mgmt *mgmt, size_t len, |
883 | struct ieee80211_rx_status *rx_status) | 881 | struct ieee80211_rx_status *rx_status) |
884 | { | 882 | { |
885 | size_t baselen; | 883 | size_t baselen; |
886 | struct ieee802_11_elems elems; | 884 | struct ieee802_11_elems elems; |
887 | 885 | ||
886 | BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) != | ||
887 | offsetof(typeof(mgmt->u.beacon), variable)); | ||
888 | |||
889 | /* | ||
890 | * either beacon or probe_resp but the variable field is at the | ||
891 | * same offset | ||
892 | */ | ||
888 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 893 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
889 | if (baselen > len) | 894 | if (baselen > len) |
890 | return; | 895 | return; |
@@ -892,25 +897,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
892 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 897 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
893 | &elems); | 898 | &elems); |
894 | 899 | ||
895 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 900 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
896 | } | ||
897 | |||
898 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||
899 | struct ieee80211_mgmt *mgmt, | ||
900 | size_t len, | ||
901 | struct ieee80211_rx_status *rx_status) | ||
902 | { | ||
903 | size_t baselen; | ||
904 | struct ieee802_11_elems elems; | ||
905 | |||
906 | /* Process beacon from the current BSS */ | ||
907 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | ||
908 | if (baselen > len) | ||
909 | return; | ||
910 | |||
911 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | ||
912 | |||
913 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | ||
914 | } | 901 | } |
915 | 902 | ||
916 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 903 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -934,12 +921,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
934 | ieee80211_rx_mgmt_probe_req(sdata, skb); | 921 | ieee80211_rx_mgmt_probe_req(sdata, skb); |
935 | break; | 922 | break; |
936 | case IEEE80211_STYPE_PROBE_RESP: | 923 | case IEEE80211_STYPE_PROBE_RESP: |
937 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | ||
938 | rx_status); | ||
939 | break; | ||
940 | case IEEE80211_STYPE_BEACON: | 924 | case IEEE80211_STYPE_BEACON: |
941 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 925 | ieee80211_rx_mgmt_probe_beacon(sdata, mgmt, skb->len, |
942 | rx_status); | 926 | rx_status); |
943 | break; | 927 | break; |
944 | case IEEE80211_STYPE_AUTH: | 928 | case IEEE80211_STYPE_AUTH: |
945 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); | 929 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); |
@@ -1117,10 +1101,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1117 | 1101 | ||
1118 | mutex_unlock(&sdata->u.ibss.mtx); | 1102 | mutex_unlock(&sdata->u.ibss.mtx); |
1119 | 1103 | ||
1120 | mutex_lock(&sdata->local->mtx); | ||
1121 | ieee80211_recalc_idle(sdata->local); | ||
1122 | mutex_unlock(&sdata->local->mtx); | ||
1123 | |||
1124 | /* | 1104 | /* |
1125 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is | 1105 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is |
1126 | * reserved, but an HT STA shall protect HT transmissions as though | 1106 | * reserved, but an HT STA shall protect HT transmissions as though |
@@ -1174,7 +1154,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1174 | 1154 | ||
1175 | if (cbss) { | 1155 | if (cbss) { |
1176 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | 1156 | cfg80211_unlink_bss(local->hw.wiphy, cbss); |
1177 | cfg80211_put_bss(cbss); | 1157 | cfg80211_put_bss(local->hw.wiphy, cbss); |
1178 | } | 1158 | } |
1179 | } | 1159 | } |
1180 | 1160 | ||
@@ -1182,7 +1162,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1182 | memset(ifibss->bssid, 0, ETH_ALEN); | 1162 | memset(ifibss->bssid, 0, ETH_ALEN); |
1183 | ifibss->ssid_len = 0; | 1163 | ifibss->ssid_len = 0; |
1184 | 1164 | ||
1185 | sta_info_flush(sdata->local, sdata); | 1165 | sta_info_flush(sdata); |
1186 | 1166 | ||
1187 | spin_lock_bh(&ifibss->incomplete_lock); | 1167 | spin_lock_bh(&ifibss->incomplete_lock); |
1188 | while (!list_empty(&ifibss->incomplete_stations)) { | 1168 | while (!list_empty(&ifibss->incomplete_stations)) { |
@@ -1205,6 +1185,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1205 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1185 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
1206 | sdata->vif.bss_conf.ibss_joined = false; | 1186 | sdata->vif.bss_conf.ibss_joined = false; |
1207 | sdata->vif.bss_conf.ibss_creator = false; | 1187 | sdata->vif.bss_conf.ibss_creator = false; |
1188 | sdata->vif.bss_conf.enable_beacon = false; | ||
1189 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
1208 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 1190 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
1209 | BSS_CHANGED_IBSS); | 1191 | BSS_CHANGED_IBSS); |
1210 | synchronize_rcu(); | 1192 | synchronize_rcu(); |
@@ -1216,9 +1198,5 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1216 | 1198 | ||
1217 | mutex_unlock(&sdata->u.ibss.mtx); | 1199 | mutex_unlock(&sdata->u.ibss.mtx); |
1218 | 1200 | ||
1219 | mutex_lock(&local->mtx); | ||
1220 | ieee80211_recalc_idle(sdata->local); | ||
1221 | mutex_unlock(&local->mtx); | ||
1222 | |||
1223 | return 0; | 1201 | return 0; |
1224 | } | 1202 | } |