fix up hostapd for mac80211
[librecmc/librecmc.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));