aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-12-18 20:03:33 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:09:38 -0500
commit5dfdaf58d61f06a458529430c24b1191ea4d1a27 (patch)
treebd3fac57f66e80bf2a31d253af19093f4020ba79 /net
parent51fb61e76d952e6bc2fbdd9f0d38425fbab1cf31 (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.c156
-rw-r--r--net/mac80211/debugfs_netdev.c27
-rw-r--r--net/mac80211/ieee80211.c9
-rw-r--r--net/mac80211/ieee80211_i.h14
-rw-r--r--net/mac80211/ieee80211_iface.c4
-rw-r--r--net/mac80211/tx.c65
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 */
301static 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
396static 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
413static 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
430static 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
297struct cfg80211_ops mac80211_config_ops = { 450struct 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 */
126IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 126IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
127IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
128IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 127IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
129IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); 128IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
130IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); 129IEEE80211_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
141static 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
151static 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 */
162IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 141IEEE80211_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
205static void add_wds_files(struct ieee80211_sub_if_data *sdata) 181static 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
294static void del_wds_files(struct ieee80211_sub_if_data *sdata) 267static 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)
190typedef ieee80211_txrx_result (*ieee80211_rx_handler) 190typedef ieee80211_txrx_result (*ieee80211_rx_handler)
191(struct ieee80211_txrx_data *rx); 191(struct ieee80211_txrx_data *rx);
192 192
193struct beacon_data {
194 u8 *head, *tail;
195 int head_len, tail_len;
196 int dtim_period;
197};
198
193struct ieee80211_if_ap { 199struct 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
1629static void ieee80211_beacon_add_tim(struct ieee80211_local *local, 1629static 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}
1769EXPORT_SYMBOL(ieee80211_beacon_get); 1773EXPORT_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 */