Root/
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 <net/mac80211.h> |
16 | #include "ieee80211_i.h" |
17 | |
18 | /* |
19 | * inform AP that we will go to sleep so that it will buffer the frames |
20 | * while we scan |
21 | */ |
22 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) |
23 | { |
24 | struct ieee80211_local *local = sdata->local; |
25 | |
26 | local->offchannel_ps_enabled = false; |
27 | |
28 | /* FIXME: what to do when local->pspolling is true? */ |
29 | |
30 | del_timer_sync(&local->dynamic_ps_timer); |
31 | cancel_work_sync(&local->dynamic_ps_enable_work); |
32 | |
33 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
34 | local->offchannel_ps_enabled = true; |
35 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
36 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
37 | } |
38 | |
39 | if (!(local->offchannel_ps_enabled) || |
40 | !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) |
41 | /* |
42 | * If power save was enabled, no need to send a nullfunc |
43 | * frame because AP knows that we are sleeping. But if the |
44 | * hardware is creating the nullfunc frame for power save |
45 | * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not |
46 | * enabled) and power save was enabled, the firmware just |
47 | * sent a null frame with power save disabled. So we need |
48 | * to send a new nullfunc frame to inform the AP that we |
49 | * are again sleeping. |
50 | */ |
51 | ieee80211_send_nullfunc(local, sdata, 1); |
52 | } |
53 | |
54 | /* inform AP that we are awake again, unless power save is enabled */ |
55 | static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) |
56 | { |
57 | struct ieee80211_local *local = sdata->local; |
58 | |
59 | if (!local->ps_sdata) |
60 | ieee80211_send_nullfunc(local, sdata, 0); |
61 | else if (local->offchannel_ps_enabled) { |
62 | /* |
63 | * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware |
64 | * will send a nullfunc frame with the powersave bit set |
65 | * even though the AP already knows that we are sleeping. |
66 | * This could be avoided by sending a null frame with power |
67 | * save bit disabled before enabling the power save, but |
68 | * this doesn't gain anything. |
69 | * |
70 | * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need |
71 | * to send a nullfunc frame because AP already knows that |
72 | * we are sleeping, let's just enable power save mode in |
73 | * hardware. |
74 | */ |
75 | local->hw.conf.flags |= IEEE80211_CONF_PS; |
76 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
77 | } else if (local->hw.conf.dynamic_ps_timeout > 0) { |
78 | /* |
79 | * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer |
80 | * had been running before leaving the operating channel, |
81 | * restart the timer now and send a nullfunc frame to inform |
82 | * the AP that we are awake. |
83 | */ |
84 | ieee80211_send_nullfunc(local, sdata, 0); |
85 | mod_timer(&local->dynamic_ps_timer, jiffies + |
86 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); |
87 | } |
88 | } |
89 | |
90 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) |
91 | { |
92 | struct ieee80211_sub_if_data *sdata; |
93 | |
94 | mutex_lock(&local->iflist_mtx); |
95 | list_for_each_entry(sdata, &local->interfaces, list) { |
96 | if (!ieee80211_sdata_running(sdata)) |
97 | continue; |
98 | |
99 | /* disable beaconing */ |
100 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
101 | sdata->vif.type == NL80211_IFTYPE_ADHOC || |
102 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
103 | ieee80211_bss_info_change_notify( |
104 | sdata, BSS_CHANGED_BEACON_ENABLED); |
105 | |
106 | /* |
107 | * only handle non-STA interfaces here, STA interfaces |
108 | * are handled in ieee80211_offchannel_stop_station(), |
109 | * e.g., from the background scan state machine. |
110 | * |
111 | * In addition, do not stop monitor interface to allow it to be |
112 | * used from user space controlled off-channel operations. |
113 | */ |
114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) |
116 | netif_tx_stop_all_queues(sdata->dev); |
117 | } |
118 | mutex_unlock(&local->iflist_mtx); |
119 | } |
120 | |
121 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local) |
122 | { |
123 | struct ieee80211_sub_if_data *sdata; |
124 | |
125 | /* |
126 | * notify the AP about us leaving the channel and stop all STA interfaces |
127 | */ |
128 | mutex_lock(&local->iflist_mtx); |
129 | list_for_each_entry(sdata, &local->interfaces, list) { |
130 | if (!ieee80211_sdata_running(sdata)) |
131 | continue; |
132 | |
133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
134 | netif_tx_stop_all_queues(sdata->dev); |
135 | if (sdata->u.mgd.associated) |
136 | ieee80211_offchannel_ps_enable(sdata); |
137 | } |
138 | } |
139 | mutex_unlock(&local->iflist_mtx); |
140 | } |
141 | |
142 | void ieee80211_offchannel_return(struct ieee80211_local *local, |
143 | bool enable_beaconing) |
144 | { |
145 | struct ieee80211_sub_if_data *sdata; |
146 | |
147 | mutex_lock(&local->iflist_mtx); |
148 | list_for_each_entry(sdata, &local->interfaces, list) { |
149 | if (!ieee80211_sdata_running(sdata)) |
150 | continue; |
151 | |
152 | /* Tell AP we're back */ |
153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
154 | if (sdata->u.mgd.associated) |
155 | ieee80211_offchannel_ps_disable(sdata); |
156 | } |
157 | |
158 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
159 | netif_tx_wake_all_queues(sdata->dev); |
160 | |
161 | /* re-enable beaconing */ |
162 | if (enable_beaconing && |
163 | (sdata->vif.type == NL80211_IFTYPE_AP || |
164 | sdata->vif.type == NL80211_IFTYPE_ADHOC || |
165 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) |
166 | ieee80211_bss_info_change_notify( |
167 | sdata, BSS_CHANGED_BEACON_ENABLED); |
168 | } |
169 | mutex_unlock(&local->iflist_mtx); |
170 | } |
171 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9