aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
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/mac80211/cfg.c
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/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c156
1 files changed, 156 insertions, 0 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};