aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-02-13 09:17:18 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-22 14:51:18 -0500
commit8860020e0be1f03d83dc9e9e93e18a4ddbe01038 (patch)
tree09fa9089770e8a42e913f6c11abbba04bec20fad
parent4e3bc141d480661634d0fadad7dbb1ddde70b4d4 (diff)
cfg80211: restructure AP/GO mode API
The AP/GO mode API isn't very clearly defined, it has "set beacon" and "new beacon" etc. Modify the API to the following: * start AP -- all settings * change beacon -- new beacon data * stop AP -- stop AP mode operation This also reflects in the nl80211 API, rename the commands there correspondingly (but keep the old names for compatibility.) Overall, this makes it much clearer what's going on in the API. Kalle developed the ath6kl changes, I created the rest of the patch. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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 },