pm.c 2.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#include <net/mac80211.h>
#include <net/rtnetlink.h>

#include "ieee80211_i.h"
#include "led.h"

int __ieee80211_suspend(struct ieee80211_hw *hw)
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_if_init_conf conf;
	struct sta_info *sta;

	flush_workqueue(local->hw.workqueue);

	/* disable keys */
	list_for_each_entry(sdata, &local->interfaces, list)
		ieee80211_disable_keys(sdata);

	/* remove STAs */
	list_for_each_entry(sta, &local->sta_list, list) {

		if (local->ops->sta_notify) {
			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
				sdata = container_of(sdata->bss,
					     struct ieee80211_sub_if_data,
					     u.ap);

			local->ops->sta_notify(hw, &sdata->vif,
				STA_NOTIFY_REMOVE, &sta->sta);
		}
	}

	/* remove all interfaces */
	list_for_each_entry(sdata, &local->interfaces, list) {

		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
		    netif_running(sdata->dev)) {
			conf.vif = &sdata->vif;
			conf.type = sdata->vif.type;
			conf.mac_addr = sdata->dev->dev_addr;
			local->ops->remove_interface(hw, &conf);
		}
	}

	/* stop hardware */
	if (local->open_count) {
		ieee80211_led_radio(local, false);
		local->ops->stop(hw);
	}
	return 0;
}

int __ieee80211_resume(struct ieee80211_hw *hw)
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_if_init_conf conf;
	struct sta_info *sta;
	int res;

	/* restart hardware */
	if (local->open_count) {
		res = local->ops->start(hw);

		ieee80211_led_radio(local, hw->conf.radio_enabled);
	}

	/* add interfaces */
	list_for_each_entry(sdata, &local->interfaces, list) {

		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
		    netif_running(sdata->dev)) {
			conf.vif = &sdata->vif;
			conf.type = sdata->vif.type;
			conf.mac_addr = sdata->dev->dev_addr;
			res = local->ops->add_interface(hw, &conf);
		}
	}

	/* add STAs back */
	list_for_each_entry(sta, &local->sta_list, list) {

		if (local->ops->sta_notify) {
			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
				sdata = container_of(sdata->bss,
					     struct ieee80211_sub_if_data,
					     u.ap);

			local->ops->sta_notify(hw, &sdata->vif,
				STA_NOTIFY_ADD, &sta->sta);
		}
	}

	/* add back keys */
	list_for_each_entry(sdata, &local->interfaces, list)
		if (netif_running(sdata->dev))
			ieee80211_enable_keys(sdata);

	/* setup RTS threshold */
	if (local->ops->set_rts_threshold)
		local->ops->set_rts_threshold(hw, local->rts_threshold);

	/* reconfigure hardware */
	ieee80211_hw_config(local, ~0);

	netif_addr_lock_bh(local->mdev);
	ieee80211_configure_filter(local);
	netif_addr_unlock_bh(local->mdev);

	return 0;
}