aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ibss.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r--net/mac80211/ibss.c110
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
276static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, 283static 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
427static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, 434static 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
880static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, 878static
881 struct ieee80211_mgmt *mgmt, 879void 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
898static 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
916void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, 903void 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}