aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2015-11-23 11:18:35 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-12-04 08:43:32 -0500
commita2fcfccbad43e413de7e7ac39879ba91548f06c1 (patch)
tree619f32e285dea1400b52e7acb0d72d22f68df64c /net/mac80211/cfg.c
parente673a65952b4ab045a3e3eb200fdf408004fb4fd (diff)
mac80211: move off-channel/mgmt-tx code to offchannel.c
This is quite a bit of code that logically depends here since it has to deal with all the remain-on-channel logic. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c504
1 files changed, 16 insertions, 488 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 6bcdbab65a8c..b8ef33e62851 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2504,294 +2504,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
2504 return 0; 2504 return 0;
2505} 2505}
2506 2506
2507static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
2508 struct ieee80211_roc_work *new_roc,
2509 struct ieee80211_roc_work *cur_roc)
2510{
2511 unsigned long now = jiffies;
2512 unsigned long remaining = cur_roc->hw_start_time +
2513 msecs_to_jiffies(cur_roc->duration) -
2514 now;
2515
2516 if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
2517 return false;
2518
2519 /* if it doesn't fit entirely, schedule a new one */
2520 if (new_roc->duration > jiffies_to_msecs(remaining))
2521 return false;
2522
2523 ieee80211_handle_roc_started(new_roc);
2524
2525 /* add to dependents so we send the expired event properly */
2526 list_add_tail(&new_roc->list, &cur_roc->dependents);
2527 return true;
2528}
2529
2530static u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local)
2531{
2532 lockdep_assert_held(&local->mtx);
2533
2534 local->roc_cookie_counter++;
2535
2536 /* wow, you wrapped 64 bits ... more likely a bug */
2537 if (WARN_ON(local->roc_cookie_counter == 0))
2538 local->roc_cookie_counter++;
2539
2540 return local->roc_cookie_counter;
2541}
2542
2543static int ieee80211_start_roc_work(struct ieee80211_local *local,
2544 struct ieee80211_sub_if_data *sdata,
2545 struct ieee80211_channel *channel,
2546 unsigned int duration, u64 *cookie,
2547 struct sk_buff *txskb,
2548 enum ieee80211_roc_type type)
2549{
2550 struct ieee80211_roc_work *roc, *tmp;
2551 bool queued = false;
2552 int ret;
2553
2554 lockdep_assert_held(&local->mtx);
2555
2556 if (local->use_chanctx && !local->ops->remain_on_channel)
2557 return -EOPNOTSUPP;
2558
2559 roc = kzalloc(sizeof(*roc), GFP_KERNEL);
2560 if (!roc)
2561 return -ENOMEM;
2562
2563 /*
2564 * If the duration is zero, then the driver
2565 * wouldn't actually do anything. Set it to
2566 * 10 for now.
2567 *
2568 * TODO: cancel the off-channel operation
2569 * when we get the SKB's TX status and
2570 * the wait time was zero before.
2571 */
2572 if (!duration)
2573 duration = 10;
2574
2575 roc->chan = channel;
2576 roc->duration = duration;
2577 roc->req_duration = duration;
2578 roc->frame = txskb;
2579 roc->type = type;
2580 roc->sdata = sdata;
2581 INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
2582 INIT_LIST_HEAD(&roc->dependents);
2583
2584 /*
2585 * cookie is either the roc cookie (for normal roc)
2586 * or the SKB (for mgmt TX)
2587 */
2588 if (!txskb) {
2589 roc->cookie = ieee80211_mgmt_tx_cookie(local);
2590 *cookie = roc->cookie;
2591 } else {
2592 roc->mgmt_tx_cookie = *cookie;
2593 }
2594
2595 /* if there's one pending or we're scanning, queue this one */
2596 if (!list_empty(&local->roc_list) ||
2597 local->scanning || ieee80211_is_radar_required(local))
2598 goto out_check_combine;
2599
2600 /* if not HW assist, just queue & schedule work */
2601 if (!local->ops->remain_on_channel) {
2602 ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
2603 goto out_queue;
2604 }
2605
2606 /* otherwise actually kick it off here (for error handling) */
2607
2608 ret = drv_remain_on_channel(local, sdata, channel, duration, type);
2609 if (ret) {
2610 kfree(roc);
2611 return ret;
2612 }
2613
2614 roc->started = true;
2615 goto out_queue;
2616
2617 out_check_combine:
2618 list_for_each_entry(tmp, &local->roc_list, list) {
2619 if (tmp->chan != channel || tmp->sdata != sdata)
2620 continue;
2621
2622 /*
2623 * Extend this ROC if possible:
2624 *
2625 * If it hasn't started yet, just increase the duration
2626 * and add the new one to the list of dependents.
2627 * If the type of the new ROC has higher priority, modify the
2628 * type of the previous one to match that of the new one.
2629 */
2630 if (!tmp->started) {
2631 list_add_tail(&roc->list, &tmp->dependents);
2632 tmp->duration = max(tmp->duration, roc->duration);
2633 tmp->type = max(tmp->type, roc->type);
2634 queued = true;
2635 break;
2636 }
2637
2638 /* If it has already started, it's more difficult ... */
2639 if (local->ops->remain_on_channel) {
2640 /*
2641 * In the offloaded ROC case, if it hasn't begun, add
2642 * this new one to the dependent list to be handled
2643 * when the master one begins. If it has begun,
2644 * check if it fits entirely within the existing one,
2645 * in which case it will just be dependent as well.
2646 * Otherwise, schedule it by itself.
2647 */
2648 if (!tmp->hw_begun) {
2649 list_add_tail(&roc->list, &tmp->dependents);
2650 queued = true;
2651 break;
2652 }
2653
2654 if (ieee80211_coalesce_started_roc(local, roc, tmp))
2655 queued = true;
2656 } else if (del_timer_sync(&tmp->work.timer)) {
2657 unsigned long new_end;
2658
2659 /*
2660 * In the software ROC case, cancel the timer, if
2661 * that fails then the finish work is already
2662 * queued/pending and thus we queue the new ROC
2663 * normally, if that succeeds then we can extend
2664 * the timer duration and TX the frame (if any.)
2665 */
2666
2667 list_add_tail(&roc->list, &tmp->dependents);
2668 queued = true;
2669
2670 new_end = jiffies + msecs_to_jiffies(roc->duration);
2671
2672 /* ok, it was started & we canceled timer */
2673 if (time_after(new_end, tmp->work.timer.expires))
2674 mod_timer(&tmp->work.timer, new_end);
2675 else
2676 add_timer(&tmp->work.timer);
2677
2678 ieee80211_handle_roc_started(roc);
2679 }
2680 break;
2681 }
2682
2683 out_queue:
2684 if (!queued)
2685 list_add_tail(&roc->list, &local->roc_list);
2686
2687 return 0;
2688}
2689
2690static int ieee80211_remain_on_channel(struct wiphy *wiphy,
2691 struct wireless_dev *wdev,
2692 struct ieee80211_channel *chan,
2693 unsigned int duration,
2694 u64 *cookie)
2695{
2696 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2697 struct ieee80211_local *local = sdata->local;
2698 int ret;
2699
2700 mutex_lock(&local->mtx);
2701 ret = ieee80211_start_roc_work(local, sdata, chan,
2702 duration, cookie, NULL,
2703 IEEE80211_ROC_TYPE_NORMAL);
2704 mutex_unlock(&local->mtx);
2705
2706 return ret;
2707}
2708
2709static int ieee80211_cancel_roc(struct ieee80211_local *local,
2710 u64 cookie, bool mgmt_tx)
2711{
2712 struct ieee80211_roc_work *roc, *tmp, *found = NULL;
2713 int ret;
2714
2715 mutex_lock(&local->mtx);
2716 list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
2717 struct ieee80211_roc_work *dep, *tmp2;
2718
2719 list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) {
2720 if (!mgmt_tx && dep->cookie != cookie)
2721 continue;
2722 else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)
2723 continue;
2724 /* found dependent item -- just remove it */
2725 list_del(&dep->list);
2726 mutex_unlock(&local->mtx);
2727
2728 ieee80211_roc_notify_destroy(dep, true);
2729 return 0;
2730 }
2731
2732 if (!mgmt_tx && roc->cookie != cookie)
2733 continue;
2734 else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
2735 continue;
2736
2737 found = roc;
2738 break;
2739 }
2740
2741 if (!found) {
2742 mutex_unlock(&local->mtx);
2743 return -ENOENT;
2744 }
2745
2746 /*
2747 * We found the item to cancel, so do that. Note that it
2748 * may have dependents, which we also cancel (and send
2749 * the expired signal for.) Not doing so would be quite
2750 * tricky here, but we may need to fix it later.
2751 */
2752
2753 if (local->ops->remain_on_channel) {
2754 if (found->started) {
2755 ret = drv_cancel_remain_on_channel(local);
2756 if (WARN_ON_ONCE(ret)) {
2757 mutex_unlock(&local->mtx);
2758 return ret;
2759 }
2760 }
2761
2762 list_del(&found->list);
2763
2764 if (found->started)
2765 ieee80211_start_next_roc(local);
2766 mutex_unlock(&local->mtx);
2767
2768 ieee80211_roc_notify_destroy(found, true);
2769 } else {
2770 /* work may be pending so use it all the time */
2771 found->abort = true;
2772 ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
2773
2774 mutex_unlock(&local->mtx);
2775
2776 /* work will clean up etc */
2777 flush_delayed_work(&found->work);
2778 WARN_ON(!found->to_be_freed);
2779 kfree(found);
2780 }
2781
2782 return 0;
2783}
2784
2785static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
2786 struct wireless_dev *wdev,
2787 u64 cookie)
2788{
2789 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2790 struct ieee80211_local *local = sdata->local;
2791
2792 return ieee80211_cancel_roc(local, cookie, false);
2793}
2794
2795static int ieee80211_start_radar_detection(struct wiphy *wiphy, 2507static int ieee80211_start_radar_detection(struct wiphy *wiphy,
2796 struct net_device *dev, 2508 struct net_device *dev,
2797 struct cfg80211_chan_def *chandef, 2509 struct cfg80211_chan_def *chandef,
@@ -3262,9 +2974,22 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3262 return err; 2974 return err;
3263} 2975}
3264 2976
3265static struct sk_buff *ieee80211_make_ack_skb(struct ieee80211_local *local, 2977u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local)
3266 struct sk_buff *skb, u64 *cookie, 2978{
3267 gfp_t gfp) 2979 lockdep_assert_held(&local->mtx);
2980
2981 local->roc_cookie_counter++;
2982
2983 /* wow, you wrapped 64 bits ... more likely a bug */
2984 if (WARN_ON(local->roc_cookie_counter == 0))
2985 local->roc_cookie_counter++;
2986
2987 return local->roc_cookie_counter;
2988}
2989
2990struct sk_buff *ieee80211_make_ack_skb(struct ieee80211_local *local,
2991 struct sk_buff *skb, u64 *cookie,
2992 gfp_t gfp)
3268{ 2993{
3269 unsigned long spin_flags; 2994 unsigned long spin_flags;
3270 struct sk_buff *ack_skb; 2995 struct sk_buff *ack_skb;
@@ -3292,203 +3017,6 @@ static struct sk_buff *ieee80211_make_ack_skb(struct ieee80211_local *local,
3292 return ack_skb; 3017 return ack_skb;
3293} 3018}
3294 3019
3295static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3296 struct cfg80211_mgmt_tx_params *params,
3297 u64 *cookie)
3298{
3299 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
3300 struct ieee80211_local *local = sdata->local;
3301 struct sk_buff *skb, *ack_skb;
3302 struct sta_info *sta;
3303 const struct ieee80211_mgmt *mgmt = (void *)params->buf;
3304 bool need_offchan = false;
3305 u32 flags;
3306 int ret;
3307 u8 *data;
3308
3309 if (params->dont_wait_for_ack)
3310 flags = IEEE80211_TX_CTL_NO_ACK;
3311 else
3312 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
3313 IEEE80211_TX_CTL_REQ_TX_STATUS;
3314
3315 if (params->no_cck)
3316 flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
3317
3318 switch (sdata->vif.type) {
3319 case NL80211_IFTYPE_ADHOC:
3320 if (!sdata->vif.bss_conf.ibss_joined)
3321 need_offchan = true;
3322 /* fall through */
3323#ifdef CONFIG_MAC80211_MESH
3324 case NL80211_IFTYPE_MESH_POINT:
3325 if (ieee80211_vif_is_mesh(&sdata->vif) &&
3326 !sdata->u.mesh.mesh_id_len)
3327 need_offchan = true;
3328 /* fall through */
3329#endif
3330 case NL80211_IFTYPE_AP:
3331 case NL80211_IFTYPE_AP_VLAN:
3332 case NL80211_IFTYPE_P2P_GO:
3333 if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3334 !ieee80211_vif_is_mesh(&sdata->vif) &&
3335 !rcu_access_pointer(sdata->bss->beacon))
3336 need_offchan = true;
3337 if (!ieee80211_is_action(mgmt->frame_control) ||
3338 mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
3339 mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
3340 mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
3341 break;
3342 rcu_read_lock();
3343 sta = sta_info_get(sdata, mgmt->da);
3344 rcu_read_unlock();
3345 if (!sta)
3346 return -ENOLINK;
3347 break;
3348 case NL80211_IFTYPE_STATION:
3349 case NL80211_IFTYPE_P2P_CLIENT:
3350 sdata_lock(sdata);
3351 if (!sdata->u.mgd.associated ||
3352 (params->offchan && params->wait &&
3353 local->ops->remain_on_channel &&
3354 memcmp(sdata->u.mgd.associated->bssid,
3355 mgmt->bssid, ETH_ALEN)))
3356 need_offchan = true;
3357 sdata_unlock(sdata);
3358 break;
3359 case NL80211_IFTYPE_P2P_DEVICE:
3360 need_offchan = true;
3361 break;
3362 default:
3363 return -EOPNOTSUPP;
3364 }
3365
3366 /* configurations requiring offchan cannot work if no channel has been
3367 * specified
3368 */
3369 if (need_offchan && !params->chan)
3370 return -EINVAL;
3371
3372 mutex_lock(&local->mtx);
3373
3374 /* Check if the operating channel is the requested channel */
3375 if (!need_offchan) {
3376 struct ieee80211_chanctx_conf *chanctx_conf;
3377
3378 rcu_read_lock();
3379 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
3380
3381 if (chanctx_conf) {
3382 need_offchan = params->chan &&
3383 (params->chan !=
3384 chanctx_conf->def.chan);
3385 } else if (!params->chan) {
3386 ret = -EINVAL;
3387 rcu_read_unlock();
3388 goto out_unlock;
3389 } else {
3390 need_offchan = true;
3391 }
3392 rcu_read_unlock();
3393 }
3394
3395 if (need_offchan && !params->offchan) {
3396 ret = -EBUSY;
3397 goto out_unlock;
3398 }
3399
3400 skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);
3401 if (!skb) {
3402 ret = -ENOMEM;
3403 goto out_unlock;
3404 }
3405 skb_reserve(skb, local->hw.extra_tx_headroom);
3406
3407 data = skb_put(skb, params->len);
3408 memcpy(data, params->buf, params->len);
3409
3410 /* Update CSA counters */
3411 if (sdata->vif.csa_active &&
3412 (sdata->vif.type == NL80211_IFTYPE_AP ||
3413 sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
3414 sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
3415 params->n_csa_offsets) {
3416 int i;
3417 struct beacon_data *beacon = NULL;
3418
3419 rcu_read_lock();
3420
3421 if (sdata->vif.type == NL80211_IFTYPE_AP)
3422 beacon = rcu_dereference(sdata->u.ap.beacon);
3423 else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
3424 beacon = rcu_dereference(sdata->u.ibss.presp);
3425 else if (ieee80211_vif_is_mesh(&sdata->vif))
3426 beacon = rcu_dereference(sdata->u.mesh.beacon);
3427
3428 if (beacon)
3429 for (i = 0; i < params->n_csa_offsets; i++)
3430 data[params->csa_offsets[i]] =
3431 beacon->csa_current_counter;
3432
3433 rcu_read_unlock();
3434 }
3435
3436 IEEE80211_SKB_CB(skb)->flags = flags;
3437
3438 skb->dev = sdata->dev;
3439
3440 if (!params->dont_wait_for_ack) {
3441 /* make a copy to preserve the frame contents
3442 * in case of encryption.
3443 */
3444 ack_skb = ieee80211_make_ack_skb(local, skb, cookie,
3445 GFP_KERNEL);
3446 if (IS_ERR(ack_skb)) {
3447 ret = PTR_ERR(ack_skb);
3448 kfree_skb(skb);
3449 goto out_unlock;
3450 }
3451 } else {
3452 /* Assign a dummy non-zero cookie, it's not sent to
3453 * userspace in this case but we rely on its value
3454 * internally in the need_offchan case to distinguish
3455 * mgmt-tx from remain-on-channel.
3456 */
3457 *cookie = 0xffffffff;
3458 }
3459
3460 if (!need_offchan) {
3461 ieee80211_tx_skb(sdata, skb);
3462 ret = 0;
3463 goto out_unlock;
3464 }
3465
3466 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
3467 IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
3468 if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
3469 IEEE80211_SKB_CB(skb)->hw_queue =
3470 local->hw.offchannel_tx_hw_queue;
3471
3472 /* This will handle all kinds of coalescing and immediate TX */
3473 ret = ieee80211_start_roc_work(local, sdata, params->chan,
3474 params->wait, cookie, skb,
3475 IEEE80211_ROC_TYPE_MGMT_TX);
3476 if (ret)
3477 ieee80211_free_txskb(&local->hw, skb);
3478 out_unlock:
3479 mutex_unlock(&local->mtx);
3480 return ret;
3481}
3482
3483static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
3484 struct wireless_dev *wdev,
3485 u64 cookie)
3486{
3487 struct ieee80211_local *local = wiphy_priv(wiphy);
3488
3489 return ieee80211_cancel_roc(local, cookie, true);
3490}
3491
3492static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, 3020static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
3493 struct wireless_dev *wdev, 3021 struct wireless_dev *wdev,
3494 u16 frame_type, bool reg) 3022 u16 frame_type, bool reg)