diff options
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 501 |
1 files changed, 270 insertions, 231 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3201e1f96365..0b30277eb366 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/unaligned.h> | 22 | #include <asm/unaligned.h> |
23 | 23 | ||
24 | #include "ieee80211_i.h" | 24 | #include "ieee80211_i.h" |
25 | #include "driver-ops.h" | ||
25 | #include "rate.h" | 26 | #include "rate.h" |
26 | 27 | ||
27 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | 28 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) |
@@ -59,74 +60,65 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
59 | sdata->u.ibss.bssid, 0); | 60 | sdata->u.ibss.bssid, 0); |
60 | } | 61 | } |
61 | 62 | ||
62 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 63 | static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
63 | const u8 *bssid, const int beacon_int, | 64 | const u8 *bssid, const int beacon_int, |
64 | const int freq, | 65 | struct ieee80211_channel *chan, |
65 | const size_t supp_rates_len, | 66 | const u32 basic_rates, |
66 | const u8 *supp_rates, | 67 | const u16 capability, u64 tsf) |
67 | const u16 capability, u64 tsf) | ||
68 | { | 68 | { |
69 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 69 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
70 | struct ieee80211_local *local = sdata->local; | 70 | struct ieee80211_local *local = sdata->local; |
71 | int res = 0, rates, i, j; | 71 | int rates, i; |
72 | struct sk_buff *skb; | 72 | struct sk_buff *skb; |
73 | struct ieee80211_mgmt *mgmt; | 73 | struct ieee80211_mgmt *mgmt; |
74 | u8 *pos; | 74 | u8 *pos; |
75 | struct ieee80211_supported_band *sband; | 75 | struct ieee80211_supported_band *sband; |
76 | union iwreq_data wrqu; | 76 | u32 bss_change; |
77 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
77 | 78 | ||
78 | if (local->ops->reset_tsf) { | 79 | /* Reset own TSF to allow time synchronization work. */ |
79 | /* Reset own TSF to allow time synchronization work. */ | 80 | drv_reset_tsf(local); |
80 | local->ops->reset_tsf(local_to_hw(local)); | ||
81 | } | ||
82 | 81 | ||
83 | if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) && | 82 | skb = ifibss->skb; |
84 | memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0) | 83 | rcu_assign_pointer(ifibss->presp, NULL); |
85 | return res; | 84 | synchronize_rcu(); |
85 | skb->data = skb->head; | ||
86 | skb->len = 0; | ||
87 | skb_reset_tail_pointer(skb); | ||
88 | skb_reserve(skb, sdata->local->hw.extra_tx_headroom); | ||
86 | 89 | ||
87 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 90 | if (memcmp(ifibss->bssid, bssid, ETH_ALEN)) |
88 | if (!skb) { | 91 | sta_info_flush(sdata->local, sdata); |
89 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
90 | "response\n", sdata->dev->name); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) { | ||
95 | /* Remove possible STA entries from other IBSS networks. */ | ||
96 | sta_info_flush_delayed(sdata); | ||
97 | } | ||
98 | 92 | ||
99 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 93 | memcpy(ifibss->bssid, bssid, ETH_ALEN); |
100 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
101 | if (res) | ||
102 | return res; | ||
103 | |||
104 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | ||
105 | 94 | ||
106 | sdata->drop_unencrypted = capability & | 95 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
107 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
108 | 96 | ||
109 | res = ieee80211_set_freq(sdata, freq); | 97 | local->oper_channel = chan; |
98 | local->oper_channel_type = NL80211_CHAN_NO_HT; | ||
99 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
110 | 100 | ||
111 | if (res) | 101 | sband = local->hw.wiphy->bands[chan->band]; |
112 | return res; | ||
113 | 102 | ||
114 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 103 | /* build supported rates array */ |
104 | pos = supp_rates; | ||
105 | for (i = 0; i < sband->n_bitrates; i++) { | ||
106 | int rate = sband->bitrates[i].bitrate; | ||
107 | u8 basic = 0; | ||
108 | if (basic_rates & BIT(i)) | ||
109 | basic = 0x80; | ||
110 | *pos++ = basic | (u8) (rate / 5); | ||
111 | } | ||
115 | 112 | ||
116 | /* Build IBSS probe response */ | 113 | /* Build IBSS probe response */ |
117 | 114 | mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | |
118 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
119 | |||
120 | mgmt = (struct ieee80211_mgmt *) | ||
121 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
122 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 115 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); |
123 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 116 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
124 | IEEE80211_STYPE_PROBE_RESP); | 117 | IEEE80211_STYPE_PROBE_RESP); |
125 | memset(mgmt->da, 0xff, ETH_ALEN); | 118 | memset(mgmt->da, 0xff, ETH_ALEN); |
126 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 119 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
127 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | 120 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); |
128 | mgmt->u.beacon.beacon_int = | 121 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); |
129 | cpu_to_le16(local->hw.conf.beacon_int); | ||
130 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); | 122 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); |
131 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | 123 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); |
132 | 124 | ||
@@ -135,7 +127,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
135 | *pos++ = ifibss->ssid_len; | 127 | *pos++ = ifibss->ssid_len; |
136 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | 128 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); |
137 | 129 | ||
138 | rates = supp_rates_len; | 130 | rates = sband->n_bitrates; |
139 | if (rates > 8) | 131 | if (rates > 8) |
140 | rates = 8; | 132 | rates = 8; |
141 | pos = skb_put(skb, 2 + rates); | 133 | pos = skb_put(skb, 2 + rates); |
@@ -147,7 +139,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
147 | pos = skb_put(skb, 2 + 1); | 139 | pos = skb_put(skb, 2 + 1); |
148 | *pos++ = WLAN_EID_DS_PARAMS; | 140 | *pos++ = WLAN_EID_DS_PARAMS; |
149 | *pos++ = 1; | 141 | *pos++ = 1; |
150 | *pos++ = ieee80211_frequency_to_channel(freq); | 142 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); |
151 | } | 143 | } |
152 | 144 | ||
153 | pos = skb_put(skb, 2 + 2); | 145 | pos = skb_put(skb, 2 + 2); |
@@ -157,51 +149,73 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
157 | *pos++ = 0; | 149 | *pos++ = 0; |
158 | *pos++ = 0; | 150 | *pos++ = 0; |
159 | 151 | ||
160 | if (supp_rates_len > 8) { | 152 | if (sband->n_bitrates > 8) { |
161 | rates = supp_rates_len - 8; | 153 | rates = sband->n_bitrates - 8; |
162 | pos = skb_put(skb, 2 + rates); | 154 | pos = skb_put(skb, 2 + rates); |
163 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 155 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
164 | *pos++ = rates; | 156 | *pos++ = rates; |
165 | memcpy(pos, &supp_rates[8], rates); | 157 | memcpy(pos, &supp_rates[8], rates); |
166 | } | 158 | } |
167 | 159 | ||
168 | ifibss->probe_resp = skb; | 160 | if (ifibss->ie_len) |
161 | memcpy(skb_put(skb, ifibss->ie_len), | ||
162 | ifibss->ie, ifibss->ie_len); | ||
169 | 163 | ||
170 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | 164 | rcu_assign_pointer(ifibss->presp, skb); |
171 | IEEE80211_IFCC_BEACON_ENABLED); | ||
172 | 165 | ||
166 | sdata->vif.bss_conf.beacon_int = beacon_int; | ||
167 | bss_change = BSS_CHANGED_BEACON_INT; | ||
168 | bss_change |= ieee80211_reset_erp_info(sdata); | ||
169 | bss_change |= BSS_CHANGED_BSSID; | ||
170 | bss_change |= BSS_CHANGED_BEACON; | ||
171 | bss_change |= BSS_CHANGED_BEACON_ENABLED; | ||
172 | ieee80211_bss_info_change_notify(sdata, bss_change); | ||
173 | 173 | ||
174 | rates = 0; | 174 | ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); |
175 | for (i = 0; i < supp_rates_len; i++) { | ||
176 | int bitrate = (supp_rates[i] & 0x7f) * 5; | ||
177 | for (j = 0; j < sband->n_bitrates; j++) | ||
178 | if (sband->bitrates[j].bitrate == bitrate) | ||
179 | rates |= BIT(j); | ||
180 | } | ||
181 | 175 | ||
182 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | ||
183 | |||
184 | ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; | ||
185 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 176 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
186 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 177 | mod_timer(&ifibss->timer, |
187 | 178 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | |
188 | memset(&wrqu, 0, sizeof(wrqu)); | ||
189 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
190 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
191 | 179 | ||
192 | return res; | 180 | cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, |
181 | mgmt, skb->len, 0, GFP_KERNEL); | ||
182 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | ||
193 | } | 183 | } |
194 | 184 | ||
195 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 185 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
196 | struct ieee80211_bss *bss) | 186 | struct ieee80211_bss *bss) |
197 | { | 187 | { |
198 | return __ieee80211_sta_join_ibss(sdata, | 188 | struct ieee80211_supported_band *sband; |
199 | bss->cbss.bssid, | 189 | u32 basic_rates; |
200 | bss->cbss.beacon_interval, | 190 | int i, j; |
201 | bss->cbss.channel->center_freq, | 191 | u16 beacon_int = bss->cbss.beacon_interval; |
202 | bss->supp_rates_len, bss->supp_rates, | 192 | |
203 | bss->cbss.capability, | 193 | if (beacon_int < 10) |
204 | bss->cbss.tsf); | 194 | beacon_int = 10; |
195 | |||
196 | sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; | ||
197 | |||
198 | basic_rates = 0; | ||
199 | |||
200 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
201 | int rate = (bss->supp_rates[i] & 0x7f) * 5; | ||
202 | bool is_basic = !!(bss->supp_rates[i] & 0x80); | ||
203 | |||
204 | for (j = 0; j < sband->n_bitrates; j++) { | ||
205 | if (sband->bitrates[j].bitrate == rate) { | ||
206 | if (is_basic) | ||
207 | basic_rates |= BIT(j); | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, | ||
214 | beacon_int, | ||
215 | bss->cbss.channel, | ||
216 | basic_rates, | ||
217 | bss->cbss.capability, | ||
218 | bss->cbss.tsf); | ||
205 | } | 219 | } |
206 | 220 | ||
207 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 221 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
@@ -277,7 +291,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
277 | goto put_bss; | 291 | goto put_bss; |
278 | 292 | ||
279 | /* we use a fixed BSSID */ | 293 | /* we use a fixed BSSID */ |
280 | if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) | 294 | if (sdata->u.ibss.bssid) |
281 | goto put_bss; | 295 | goto put_bss; |
282 | 296 | ||
283 | /* not an IBSS */ | 297 | /* not an IBSS */ |
@@ -322,12 +336,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
322 | bitrates[rx_status->rate_idx].bitrate; | 336 | bitrates[rx_status->rate_idx].bitrate; |
323 | 337 | ||
324 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | 338 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); |
325 | } else if (local && local->ops && local->ops->get_tsf) | 339 | } else { |
326 | /* second best option: get current TSF */ | 340 | /* |
327 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | 341 | * second best option: get current TSF |
328 | else | 342 | * (will return -1 if not supported) |
329 | /* can't merge without knowing the TSF */ | 343 | */ |
330 | rx_timestamp = -1LLU; | 344 | rx_timestamp = drv_get_tsf(local); |
345 | } | ||
331 | 346 | ||
332 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 347 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
333 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | 348 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" |
@@ -369,13 +384,14 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
369 | struct sta_info *sta; | 384 | struct sta_info *sta; |
370 | int band = local->hw.conf.channel->band; | 385 | int band = local->hw.conf.channel->band; |
371 | 386 | ||
372 | /* TODO: Could consider removing the least recently used entry and | 387 | /* |
373 | * allow new one to be added. */ | 388 | * XXX: Consider removing the least recently used entry and |
389 | * allow new one to be added. | ||
390 | */ | ||
374 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | 391 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { |
375 | if (net_ratelimit()) { | 392 | if (net_ratelimit()) |
376 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | 393 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", |
377 | "entry %pM\n", sdata->dev->name, addr); | 394 | sdata->dev->name, addr); |
378 | } | ||
379 | return NULL; | 395 | return NULL; |
380 | } | 396 | } |
381 | 397 | ||
@@ -432,41 +448,33 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
432 | { | 448 | { |
433 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 449 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
434 | 450 | ||
435 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 451 | mod_timer(&ifibss->timer, |
452 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||
436 | 453 | ||
437 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | 454 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); |
455 | |||
438 | if (ieee80211_sta_active_ibss(sdata)) | 456 | if (ieee80211_sta_active_ibss(sdata)) |
439 | return; | 457 | return; |
440 | 458 | ||
441 | if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && | 459 | if (ifibss->fixed_channel) |
442 | (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) | ||
443 | return; | 460 | return; |
444 | 461 | ||
445 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 462 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
446 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 463 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); |
447 | 464 | ||
448 | /* XXX maybe racy? */ | 465 | ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); |
449 | if (sdata->local->scan_req) | ||
450 | return; | ||
451 | |||
452 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
453 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
454 | sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
455 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | ||
456 | } | 466 | } |
457 | 467 | ||
458 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 468 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
459 | { | 469 | { |
460 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 470 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
461 | struct ieee80211_local *local = sdata->local; | 471 | struct ieee80211_local *local = sdata->local; |
462 | struct ieee80211_supported_band *sband; | 472 | struct ieee80211_supported_band *sband; |
463 | u8 *pos; | ||
464 | u8 bssid[ETH_ALEN]; | 473 | u8 bssid[ETH_ALEN]; |
465 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
466 | u16 capability; | 474 | u16 capability; |
467 | int i; | 475 | int i; |
468 | 476 | ||
469 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { | 477 | if (ifibss->fixed_bssid) { |
470 | memcpy(bssid, ifibss->bssid, ETH_ALEN); | 478 | memcpy(bssid, ifibss->bssid, ETH_ALEN); |
471 | } else { | 479 | } else { |
472 | /* Generate random, not broadcast, locally administered BSSID. Mix in | 480 | /* Generate random, not broadcast, locally administered BSSID. Mix in |
@@ -482,10 +490,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
482 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 490 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
483 | sdata->dev->name, bssid); | 491 | sdata->dev->name, bssid); |
484 | 492 | ||
485 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 493 | sband = local->hw.wiphy->bands[ifibss->channel->band]; |
486 | |||
487 | if (local->hw.conf.beacon_int == 0) | ||
488 | local->hw.conf.beacon_int = 100; | ||
489 | 494 | ||
490 | capability = WLAN_CAPABILITY_IBSS; | 495 | capability = WLAN_CAPABILITY_IBSS; |
491 | 496 | ||
@@ -494,29 +499,20 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
494 | else | 499 | else |
495 | sdata->drop_unencrypted = 0; | 500 | sdata->drop_unencrypted = 0; |
496 | 501 | ||
497 | pos = supp_rates; | 502 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, |
498 | for (i = 0; i < sband->n_bitrates; i++) { | 503 | ifibss->channel, 3, /* first two are basic */ |
499 | int rate = sband->bitrates[i].bitrate; | 504 | capability, 0); |
500 | *pos++ = (u8) (rate / 5); | ||
501 | } | ||
502 | |||
503 | return __ieee80211_sta_join_ibss(sdata, | ||
504 | bssid, local->hw.conf.beacon_int, | ||
505 | local->hw.conf.channel->center_freq, | ||
506 | sband->n_bitrates, supp_rates, | ||
507 | capability, 0); | ||
508 | } | 505 | } |
509 | 506 | ||
510 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | 507 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) |
511 | { | 508 | { |
512 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 509 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
513 | struct ieee80211_local *local = sdata->local; | 510 | struct ieee80211_local *local = sdata->local; |
514 | struct ieee80211_bss *bss; | 511 | struct ieee80211_bss *bss; |
512 | struct ieee80211_channel *chan = NULL; | ||
515 | const u8 *bssid = NULL; | 513 | const u8 *bssid = NULL; |
516 | int active_ibss; | 514 | int active_ibss; |
517 | 515 | u16 capability; | |
518 | if (ifibss->ssid_len == 0) | ||
519 | return -EINVAL; | ||
520 | 516 | ||
521 | active_ibss = ieee80211_sta_active_ibss(sdata); | 517 | active_ibss = ieee80211_sta_active_ibss(sdata); |
522 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 518 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
@@ -525,14 +521,23 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
525 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 521 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
526 | 522 | ||
527 | if (active_ibss) | 523 | if (active_ibss) |
528 | return 0; | 524 | return; |
529 | 525 | ||
530 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) | 526 | capability = WLAN_CAPABILITY_IBSS; |
527 | if (sdata->default_key) | ||
528 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
529 | |||
530 | if (ifibss->fixed_bssid) | ||
531 | bssid = ifibss->bssid; | 531 | bssid = ifibss->bssid; |
532 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, | 532 | if (ifibss->fixed_channel) |
533 | chan = ifibss->channel; | ||
534 | if (!is_zero_ether_addr(ifibss->bssid)) | ||
535 | bssid = ifibss->bssid; | ||
536 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, | ||
533 | ifibss->ssid, ifibss->ssid_len, | 537 | ifibss->ssid, ifibss->ssid_len, |
534 | WLAN_CAPABILITY_IBSS, | 538 | WLAN_CAPABILITY_IBSS | |
535 | WLAN_CAPABILITY_IBSS); | 539 | WLAN_CAPABILITY_PRIVACY, |
540 | capability); | ||
536 | 541 | ||
537 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 542 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
538 | if (bss) | 543 | if (bss) |
@@ -540,18 +545,14 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
540 | "%pM\n", bss->cbss.bssid, ifibss->bssid); | 545 | "%pM\n", bss->cbss.bssid, ifibss->bssid); |
541 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 546 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
542 | 547 | ||
543 | if (bss && | 548 | if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { |
544 | (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) || | ||
545 | memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) { | ||
546 | int ret; | ||
547 | |||
548 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | 549 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" |
549 | " based on configured SSID\n", | 550 | " based on configured SSID\n", |
550 | sdata->dev->name, bss->cbss.bssid); | 551 | sdata->dev->name, bss->cbss.bssid); |
551 | 552 | ||
552 | ret = ieee80211_sta_join_ibss(sdata, bss); | 553 | ieee80211_sta_join_ibss(sdata, bss); |
553 | ieee80211_rx_bss_put(local, bss); | 554 | ieee80211_rx_bss_put(local, bss); |
554 | return ret; | 555 | return; |
555 | } else if (bss) | 556 | } else if (bss) |
556 | ieee80211_rx_bss_put(local, bss); | 557 | ieee80211_rx_bss_put(local, bss); |
557 | 558 | ||
@@ -562,29 +563,24 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
562 | /* Selected IBSS not found in current scan results - try to scan */ | 563 | /* Selected IBSS not found in current scan results - try to scan */ |
563 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | 564 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && |
564 | !ieee80211_sta_active_ibss(sdata)) { | 565 | !ieee80211_sta_active_ibss(sdata)) { |
565 | mod_timer(&ifibss->timer, jiffies + | 566 | mod_timer(&ifibss->timer, |
566 | IEEE80211_IBSS_MERGE_INTERVAL); | 567 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
567 | } else if (time_after(jiffies, local->last_scan_completed + | 568 | } else if (time_after(jiffies, ifibss->last_scan_completed + |
568 | IEEE80211_SCAN_INTERVAL)) { | 569 | IEEE80211_SCAN_INTERVAL)) { |
569 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 570 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
570 | "join\n", sdata->dev->name); | 571 | "join\n", sdata->dev->name); |
571 | 572 | ||
572 | /* XXX maybe racy? */ | 573 | ieee80211_request_internal_scan(sdata, ifibss->ssid, |
573 | if (local->scan_req) | 574 | ifibss->ssid_len); |
574 | return -EBUSY; | ||
575 | |||
576 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
577 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
578 | local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
579 | return ieee80211_request_scan(sdata, &local->int_scan_req); | ||
580 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | 575 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { |
581 | int interval = IEEE80211_SCAN_INTERVAL; | 576 | int interval = IEEE80211_SCAN_INTERVAL; |
582 | 577 | ||
583 | if (time_after(jiffies, ifibss->ibss_join_req + | 578 | if (time_after(jiffies, ifibss->ibss_join_req + |
584 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | 579 | IEEE80211_IBSS_JOIN_TIMEOUT)) { |
585 | if (!(local->oper_channel->flags & | 580 | if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { |
586 | IEEE80211_CHAN_NO_IBSS)) | 581 | ieee80211_sta_create_ibss(sdata); |
587 | return ieee80211_sta_create_ibss(sdata); | 582 | return; |
583 | } | ||
588 | printk(KERN_DEBUG "%s: IBSS not allowed on" | 584 | printk(KERN_DEBUG "%s: IBSS not allowed on" |
589 | " %d MHz\n", sdata->dev->name, | 585 | " %d MHz\n", sdata->dev->name, |
590 | local->hw.conf.channel->center_freq); | 586 | local->hw.conf.channel->center_freq); |
@@ -595,11 +591,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
595 | } | 591 | } |
596 | 592 | ||
597 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | 593 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; |
598 | mod_timer(&ifibss->timer, jiffies + interval); | 594 | mod_timer(&ifibss->timer, |
599 | return 0; | 595 | round_jiffies(jiffies + interval)); |
600 | } | 596 | } |
601 | |||
602 | return 0; | ||
603 | } | 597 | } |
604 | 598 | ||
605 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 599 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, |
@@ -614,13 +608,10 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
614 | u8 *pos, *end; | 608 | u8 *pos, *end; |
615 | 609 | ||
616 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 610 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
617 | len < 24 + 2 || !ifibss->probe_resp) | 611 | len < 24 + 2 || !ifibss->presp) |
618 | return; | 612 | return; |
619 | 613 | ||
620 | if (local->ops->tx_last_beacon) | 614 | tx_last_beacon = drv_tx_last_beacon(local); |
621 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
622 | else | ||
623 | tx_last_beacon = 1; | ||
624 | 615 | ||
625 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 616 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
626 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | 617 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" |
@@ -649,13 +640,13 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
649 | } | 640 | } |
650 | if (pos[1] != 0 && | 641 | if (pos[1] != 0 && |
651 | (pos[1] != ifibss->ssid_len || | 642 | (pos[1] != ifibss->ssid_len || |
652 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { | 643 | !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { |
653 | /* Ignore ProbeReq for foreign SSID */ | 644 | /* Ignore ProbeReq for foreign SSID */ |
654 | return; | 645 | return; |
655 | } | 646 | } |
656 | 647 | ||
657 | /* Reply with ProbeResp */ | 648 | /* Reply with ProbeResp */ |
658 | skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); | 649 | skb = skb_copy(ifibss->presp, GFP_KERNEL); |
659 | if (!skb) | 650 | if (!skb) |
660 | return; | 651 | return; |
661 | 652 | ||
@@ -746,6 +737,9 @@ static void ieee80211_ibss_work(struct work_struct *work) | |||
746 | struct ieee80211_if_ibss *ifibss; | 737 | struct ieee80211_if_ibss *ifibss; |
747 | struct sk_buff *skb; | 738 | struct sk_buff *skb; |
748 | 739 | ||
740 | if (WARN_ON(local->suspended)) | ||
741 | return; | ||
742 | |||
749 | if (!netif_running(sdata->dev)) | 743 | if (!netif_running(sdata->dev)) |
750 | return; | 744 | return; |
751 | 745 | ||
@@ -782,101 +776,63 @@ static void ieee80211_ibss_timer(unsigned long data) | |||
782 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 776 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
783 | struct ieee80211_local *local = sdata->local; | 777 | struct ieee80211_local *local = sdata->local; |
784 | 778 | ||
779 | if (local->quiescing) { | ||
780 | ifibss->timer_running = true; | ||
781 | return; | ||
782 | } | ||
783 | |||
785 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | 784 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); |
786 | queue_work(local->hw.workqueue, &ifibss->work); | 785 | queue_work(local->hw.workqueue, &ifibss->work); |
787 | } | 786 | } |
788 | 787 | ||
789 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | 788 | #ifdef CONFIG_PM |
789 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) | ||
790 | { | 790 | { |
791 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 791 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
792 | 792 | ||
793 | INIT_WORK(&ifibss->work, ieee80211_ibss_work); | 793 | cancel_work_sync(&ifibss->work); |
794 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | 794 | if (del_timer_sync(&ifibss->timer)) |
795 | (unsigned long) sdata); | 795 | ifibss->timer_running = true; |
796 | skb_queue_head_init(&ifibss->skb_queue); | ||
797 | |||
798 | ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
799 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
800 | } | 796 | } |
801 | 797 | ||
802 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) | 798 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) |
803 | { | 799 | { |
804 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 800 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
805 | 801 | ||
806 | ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | 802 | if (ifibss->timer_running) { |
807 | 803 | add_timer(&ifibss->timer); | |
808 | if (ifibss->ssid_len) | 804 | ifibss->timer_running = false; |
809 | ifibss->flags |= IEEE80211_IBSS_SSID_SET; | ||
810 | else | ||
811 | ifibss->flags &= ~IEEE80211_IBSS_SSID_SET; | ||
812 | |||
813 | ifibss->ibss_join_req = jiffies; | ||
814 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
815 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | ||
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | ||
821 | { | ||
822 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
823 | |||
824 | if (len > IEEE80211_MAX_SSID_LEN) | ||
825 | return -EINVAL; | ||
826 | |||
827 | if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) { | ||
828 | memset(ifibss->ssid, 0, sizeof(ifibss->ssid)); | ||
829 | memcpy(ifibss->ssid, ssid, len); | ||
830 | ifibss->ssid_len = len; | ||
831 | } | 805 | } |
832 | |||
833 | return ieee80211_ibss_commit(sdata); | ||
834 | } | ||
835 | |||
836 | int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | ||
837 | { | ||
838 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
839 | |||
840 | memcpy(ssid, ifibss->ssid, ifibss->ssid_len); | ||
841 | *len = ifibss->ssid_len; | ||
842 | |||
843 | return 0; | ||
844 | } | 806 | } |
807 | #endif | ||
845 | 808 | ||
846 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 809 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) |
847 | { | 810 | { |
848 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 811 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
849 | 812 | ||
850 | if (is_valid_ether_addr(bssid)) { | 813 | INIT_WORK(&ifibss->work, ieee80211_ibss_work); |
851 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 814 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, |
852 | ifibss->flags |= IEEE80211_IBSS_BSSID_SET; | 815 | (unsigned long) sdata); |
853 | } else { | 816 | skb_queue_head_init(&ifibss->skb_queue); |
854 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
855 | ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET; | ||
856 | } | ||
857 | |||
858 | if (netif_running(sdata->dev)) { | ||
859 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { | ||
860 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
861 | "the low-level driver\n", sdata->dev->name); | ||
862 | } | ||
863 | } | ||
864 | |||
865 | return ieee80211_ibss_commit(sdata); | ||
866 | } | 817 | } |
867 | 818 | ||
868 | /* scan finished notification */ | 819 | /* scan finished notification */ |
869 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | 820 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) |
870 | { | 821 | { |
871 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 822 | struct ieee80211_sub_if_data *sdata; |
872 | struct ieee80211_if_ibss *ifibss; | 823 | |
873 | 824 | mutex_lock(&local->iflist_mtx); | |
874 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 825 | list_for_each_entry(sdata, &local->interfaces, list) { |
875 | ifibss = &sdata->u.ibss; | 826 | if (!netif_running(sdata->dev)) |
876 | if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || | 827 | continue; |
877 | !ieee80211_sta_active_ibss(sdata)) | 828 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
878 | ieee80211_sta_find_ibss(sdata); | 829 | continue; |
830 | if (!sdata->u.ibss.ssid_len) | ||
831 | continue; | ||
832 | sdata->u.ibss.last_scan_completed = jiffies; | ||
833 | ieee80211_sta_find_ibss(sdata); | ||
879 | } | 834 | } |
835 | mutex_unlock(&local->iflist_mtx); | ||
880 | } | 836 | } |
881 | 837 | ||
882 | ieee80211_rx_result | 838 | ieee80211_rx_result |
@@ -906,3 +862,86 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
906 | 862 | ||
907 | return RX_DROP_MONITOR; | 863 | return RX_DROP_MONITOR; |
908 | } | 864 | } |
865 | |||
866 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | ||
867 | struct cfg80211_ibss_params *params) | ||
868 | { | ||
869 | struct sk_buff *skb; | ||
870 | |||
871 | if (params->bssid) { | ||
872 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | ||
873 | sdata->u.ibss.fixed_bssid = true; | ||
874 | } else | ||
875 | sdata->u.ibss.fixed_bssid = false; | ||
876 | |||
877 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | ||
878 | |||
879 | sdata->u.ibss.channel = params->channel; | ||
880 | sdata->u.ibss.fixed_channel = params->channel_fixed; | ||
881 | |||
882 | if (params->ie) { | ||
883 | sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, | ||
884 | GFP_KERNEL); | ||
885 | if (sdata->u.ibss.ie) | ||
886 | sdata->u.ibss.ie_len = params->ie_len; | ||
887 | } | ||
888 | |||
889 | skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + | ||
890 | 36 /* bitrates */ + | ||
891 | 34 /* SSID */ + | ||
892 | 3 /* DS params */ + | ||
893 | 4 /* IBSS params */ + | ||
894 | params->ie_len); | ||
895 | if (!skb) | ||
896 | return -ENOMEM; | ||
897 | |||
898 | sdata->u.ibss.skb = skb; | ||
899 | sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; | ||
900 | sdata->u.ibss.ibss_join_req = jiffies; | ||
901 | |||
902 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); | ||
903 | |||
904 | /* | ||
905 | * The ssid_len setting below is used to see whether | ||
906 | * we are active, and we need all other settings | ||
907 | * before that may get visible. | ||
908 | */ | ||
909 | mb(); | ||
910 | |||
911 | sdata->u.ibss.ssid_len = params->ssid_len; | ||
912 | |||
913 | ieee80211_recalc_idle(sdata->local); | ||
914 | |||
915 | set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
916 | queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | ||
922 | { | ||
923 | struct sk_buff *skb; | ||
924 | |||
925 | del_timer_sync(&sdata->u.ibss.timer); | ||
926 | clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
927 | cancel_work_sync(&sdata->u.ibss.work); | ||
928 | clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
929 | |||
930 | sta_info_flush(sdata->local, sdata); | ||
931 | |||
932 | /* remove beacon */ | ||
933 | kfree(sdata->u.ibss.ie); | ||
934 | skb = sdata->u.ibss.presp; | ||
935 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); | ||
936 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | ||
937 | synchronize_rcu(); | ||
938 | kfree_skb(skb); | ||
939 | |||
940 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
941 | memset(sdata->u.ibss.bssid, 0, ETH_ALEN); | ||
942 | sdata->u.ibss.ssid_len = 0; | ||
943 | |||
944 | ieee80211_recalc_idle(sdata->local); | ||
945 | |||
946 | return 0; | ||
947 | } | ||