1 Subject: mac80211: add beacon configuration via cfg80211
3 This patch implements the cfg80211 hooks for configuring beaconing
4 on an access point interface in mac80211. While doing so, it fixes
5 a number of races that could badly crash the machine when the
6 beacon is changed while being requested by the driver.
8 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
11 The dtim_count field should possibly also be part of the beacon
12 structure, but the possible race there doesn't really matter,
13 worst thing is that one beacon will be sent with a wrong dtim
14 count if (and only if) userspace changes the dtim period during
17 net/mac80211/cfg.c | 156 +++++++++++++++++++++++++++++++++++++++++
18 net/mac80211/debugfs_netdev.c | 27 -------
19 net/mac80211/ieee80211_i.h | 14 ++-
20 net/mac80211/ieee80211_iface.c | 4 -
21 net/mac80211/tx.c | 63 ++++++++++------
22 5 files changed, 204 insertions(+), 60 deletions(-)
24 Index: mac80211/net/mac80211/cfg.c
25 ===================================================================
26 --- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:17:12.837164411 +0100
27 +++ mac80211/net/mac80211/cfg.c 2007-11-11 15:18:36.853952256 +0100
29 #include <linux/ieee80211.h>
30 #include <linux/nl80211.h>
31 #include <linux/rtnetlink.h>
32 +#include <linux/rcupdate.h>
33 #include <net/cfg80211.h>
34 #include "ieee80211_i.h"
41 + * This handles both adding a beacon and setting new beacon info
43 +static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
44 + struct beacon_parameters *params)
46 + struct beacon_data *new, *old;
47 + int new_head_len, new_tail_len;
51 + old = sdata->u.ap.beacon;
53 + /* head must not be zero-length */
54 + if (params->head && !params->head_len)
58 + * This is a kludge. beacon interval should really be part
59 + * of the beacon information.
61 + if (params->interval) {
62 + sdata->local->hw.conf.beacon_int = params->interval;
63 + if (ieee80211_hw_config(sdata->local))
66 + * We updated some parameter so if below bails out
67 + * it's not an error.
72 + /* Need to have a beacon head if we don't have one yet */
73 + if (!params->head && !old)
76 + /* sorry, no way to start beaconing without dtim period */
77 + if (!params->dtim_period && !old)
80 + /* new or old head? */
82 + new_head_len = params->head_len;
84 + new_head_len = old->head_len;
86 + /* new or old tail? */
87 + if (params->tail || !old)
88 + /* params->tail_len will be zero for !params->tail */
89 + new_tail_len = params->tail_len;
91 + new_tail_len = old->tail_len;
93 + size = sizeof(*new) + new_head_len + new_tail_len;
95 + new = kzalloc(size, GFP_KERNEL);
99 + /* start filling the new info now */
101 + /* new or old dtim period? */
102 + if (params->dtim_period)
103 + new->dtim_period = params->dtim_period;
105 + new->dtim_period = old->dtim_period;
108 + * pointers go into the block we allocated,
109 + * memory is | beacon_data | head | tail |
111 + new->head = ((u8 *) new) + sizeof(*new);
112 + new->tail = new->head + new_head_len;
113 + new->head_len = new_head_len;
114 + new->tail_len = new_tail_len;
118 + memcpy(new->head, params->head, new_head_len);
120 + memcpy(new->head, old->head, new_head_len);
122 + /* copy in optional tail */
124 + memcpy(new->tail, params->tail, new_tail_len);
127 + memcpy(new->tail, old->tail, new_tail_len);
129 + rcu_assign_pointer(sdata->u.ap.beacon, new);
135 + return ieee80211_if_config_beacon(sdata->dev);
138 +static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
139 + struct beacon_parameters *params)
141 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
142 + struct beacon_data *old;
144 + if (sdata->type != IEEE80211_IF_TYPE_AP)
147 + old = sdata->u.ap.beacon;
152 + return ieee80211_config_beacon(sdata, params);
155 +static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
156 + struct beacon_parameters *params)
158 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
159 + struct beacon_data *old;
161 + if (sdata->type != IEEE80211_IF_TYPE_AP)
164 + old = sdata->u.ap.beacon;
169 + return ieee80211_config_beacon(sdata, params);
172 +static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
174 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
175 + struct beacon_data *old;
177 + if (sdata->type != IEEE80211_IF_TYPE_AP)
180 + old = sdata->u.ap.beacon;
185 + rcu_assign_pointer(sdata->u.ap.beacon, NULL);
189 + return ieee80211_if_config_beacon(dev);
192 struct cfg80211_ops mac80211_config_ops = {
193 .add_virtual_intf = ieee80211_add_iface,
194 .del_virtual_intf = ieee80211_del_iface,
196 .del_key = ieee80211_del_key,
197 .get_key = ieee80211_get_key,
198 .set_default_key = ieee80211_config_default_key,
199 + .add_beacon = ieee80211_add_beacon,
200 + .set_beacon = ieee80211_set_beacon,
201 + .del_beacon = ieee80211_del_beacon,
203 Index: mac80211/net/mac80211/debugfs_netdev.c
204 ===================================================================
205 --- mac80211.orig/net/mac80211/debugfs_netdev.c 2007-10-14 00:42:30.054156000 +0200
206 +++ mac80211/net/mac80211/debugfs_netdev.c 2007-11-11 15:18:11.852527505 +0100
210 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
211 -IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
212 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
213 IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
214 IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
217 __IEEE80211_IF_FILE(num_buffered_multicast);
219 -static ssize_t ieee80211_if_fmt_beacon_head_len(
220 - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
222 - if (sdata->u.ap.beacon_head)
223 - return scnprintf(buf, buflen, "%d\n",
224 - sdata->u.ap.beacon_head_len);
225 - return scnprintf(buf, buflen, "\n");
227 -__IEEE80211_IF_FILE(beacon_head_len);
229 -static ssize_t ieee80211_if_fmt_beacon_tail_len(
230 - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
232 - if (sdata->u.ap.beacon_tail)
233 - return scnprintf(buf, buflen, "%d\n",
234 - sdata->u.ap.beacon_tail_len);
235 - return scnprintf(buf, buflen, "\n");
237 -__IEEE80211_IF_FILE(beacon_tail_len);
240 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
242 @@ -194,14 +173,11 @@
243 DEBUGFS_ADD(eapol, ap);
244 DEBUGFS_ADD(ieee8021_x, ap);
245 DEBUGFS_ADD(num_sta_ps, ap);
246 - DEBUGFS_ADD(dtim_period, ap);
247 DEBUGFS_ADD(dtim_count, ap);
248 DEBUGFS_ADD(num_beacons, ap);
249 DEBUGFS_ADD(force_unicast_rateidx, ap);
250 DEBUGFS_ADD(max_ratectrl_rateidx, ap);
251 DEBUGFS_ADD(num_buffered_multicast, ap);
252 - DEBUGFS_ADD(beacon_head_len, ap);
253 - DEBUGFS_ADD(beacon_tail_len, ap);
256 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
257 @@ -287,14 +263,11 @@
258 DEBUGFS_DEL(eapol, ap);
259 DEBUGFS_DEL(ieee8021_x, ap);
260 DEBUGFS_DEL(num_sta_ps, ap);
261 - DEBUGFS_DEL(dtim_period, ap);
262 DEBUGFS_DEL(dtim_count, ap);
263 DEBUGFS_DEL(num_beacons, ap);
264 DEBUGFS_DEL(force_unicast_rateidx, ap);
265 DEBUGFS_DEL(max_ratectrl_rateidx, ap);
266 DEBUGFS_DEL(num_buffered_multicast, ap);
267 - DEBUGFS_DEL(beacon_head_len, ap);
268 - DEBUGFS_DEL(beacon_tail_len, ap);
271 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
272 Index: mac80211/net/mac80211/ieee80211_i.h
273 ===================================================================
274 --- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100
275 +++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:18:11.864528190 +0100
277 typedef ieee80211_txrx_result (*ieee80211_rx_handler)
278 (struct ieee80211_txrx_data *rx);
280 +struct beacon_data {
282 + int head_len, tail_len;
286 struct ieee80211_if_ap {
287 - u8 *beacon_head, *beacon_tail;
288 - int beacon_head_len, beacon_tail_len;
289 + struct beacon_data *beacon;
291 struct list_head vlans;
294 u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
295 atomic_t num_sta_ps; /* number of stations in PS mode */
296 struct sk_buff_head ps_bc_buf;
297 - int dtim_period, dtim_count;
299 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
300 int max_ratectrl_rateidx; /* max TX rateidx for rate control */
301 int num_beacons; /* number of TXed beacon frames for this BSS */
302 @@ -361,14 +366,11 @@
303 struct dentry *eapol;
304 struct dentry *ieee8021_x;
305 struct dentry *num_sta_ps;
306 - struct dentry *dtim_period;
307 struct dentry *dtim_count;
308 struct dentry *num_beacons;
309 struct dentry *force_unicast_rateidx;
310 struct dentry *max_ratectrl_rateidx;
311 struct dentry *num_buffered_multicast;
312 - struct dentry *beacon_head_len;
313 - struct dentry *beacon_tail_len;
316 struct dentry *channel_use;
317 Index: mac80211/net/mac80211/ieee80211_iface.c
318 ===================================================================
319 --- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100
320 +++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:18:11.868528415 +0100
322 sdata->u.vlan.ap = NULL;
324 case IEEE80211_IF_TYPE_AP:
325 - sdata->u.ap.dtim_period = 2;
326 sdata->u.ap.force_unicast_rateidx = -1;
327 sdata->u.ap.max_ratectrl_rateidx = -1;
328 skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
333 - kfree(sdata->u.ap.beacon_head);
334 - kfree(sdata->u.ap.beacon_tail);
335 + kfree(sdata->u.ap.beacon);
337 while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
338 local->total_ps_buffered--;
339 Index: mac80211/net/mac80211/tx.c
340 ===================================================================
341 --- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100
342 +++ mac80211/net/mac80211/tx.c 2007-11-11 15:18:11.868528415 +0100
343 @@ -1656,7 +1656,8 @@
345 static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
346 struct ieee80211_if_ap *bss,
347 - struct sk_buff *skb)
348 + struct sk_buff *skb,
349 + struct beacon_data *beacon)
353 @@ -1672,7 +1673,7 @@
354 IEEE80211_MAX_AID+1);
356 if (bss->dtim_count == 0)
357 - bss->dtim_count = bss->dtim_period - 1;
358 + bss->dtim_count = beacon->dtim_period - 1;
362 @@ -1680,7 +1681,7 @@
363 *pos++ = WLAN_EID_TIM;
365 *pos++ = bss->dtim_count;
366 - *pos++ = bss->dtim_period;
367 + *pos++ = beacon->dtim_period;
369 if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
371 @@ -1728,8 +1729,9 @@
372 struct ieee80211_if_ap *ap = NULL;
373 struct ieee80211_rate *rate;
374 struct rate_control_extra extra;
375 - u8 *b_head, *b_tail;
376 - int bh_len, bt_len;
377 + struct beacon_data *beacon;
381 bdev = dev_get_by_index(if_id);
383 @@ -1738,37 +1740,35 @@
387 - if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
388 - !ap->beacon_head) {
389 + beacon = rcu_dereference(ap->beacon);
391 + if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) {
392 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
394 printk(KERN_DEBUG "no beacon data avail for idx=%d "
395 "(%s)\n", if_id, bdev ? bdev->name : "N/A");
396 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
402 - /* Assume we are generating the normal beacon locally */
403 - b_head = ap->beacon_head;
404 - b_tail = ap->beacon_tail;
405 - bh_len = ap->beacon_head_len;
406 - bt_len = ap->beacon_tail_len;
408 - skb = dev_alloc_skb(local->tx_headroom +
409 - bh_len + bt_len + 256 /* maximum TIM len */);
410 + /* headroom, head length, tail length and maximum TIM length */
411 + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
412 + beacon->tail_len + 256);
417 skb_reserve(skb, local->tx_headroom);
418 - memcpy(skb_put(skb, bh_len), b_head, bh_len);
419 + memcpy(skb_put(skb, beacon->head_len), beacon->head,
422 ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
424 - ieee80211_beacon_add_tim(local, ap, skb);
425 + ieee80211_beacon_add_tim(local, ap, skb, beacon);
428 - memcpy(skb_put(skb, bt_len), b_tail, bt_len);
431 + memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
435 memset(&extra, 0, sizeof(extra));
436 @@ -1781,7 +1781,8 @@
437 "found\n", wiphy_name(local->hw.wiphy));
446 @@ -1796,6 +1797,9 @@
455 EXPORT_SYMBOL(ieee80211_beacon_get);
456 @@ -1844,6 +1848,7 @@
457 struct net_device *bdev;
458 struct ieee80211_sub_if_data *sdata;
459 struct ieee80211_if_ap *bss = NULL;
460 + struct beacon_data *beacon;
462 bdev = dev_get_by_index(if_id);
464 @@ -1851,9 +1856,19 @@
468 - if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
474 + beacon = rcu_dereference(bss->beacon);
476 + if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) {
482 if (bss->dtim_count != 0)
483 return NULL; /* send buffered bc/mc only after DTIM beacon */
484 memset(control, 0, sizeof(*control));