diff options
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 82 | ||||
-rw-r--r-- | include/linux/nl80211.h | 34 | ||||
-rw-r--r-- | include/net/cfg80211.h | 70 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 146 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 13 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 255 |
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 | ||
2272 | static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, | 2272 | static 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 | |||
2306 | static 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 | ||
2439 | static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 2449 | static 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 | ||
2445 | static 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 | ||
2451 | static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) | 2463 | static 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 | */ |
399 | struct beacon_parameters { | 387 | struct 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 | */ | ||
417 | struct 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 | ||
492 | static 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 | |||
506 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 492 | static 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 | /* | 518 | static 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 | */ | ||
534 | static 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 | ||
639 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 590 | static 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, ¶ms->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 | ||
673 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | 639 | static 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 | ||
688 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | 659 | static 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 { | |||
228 | struct beacon_data { | 228 | struct 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 | ||
234 | struct ieee80211_if_ap { | 234 | struct 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 | ||
2209 | static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, | 2209 | static 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 | ||
2078 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | 2078 | static 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(¶ms, 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, ¶ms.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, ¶ms); | 2135 | return 0; |
2217 | if (!err && params.interval) | 2136 | } |
2218 | wdev->beacon_interval = params.interval; | 2137 | |
2138 | static 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(¶ms, 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, ¶ms.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, ¶ms.crypto, | ||
2213 | NL80211_MAX_NR_CIPHER_SUITES); | ||
2214 | if (err) | ||
2215 | return err; | ||
2216 | |||
2217 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | ||
2218 | if (!err) | ||
2219 | wdev->beacon_interval = params.beacon_interval; | ||
2219 | return err; | 2220 | return err; |
2220 | } | 2221 | } |
2221 | 2222 | ||
2222 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 2223 | static 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, ¶ms); | ||
2242 | if (err) | ||
2243 | return err; | ||
2244 | |||
2245 | return rdev->ops->change_beacon(&rdev->wiphy, dev, ¶ms); | ||
2246 | } | ||
2247 | |||
2248 | static 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 | }, |