diff options
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 347 |
1 files changed, 165 insertions, 182 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3201e1f96365..4f7a54518be4 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -59,74 +59,59 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
59 | sdata->u.ibss.bssid, 0); | 59 | sdata->u.ibss.bssid, 0); |
60 | } | 60 | } |
61 | 61 | ||
62 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 62 | static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
63 | const u8 *bssid, const int beacon_int, | 63 | const u8 *bssid, const int beacon_int, |
64 | const int freq, | 64 | struct ieee80211_channel *chan, |
65 | const size_t supp_rates_len, | 65 | const size_t supp_rates_len, |
66 | const u8 *supp_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, j; |
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; | ||
77 | 76 | ||
78 | if (local->ops->reset_tsf) { | 77 | if (local->ops->reset_tsf) { |
79 | /* Reset own TSF to allow time synchronization work. */ | 78 | /* Reset own TSF to allow time synchronization work. */ |
80 | local->ops->reset_tsf(local_to_hw(local)); | 79 | local->ops->reset_tsf(local_to_hw(local)); |
81 | } | 80 | } |
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 | 94 | ||
104 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | 95 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; |
105 | 96 | ||
106 | sdata->drop_unencrypted = capability & | 97 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
107 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
108 | |||
109 | res = ieee80211_set_freq(sdata, freq); | ||
110 | 98 | ||
111 | if (res) | 99 | ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); |
112 | return res; | ||
113 | 100 | ||
114 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 101 | local->oper_channel = chan; |
102 | local->oper_channel_type = NL80211_CHAN_NO_HT; | ||
103 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
104 | sband = local->hw.wiphy->bands[chan->band]; | ||
115 | 105 | ||
116 | /* Build IBSS probe response */ | 106 | /* Build IBSS probe response */ |
117 | 107 | 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)); | 108 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); |
123 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 109 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
124 | IEEE80211_STYPE_PROBE_RESP); | 110 | IEEE80211_STYPE_PROBE_RESP); |
125 | memset(mgmt->da, 0xff, ETH_ALEN); | 111 | memset(mgmt->da, 0xff, ETH_ALEN); |
126 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 112 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
127 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | 113 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); |
128 | mgmt->u.beacon.beacon_int = | 114 | mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int); |
129 | cpu_to_le16(local->hw.conf.beacon_int); | ||
130 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); | 115 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); |
131 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | 116 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); |
132 | 117 | ||
@@ -147,7 +132,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
147 | pos = skb_put(skb, 2 + 1); | 132 | pos = skb_put(skb, 2 + 1); |
148 | *pos++ = WLAN_EID_DS_PARAMS; | 133 | *pos++ = WLAN_EID_DS_PARAMS; |
149 | *pos++ = 1; | 134 | *pos++ = 1; |
150 | *pos++ = ieee80211_frequency_to_channel(freq); | 135 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); |
151 | } | 136 | } |
152 | 137 | ||
153 | pos = skb_put(skb, 2 + 2); | 138 | pos = skb_put(skb, 2 + 2); |
@@ -165,12 +150,15 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
165 | memcpy(pos, &supp_rates[8], rates); | 150 | memcpy(pos, &supp_rates[8], rates); |
166 | } | 151 | } |
167 | 152 | ||
168 | ifibss->probe_resp = skb; | 153 | if (ifibss->ie_len) |
154 | memcpy(skb_put(skb, ifibss->ie_len), | ||
155 | ifibss->ie, ifibss->ie_len); | ||
156 | |||
157 | rcu_assign_pointer(ifibss->presp, skb); | ||
169 | 158 | ||
170 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | 159 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | |
171 | IEEE80211_IFCC_BEACON_ENABLED); | 160 | IEEE80211_IFCC_BEACON_ENABLED); |
172 | 161 | ||
173 | |||
174 | rates = 0; | 162 | rates = 0; |
175 | for (i = 0; i < supp_rates_len; i++) { | 163 | for (i = 0; i < supp_rates_len; i++) { |
176 | int bitrate = (supp_rates[i] & 0x7f) * 5; | 164 | int bitrate = (supp_rates[i] & 0x7f) * 5; |
@@ -181,27 +169,24 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
181 | 169 | ||
182 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | 170 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); |
183 | 171 | ||
184 | ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; | ||
185 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 172 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
186 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 173 | mod_timer(&ifibss->timer, |
174 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||
187 | 175 | ||
188 | memset(&wrqu, 0, sizeof(wrqu)); | 176 | cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, |
189 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 177 | mgmt, skb->len, 0, GFP_KERNEL); |
190 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 178 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
191 | |||
192 | return res; | ||
193 | } | 179 | } |
194 | 180 | ||
195 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 181 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
196 | struct ieee80211_bss *bss) | 182 | struct ieee80211_bss *bss) |
197 | { | 183 | { |
198 | return __ieee80211_sta_join_ibss(sdata, | 184 | __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, |
199 | bss->cbss.bssid, | 185 | bss->cbss.beacon_interval, |
200 | bss->cbss.beacon_interval, | 186 | bss->cbss.channel, |
201 | bss->cbss.channel->center_freq, | 187 | bss->supp_rates_len, bss->supp_rates, |
202 | bss->supp_rates_len, bss->supp_rates, | 188 | bss->cbss.capability, |
203 | bss->cbss.capability, | 189 | bss->cbss.tsf); |
204 | bss->cbss.tsf); | ||
205 | } | 190 | } |
206 | 191 | ||
207 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 192 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
@@ -277,7 +262,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
277 | goto put_bss; | 262 | goto put_bss; |
278 | 263 | ||
279 | /* we use a fixed BSSID */ | 264 | /* we use a fixed BSSID */ |
280 | if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) | 265 | if (sdata->u.ibss.bssid) |
281 | goto put_bss; | 266 | goto put_bss; |
282 | 267 | ||
283 | /* not an IBSS */ | 268 | /* not an IBSS */ |
@@ -369,13 +354,14 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
369 | struct sta_info *sta; | 354 | struct sta_info *sta; |
370 | int band = local->hw.conf.channel->band; | 355 | int band = local->hw.conf.channel->band; |
371 | 356 | ||
372 | /* TODO: Could consider removing the least recently used entry and | 357 | /* |
373 | * allow new one to be added. */ | 358 | * XXX: Consider removing the least recently used entry and |
359 | * allow new one to be added. | ||
360 | */ | ||
374 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | 361 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { |
375 | if (net_ratelimit()) { | 362 | if (net_ratelimit()) |
376 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | 363 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", |
377 | "entry %pM\n", sdata->dev->name, addr); | 364 | sdata->dev->name, addr); |
378 | } | ||
379 | return NULL; | 365 | return NULL; |
380 | } | 366 | } |
381 | 367 | ||
@@ -432,14 +418,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
432 | { | 418 | { |
433 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 419 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
434 | 420 | ||
435 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 421 | mod_timer(&ifibss->timer, |
422 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||
436 | 423 | ||
437 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | 424 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); |
425 | |||
438 | if (ieee80211_sta_active_ibss(sdata)) | 426 | if (ieee80211_sta_active_ibss(sdata)) |
439 | return; | 427 | return; |
440 | 428 | ||
441 | if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && | 429 | if (ifibss->fixed_channel) |
442 | (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) | ||
443 | return; | 430 | return; |
444 | 431 | ||
445 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 432 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
@@ -455,7 +442,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
455 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | 442 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); |
456 | } | 443 | } |
457 | 444 | ||
458 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 445 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
459 | { | 446 | { |
460 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 447 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
461 | struct ieee80211_local *local = sdata->local; | 448 | struct ieee80211_local *local = sdata->local; |
@@ -466,7 +453,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
466 | u16 capability; | 453 | u16 capability; |
467 | int i; | 454 | int i; |
468 | 455 | ||
469 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { | 456 | if (ifibss->fixed_bssid) { |
470 | memcpy(bssid, ifibss->bssid, ETH_ALEN); | 457 | memcpy(bssid, ifibss->bssid, ETH_ALEN); |
471 | } else { | 458 | } else { |
472 | /* Generate random, not broadcast, locally administered BSSID. Mix in | 459 | /* Generate random, not broadcast, locally administered BSSID. Mix in |
@@ -482,7 +469,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", | 469 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
483 | sdata->dev->name, bssid); | 470 | sdata->dev->name, bssid); |
484 | 471 | ||
485 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 472 | sband = local->hw.wiphy->bands[ifibss->channel->band]; |
486 | 473 | ||
487 | if (local->hw.conf.beacon_int == 0) | 474 | if (local->hw.conf.beacon_int == 0) |
488 | local->hw.conf.beacon_int = 100; | 475 | local->hw.conf.beacon_int = 100; |
@@ -500,24 +487,20 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
500 | *pos++ = (u8) (rate / 5); | 487 | *pos++ = (u8) (rate / 5); |
501 | } | 488 | } |
502 | 489 | ||
503 | return __ieee80211_sta_join_ibss(sdata, | 490 | __ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int, |
504 | bssid, local->hw.conf.beacon_int, | 491 | ifibss->channel, sband->n_bitrates, |
505 | local->hw.conf.channel->center_freq, | 492 | supp_rates, capability, 0); |
506 | sband->n_bitrates, supp_rates, | ||
507 | capability, 0); | ||
508 | } | 493 | } |
509 | 494 | ||
510 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | 495 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) |
511 | { | 496 | { |
512 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 497 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
513 | struct ieee80211_local *local = sdata->local; | 498 | struct ieee80211_local *local = sdata->local; |
514 | struct ieee80211_bss *bss; | 499 | struct ieee80211_bss *bss; |
500 | struct ieee80211_channel *chan = NULL; | ||
515 | const u8 *bssid = NULL; | 501 | const u8 *bssid = NULL; |
516 | int active_ibss; | 502 | int active_ibss; |
517 | 503 | ||
518 | if (ifibss->ssid_len == 0) | ||
519 | return -EINVAL; | ||
520 | |||
521 | active_ibss = ieee80211_sta_active_ibss(sdata); | 504 | active_ibss = ieee80211_sta_active_ibss(sdata); |
522 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 505 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
523 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | 506 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", |
@@ -525,11 +508,15 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
525 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 508 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
526 | 509 | ||
527 | if (active_ibss) | 510 | if (active_ibss) |
528 | return 0; | 511 | return; |
529 | 512 | ||
530 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) | 513 | if (ifibss->fixed_bssid) |
514 | bssid = ifibss->bssid; | ||
515 | if (ifibss->fixed_channel) | ||
516 | chan = ifibss->channel; | ||
517 | if (!is_zero_ether_addr(ifibss->bssid)) | ||
531 | bssid = ifibss->bssid; | 518 | bssid = ifibss->bssid; |
532 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, | 519 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, |
533 | ifibss->ssid, ifibss->ssid_len, | 520 | ifibss->ssid, ifibss->ssid_len, |
534 | WLAN_CAPABILITY_IBSS, | 521 | WLAN_CAPABILITY_IBSS, |
535 | WLAN_CAPABILITY_IBSS); | 522 | WLAN_CAPABILITY_IBSS); |
@@ -540,18 +527,14 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
540 | "%pM\n", bss->cbss.bssid, ifibss->bssid); | 527 | "%pM\n", bss->cbss.bssid, ifibss->bssid); |
541 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 528 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
542 | 529 | ||
543 | if (bss && | 530 | 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" | 531 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" |
549 | " based on configured SSID\n", | 532 | " based on configured SSID\n", |
550 | sdata->dev->name, bss->cbss.bssid); | 533 | sdata->dev->name, bss->cbss.bssid); |
551 | 534 | ||
552 | ret = ieee80211_sta_join_ibss(sdata, bss); | 535 | ieee80211_sta_join_ibss(sdata, bss); |
553 | ieee80211_rx_bss_put(local, bss); | 536 | ieee80211_rx_bss_put(local, bss); |
554 | return ret; | 537 | return; |
555 | } else if (bss) | 538 | } else if (bss) |
556 | ieee80211_rx_bss_put(local, bss); | 539 | ieee80211_rx_bss_put(local, bss); |
557 | 540 | ||
@@ -562,29 +545,31 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
562 | /* Selected IBSS not found in current scan results - try to scan */ | 545 | /* Selected IBSS not found in current scan results - try to scan */ |
563 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | 546 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && |
564 | !ieee80211_sta_active_ibss(sdata)) { | 547 | !ieee80211_sta_active_ibss(sdata)) { |
565 | mod_timer(&ifibss->timer, jiffies + | 548 | mod_timer(&ifibss->timer, |
566 | IEEE80211_IBSS_MERGE_INTERVAL); | 549 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
567 | } else if (time_after(jiffies, local->last_scan_completed + | 550 | } else if (time_after(jiffies, ifibss->last_scan_completed + |
568 | IEEE80211_SCAN_INTERVAL)) { | 551 | IEEE80211_SCAN_INTERVAL)) { |
569 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 552 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
570 | "join\n", sdata->dev->name); | 553 | "join\n", sdata->dev->name); |
571 | 554 | ||
572 | /* XXX maybe racy? */ | 555 | /* XXX maybe racy? */ |
573 | if (local->scan_req) | 556 | if (local->scan_req) |
574 | return -EBUSY; | 557 | return; |
575 | 558 | ||
576 | memcpy(local->int_scan_req.ssids[0].ssid, | 559 | memcpy(local->int_scan_req.ssids[0].ssid, |
577 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | 560 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); |
578 | local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | 561 | local->int_scan_req.ssids[0].ssid_len = |
579 | return ieee80211_request_scan(sdata, &local->int_scan_req); | 562 | ifibss->ssid_len; |
563 | ieee80211_request_scan(sdata, &local->int_scan_req); | ||
580 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | 564 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { |
581 | int interval = IEEE80211_SCAN_INTERVAL; | 565 | int interval = IEEE80211_SCAN_INTERVAL; |
582 | 566 | ||
583 | if (time_after(jiffies, ifibss->ibss_join_req + | 567 | if (time_after(jiffies, ifibss->ibss_join_req + |
584 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | 568 | IEEE80211_IBSS_JOIN_TIMEOUT)) { |
585 | if (!(local->oper_channel->flags & | 569 | if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { |
586 | IEEE80211_CHAN_NO_IBSS)) | 570 | ieee80211_sta_create_ibss(sdata); |
587 | return ieee80211_sta_create_ibss(sdata); | 571 | return; |
572 | } | ||
588 | printk(KERN_DEBUG "%s: IBSS not allowed on" | 573 | printk(KERN_DEBUG "%s: IBSS not allowed on" |
589 | " %d MHz\n", sdata->dev->name, | 574 | " %d MHz\n", sdata->dev->name, |
590 | local->hw.conf.channel->center_freq); | 575 | local->hw.conf.channel->center_freq); |
@@ -595,11 +580,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
595 | } | 580 | } |
596 | 581 | ||
597 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | 582 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; |
598 | mod_timer(&ifibss->timer, jiffies + interval); | 583 | mod_timer(&ifibss->timer, |
599 | return 0; | 584 | round_jiffies(jiffies + interval)); |
600 | } | 585 | } |
601 | |||
602 | return 0; | ||
603 | } | 586 | } |
604 | 587 | ||
605 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 588 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, |
@@ -614,7 +597,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
614 | u8 *pos, *end; | 597 | u8 *pos, *end; |
615 | 598 | ||
616 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 599 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
617 | len < 24 + 2 || !ifibss->probe_resp) | 600 | len < 24 + 2 || !ifibss->presp) |
618 | return; | 601 | return; |
619 | 602 | ||
620 | if (local->ops->tx_last_beacon) | 603 | if (local->ops->tx_last_beacon) |
@@ -649,13 +632,13 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
649 | } | 632 | } |
650 | if (pos[1] != 0 && | 633 | if (pos[1] != 0 && |
651 | (pos[1] != ifibss->ssid_len || | 634 | (pos[1] != ifibss->ssid_len || |
652 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { | 635 | !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { |
653 | /* Ignore ProbeReq for foreign SSID */ | 636 | /* Ignore ProbeReq for foreign SSID */ |
654 | return; | 637 | return; |
655 | } | 638 | } |
656 | 639 | ||
657 | /* Reply with ProbeResp */ | 640 | /* Reply with ProbeResp */ |
658 | skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); | 641 | skb = skb_copy(ifibss->presp, GFP_KERNEL); |
659 | if (!skb) | 642 | if (!skb) |
660 | return; | 643 | return; |
661 | 644 | ||
@@ -794,89 +777,21 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
794 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | 777 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, |
795 | (unsigned long) sdata); | 778 | (unsigned long) sdata); |
796 | skb_queue_head_init(&ifibss->skb_queue); | 779 | skb_queue_head_init(&ifibss->skb_queue); |
797 | |||
798 | ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
799 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
800 | } | ||
801 | |||
802 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) | ||
803 | { | ||
804 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
805 | |||
806 | ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
807 | |||
808 | if (ifibss->ssid_len) | ||
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 | } | ||
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 | } | ||
845 | |||
846 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | ||
847 | { | ||
848 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
849 | |||
850 | if (is_valid_ether_addr(bssid)) { | ||
851 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
852 | ifibss->flags |= IEEE80211_IBSS_BSSID_SET; | ||
853 | } else { | ||
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 | } | 780 | } |
867 | 781 | ||
868 | /* scan finished notification */ | 782 | /* scan finished notification */ |
869 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | 783 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) |
870 | { | 784 | { |
871 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 785 | struct ieee80211_sub_if_data *sdata; |
872 | struct ieee80211_if_ibss *ifibss; | ||
873 | 786 | ||
874 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 787 | rcu_read_lock(); |
875 | ifibss = &sdata->u.ibss; | 788 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
876 | if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || | 789 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
877 | !ieee80211_sta_active_ibss(sdata)) | 790 | continue; |
878 | ieee80211_sta_find_ibss(sdata); | 791 | sdata->u.ibss.last_scan_completed = jiffies; |
792 | ieee80211_sta_find_ibss(sdata); | ||
879 | } | 793 | } |
794 | rcu_read_unlock(); | ||
880 | } | 795 | } |
881 | 796 | ||
882 | ieee80211_rx_result | 797 | ieee80211_rx_result |
@@ -906,3 +821,71 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
906 | 821 | ||
907 | return RX_DROP_MONITOR; | 822 | return RX_DROP_MONITOR; |
908 | } | 823 | } |
824 | |||
825 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | ||
826 | struct cfg80211_ibss_params *params) | ||
827 | { | ||
828 | struct sk_buff *skb; | ||
829 | |||
830 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); | ||
831 | sdata->u.ibss.ssid_len = params->ssid_len; | ||
832 | |||
833 | if (params->bssid) { | ||
834 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | ||
835 | sdata->u.ibss.fixed_bssid = true; | ||
836 | } else | ||
837 | sdata->u.ibss.fixed_bssid = false; | ||
838 | |||
839 | sdata->u.ibss.channel = params->channel; | ||
840 | sdata->u.ibss.fixed_channel = params->channel_fixed; | ||
841 | |||
842 | if (params->ie) { | ||
843 | sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, | ||
844 | GFP_KERNEL); | ||
845 | if (sdata->u.ibss.ie) | ||
846 | sdata->u.ibss.ie_len = params->ie_len; | ||
847 | } | ||
848 | |||
849 | skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + | ||
850 | 36 /* bitrates */ + | ||
851 | 34 /* SSID */ + | ||
852 | 3 /* DS params */ + | ||
853 | 4 /* IBSS params */ + | ||
854 | params->ie_len); | ||
855 | if (!skb) | ||
856 | return -ENOMEM; | ||
857 | |||
858 | sdata->u.ibss.skb = skb; | ||
859 | sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; | ||
860 | sdata->u.ibss.ibss_join_req = jiffies; | ||
861 | |||
862 | set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
863 | queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); | ||
864 | |||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | ||
869 | { | ||
870 | struct sk_buff *skb; | ||
871 | |||
872 | del_timer_sync(&sdata->u.ibss.timer); | ||
873 | clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
874 | cancel_work_sync(&sdata->u.ibss.work); | ||
875 | clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | ||
876 | |||
877 | sta_info_flush(sdata->local, sdata); | ||
878 | |||
879 | /* remove beacon */ | ||
880 | kfree(sdata->u.ibss.ie); | ||
881 | skb = sdata->u.ibss.presp; | ||
882 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); | ||
883 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | ||
884 | synchronize_rcu(); | ||
885 | kfree_skb(skb); | ||
886 | |||
887 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
888 | memset(sdata->u.ibss.bssid, 0, ETH_ALEN); | ||
889 | |||
890 | return 0; | ||
891 | } | ||