aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c82
-rw-r--r--include/linux/nl80211.h34
-rw-r--r--include/net/cfg80211.h70
-rw-r--r--net/mac80211/cfg.c146
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/tx.c13
-rw-r--r--net/wireless/nl80211.c255
7 files changed, 316 insertions, 286 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d1922d8eb3bb..5370333883e4 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2269,25 +2269,11 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2269 return ret; 2269 return ret;
2270} 2270}
2271 2271
2272static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, 2272static int ath6kl_set_ies(struct ath6kl_vif *vif,
2273 struct beacon_parameters *info, bool add) 2273 struct cfg80211_beacon_data *info)
2274{ 2274{
2275 struct ath6kl *ar = ath6kl_priv(dev); 2275 struct ath6kl *ar = vif->ar;
2276 struct ath6kl_vif *vif = netdev_priv(dev);
2277 struct ieee80211_mgmt *mgmt;
2278 u8 *ies;
2279 int ies_len;
2280 struct wmi_connect_cmd p;
2281 int res; 2276 int res;
2282 int i, ret;
2283
2284 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2285
2286 if (!ath6kl_cfg80211_ready(vif))
2287 return -EIO;
2288
2289 if (vif->next_mode != AP_NETWORK)
2290 return -EOPNOTSUPP;
2291 2277
2292 if (info->beacon_ies) { 2278 if (info->beacon_ies) {
2293 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, 2279 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
@@ -2297,12 +2283,14 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2297 if (res) 2283 if (res)
2298 return res; 2284 return res;
2299 } 2285 }
2286
2300 if (info->proberesp_ies) { 2287 if (info->proberesp_ies) {
2301 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, 2288 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
2302 info->proberesp_ies_len); 2289 info->proberesp_ies_len);
2303 if (res) 2290 if (res)
2304 return res; 2291 return res;
2305 } 2292 }
2293
2306 if (info->assocresp_ies) { 2294 if (info->assocresp_ies) {
2307 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, 2295 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2308 WMI_FRAME_ASSOC_RESP, 2296 WMI_FRAME_ASSOC_RESP,
@@ -2312,8 +2300,30 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2312 return res; 2300 return res;
2313 } 2301 }
2314 2302
2315 if (!add) 2303 return 0;
2316 return 0; 2304}
2305
2306static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2307 struct cfg80211_ap_settings *info)
2308{
2309 struct ath6kl *ar = ath6kl_priv(dev);
2310 struct ath6kl_vif *vif = netdev_priv(dev);
2311 struct ieee80211_mgmt *mgmt;
2312 u8 *ies;
2313 int ies_len;
2314 struct wmi_connect_cmd p;
2315 int res;
2316 int i, ret;
2317
2318 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
2319
2320 if (!ath6kl_cfg80211_ready(vif))
2321 return -EIO;
2322
2323 if (vif->next_mode != AP_NETWORK)
2324 return -EOPNOTSUPP;
2325
2326 res = ath6kl_set_ies(vif, &info->beacon);
2317 2327
2318 ar->ap_mode_bkey.valid = false; 2328 ar->ap_mode_bkey.valid = false;
2319 2329
@@ -2322,13 +2332,13 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2322 * info->dtim_period 2332 * info->dtim_period
2323 */ 2333 */
2324 2334
2325 if (info->head == NULL) 2335 if (info->beacon.head == NULL)
2326 return -EINVAL; 2336 return -EINVAL;
2327 mgmt = (struct ieee80211_mgmt *) info->head; 2337 mgmt = (struct ieee80211_mgmt *) info->beacon.head;
2328 ies = mgmt->u.beacon.variable; 2338 ies = mgmt->u.beacon.variable;
2329 if (ies > info->head + info->head_len) 2339 if (ies > info->beacon.head + info->beacon.head_len)
2330 return -EINVAL; 2340 return -EINVAL;
2331 ies_len = info->head + info->head_len - ies; 2341 ies_len = info->beacon.head + info->beacon.head_len - ies;
2332 2342
2333 if (info->ssid == NULL) 2343 if (info->ssid == NULL)
2334 return -EINVAL; 2344 return -EINVAL;
@@ -2436,19 +2446,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2436 return 0; 2446 return 0;
2437} 2447}
2438 2448
2439static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, 2449static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
2440 struct beacon_parameters *info) 2450 struct cfg80211_beacon_data *beacon)
2441{ 2451{
2442 return ath6kl_ap_beacon(wiphy, dev, info, true); 2452 struct ath6kl_vif *vif = netdev_priv(dev);
2443}
2444 2453
2445static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, 2454 if (!ath6kl_cfg80211_ready(vif))
2446 struct beacon_parameters *info) 2455 return -EIO;
2447{ 2456
2448 return ath6kl_ap_beacon(wiphy, dev, info, false); 2457 if (vif->next_mode != AP_NETWORK)
2458 return -EOPNOTSUPP;
2459
2460 return ath6kl_set_ies(vif, beacon);
2449} 2461}
2450 2462
2451static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) 2463static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
2452{ 2464{
2453 struct ath6kl *ar = ath6kl_priv(dev); 2465 struct ath6kl *ar = ath6kl_priv(dev);
2454 struct ath6kl_vif *vif = netdev_priv(dev); 2466 struct ath6kl_vif *vif = netdev_priv(dev);
@@ -2783,9 +2795,9 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
2783 .resume = __ath6kl_cfg80211_resume, 2795 .resume = __ath6kl_cfg80211_resume,
2784#endif 2796#endif
2785 .set_channel = ath6kl_set_channel, 2797 .set_channel = ath6kl_set_channel,
2786 .add_beacon = ath6kl_add_beacon, 2798 .start_ap = ath6kl_start_ap,
2787 .set_beacon = ath6kl_set_beacon, 2799 .change_beacon = ath6kl_change_beacon,
2788 .del_beacon = ath6kl_del_beacon, 2800 .stop_ap = ath6kl_stop_ap,
2789 .del_station = ath6kl_del_station, 2801 .del_station = ath6kl_del_station,
2790 .change_station = ath6kl_change_station, 2802 .change_station = ath6kl_change_station,
2791 .remain_on_channel = ath6kl_remain_on_channel, 2803 .remain_on_channel = ath6kl_remain_on_channel,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ad56e21a9f10..be35a68746a7 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -156,21 +156,23 @@
156 * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX 156 * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
157 * or %NL80211_ATTR_MAC. 157 * or %NL80211_ATTR_MAC.
158 * 158 *
159 * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a 159 * @NL80211_CMD_GET_BEACON: (not used)
160 * %NL80222_CMD_NEW_BEACON message) 160 * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
161 * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface 161 * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
162 * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, 162 * attributes. For drivers that generate the beacon and probe responses
163 * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. 163 * internally, the following attributes must be provided: %NL80211_ATTR_IE,
164 * Following attributes are provided for drivers that generate full Beacon 164 * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
165 * and Probe Response frames internally: %NL80211_ATTR_SSID, 165 * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
166 * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
167 * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
168 * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
166 * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, 169 * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
167 * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, 170 * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
168 * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, 171 * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and
169 * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, 172 * %NL80211_ATTR_AUTH_TYPE.
170 * %NL80211_ATTR_IE_ASSOC_RESP. 173 * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
171 * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, 174 * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
172 * parameters are like for %NL80211_CMD_SET_BEACON. 175 * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
173 * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
174 * 176 *
175 * @NL80211_CMD_GET_STATION: Get station attributes for station identified by 177 * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
176 * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. 178 * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
@@ -565,8 +567,10 @@ enum nl80211_commands {
565 567
566 NL80211_CMD_GET_BEACON, 568 NL80211_CMD_GET_BEACON,
567 NL80211_CMD_SET_BEACON, 569 NL80211_CMD_SET_BEACON,
568 NL80211_CMD_NEW_BEACON, 570 NL80211_CMD_START_AP,
569 NL80211_CMD_DEL_BEACON, 571 NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
572 NL80211_CMD_STOP_AP,
573 NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
570 574
571 NL80211_CMD_GET_STATION, 575 NL80211_CMD_GET_STATION,
572 NL80211_CMD_SET_STATION, 576 NL80211_CMD_SET_STATION,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e0c9ff3a1977..755a7707a7c5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -366,25 +366,13 @@ struct cfg80211_crypto_settings {
366}; 366};
367 367
368/** 368/**
369 * struct beacon_parameters - beacon parameters 369 * struct cfg80211_beacon_data - beacon data
370 *
371 * Used to configure the beacon for an interface.
372 *
373 * @head: head portion of beacon (before TIM IE) 370 * @head: head portion of beacon (before TIM IE)
374 * or %NULL if not changed 371 * or %NULL if not changed
375 * @tail: tail portion of beacon (after TIM IE) 372 * @tail: tail portion of beacon (after TIM IE)
376 * or %NULL if not changed 373 * or %NULL if not changed
377 * @interval: beacon interval or zero if not changed
378 * @dtim_period: DTIM period or zero if not changed
379 * @head_len: length of @head 374 * @head_len: length of @head
380 * @tail_len: length of @tail 375 * @tail_len: length of @tail
381 * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
382 * user space)
383 * @ssid_len: length of @ssid
384 * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
385 * @crypto: crypto settings
386 * @privacy: the BSS uses privacy
387 * @auth_type: Authentication type (algorithm)
388 * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL 376 * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
389 * @beacon_ies_len: length of beacon_ies in octets 377 * @beacon_ies_len: length of beacon_ies in octets
390 * @proberesp_ies: extra information element(s) to add into Probe Response 378 * @proberesp_ies: extra information element(s) to add into Probe Response
@@ -396,24 +384,46 @@ struct cfg80211_crypto_settings {
396 * @probe_resp_len: length of probe response template (@probe_resp) 384 * @probe_resp_len: length of probe response template (@probe_resp)
397 * @probe_resp: probe response template (AP mode only) 385 * @probe_resp: probe response template (AP mode only)
398 */ 386 */
399struct beacon_parameters { 387struct cfg80211_beacon_data {
400 u8 *head, *tail; 388 const u8 *head, *tail;
401 int interval, dtim_period; 389 const u8 *beacon_ies;
402 int head_len, tail_len; 390 const u8 *proberesp_ies;
391 const u8 *assocresp_ies;
392 const u8 *probe_resp;
393
394 size_t head_len, tail_len;
395 size_t beacon_ies_len;
396 size_t proberesp_ies_len;
397 size_t assocresp_ies_len;
398 size_t probe_resp_len;
399};
400
401/**
402 * struct cfg80211_ap_settings - AP configuration
403 *
404 * Used to configure an AP interface.
405 *
406 * @beacon: beacon data
407 * @beacon_interval: beacon interval
408 * @dtim_period: DTIM period
409 * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
410 * user space)
411 * @ssid_len: length of @ssid
412 * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
413 * @crypto: crypto settings
414 * @privacy: the BSS uses privacy
415 * @auth_type: Authentication type (algorithm)
416 */
417struct cfg80211_ap_settings {
418 struct cfg80211_beacon_data beacon;
419
420 int beacon_interval, dtim_period;
403 const u8 *ssid; 421 const u8 *ssid;
404 size_t ssid_len; 422 size_t ssid_len;
405 enum nl80211_hidden_ssid hidden_ssid; 423 enum nl80211_hidden_ssid hidden_ssid;
406 struct cfg80211_crypto_settings crypto; 424 struct cfg80211_crypto_settings crypto;
407 bool privacy; 425 bool privacy;
408 enum nl80211_auth_type auth_type; 426 enum nl80211_auth_type auth_type;
409 const u8 *beacon_ies;
410 size_t beacon_ies_len;
411 const u8 *proberesp_ies;
412 size_t proberesp_ies_len;
413 const u8 *assocresp_ies;
414 size_t assocresp_ies_len;
415 int probe_resp_len;
416 u8 *probe_resp;
417}; 427};
418 428
419/** 429/**
@@ -1518,11 +1528,11 @@ struct cfg80211_ops {
1518 struct net_device *netdev, 1528 struct net_device *netdev,
1519 u8 key_index); 1529 u8 key_index);
1520 1530
1521 int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, 1531 int (*start_ap)(struct wiphy *wiphy, struct net_device *dev,
1522 struct beacon_parameters *info); 1532 struct cfg80211_ap_settings *settings);
1523 int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, 1533 int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
1524 struct beacon_parameters *info); 1534 struct cfg80211_beacon_data *info);
1525 int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); 1535 int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev);
1526 1536
1527 1537
1528 int (*add_station)(struct wiphy *wiphy, struct net_device *dev, 1538 int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c3de921c8cfd..f7eb25aabf8f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -489,27 +489,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
489 return ret; 489 return ret;
490} 490}
491 491
492static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
493 struct beacon_parameters *params)
494{
495 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
496
497 bss_conf->ssid_len = params->ssid_len;
498
499 if (params->ssid_len)
500 memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
501
502 bss_conf->hidden_ssid =
503 (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
504}
505
506static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, 492static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
507 u8 *resp, size_t resp_len) 493 const u8 *resp, size_t resp_len)
508{ 494{
509 struct sk_buff *new, *old; 495 struct sk_buff *new, *old;
510 496
511 if (!resp || !resp_len) 497 if (!resp || !resp_len)
512 return -EINVAL; 498 return 1;
513 499
514 old = rtnl_dereference(sdata->u.ap.probe_resp); 500 old = rtnl_dereference(sdata->u.ap.probe_resp);
515 501
@@ -520,50 +506,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
520 memcpy(skb_put(new, resp_len), resp, resp_len); 506 memcpy(skb_put(new, resp_len), resp, resp_len);
521 507
522 rcu_assign_pointer(sdata->u.ap.probe_resp, new); 508 rcu_assign_pointer(sdata->u.ap.probe_resp, new);
523 synchronize_rcu(); 509 if (old) {
524 510 /* TODO: use call_rcu() */
525 if (old) 511 synchronize_rcu();
526 dev_kfree_skb(old); 512 dev_kfree_skb(old);
513 }
527 514
528 return 0; 515 return 0;
529} 516}
530 517
531/* 518static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
532 * This handles both adding a beacon and setting new beacon info 519 struct cfg80211_beacon_data *params)
533 */
534static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
535 struct beacon_parameters *params)
536{ 520{
537 struct beacon_data *new, *old; 521 struct beacon_data *new, *old;
538 int new_head_len, new_tail_len; 522 int new_head_len, new_tail_len;
539 int size; 523 int size, err;
540 int err = -EINVAL; 524 u32 changed = BSS_CHANGED_BEACON;
541 u32 changed = 0;
542 525
543 old = rtnl_dereference(sdata->u.ap.beacon); 526 old = rtnl_dereference(sdata->u.ap.beacon);
544 527
545 /* head must not be zero-length */
546 if (params->head && !params->head_len)
547 return -EINVAL;
548
549 /*
550 * This is a kludge. beacon interval should really be part
551 * of the beacon information.
552 */
553 if (params->interval &&
554 (sdata->vif.bss_conf.beacon_int != params->interval)) {
555 sdata->vif.bss_conf.beacon_int = params->interval;
556 ieee80211_bss_info_change_notify(sdata,
557 BSS_CHANGED_BEACON_INT);
558 }
559
560 /* Need to have a beacon head if we don't have one yet */ 528 /* Need to have a beacon head if we don't have one yet */
561 if (!params->head && !old) 529 if (!params->head && !old)
562 return err; 530 return -EINVAL;
563
564 /* sorry, no way to start beaconing without dtim period */
565 if (!params->dtim_period && !old)
566 return err;
567 531
568 /* new or old head? */ 532 /* new or old head? */
569 if (params->head) 533 if (params->head)
@@ -586,12 +550,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
586 550
587 /* start filling the new info now */ 551 /* start filling the new info now */
588 552
589 /* new or old dtim period? */
590 if (params->dtim_period)
591 new->dtim_period = params->dtim_period;
592 else
593 new->dtim_period = old->dtim_period;
594
595 /* 553 /*
596 * pointers go into the block we allocated, 554 * pointers go into the block we allocated,
597 * memory is | beacon_data | head | tail | 555 * memory is | beacon_data | head | tail |
@@ -614,46 +572,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
614 if (old) 572 if (old)
615 memcpy(new->tail, old->tail, new_tail_len); 573 memcpy(new->tail, old->tail, new_tail_len);
616 574
617 sdata->vif.bss_conf.dtim_period = new->dtim_period;
618
619 rcu_assign_pointer(sdata->u.ap.beacon, new);
620
621 synchronize_rcu();
622
623 kfree(old);
624
625 err = ieee80211_set_probe_resp(sdata, params->probe_resp, 575 err = ieee80211_set_probe_resp(sdata, params->probe_resp,
626 params->probe_resp_len); 576 params->probe_resp_len);
627 if (!err) 577 if (err < 0)
578 return err;
579 if (err == 0)
628 changed |= BSS_CHANGED_AP_PROBE_RESP; 580 changed |= BSS_CHANGED_AP_PROBE_RESP;
629 581
630 ieee80211_config_ap_ssid(sdata, params); 582 rcu_assign_pointer(sdata->u.ap.beacon, new);
631 changed |= BSS_CHANGED_BEACON_ENABLED | 583
632 BSS_CHANGED_BEACON | 584 if (old)
633 BSS_CHANGED_SSID; 585 kfree_rcu(old, rcu_head);
634 586
635 ieee80211_bss_info_change_notify(sdata, changed); 587 return changed;
636 return 0;
637} 588}
638 589
639static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, 590static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
640 struct beacon_parameters *params) 591 struct cfg80211_ap_settings *params)
641{ 592{
642 struct ieee80211_sub_if_data *sdata; 593 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
643 struct beacon_data *old; 594 struct beacon_data *old;
644 struct ieee80211_sub_if_data *vlan; 595 struct ieee80211_sub_if_data *vlan;
645 int ret; 596 u32 changed = BSS_CHANGED_BEACON_INT |
646 597 BSS_CHANGED_BEACON_ENABLED |
647 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 598 BSS_CHANGED_BEACON |
599 BSS_CHANGED_SSID;
600 int err;
648 601
649 old = rtnl_dereference(sdata->u.ap.beacon); 602 old = rtnl_dereference(sdata->u.ap.beacon);
650 if (old) 603 if (old)
651 return -EALREADY; 604 return -EALREADY;
652 605
653 ret = ieee80211_config_beacon(sdata, params);
654 if (ret)
655 return ret;
656
657 /* 606 /*
658 * Apply control port protocol, this allows us to 607 * Apply control port protocol, this allows us to
659 * not encrypt dynamic WEP control frames. 608 * not encrypt dynamic WEP control frames.
@@ -667,14 +616,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
667 params->crypto.control_port_no_encrypt; 616 params->crypto.control_port_no_encrypt;
668 } 617 }
669 618
619 sdata->vif.bss_conf.beacon_int = params->beacon_interval;
620 sdata->vif.bss_conf.dtim_period = params->dtim_period;
621
622 sdata->vif.bss_conf.ssid_len = params->ssid_len;
623 if (params->ssid_len)
624 memcpy(sdata->vif.bss_conf.ssid, params->ssid,
625 params->ssid_len);
626 sdata->vif.bss_conf.hidden_ssid =
627 (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
628
629 err = ieee80211_assign_beacon(sdata, &params->beacon);
630 if (err < 0)
631 return err;
632 changed |= err;
633
634 ieee80211_bss_info_change_notify(sdata, changed);
635
670 return 0; 636 return 0;
671} 637}
672 638
673static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, 639static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
674 struct beacon_parameters *params) 640 struct cfg80211_beacon_data *params)
675{ 641{
676 struct ieee80211_sub_if_data *sdata; 642 struct ieee80211_sub_if_data *sdata;
677 struct beacon_data *old; 643 struct beacon_data *old;
644 int err;
678 645
679 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 646 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
680 647
@@ -682,10 +649,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
682 if (!old) 649 if (!old)
683 return -ENOENT; 650 return -ENOENT;
684 651
685 return ieee80211_config_beacon(sdata, params); 652 err = ieee80211_assign_beacon(sdata, params);
653 if (err < 0)
654 return err;
655 ieee80211_bss_info_change_notify(sdata, err);
656 return 0;
686} 657}
687 658
688static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) 659static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
689{ 660{
690 struct ieee80211_sub_if_data *sdata; 661 struct ieee80211_sub_if_data *sdata;
691 struct beacon_data *old; 662 struct beacon_data *old;
@@ -697,10 +668,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
697 return -ENOENT; 668 return -ENOENT;
698 669
699 RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); 670 RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
700 synchronize_rcu(); 671
701 kfree(old); 672 kfree_rcu(old, rcu_head);
702 673
703 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); 674 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
675
704 return 0; 676 return 0;
705} 677}
706 678
@@ -2699,9 +2671,9 @@ struct cfg80211_ops mac80211_config_ops = {
2699 .get_key = ieee80211_get_key, 2671 .get_key = ieee80211_get_key,
2700 .set_default_key = ieee80211_config_default_key, 2672 .set_default_key = ieee80211_config_default_key,
2701 .set_default_mgmt_key = ieee80211_config_default_mgmt_key, 2673 .set_default_mgmt_key = ieee80211_config_default_mgmt_key,
2702 .add_beacon = ieee80211_add_beacon, 2674 .start_ap = ieee80211_start_ap,
2703 .set_beacon = ieee80211_set_beacon, 2675 .change_beacon = ieee80211_change_beacon,
2704 .del_beacon = ieee80211_del_beacon, 2676 .stop_ap = ieee80211_stop_ap,
2705 .add_station = ieee80211_add_station, 2677 .add_station = ieee80211_add_station,
2706 .del_station = ieee80211_del_station, 2678 .del_station = ieee80211_del_station,
2707 .change_station = ieee80211_change_station, 2679 .change_station = ieee80211_change_station,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74594f012cd3..67aed1eff135 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -228,7 +228,7 @@ struct ieee80211_rx_data {
228struct beacon_data { 228struct beacon_data {
229 u8 *head, *tail; 229 u8 *head, *tail;
230 int head_len, tail_len; 230 int head_len, tail_len;
231 int dtim_period; 231 struct rcu_head rcu_head;
232}; 232};
233 233
234struct ieee80211_if_ap { 234struct ieee80211_if_ap {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1be0ca2b5936..c6eadac9ca4e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2206,7 +2206,8 @@ void ieee80211_tx_pending(unsigned long data)
2206 2206
2207/* functions for drivers to get certain frames */ 2207/* functions for drivers to get certain frames */
2208 2208
2209static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, 2209static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2210 struct ieee80211_if_ap *bss,
2210 struct sk_buff *skb, 2211 struct sk_buff *skb,
2211 struct beacon_data *beacon) 2212 struct beacon_data *beacon)
2212{ 2213{
@@ -2223,7 +2224,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
2223 IEEE80211_MAX_AID+1); 2224 IEEE80211_MAX_AID+1);
2224 2225
2225 if (bss->dtim_count == 0) 2226 if (bss->dtim_count == 0)
2226 bss->dtim_count = beacon->dtim_period - 1; 2227 bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
2227 else 2228 else
2228 bss->dtim_count--; 2229 bss->dtim_count--;
2229 2230
@@ -2231,7 +2232,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
2231 *pos++ = WLAN_EID_TIM; 2232 *pos++ = WLAN_EID_TIM;
2232 *pos++ = 4; 2233 *pos++ = 4;
2233 *pos++ = bss->dtim_count; 2234 *pos++ = bss->dtim_count;
2234 *pos++ = beacon->dtim_period; 2235 *pos++ = sdata->vif.bss_conf.dtim_period;
2235 2236
2236 if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) 2237 if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
2237 aid0 = 1; 2238 aid0 = 1;
@@ -2324,12 +2325,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2324 * of the tim bitmap in mac80211 and the driver. 2325 * of the tim bitmap in mac80211 and the driver.
2325 */ 2326 */
2326 if (local->tim_in_locked_section) { 2327 if (local->tim_in_locked_section) {
2327 ieee80211_beacon_add_tim(ap, skb, beacon); 2328 ieee80211_beacon_add_tim(sdata, ap, skb,
2329 beacon);
2328 } else { 2330 } else {
2329 unsigned long flags; 2331 unsigned long flags;
2330 2332
2331 spin_lock_irqsave(&local->tim_lock, flags); 2333 spin_lock_irqsave(&local->tim_lock, flags);
2332 ieee80211_beacon_add_tim(ap, skb, beacon); 2334 ieee80211_beacon_add_tim(sdata, ap, skb,
2335 beacon);
2333 spin_unlock_irqrestore(&local->tim_lock, flags); 2336 spin_unlock_irqrestore(&local->tim_lock, flags);
2334 } 2337 }
2335 2338
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe2747653564..1998c3682774 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -871,7 +871,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
871 CMD(add_virtual_intf, NEW_INTERFACE); 871 CMD(add_virtual_intf, NEW_INTERFACE);
872 CMD(change_virtual_intf, SET_INTERFACE); 872 CMD(change_virtual_intf, SET_INTERFACE);
873 CMD(add_key, NEW_KEY); 873 CMD(add_key, NEW_KEY);
874 CMD(add_beacon, NEW_BEACON); 874 CMD(start_ap, START_AP);
875 CMD(add_station, NEW_STATION); 875 CMD(add_station, NEW_STATION);
876 CMD(add_mpath, NEW_MPATH); 876 CMD(add_mpath, NEW_MPATH);
877 CMD(update_mesh_config, SET_MESH_CONFIG); 877 CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2075,15 +2075,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
2075 return err; 2075 return err;
2076} 2076}
2077 2077
2078static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) 2078static int nl80211_parse_beacon(struct genl_info *info,
2079 struct cfg80211_beacon_data *bcn)
2079{ 2080{
2080 int (*call)(struct wiphy *wiphy, struct net_device *dev, 2081 bool haveinfo = false;
2081 struct beacon_parameters *info);
2082 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2083 struct net_device *dev = info->user_ptr[1];
2084 struct wireless_dev *wdev = dev->ieee80211_ptr;
2085 struct beacon_parameters params;
2086 int haveinfo = 0, err;
2087 2082
2088 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || 2083 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
2089 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || 2084 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2091,149 +2086,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
2091 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) 2086 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
2092 return -EINVAL; 2087 return -EINVAL;
2093 2088
2094 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2089 memset(bcn, 0, sizeof(*bcn));
2095 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2096 return -EOPNOTSUPP;
2097
2098 memset(&params, 0, sizeof(params));
2099
2100 switch (info->genlhdr->cmd) {
2101 case NL80211_CMD_NEW_BEACON:
2102 /* these are required for NEW_BEACON */
2103 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
2104 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
2105 !info->attrs[NL80211_ATTR_BEACON_HEAD])
2106 return -EINVAL;
2107
2108 params.interval =
2109 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
2110 params.dtim_period =
2111 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
2112
2113 err = cfg80211_validate_beacon_int(rdev, params.interval);
2114 if (err)
2115 return err;
2116
2117 /*
2118 * In theory, some of these attributes could be required for
2119 * NEW_BEACON, but since they were not used when the command was
2120 * originally added, keep them optional for old user space
2121 * programs to work with drivers that do not need the additional
2122 * information.
2123 */
2124 if (info->attrs[NL80211_ATTR_SSID]) {
2125 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2126 params.ssid_len =
2127 nla_len(info->attrs[NL80211_ATTR_SSID]);
2128 if (params.ssid_len == 0 ||
2129 params.ssid_len > IEEE80211_MAX_SSID_LEN)
2130 return -EINVAL;
2131 }
2132
2133 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
2134 params.hidden_ssid = nla_get_u32(
2135 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
2136 if (params.hidden_ssid !=
2137 NL80211_HIDDEN_SSID_NOT_IN_USE &&
2138 params.hidden_ssid !=
2139 NL80211_HIDDEN_SSID_ZERO_LEN &&
2140 params.hidden_ssid !=
2141 NL80211_HIDDEN_SSID_ZERO_CONTENTS)
2142 return -EINVAL;
2143 }
2144
2145 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
2146
2147 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2148 params.auth_type = nla_get_u32(
2149 info->attrs[NL80211_ATTR_AUTH_TYPE]);
2150 if (!nl80211_valid_auth_type(params.auth_type))
2151 return -EINVAL;
2152 } else
2153 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
2154
2155 err = nl80211_crypto_settings(rdev, info, &params.crypto,
2156 NL80211_MAX_NR_CIPHER_SUITES);
2157 if (err)
2158 return err;
2159
2160 call = rdev->ops->add_beacon;
2161 break;
2162 case NL80211_CMD_SET_BEACON:
2163 call = rdev->ops->set_beacon;
2164 break;
2165 default:
2166 WARN_ON(1);
2167 return -EOPNOTSUPP;
2168 }
2169
2170 if (!call)
2171 return -EOPNOTSUPP;
2172 2090
2173 if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { 2091 if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
2174 params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); 2092 bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
2175 params.head_len = 2093 bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
2176 nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); 2094 if (!bcn->head_len)
2177 haveinfo = 1; 2095 return -EINVAL;
2096 haveinfo = true;
2178 } 2097 }
2179 2098
2180 if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { 2099 if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
2181 params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); 2100 bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
2182 params.tail_len = 2101 bcn->tail_len =
2183 nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); 2102 nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
2184 haveinfo = 1; 2103 haveinfo = true;
2185 } 2104 }
2186 2105
2187 if (!haveinfo) 2106 if (!haveinfo)
2188 return -EINVAL; 2107 return -EINVAL;
2189 2108
2190 if (info->attrs[NL80211_ATTR_IE]) { 2109 if (info->attrs[NL80211_ATTR_IE]) {
2191 params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); 2110 bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
2192 params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); 2111 bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2193 } 2112 }
2194 2113
2195 if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { 2114 if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
2196 params.proberesp_ies = 2115 bcn->proberesp_ies =
2197 nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); 2116 nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
2198 params.proberesp_ies_len = 2117 bcn->proberesp_ies_len =
2199 nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); 2118 nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
2200 } 2119 }
2201 2120
2202 if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { 2121 if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
2203 params.assocresp_ies = 2122 bcn->assocresp_ies =
2204 nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); 2123 nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
2205 params.assocresp_ies_len = 2124 bcn->assocresp_ies_len =
2206 nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); 2125 nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
2207 } 2126 }
2208 2127
2209 if (info->attrs[NL80211_ATTR_PROBE_RESP]) { 2128 if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
2210 params.probe_resp = 2129 bcn->probe_resp =
2211 nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); 2130 nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
2212 params.probe_resp_len = 2131 bcn->probe_resp_len =
2213 nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); 2132 nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
2214 } 2133 }
2215 2134
2216 err = call(&rdev->wiphy, dev, &params); 2135 return 0;
2217 if (!err && params.interval) 2136}
2218 wdev->beacon_interval = params.interval; 2137
2138static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2139{
2140 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2141 struct net_device *dev = info->user_ptr[1];
2142 struct wireless_dev *wdev = dev->ieee80211_ptr;
2143 struct cfg80211_ap_settings params;
2144 int err;
2145
2146 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2147 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2148 return -EOPNOTSUPP;
2149
2150 if (!rdev->ops->start_ap)
2151 return -EOPNOTSUPP;
2152
2153 if (wdev->beacon_interval)
2154 return -EALREADY;
2155
2156 memset(&params, 0, sizeof(params));
2157
2158 /* these are required for START_AP */
2159 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
2160 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
2161 !info->attrs[NL80211_ATTR_BEACON_HEAD])
2162 return -EINVAL;
2163
2164 err = nl80211_parse_beacon(info, &params.beacon);
2165 if (err)
2166 return err;
2167
2168 params.beacon_interval =
2169 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
2170 params.dtim_period =
2171 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
2172
2173 err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
2174 if (err)
2175 return err;
2176
2177 /*
2178 * In theory, some of these attributes should be required here
2179 * but since they were not used when the command was originally
2180 * added, keep them optional for old user space programs to let
2181 * them continue to work with drivers that do not need the
2182 * additional information -- drivers must check!
2183 */
2184 if (info->attrs[NL80211_ATTR_SSID]) {
2185 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2186 params.ssid_len =
2187 nla_len(info->attrs[NL80211_ATTR_SSID]);
2188 if (params.ssid_len == 0 ||
2189 params.ssid_len > IEEE80211_MAX_SSID_LEN)
2190 return -EINVAL;
2191 }
2192
2193 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
2194 params.hidden_ssid = nla_get_u32(
2195 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
2196 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
2197 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
2198 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
2199 return -EINVAL;
2200 }
2201
2202 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
2203
2204 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2205 params.auth_type = nla_get_u32(
2206 info->attrs[NL80211_ATTR_AUTH_TYPE]);
2207 if (!nl80211_valid_auth_type(params.auth_type))
2208 return -EINVAL;
2209 } else
2210 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
2211
2212 err = nl80211_crypto_settings(rdev, info, &params.crypto,
2213 NL80211_MAX_NR_CIPHER_SUITES);
2214 if (err)
2215 return err;
2216
2217 err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
2218 if (!err)
2219 wdev->beacon_interval = params.beacon_interval;
2219 return err; 2220 return err;
2220} 2221}
2221 2222
2222static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) 2223static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
2224{
2225 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2226 struct net_device *dev = info->user_ptr[1];
2227 struct wireless_dev *wdev = dev->ieee80211_ptr;
2228 struct cfg80211_beacon_data params;
2229 int err;
2230
2231 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2232 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2233 return -EOPNOTSUPP;
2234
2235 if (!rdev->ops->change_beacon)
2236 return -EOPNOTSUPP;
2237
2238 if (!wdev->beacon_interval)
2239 return -EINVAL;
2240
2241 err = nl80211_parse_beacon(info, &params);
2242 if (err)
2243 return err;
2244
2245 return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
2246}
2247
2248static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
2223{ 2249{
2224 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2250 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2225 struct net_device *dev = info->user_ptr[1]; 2251 struct net_device *dev = info->user_ptr[1];
2226 struct wireless_dev *wdev = dev->ieee80211_ptr; 2252 struct wireless_dev *wdev = dev->ieee80211_ptr;
2227 int err; 2253 int err;
2228 2254
2229 if (!rdev->ops->del_beacon) 2255 if (!rdev->ops->stop_ap)
2230 return -EOPNOTSUPP; 2256 return -EOPNOTSUPP;
2231 2257
2232 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2258 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2233 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) 2259 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2234 return -EOPNOTSUPP; 2260 return -EOPNOTSUPP;
2235 2261
2236 err = rdev->ops->del_beacon(&rdev->wiphy, dev); 2262 if (!wdev->beacon_interval)
2263 return -ENOENT;
2264
2265 err = rdev->ops->stop_ap(&rdev->wiphy, dev);
2237 if (!err) 2266 if (!err)
2238 wdev->beacon_interval = 0; 2267 wdev->beacon_interval = 0;
2239 return err; 2268 return err;
@@ -6357,23 +6386,23 @@ static struct genl_ops nl80211_ops[] = {
6357 .cmd = NL80211_CMD_SET_BEACON, 6386 .cmd = NL80211_CMD_SET_BEACON,
6358 .policy = nl80211_policy, 6387 .policy = nl80211_policy,
6359 .flags = GENL_ADMIN_PERM, 6388 .flags = GENL_ADMIN_PERM,
6360 .doit = nl80211_addset_beacon, 6389 .doit = nl80211_set_beacon,
6361 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6390 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6362 NL80211_FLAG_NEED_RTNL, 6391 NL80211_FLAG_NEED_RTNL,
6363 }, 6392 },
6364 { 6393 {
6365 .cmd = NL80211_CMD_NEW_BEACON, 6394 .cmd = NL80211_CMD_START_AP,
6366 .policy = nl80211_policy, 6395 .policy = nl80211_policy,
6367 .flags = GENL_ADMIN_PERM, 6396 .flags = GENL_ADMIN_PERM,
6368 .doit = nl80211_addset_beacon, 6397 .doit = nl80211_start_ap,
6369 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6398 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6370 NL80211_FLAG_NEED_RTNL, 6399 NL80211_FLAG_NEED_RTNL,
6371 }, 6400 },
6372 { 6401 {
6373 .cmd = NL80211_CMD_DEL_BEACON, 6402 .cmd = NL80211_CMD_STOP_AP,
6374 .policy = nl80211_policy, 6403 .policy = nl80211_policy,
6375 .flags = GENL_ADMIN_PERM, 6404 .flags = GENL_ADMIN_PERM,
6376 .doit = nl80211_del_beacon, 6405 .doit = nl80211_stop_ap,
6377 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6406 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6378 NL80211_FLAG_NEED_RTNL, 6407 NL80211_FLAG_NEED_RTNL,
6379 }, 6408 },