linux/net/mac80211/pm.c
<<
>>
Prefs
   1#include <net/mac80211.h>
   2#include <net/rtnetlink.h>
   3
   4#include "ieee80211_i.h"
   5#include "led.h"
   6
   7int __ieee80211_suspend(struct ieee80211_hw *hw)
   8{
   9        struct ieee80211_local *local = hw_to_local(hw);
  10        struct ieee80211_sub_if_data *sdata;
  11        struct ieee80211_if_init_conf conf;
  12        struct sta_info *sta;
  13        unsigned long flags;
  14
  15        ieee80211_stop_queues_by_reason(hw,
  16                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
  17
  18        flush_workqueue(local->hw.workqueue);
  19
  20        /* disable keys */
  21        list_for_each_entry(sdata, &local->interfaces, list)
  22                ieee80211_disable_keys(sdata);
  23
  24        /* Tear down aggregation sessions */
  25
  26        rcu_read_lock();
  27
  28        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
  29                list_for_each_entry_rcu(sta, &local->sta_list, list) {
  30                        set_sta_flags(sta, WLAN_STA_SUSPEND);
  31                        ieee80211_sta_tear_down_BA_sessions(sta);
  32                }
  33        }
  34
  35        rcu_read_unlock();
  36
  37        /* remove STAs */
  38        if (local->ops->sta_notify) {
  39                spin_lock_irqsave(&local->sta_lock, flags);
  40                list_for_each_entry(sta, &local->sta_list, list) {
  41                        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
  42                                sdata = container_of(sdata->bss,
  43                                             struct ieee80211_sub_if_data,
  44                                             u.ap);
  45
  46                        local->ops->sta_notify(hw, &sdata->vif,
  47                                STA_NOTIFY_REMOVE, &sta->sta);
  48                }
  49                spin_unlock_irqrestore(&local->sta_lock, flags);
  50        }
  51
  52        /* remove all interfaces */
  53        list_for_each_entry(sdata, &local->interfaces, list) {
  54                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  55                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
  56                    netif_running(sdata->dev)) {
  57                        conf.vif = &sdata->vif;
  58                        conf.type = sdata->vif.type;
  59                        conf.mac_addr = sdata->dev->dev_addr;
  60                        local->ops->remove_interface(hw, &conf);
  61                }
  62        }
  63
  64        /* flush again, in case driver queued work */
  65        flush_workqueue(local->hw.workqueue);
  66
  67        /* stop hardware */
  68        if (local->open_count) {
  69                ieee80211_led_radio(local, false);
  70                local->ops->stop(hw);
  71        }
  72        return 0;
  73}
  74
  75int __ieee80211_resume(struct ieee80211_hw *hw)
  76{
  77        struct ieee80211_local *local = hw_to_local(hw);
  78        struct ieee80211_sub_if_data *sdata;
  79        struct ieee80211_if_init_conf conf;
  80        struct sta_info *sta;
  81        unsigned long flags;
  82        int res;
  83
  84        /* restart hardware */
  85        if (local->open_count) {
  86                res = local->ops->start(hw);
  87
  88                ieee80211_led_radio(local, hw->conf.radio_enabled);
  89        }
  90
  91        /* add interfaces */
  92        list_for_each_entry(sdata, &local->interfaces, list) {
  93                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  94                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
  95                    netif_running(sdata->dev)) {
  96                        conf.vif = &sdata->vif;
  97                        conf.type = sdata->vif.type;
  98                        conf.mac_addr = sdata->dev->dev_addr;
  99                        res = local->ops->add_interface(hw, &conf);
 100                }
 101        }
 102
 103        /* add STAs back */
 104        if (local->ops->sta_notify) {
 105                spin_lock_irqsave(&local->sta_lock, flags);
 106                list_for_each_entry(sta, &local->sta_list, list) {
 107                        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 108                                sdata = container_of(sdata->bss,
 109                                             struct ieee80211_sub_if_data,
 110                                             u.ap);
 111
 112                        local->ops->sta_notify(hw, &sdata->vif,
 113                                STA_NOTIFY_ADD, &sta->sta);
 114                }
 115                spin_unlock_irqrestore(&local->sta_lock, flags);
 116        }
 117
 118        /* Clear Suspend state so that ADDBA requests can be processed */
 119
 120        rcu_read_lock();
 121
 122        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
 123                list_for_each_entry_rcu(sta, &local->sta_list, list) {
 124                        clear_sta_flags(sta, WLAN_STA_SUSPEND);
 125                }
 126        }
 127
 128        rcu_read_unlock();
 129
 130        /* add back keys */
 131        list_for_each_entry(sdata, &local->interfaces, list)
 132                if (netif_running(sdata->dev))
 133                        ieee80211_enable_keys(sdata);
 134
 135        /* setup RTS threshold */
 136        if (local->ops->set_rts_threshold)
 137                local->ops->set_rts_threshold(hw, local->rts_threshold);
 138
 139        /* reconfigure hardware */
 140        ieee80211_hw_config(local, ~0);
 141
 142        netif_addr_lock_bh(local->mdev);
 143        ieee80211_configure_filter(local);
 144        netif_addr_unlock_bh(local->mdev);
 145
 146        /* Finally also reconfigure all the BSS information */
 147        list_for_each_entry(sdata, &local->interfaces, list) {
 148                u32 changed = ~0;
 149                if (!netif_running(sdata->dev))
 150                        continue;
 151                switch (sdata->vif.type) {
 152                case NL80211_IFTYPE_STATION:
 153                        /* disable beacon change bits */
 154                        changed &= ~IEEE80211_IFCC_BEACON;
 155                        /* fall through */
 156                case NL80211_IFTYPE_ADHOC:
 157                case NL80211_IFTYPE_AP:
 158                case NL80211_IFTYPE_MESH_POINT:
 159                        /*
 160                         * Driver's config_interface can fail if rfkill is
 161                         * enabled. Accommodate this return code.
 162                         * FIXME: When mac80211 has knowledge of rfkill
 163                         * state the code below can change back to:
 164                         *   WARN(ieee80211_if_config(sdata, changed));
 165                         *   ieee80211_bss_info_change_notify(sdata, ~0);
 166                         */
 167                        if (ieee80211_if_config(sdata, changed))
 168                                printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
 169                                       sdata->dev->name);
 170                        else
 171                                ieee80211_bss_info_change_notify(sdata, ~0);
 172                        break;
 173                case NL80211_IFTYPE_WDS:
 174                        break;
 175                case NL80211_IFTYPE_AP_VLAN:
 176                case NL80211_IFTYPE_MONITOR:
 177                        /* ignore virtual */
 178                        break;
 179                case NL80211_IFTYPE_UNSPECIFIED:
 180                case __NL80211_IFTYPE_AFTER_LAST:
 181                        WARN_ON(1);
 182                        break;
 183                }
 184        }
 185
 186        ieee80211_wake_queues_by_reason(hw,
 187                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 188
 189        return 0;
 190}
 191