diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-12-18 20:03:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:09:38 -0500 |
commit | 5dfdaf58d61f06a458529430c24b1191ea4d1a27 (patch) | |
tree | bd3fac57f66e80bf2a31d253af19093f4020ba79 /net | |
parent | 51fb61e76d952e6bc2fbdd9f0d38425fbab1cf31 (diff) |
mac80211: add beacon configuration via cfg80211
This patch implements the cfg80211 hooks for configuring beaconing
on an access point interface in mac80211. While doing so, it fixes
a number of races that could badly crash the machine when the
beacon is changed while being requested by the driver.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 156 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 27 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 9 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 14 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 65 |
6 files changed, 213 insertions, 62 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d02d9ef6b1ef..5a4c6edd9348 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/nl80211.h> | 10 | #include <linux/nl80211.h> |
11 | #include <linux/rtnetlink.h> | 11 | #include <linux/rtnetlink.h> |
12 | #include <net/net_namespace.h> | 12 | #include <net/net_namespace.h> |
13 | #include <linux/rcupdate.h> | ||
13 | #include <net/cfg80211.h> | 14 | #include <net/cfg80211.h> |
14 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
15 | #include "cfg.h" | 16 | #include "cfg.h" |
@@ -294,6 +295,158 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
294 | return 0; | 295 | return 0; |
295 | } | 296 | } |
296 | 297 | ||
298 | /* | ||
299 | * This handles both adding a beacon and setting new beacon info | ||
300 | */ | ||
301 | static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | ||
302 | struct beacon_parameters *params) | ||
303 | { | ||
304 | struct beacon_data *new, *old; | ||
305 | int new_head_len, new_tail_len; | ||
306 | int size; | ||
307 | int err = -EINVAL; | ||
308 | |||
309 | old = sdata->u.ap.beacon; | ||
310 | |||
311 | /* head must not be zero-length */ | ||
312 | if (params->head && !params->head_len) | ||
313 | return -EINVAL; | ||
314 | |||
315 | /* | ||
316 | * This is a kludge. beacon interval should really be part | ||
317 | * of the beacon information. | ||
318 | */ | ||
319 | if (params->interval) { | ||
320 | sdata->local->hw.conf.beacon_int = params->interval; | ||
321 | if (ieee80211_hw_config(sdata->local)) | ||
322 | return -EINVAL; | ||
323 | /* | ||
324 | * We updated some parameter so if below bails out | ||
325 | * it's not an error. | ||
326 | */ | ||
327 | err = 0; | ||
328 | } | ||
329 | |||
330 | /* Need to have a beacon head if we don't have one yet */ | ||
331 | if (!params->head && !old) | ||
332 | return err; | ||
333 | |||
334 | /* sorry, no way to start beaconing without dtim period */ | ||
335 | if (!params->dtim_period && !old) | ||
336 | return err; | ||
337 | |||
338 | /* new or old head? */ | ||
339 | if (params->head) | ||
340 | new_head_len = params->head_len; | ||
341 | else | ||
342 | new_head_len = old->head_len; | ||
343 | |||
344 | /* new or old tail? */ | ||
345 | if (params->tail || !old) | ||
346 | /* params->tail_len will be zero for !params->tail */ | ||
347 | new_tail_len = params->tail_len; | ||
348 | else | ||
349 | new_tail_len = old->tail_len; | ||
350 | |||
351 | size = sizeof(*new) + new_head_len + new_tail_len; | ||
352 | |||
353 | new = kzalloc(size, GFP_KERNEL); | ||
354 | if (!new) | ||
355 | return -ENOMEM; | ||
356 | |||
357 | /* start filling the new info now */ | ||
358 | |||
359 | /* new or old dtim period? */ | ||
360 | if (params->dtim_period) | ||
361 | new->dtim_period = params->dtim_period; | ||
362 | else | ||
363 | new->dtim_period = old->dtim_period; | ||
364 | |||
365 | /* | ||
366 | * pointers go into the block we allocated, | ||
367 | * memory is | beacon_data | head | tail | | ||
368 | */ | ||
369 | new->head = ((u8 *) new) + sizeof(*new); | ||
370 | new->tail = new->head + new_head_len; | ||
371 | new->head_len = new_head_len; | ||
372 | new->tail_len = new_tail_len; | ||
373 | |||
374 | /* copy in head */ | ||
375 | if (params->head) | ||
376 | memcpy(new->head, params->head, new_head_len); | ||
377 | else | ||
378 | memcpy(new->head, old->head, new_head_len); | ||
379 | |||
380 | /* copy in optional tail */ | ||
381 | if (params->tail) | ||
382 | memcpy(new->tail, params->tail, new_tail_len); | ||
383 | else | ||
384 | if (old) | ||
385 | memcpy(new->tail, old->tail, new_tail_len); | ||
386 | |||
387 | rcu_assign_pointer(sdata->u.ap.beacon, new); | ||
388 | |||
389 | synchronize_rcu(); | ||
390 | |||
391 | kfree(old); | ||
392 | |||
393 | return ieee80211_if_config_beacon(sdata->dev); | ||
394 | } | ||
395 | |||
396 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
397 | struct beacon_parameters *params) | ||
398 | { | ||
399 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
400 | struct beacon_data *old; | ||
401 | |||
402 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | ||
403 | return -EINVAL; | ||
404 | |||
405 | old = sdata->u.ap.beacon; | ||
406 | |||
407 | if (old) | ||
408 | return -EALREADY; | ||
409 | |||
410 | return ieee80211_config_beacon(sdata, params); | ||
411 | } | ||
412 | |||
413 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
414 | struct beacon_parameters *params) | ||
415 | { | ||
416 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
417 | struct beacon_data *old; | ||
418 | |||
419 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | ||
420 | return -EINVAL; | ||
421 | |||
422 | old = sdata->u.ap.beacon; | ||
423 | |||
424 | if (!old) | ||
425 | return -ENOENT; | ||
426 | |||
427 | return ieee80211_config_beacon(sdata, params); | ||
428 | } | ||
429 | |||
430 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | ||
431 | { | ||
432 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
433 | struct beacon_data *old; | ||
434 | |||
435 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | ||
436 | return -EINVAL; | ||
437 | |||
438 | old = sdata->u.ap.beacon; | ||
439 | |||
440 | if (!old) | ||
441 | return -ENOENT; | ||
442 | |||
443 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | ||
444 | synchronize_rcu(); | ||
445 | kfree(old); | ||
446 | |||
447 | return ieee80211_if_config_beacon(dev); | ||
448 | } | ||
449 | |||
297 | struct cfg80211_ops mac80211_config_ops = { | 450 | struct cfg80211_ops mac80211_config_ops = { |
298 | .add_virtual_intf = ieee80211_add_iface, | 451 | .add_virtual_intf = ieee80211_add_iface, |
299 | .del_virtual_intf = ieee80211_del_iface, | 452 | .del_virtual_intf = ieee80211_del_iface, |
@@ -302,5 +455,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
302 | .del_key = ieee80211_del_key, | 455 | .del_key = ieee80211_del_key, |
303 | .get_key = ieee80211_get_key, | 456 | .get_key = ieee80211_get_key, |
304 | .set_default_key = ieee80211_config_default_key, | 457 | .set_default_key = ieee80211_config_default_key, |
458 | .add_beacon = ieee80211_add_beacon, | ||
459 | .set_beacon = ieee80211_set_beacon, | ||
460 | .del_beacon = ieee80211_del_beacon, | ||
305 | .get_station = ieee80211_get_station, | 461 | .get_station = ieee80211_get_station, |
306 | }; | 462 | }; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index d2d3c076c853..3500fe0d380b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -124,7 +124,6 @@ __IEEE80211_IF_FILE(flags); | |||
124 | 124 | ||
125 | /* AP attributes */ | 125 | /* AP attributes */ |
126 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 126 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
127 | IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC); | ||
128 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | 127 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); |
129 | IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); | 128 | IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); |
130 | IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); | 129 | IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); |
@@ -138,26 +137,6 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
138 | } | 137 | } |
139 | __IEEE80211_IF_FILE(num_buffered_multicast); | 138 | __IEEE80211_IF_FILE(num_buffered_multicast); |
140 | 139 | ||
141 | static ssize_t ieee80211_if_fmt_beacon_head_len( | ||
142 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
143 | { | ||
144 | if (sdata->u.ap.beacon_head) | ||
145 | return scnprintf(buf, buflen, "%d\n", | ||
146 | sdata->u.ap.beacon_head_len); | ||
147 | return scnprintf(buf, buflen, "\n"); | ||
148 | } | ||
149 | __IEEE80211_IF_FILE(beacon_head_len); | ||
150 | |||
151 | static ssize_t ieee80211_if_fmt_beacon_tail_len( | ||
152 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
153 | { | ||
154 | if (sdata->u.ap.beacon_tail) | ||
155 | return scnprintf(buf, buflen, "%d\n", | ||
156 | sdata->u.ap.beacon_tail_len); | ||
157 | return scnprintf(buf, buflen, "\n"); | ||
158 | } | ||
159 | __IEEE80211_IF_FILE(beacon_tail_len); | ||
160 | |||
161 | /* WDS attributes */ | 140 | /* WDS attributes */ |
162 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 141 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
163 | 142 | ||
@@ -192,14 +171,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) | |||
192 | DEBUGFS_ADD(drop_unencrypted, ap); | 171 | DEBUGFS_ADD(drop_unencrypted, ap); |
193 | DEBUGFS_ADD(ieee802_1x_pac, ap); | 172 | DEBUGFS_ADD(ieee802_1x_pac, ap); |
194 | DEBUGFS_ADD(num_sta_ps, ap); | 173 | DEBUGFS_ADD(num_sta_ps, ap); |
195 | DEBUGFS_ADD(dtim_period, ap); | ||
196 | DEBUGFS_ADD(dtim_count, ap); | 174 | DEBUGFS_ADD(dtim_count, ap); |
197 | DEBUGFS_ADD(num_beacons, ap); | 175 | DEBUGFS_ADD(num_beacons, ap); |
198 | DEBUGFS_ADD(force_unicast_rateidx, ap); | 176 | DEBUGFS_ADD(force_unicast_rateidx, ap); |
199 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | 177 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); |
200 | DEBUGFS_ADD(num_buffered_multicast, ap); | 178 | DEBUGFS_ADD(num_buffered_multicast, ap); |
201 | DEBUGFS_ADD(beacon_head_len, ap); | ||
202 | DEBUGFS_ADD(beacon_tail_len, ap); | ||
203 | } | 179 | } |
204 | 180 | ||
205 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 181 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
@@ -281,14 +257,11 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) | |||
281 | DEBUGFS_DEL(drop_unencrypted, ap); | 257 | DEBUGFS_DEL(drop_unencrypted, ap); |
282 | DEBUGFS_DEL(ieee802_1x_pac, ap); | 258 | DEBUGFS_DEL(ieee802_1x_pac, ap); |
283 | DEBUGFS_DEL(num_sta_ps, ap); | 259 | DEBUGFS_DEL(num_sta_ps, ap); |
284 | DEBUGFS_DEL(dtim_period, ap); | ||
285 | DEBUGFS_DEL(dtim_count, ap); | 260 | DEBUGFS_DEL(dtim_count, ap); |
286 | DEBUGFS_DEL(num_beacons, ap); | 261 | DEBUGFS_DEL(num_beacons, ap); |
287 | DEBUGFS_DEL(force_unicast_rateidx, ap); | 262 | DEBUGFS_DEL(force_unicast_rateidx, ap); |
288 | DEBUGFS_DEL(max_ratectrl_rateidx, ap); | 263 | DEBUGFS_DEL(max_ratectrl_rateidx, ap); |
289 | DEBUGFS_DEL(num_buffered_multicast, ap); | 264 | DEBUGFS_DEL(num_buffered_multicast, ap); |
290 | DEBUGFS_DEL(beacon_head_len, ap); | ||
291 | DEBUGFS_DEL(beacon_tail_len, ap); | ||
292 | } | 265 | } |
293 | 266 | ||
294 | static void del_wds_files(struct ieee80211_sub_if_data *sdata) | 267 | static void del_wds_files(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index c9981701ef68..859682eee547 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -321,10 +321,17 @@ static int ieee80211_stop(struct net_device *dev) | |||
321 | 321 | ||
322 | dev_mc_unsync(local->mdev, dev); | 322 | dev_mc_unsync(local->mdev, dev); |
323 | 323 | ||
324 | /* down all dependent devices, that is VLANs */ | 324 | /* APs need special treatment */ |
325 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { | 325 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { |
326 | struct ieee80211_sub_if_data *vlan, *tmp; | 326 | struct ieee80211_sub_if_data *vlan, *tmp; |
327 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | ||
327 | 328 | ||
329 | /* remove beacon */ | ||
330 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | ||
331 | synchronize_rcu(); | ||
332 | kfree(old_beacon); | ||
333 | |||
334 | /* down all dependent devices, that is VLANs */ | ||
328 | list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, | 335 | list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, |
329 | u.vlan.list) | 336 | u.vlan.list) |
330 | dev_close(vlan->dev); | 337 | dev_close(vlan->dev); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 91edaad4c620..08a6c0cff690 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -190,9 +190,14 @@ typedef ieee80211_txrx_result (*ieee80211_tx_handler) | |||
190 | typedef ieee80211_txrx_result (*ieee80211_rx_handler) | 190 | typedef ieee80211_txrx_result (*ieee80211_rx_handler) |
191 | (struct ieee80211_txrx_data *rx); | 191 | (struct ieee80211_txrx_data *rx); |
192 | 192 | ||
193 | struct beacon_data { | ||
194 | u8 *head, *tail; | ||
195 | int head_len, tail_len; | ||
196 | int dtim_period; | ||
197 | }; | ||
198 | |||
193 | struct ieee80211_if_ap { | 199 | struct ieee80211_if_ap { |
194 | u8 *beacon_head, *beacon_tail; | 200 | struct beacon_data *beacon; |
195 | int beacon_head_len, beacon_tail_len; | ||
196 | 201 | ||
197 | struct list_head vlans; | 202 | struct list_head vlans; |
198 | 203 | ||
@@ -205,7 +210,7 @@ struct ieee80211_if_ap { | |||
205 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; | 210 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; |
206 | atomic_t num_sta_ps; /* number of stations in PS mode */ | 211 | atomic_t num_sta_ps; /* number of stations in PS mode */ |
207 | struct sk_buff_head ps_bc_buf; | 212 | struct sk_buff_head ps_bc_buf; |
208 | int dtim_period, dtim_count; | 213 | int dtim_count; |
209 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 214 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ |
210 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 215 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ |
211 | int num_beacons; /* number of TXed beacon frames for this BSS */ | 216 | int num_beacons; /* number of TXed beacon frames for this BSS */ |
@@ -360,14 +365,11 @@ struct ieee80211_sub_if_data { | |||
360 | struct dentry *drop_unencrypted; | 365 | struct dentry *drop_unencrypted; |
361 | struct dentry *ieee802_1x_pac; | 366 | struct dentry *ieee802_1x_pac; |
362 | struct dentry *num_sta_ps; | 367 | struct dentry *num_sta_ps; |
363 | struct dentry *dtim_period; | ||
364 | struct dentry *dtim_count; | 368 | struct dentry *dtim_count; |
365 | struct dentry *num_beacons; | 369 | struct dentry *num_beacons; |
366 | struct dentry *force_unicast_rateidx; | 370 | struct dentry *force_unicast_rateidx; |
367 | struct dentry *max_ratectrl_rateidx; | 371 | struct dentry *max_ratectrl_rateidx; |
368 | struct dentry *num_buffered_multicast; | 372 | struct dentry *num_buffered_multicast; |
369 | struct dentry *beacon_head_len; | ||
370 | struct dentry *beacon_tail_len; | ||
371 | } ap; | 373 | } ap; |
372 | struct { | 374 | struct { |
373 | struct dentry *channel_use; | 375 | struct dentry *channel_use; |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index be96aa84c79a..92f1eb2da311 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -126,7 +126,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
126 | sdata->u.vlan.ap = NULL; | 126 | sdata->u.vlan.ap = NULL; |
127 | break; | 127 | break; |
128 | case IEEE80211_IF_TYPE_AP: | 128 | case IEEE80211_IF_TYPE_AP: |
129 | sdata->u.ap.dtim_period = 2; | ||
130 | sdata->u.ap.force_unicast_rateidx = -1; | 129 | sdata->u.ap.force_unicast_rateidx = -1; |
131 | sdata->u.ap.max_ratectrl_rateidx = -1; | 130 | sdata->u.ap.max_ratectrl_rateidx = -1; |
132 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 131 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
@@ -207,8 +206,7 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
207 | } | 206 | } |
208 | } | 207 | } |
209 | 208 | ||
210 | kfree(sdata->u.ap.beacon_head); | 209 | kfree(sdata->u.ap.beacon); |
211 | kfree(sdata->u.ap.beacon_tail); | ||
212 | 210 | ||
213 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | 211 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { |
214 | local->total_ps_buffered--; | 212 | local->total_ps_buffered--; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 99590e4ce30b..51c0f00d02d1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1628,7 +1628,8 @@ void ieee80211_tx_pending(unsigned long data) | |||
1628 | 1628 | ||
1629 | static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | 1629 | static void ieee80211_beacon_add_tim(struct ieee80211_local *local, |
1630 | struct ieee80211_if_ap *bss, | 1630 | struct ieee80211_if_ap *bss, |
1631 | struct sk_buff *skb) | 1631 | struct sk_buff *skb, |
1632 | struct beacon_data *beacon) | ||
1632 | { | 1633 | { |
1633 | u8 *pos, *tim; | 1634 | u8 *pos, *tim; |
1634 | int aid0 = 0; | 1635 | int aid0 = 0; |
@@ -1644,7 +1645,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1644 | IEEE80211_MAX_AID+1); | 1645 | IEEE80211_MAX_AID+1); |
1645 | 1646 | ||
1646 | if (bss->dtim_count == 0) | 1647 | if (bss->dtim_count == 0) |
1647 | bss->dtim_count = bss->dtim_period - 1; | 1648 | bss->dtim_count = beacon->dtim_period - 1; |
1648 | else | 1649 | else |
1649 | bss->dtim_count--; | 1650 | bss->dtim_count--; |
1650 | 1651 | ||
@@ -1652,7 +1653,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1652 | *pos++ = WLAN_EID_TIM; | 1653 | *pos++ = WLAN_EID_TIM; |
1653 | *pos++ = 4; | 1654 | *pos++ = 4; |
1654 | *pos++ = bss->dtim_count; | 1655 | *pos++ = bss->dtim_count; |
1655 | *pos++ = bss->dtim_period; | 1656 | *pos++ = beacon->dtim_period; |
1656 | 1657 | ||
1657 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) | 1658 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) |
1658 | aid0 = 1; | 1659 | aid0 = 1; |
@@ -1700,44 +1701,43 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1700 | struct ieee80211_sub_if_data *sdata = NULL; | 1701 | struct ieee80211_sub_if_data *sdata = NULL; |
1701 | struct ieee80211_if_ap *ap = NULL; | 1702 | struct ieee80211_if_ap *ap = NULL; |
1702 | struct rate_selection rsel; | 1703 | struct rate_selection rsel; |
1703 | u8 *b_head, *b_tail; | 1704 | struct beacon_data *beacon; |
1704 | int bh_len, bt_len; | 1705 | |
1706 | rcu_read_lock(); | ||
1705 | 1707 | ||
1706 | sdata = vif_to_sdata(vif); | 1708 | sdata = vif_to_sdata(vif); |
1707 | bdev = sdata->dev; | 1709 | bdev = sdata->dev; |
1708 | ap = &sdata->u.ap; | 1710 | ap = &sdata->u.ap; |
1709 | 1711 | ||
1710 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || | 1712 | beacon = rcu_dereference(ap->beacon); |
1711 | !ap->beacon_head) { | 1713 | |
1714 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { | ||
1712 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1715 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1713 | if (net_ratelimit()) | 1716 | if (net_ratelimit()) |
1714 | printk(KERN_DEBUG "no beacon data avail for %s\n", | 1717 | printk(KERN_DEBUG "no beacon data avail for %s\n", |
1715 | bdev->name); | 1718 | bdev->name); |
1716 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 1719 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
1717 | return NULL; | 1720 | skb = NULL; |
1721 | goto out; | ||
1718 | } | 1722 | } |
1719 | 1723 | ||
1720 | /* Assume we are generating the normal beacon locally */ | 1724 | /* headroom, head length, tail length and maximum TIM length */ |
1721 | b_head = ap->beacon_head; | 1725 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
1722 | b_tail = ap->beacon_tail; | 1726 | beacon->tail_len + 256); |
1723 | bh_len = ap->beacon_head_len; | ||
1724 | bt_len = ap->beacon_tail_len; | ||
1725 | |||
1726 | skb = dev_alloc_skb(local->tx_headroom + | ||
1727 | bh_len + bt_len + 256 /* maximum TIM len */); | ||
1728 | if (!skb) | 1727 | if (!skb) |
1729 | return NULL; | 1728 | goto out; |
1730 | 1729 | ||
1731 | skb_reserve(skb, local->tx_headroom); | 1730 | skb_reserve(skb, local->tx_headroom); |
1732 | memcpy(skb_put(skb, bh_len), b_head, bh_len); | 1731 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
1732 | beacon->head_len); | ||
1733 | 1733 | ||
1734 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | 1734 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); |
1735 | 1735 | ||
1736 | ieee80211_beacon_add_tim(local, ap, skb); | 1736 | ieee80211_beacon_add_tim(local, ap, skb, beacon); |
1737 | 1737 | ||
1738 | if (b_tail) { | 1738 | if (beacon->tail) |
1739 | memcpy(skb_put(skb, bt_len), b_tail, bt_len); | 1739 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, |
1740 | } | 1740 | beacon->tail_len); |
1741 | 1741 | ||
1742 | if (control) { | 1742 | if (control) { |
1743 | rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, | 1743 | rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, |
@@ -1749,7 +1749,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1749 | wiphy_name(local->hw.wiphy)); | 1749 | wiphy_name(local->hw.wiphy)); |
1750 | } | 1750 | } |
1751 | dev_kfree_skb(skb); | 1751 | dev_kfree_skb(skb); |
1752 | return NULL; | 1752 | skb = NULL; |
1753 | goto out; | ||
1753 | } | 1754 | } |
1754 | 1755 | ||
1755 | control->tx_rate = | 1756 | control->tx_rate = |
@@ -1764,6 +1765,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1764 | } | 1765 | } |
1765 | 1766 | ||
1766 | ap->num_beacons++; | 1767 | ap->num_beacons++; |
1768 | |||
1769 | out: | ||
1770 | rcu_read_unlock(); | ||
1767 | return skb; | 1771 | return skb; |
1768 | } | 1772 | } |
1769 | EXPORT_SYMBOL(ieee80211_beacon_get); | 1773 | EXPORT_SYMBOL(ieee80211_beacon_get); |
@@ -1815,13 +1819,24 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1815 | struct net_device *bdev; | 1819 | struct net_device *bdev; |
1816 | struct ieee80211_sub_if_data *sdata; | 1820 | struct ieee80211_sub_if_data *sdata; |
1817 | struct ieee80211_if_ap *bss = NULL; | 1821 | struct ieee80211_if_ap *bss = NULL; |
1822 | struct beacon_data *beacon; | ||
1818 | 1823 | ||
1819 | sdata = vif_to_sdata(vif); | 1824 | sdata = vif_to_sdata(vif); |
1820 | bdev = sdata->dev; | 1825 | bdev = sdata->dev; |
1821 | 1826 | ||
1822 | if (!bss || sdata->vif.type != IEEE80211_IF_TYPE_AP || | 1827 | |
1823 | !bss->beacon_head) | 1828 | if (!bss) |
1829 | return NULL; | ||
1830 | |||
1831 | rcu_read_lock(); | ||
1832 | beacon = rcu_dereference(bss->beacon); | ||
1833 | |||
1834 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || | ||
1835 | !beacon->head) { | ||
1836 | rcu_read_unlock(); | ||
1824 | return NULL; | 1837 | return NULL; |
1838 | } | ||
1839 | rcu_read_unlock(); | ||
1825 | 1840 | ||
1826 | if (bss->dtim_count != 0) | 1841 | if (bss->dtim_count != 0) |
1827 | return NULL; /* send buffered bc/mc only after DTIM beacon */ | 1842 | return NULL; /* send buffered bc/mc only after DTIM beacon */ |