linux/net/mac80211/offchannel.c
<<
>>
Prefs
   1/*
   2 * Off-channel operation helpers
   3 *
   4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
   5 * Copyright 2004, Instant802 Networks, Inc.
   6 * Copyright 2005, Devicescape Software, Inc.
   7 * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
   8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   9 * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15#include <linux/export.h>
  16#include <net/mac80211.h>
  17#include "ieee80211_i.h"
  18#include "driver-ops.h"
  19
  20/*
  21 * Tell our hardware to disable PS.
  22 * Optionally inform AP that we will go to sleep so that it will buffer
  23 * the frames while we are doing off-channel work.  This is optional
  24 * because we *may* be doing work on-operating channel, and want our
  25 * hardware unconditionally awake, but still let the AP send us normal frames.
  26 */
  27static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
  28{
  29        struct ieee80211_local *local = sdata->local;
  30        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
  31
  32        local->offchannel_ps_enabled = false;
  33
  34        /* FIXME: what to do when local->pspolling is true? */
  35
  36        del_timer_sync(&local->dynamic_ps_timer);
  37        del_timer_sync(&ifmgd->bcn_mon_timer);
  38        del_timer_sync(&ifmgd->conn_mon_timer);
  39
  40        cancel_work_sync(&local->dynamic_ps_enable_work);
  41
  42        if (local->hw.conf.flags & IEEE80211_CONF_PS) {
  43                local->offchannel_ps_enabled = true;
  44                local->hw.conf.flags &= ~IEEE80211_CONF_PS;
  45                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
  46        }
  47
  48        if (!local->offchannel_ps_enabled ||
  49            !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
  50                /*
  51                 * If power save was enabled, no need to send a nullfunc
  52                 * frame because AP knows that we are sleeping. But if the
  53                 * hardware is creating the nullfunc frame for power save
  54                 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
  55                 * enabled) and power save was enabled, the firmware just
  56                 * sent a null frame with power save disabled. So we need
  57                 * to send a new nullfunc frame to inform the AP that we
  58                 * are again sleeping.
  59                 */
  60                ieee80211_send_nullfunc(local, sdata, 1);
  61}
  62
  63/* inform AP that we are awake again, unless power save is enabled */
  64static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
  65{
  66        struct ieee80211_local *local = sdata->local;
  67
  68        if (!local->ps_sdata)
  69                ieee80211_send_nullfunc(local, sdata, 0);
  70        else if (local->offchannel_ps_enabled) {
  71                /*
  72                 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
  73                 * will send a nullfunc frame with the powersave bit set
  74                 * even though the AP already knows that we are sleeping.
  75                 * This could be avoided by sending a null frame with power
  76                 * save bit disabled before enabling the power save, but
  77                 * this doesn't gain anything.
  78                 *
  79                 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
  80                 * to send a nullfunc frame because AP already knows that
  81                 * we are sleeping, let's just enable power save mode in
  82                 * hardware.
  83                 */
  84                /* TODO:  Only set hardware if CONF_PS changed?
  85                 * TODO:  Should we set offchannel_ps_enabled to false?
  86                 */
  87                local->hw.conf.flags |= IEEE80211_CONF_PS;
  88                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
  89        } else if (local->hw.conf.dynamic_ps_timeout > 0) {
  90                /*
  91                 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
  92                 * had been running before leaving the operating channel,
  93                 * restart the timer now and send a nullfunc frame to inform
  94                 * the AP that we are awake.
  95                 */
  96                ieee80211_send_nullfunc(local, sdata, 0);
  97                mod_timer(&local->dynamic_ps_timer, jiffies +
  98                          msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
  99        }
 100
 101        ieee80211_sta_reset_beacon_monitor(sdata);
 102        ieee80211_sta_reset_conn_monitor(sdata);
 103}
 104
 105void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
 106{
 107        struct ieee80211_sub_if_data *sdata;
 108
 109        if (WARN_ON(local->use_chanctx))
 110                return;
 111
 112        /*
 113         * notify the AP about us leaving the channel and stop all
 114         * STA interfaces.
 115         */
 116
 117        /*
 118         * Stop queues and transmit all frames queued by the driver
 119         * before sending nullfunc to enable powersave at the AP.
 120         */
 121        ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
 122                                        IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
 123        ieee80211_flush_queues(local, NULL);
 124
 125        mutex_lock(&local->iflist_mtx);
 126        list_for_each_entry(sdata, &local->interfaces, list) {
 127                if (!ieee80211_sdata_running(sdata))
 128                        continue;
 129
 130                if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
 131                        continue;
 132
 133                if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 134                        set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
 135
 136                /* Check to see if we should disable beaconing. */
 137                if (sdata->vif.bss_conf.enable_beacon) {
 138                        set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
 139                                &sdata->state);
 140                        sdata->vif.bss_conf.enable_beacon = false;
 141                        ieee80211_bss_info_change_notify(
 142                                sdata, BSS_CHANGED_BEACON_ENABLED);
 143                }
 144
 145                if (sdata->vif.type == NL80211_IFTYPE_STATION &&
 146                    sdata->u.mgd.associated)
 147                        ieee80211_offchannel_ps_enable(sdata);
 148        }
 149        mutex_unlock(&local->iflist_mtx);
 150}
 151
 152void ieee80211_offchannel_return(struct ieee80211_local *local)
 153{
 154        struct ieee80211_sub_if_data *sdata;
 155
 156        if (WARN_ON(local->use_chanctx))
 157                return;
 158
 159        mutex_lock(&local->iflist_mtx);
 160        list_for_each_entry(sdata, &local->interfaces, list) {
 161                if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
 162                        continue;
 163
 164                if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 165                        clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
 166
 167                if (!ieee80211_sdata_running(sdata))
 168                        continue;
 169
 170                /* Tell AP we're back */
 171                if (sdata->vif.type == NL80211_IFTYPE_STATION &&
 172                    sdata->u.mgd.associated)
 173                        ieee80211_offchannel_ps_disable(sdata);
 174
 175                if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
 176                                       &sdata->state)) {
 177                        sdata->vif.bss_conf.enable_beacon = true;
 178                        ieee80211_bss_info_change_notify(
 179                                sdata, BSS_CHANGED_BEACON_ENABLED);
 180                }
 181        }
 182        mutex_unlock(&local->iflist_mtx);
 183
 184        ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
 185                                        IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
 186}
 187
 188void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
 189{
 190        if (roc->notified)
 191                return;
 192
 193        if (roc->mgmt_tx_cookie) {
 194                if (!WARN_ON(!roc->frame)) {
 195                        ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
 196                                                  roc->chan->band);
 197                        roc->frame = NULL;
 198                }
 199        } else {
 200                cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,
 201                                          roc->chan, roc->req_duration,
 202                                          GFP_KERNEL);
 203        }
 204
 205        roc->notified = true;
 206}
 207
 208static void ieee80211_hw_roc_start(struct work_struct *work)
 209{
 210        struct ieee80211_local *local =
 211                container_of(work, struct ieee80211_local, hw_roc_start);
 212        struct ieee80211_roc_work *roc, *dep, *tmp;
 213
 214        mutex_lock(&local->mtx);
 215
 216        if (list_empty(&local->roc_list))
 217                goto out_unlock;
 218
 219        roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
 220                               list);
 221
 222        if (!roc->started)
 223                goto out_unlock;
 224
 225        roc->hw_begun = true;
 226        roc->hw_start_time = local->hw_roc_start_time;
 227
 228        ieee80211_handle_roc_started(roc);
 229        list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
 230                ieee80211_handle_roc_started(dep);
 231
 232                if (dep->duration > roc->duration) {
 233                        u32 dur = dep->duration;
 234                        dep->duration = dur - roc->duration;
 235                        roc->duration = dur;
 236                        list_move(&dep->list, &roc->list);
 237                }
 238        }
 239 out_unlock:
 240        mutex_unlock(&local->mtx);
 241}
 242
 243void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
 244{
 245        struct ieee80211_local *local = hw_to_local(hw);
 246
 247        local->hw_roc_start_time = jiffies;
 248
 249        trace_api_ready_on_channel(local);
 250
 251        ieee80211_queue_work(hw, &local->hw_roc_start);
 252}
 253EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
 254
 255void ieee80211_start_next_roc(struct ieee80211_local *local)
 256{
 257        struct ieee80211_roc_work *roc;
 258
 259        lockdep_assert_held(&local->mtx);
 260
 261        if (list_empty(&local->roc_list)) {
 262                ieee80211_run_deferred_scan(local);
 263                return;
 264        }
 265
 266        roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
 267                               list);
 268
 269        if (WARN_ON_ONCE(roc->started))
 270                return;
 271
 272        if (local->ops->remain_on_channel) {
 273                int ret, duration = roc->duration;
 274
 275                /* XXX: duplicated, see ieee80211_start_roc_work() */
 276                if (!duration)
 277                        duration = 10;
 278
 279                ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
 280                                            duration, roc->type);
 281
 282                roc->started = true;
 283
 284                if (ret) {
 285                        wiphy_warn(local->hw.wiphy,
 286                                   "failed to start next HW ROC (%d)\n", ret);
 287                        /*
 288                         * queue the work struct again to avoid recursion
 289                         * when multiple failures occur
 290                         */
 291                        ieee80211_remain_on_channel_expired(&local->hw);
 292                }
 293        } else {
 294                /* delay it a bit */
 295                ieee80211_queue_delayed_work(&local->hw, &roc->work,
 296                                             round_jiffies_relative(HZ/2));
 297        }
 298}
 299
 300void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free)
 301{
 302        struct ieee80211_roc_work *dep, *tmp;
 303
 304        if (WARN_ON(roc->to_be_freed))
 305                return;
 306
 307        /* was never transmitted */
 308        if (roc->frame) {
 309                cfg80211_mgmt_tx_status(&roc->sdata->wdev,
 310                                        (unsigned long)roc->frame,
 311                                        roc->frame->data, roc->frame->len,
 312                                        false, GFP_KERNEL);
 313                kfree_skb(roc->frame);
 314        }
 315
 316        if (!roc->mgmt_tx_cookie)
 317                cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
 318                                                   roc->cookie, roc->chan,
 319                                                   GFP_KERNEL);
 320
 321        list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
 322                ieee80211_roc_notify_destroy(dep, true);
 323
 324        if (free)
 325                kfree(roc);
 326        else
 327                roc->to_be_freed = true;
 328}
 329
 330void ieee80211_sw_roc_work(struct work_struct *work)
 331{
 332        struct ieee80211_roc_work *roc =
 333                container_of(work, struct ieee80211_roc_work, work.work);
 334        struct ieee80211_sub_if_data *sdata = roc->sdata;
 335        struct ieee80211_local *local = sdata->local;
 336        bool started;
 337
 338        mutex_lock(&local->mtx);
 339
 340        if (roc->to_be_freed)
 341                goto out_unlock;
 342
 343        if (roc->abort)
 344                goto finish;
 345
 346        if (WARN_ON(list_empty(&local->roc_list)))
 347                goto out_unlock;
 348
 349        if (WARN_ON(roc != list_first_entry(&local->roc_list,
 350                                            struct ieee80211_roc_work,
 351                                            list)))
 352                goto out_unlock;
 353
 354        if (!roc->started) {
 355                struct ieee80211_roc_work *dep;
 356
 357                /* start this ROC */
 358
 359                /* switch channel etc */
 360                ieee80211_recalc_idle(local);
 361
 362                local->tmp_channel = roc->chan;
 363                ieee80211_hw_config(local, 0);
 364
 365                /* tell userspace or send frame */
 366                ieee80211_handle_roc_started(roc);
 367                list_for_each_entry(dep, &roc->dependents, list)
 368                        ieee80211_handle_roc_started(dep);
 369
 370                /* if it was pure TX, just finish right away */
 371                if (!roc->duration)
 372                        goto finish;
 373
 374                roc->started = true;
 375                ieee80211_queue_delayed_work(&local->hw, &roc->work,
 376                                             msecs_to_jiffies(roc->duration));
 377        } else {
 378                /* finish this ROC */
 379 finish:
 380                list_del(&roc->list);
 381                started = roc->started;
 382                ieee80211_roc_notify_destroy(roc, !roc->abort);
 383
 384                if (started) {
 385                        ieee80211_flush_queues(local, NULL);
 386
 387                        local->tmp_channel = NULL;
 388                        ieee80211_hw_config(local, 0);
 389
 390                        ieee80211_offchannel_return(local);
 391                }
 392
 393                ieee80211_recalc_idle(local);
 394
 395                if (started)
 396                        ieee80211_start_next_roc(local);
 397                else if (list_empty(&local->roc_list))
 398                        ieee80211_run_deferred_scan(local);
 399        }
 400
 401 out_unlock:
 402        mutex_unlock(&local->mtx);
 403}
 404
 405static void ieee80211_hw_roc_done(struct work_struct *work)
 406{
 407        struct ieee80211_local *local =
 408                container_of(work, struct ieee80211_local, hw_roc_done);
 409        struct ieee80211_roc_work *roc;
 410
 411        mutex_lock(&local->mtx);
 412
 413        if (list_empty(&local->roc_list))
 414                goto out_unlock;
 415
 416        roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
 417                               list);
 418
 419        if (!roc->started)
 420                goto out_unlock;
 421
 422        list_del(&roc->list);
 423
 424        ieee80211_roc_notify_destroy(roc, true);
 425
 426        /* if there's another roc, start it now */
 427        ieee80211_start_next_roc(local);
 428
 429 out_unlock:
 430        mutex_unlock(&local->mtx);
 431}
 432
 433void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
 434{
 435        struct ieee80211_local *local = hw_to_local(hw);
 436
 437        trace_api_remain_on_channel_expired(local);
 438
 439        ieee80211_queue_work(hw, &local->hw_roc_done);
 440}
 441EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
 442
 443void ieee80211_roc_setup(struct ieee80211_local *local)
 444{
 445        INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
 446        INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
 447        INIT_LIST_HEAD(&local->roc_list);
 448}
 449
 450void ieee80211_roc_purge(struct ieee80211_local *local,
 451                         struct ieee80211_sub_if_data *sdata)
 452{
 453        struct ieee80211_roc_work *roc, *tmp;
 454        LIST_HEAD(tmp_list);
 455
 456        mutex_lock(&local->mtx);
 457        list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
 458                if (sdata && roc->sdata != sdata)
 459                        continue;
 460
 461                if (roc->started && local->ops->remain_on_channel) {
 462                        /* can race, so ignore return value */
 463                        drv_cancel_remain_on_channel(local);
 464                }
 465
 466                list_move_tail(&roc->list, &tmp_list);
 467                roc->abort = true;
 468        }
 469        mutex_unlock(&local->mtx);
 470
 471        list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
 472                if (local->ops->remain_on_channel) {
 473                        list_del(&roc->list);
 474                        ieee80211_roc_notify_destroy(roc, true);
 475                } else {
 476                        ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
 477
 478                        /* work will clean up etc */
 479                        flush_delayed_work(&roc->work);
 480                        WARN_ON(!roc->to_be_freed);
 481                        kfree(roc);
 482                }
 483        }
 484
 485        WARN_ON_ONCE(!list_empty(&tmp_list));
 486}
 487