package uuidgen
[openwrt.git] / package / mac80211 / patches / 021-mac80211-beacon-via-nl80211.patch
1 Subject: mac80211: add beacon configuration via cfg80211
2
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.
7
8 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
9
10 ---
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
15 operation.
16
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(-)
23
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
28 @@ -9,6 +9,7 @@
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"
35 #include "cfg.h"
36 @@ -274,6 +275,158 @@
37 return 0;
38 }
39
40 +/*
41 + * This handles both adding a beacon and setting new beacon info
42 + */
43 +static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
44 + struct beacon_parameters *params)
45 +{
46 + struct beacon_data *new, *old;
47 + int new_head_len, new_tail_len;
48 + int size;
49 + int err = -EINVAL;
50 +
51 + old = sdata->u.ap.beacon;
52 +
53 + /* head must not be zero-length */
54 + if (params->head && !params->head_len)
55 + return -EINVAL;
56 +
57 + /*
58 + * This is a kludge. beacon interval should really be part
59 + * of the beacon information.
60 + */
61 + if (params->interval) {
62 + sdata->local->hw.conf.beacon_int = params->interval;
63 + if (ieee80211_hw_config(sdata->local))
64 + return -EINVAL;
65 + /*
66 + * We updated some parameter so if below bails out
67 + * it's not an error.
68 + */
69 + err = 0;
70 + }
71 +
72 + /* Need to have a beacon head if we don't have one yet */
73 + if (!params->head && !old)
74 + return err;
75 +
76 + /* sorry, no way to start beaconing without dtim period */
77 + if (!params->dtim_period && !old)
78 + return err;
79 +
80 + /* new or old head? */
81 + if (params->head)
82 + new_head_len = params->head_len;
83 + else
84 + new_head_len = old->head_len;
85 +
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;
90 + else
91 + new_tail_len = old->tail_len;
92 +
93 + size = sizeof(*new) + new_head_len + new_tail_len;
94 +
95 + new = kzalloc(size, GFP_KERNEL);
96 + if (!new)
97 + return -ENOMEM;
98 +
99 + /* start filling the new info now */
100 +
101 + /* new or old dtim period? */
102 + if (params->dtim_period)
103 + new->dtim_period = params->dtim_period;
104 + else
105 + new->dtim_period = old->dtim_period;
106 +
107 + /*
108 + * pointers go into the block we allocated,
109 + * memory is | beacon_data | head | tail |
110 + */
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;
115 +
116 + /* copy in head */
117 + if (params->head)
118 + memcpy(new->head, params->head, new_head_len);
119 + else
120 + memcpy(new->head, old->head, new_head_len);
121 +
122 + /* copy in optional tail */
123 + if (params->tail)
124 + memcpy(new->tail, params->tail, new_tail_len);
125 + else
126 + if (old)
127 + memcpy(new->tail, old->tail, new_tail_len);
128 +
129 + rcu_assign_pointer(sdata->u.ap.beacon, new);
130 +
131 + synchronize_rcu();
132 +
133 + kfree(old);
134 +
135 + return ieee80211_if_config_beacon(sdata->dev);
136 +}
137 +
138 +static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
139 + struct beacon_parameters *params)
140 +{
141 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
142 + struct beacon_data *old;
143 +
144 + if (sdata->type != IEEE80211_IF_TYPE_AP)
145 + return -EINVAL;
146 +
147 + old = sdata->u.ap.beacon;
148 +
149 + if (old)
150 + return -EALREADY;
151 +
152 + return ieee80211_config_beacon(sdata, params);
153 +}
154 +
155 +static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
156 + struct beacon_parameters *params)
157 +{
158 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
159 + struct beacon_data *old;
160 +
161 + if (sdata->type != IEEE80211_IF_TYPE_AP)
162 + return -EINVAL;
163 +
164 + old = sdata->u.ap.beacon;
165 +
166 + if (!old)
167 + return -ENOENT;
168 +
169 + return ieee80211_config_beacon(sdata, params);
170 +}
171 +
172 +static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
173 +{
174 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
175 + struct beacon_data *old;
176 +
177 + if (sdata->type != IEEE80211_IF_TYPE_AP)
178 + return -EINVAL;
179 +
180 + old = sdata->u.ap.beacon;
181 +
182 + if (!old)
183 + return -ENOENT;
184 +
185 + rcu_assign_pointer(sdata->u.ap.beacon, NULL);
186 + synchronize_rcu();
187 + kfree(old);
188 +
189 + return ieee80211_if_config_beacon(dev);
190 +}
191 +
192 struct cfg80211_ops mac80211_config_ops = {
193 .add_virtual_intf = ieee80211_add_iface,
194 .del_virtual_intf = ieee80211_del_iface,
195 @@ -282,4 +435,7 @@
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,
202 };
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
207 @@ -124,7 +124,6 @@
208
209 /* AP attributes */
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);
215 @@ -138,26 +137,6 @@
216 }
217 __IEEE80211_IF_FILE(num_buffered_multicast);
218
219 -static ssize_t ieee80211_if_fmt_beacon_head_len(
220 - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
221 -{
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");
226 -}
227 -__IEEE80211_IF_FILE(beacon_head_len);
228 -
229 -static ssize_t ieee80211_if_fmt_beacon_tail_len(
230 - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
231 -{
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");
236 -}
237 -__IEEE80211_IF_FILE(beacon_tail_len);
238 -
239 /* WDS attributes */
240 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
241
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);
254 }
255
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);
269 }
270
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
276 @@ -190,9 +190,14 @@
277 typedef ieee80211_txrx_result (*ieee80211_rx_handler)
278 (struct ieee80211_txrx_data *rx);
279
280 +struct beacon_data {
281 + u8 *head, *tail;
282 + int head_len, tail_len;
283 + int dtim_period;
284 +};
285 +
286 struct ieee80211_if_ap {
287 - u8 *beacon_head, *beacon_tail;
288 - int beacon_head_len, beacon_tail_len;
289 + struct beacon_data *beacon;
290
291 struct list_head vlans;
292
293 @@ -205,7 +210,7 @@
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;
298 + int 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;
314 } ap;
315 struct {
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
321 @@ -187,7 +187,6 @@
322 sdata->u.vlan.ap = NULL;
323 break;
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);
329 @@ -271,8 +270,7 @@
330 }
331 }
332
333 - kfree(sdata->u.ap.beacon_head);
334 - kfree(sdata->u.ap.beacon_tail);
335 + kfree(sdata->u.ap.beacon);
336
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 @@
344
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)
350 {
351 u8 *pos, *tim;
352 int aid0 = 0;
353 @@ -1672,7 +1673,7 @@
354 IEEE80211_MAX_AID+1);
355
356 if (bss->dtim_count == 0)
357 - bss->dtim_count = bss->dtim_period - 1;
358 + bss->dtim_count = beacon->dtim_period - 1;
359 else
360 bss->dtim_count--;
361
362 @@ -1680,7 +1681,7 @@
363 *pos++ = WLAN_EID_TIM;
364 *pos++ = 4;
365 *pos++ = bss->dtim_count;
366 - *pos++ = bss->dtim_period;
367 + *pos++ = beacon->dtim_period;
368
369 if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
370 aid0 = 1;
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;
378 +
379 + rcu_read_lock();
380
381 bdev = dev_get_by_index(if_id);
382 if (bdev) {
383 @@ -1738,37 +1740,35 @@
384 dev_put(bdev);
385 }
386
387 - if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
388 - !ap->beacon_head) {
389 + beacon = rcu_dereference(ap->beacon);
390 +
391 + if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) {
392 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
393 if (net_ratelimit())
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 */
397 - return NULL;
398 + skb = NULL;
399 + goto out;
400 }
401
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;
407 -
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);
413 if (!skb)
414 - return NULL;
415 + goto out;
416
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,
420 + beacon->head_len);
421
422 ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
423
424 - ieee80211_beacon_add_tim(local, ap, skb);
425 + ieee80211_beacon_add_tim(local, ap, skb, beacon);
426
427 - if (b_tail) {
428 - memcpy(skb_put(skb, bt_len), b_tail, bt_len);
429 - }
430 + if (beacon->tail)
431 + memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
432 + beacon->tail_len);
433
434 if (control) {
435 memset(&extra, 0, sizeof(extra));
436 @@ -1781,7 +1781,8 @@
437 "found\n", wiphy_name(local->hw.wiphy));
438 }
439 dev_kfree_skb(skb);
440 - return NULL;
441 + skb = NULL;
442 + goto out;
443 }
444
445 control->tx_rate =
446 @@ -1796,6 +1797,9 @@
447 }
448
449 ap->num_beacons++;
450 +
451 + out:
452 + rcu_read_unlock();
453 return skb;
454 }
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;
461
462 bdev = dev_get_by_index(if_id);
463 if (bdev) {
464 @@ -1851,9 +1856,19 @@
465 bss = &sdata->u.ap;
466 dev_put(bdev);
467 }
468 - if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
469 +
470 + if (!bss)
471 return NULL;
472
473 + rcu_read_lock();
474 + beacon = rcu_dereference(bss->beacon);
475 +
476 + if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) {
477 + rcu_read_unlock();
478 + return NULL;
479 + }
480 + rcu_read_unlock();
481 +
482 if (bss->dtim_count != 0)
483 return NULL; /* send buffered bc/mc only after DTIM beacon */
484 memset(control, 0, sizeof(*control));
This page took 0.060906 seconds and 5 git commands to generate.