Commit 094d05dc32fc2930e381189a942016e5561775d9
Committed by
John W. Linville
1 parent
420e7fabd9
Exists in
master
and in
7 other branches
mac80211: Fix HT channel selection
HT management is done differently for AP and STA modes, unify to just the ->config() callback since HT is fundamentally a PHY property and cannot be per-BSS. Rename enum nl80211_sec_chan_offset as nl80211_channel_type to denote the channel type ( NO_HT, HT20, HT40+, HT40- ). Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 13 changed files with 109 additions and 169 deletions Inline Diff
- drivers/net/wireless/ath9k/main.c
- drivers/net/wireless/iwlwifi/iwl-agn.c
- drivers/net/wireless/mac80211_hwsim.c
- include/linux/nl80211.h
- include/net/cfg80211.h
- include/net/mac80211.h
- net/mac80211/cfg.c
- net/mac80211/ht.c
- net/mac80211/ieee80211_i.h
- net/mac80211/main.c
- net/mac80211/mlme.c
- net/mac80211/util.c
- net/wireless/nl80211.c
drivers/net/wireless/ath9k/main.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. | 6 | * copyright notice and this permission notice appear in all copies. |
7 | * | 7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/nl80211.h> | 17 | #include <linux/nl80211.h> |
18 | #include "core.h" | 18 | #include "core.h" |
19 | #include "reg.h" | 19 | #include "reg.h" |
20 | #include "hw.h" | 20 | #include "hw.h" |
21 | 21 | ||
22 | #define ATH_PCI_VERSION "0.1" | 22 | #define ATH_PCI_VERSION "0.1" |
23 | 23 | ||
24 | static char *dev_info = "ath9k"; | 24 | static char *dev_info = "ath9k"; |
25 | 25 | ||
26 | MODULE_AUTHOR("Atheros Communications"); | 26 | MODULE_AUTHOR("Atheros Communications"); |
27 | MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); | 27 | MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); |
28 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); | 28 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); |
29 | MODULE_LICENSE("Dual BSD/GPL"); | 29 | MODULE_LICENSE("Dual BSD/GPL"); |
30 | 30 | ||
31 | static struct pci_device_id ath_pci_id_table[] __devinitdata = { | 31 | static struct pci_device_id ath_pci_id_table[] __devinitdata = { |
32 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ | 32 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ |
33 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ | 33 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ |
34 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ | 34 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ |
35 | { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ | 35 | { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ |
36 | { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ | 36 | { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ |
37 | { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ | 37 | { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ |
38 | { 0 } | 38 | { 0 } |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static void ath_detach(struct ath_softc *sc); | 41 | static void ath_detach(struct ath_softc *sc); |
42 | 42 | ||
43 | /* return bus cachesize in 4B word units */ | 43 | /* return bus cachesize in 4B word units */ |
44 | 44 | ||
45 | static void bus_read_cachesize(struct ath_softc *sc, int *csz) | 45 | static void bus_read_cachesize(struct ath_softc *sc, int *csz) |
46 | { | 46 | { |
47 | u8 u8tmp; | 47 | u8 u8tmp; |
48 | 48 | ||
49 | pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); | 49 | pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); |
50 | *csz = (int)u8tmp; | 50 | *csz = (int)u8tmp; |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * This check was put in to avoid "unplesant" consequences if | 53 | * This check was put in to avoid "unplesant" consequences if |
54 | * the bootrom has not fully initialized all PCI devices. | 54 | * the bootrom has not fully initialized all PCI devices. |
55 | * Sometimes the cache line size register is not set | 55 | * Sometimes the cache line size register is not set |
56 | */ | 56 | */ |
57 | 57 | ||
58 | if (*csz == 0) | 58 | if (*csz == 0) |
59 | *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ | 59 | *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ |
60 | } | 60 | } |
61 | 61 | ||
62 | static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) | 62 | static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) |
63 | { | 63 | { |
64 | if (!sc->sc_curaid) | 64 | if (!sc->sc_curaid) |
65 | sc->cur_rate_table = sc->hw_rate_table[mode]; | 65 | sc->cur_rate_table = sc->hw_rate_table[mode]; |
66 | /* | 66 | /* |
67 | * All protection frames are transmited at 2Mb/s for | 67 | * All protection frames are transmited at 2Mb/s for |
68 | * 11g, otherwise at 1Mb/s. | 68 | * 11g, otherwise at 1Mb/s. |
69 | * XXX select protection rate index from rate table. | 69 | * XXX select protection rate index from rate table. |
70 | */ | 70 | */ |
71 | sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); | 71 | sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); |
72 | } | 72 | } |
73 | 73 | ||
74 | static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) | 74 | static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) |
75 | { | 75 | { |
76 | if (chan->chanmode == CHANNEL_A) | 76 | if (chan->chanmode == CHANNEL_A) |
77 | return ATH9K_MODE_11A; | 77 | return ATH9K_MODE_11A; |
78 | else if (chan->chanmode == CHANNEL_G) | 78 | else if (chan->chanmode == CHANNEL_G) |
79 | return ATH9K_MODE_11G; | 79 | return ATH9K_MODE_11G; |
80 | else if (chan->chanmode == CHANNEL_B) | 80 | else if (chan->chanmode == CHANNEL_B) |
81 | return ATH9K_MODE_11B; | 81 | return ATH9K_MODE_11B; |
82 | else if (chan->chanmode == CHANNEL_A_HT20) | 82 | else if (chan->chanmode == CHANNEL_A_HT20) |
83 | return ATH9K_MODE_11NA_HT20; | 83 | return ATH9K_MODE_11NA_HT20; |
84 | else if (chan->chanmode == CHANNEL_G_HT20) | 84 | else if (chan->chanmode == CHANNEL_G_HT20) |
85 | return ATH9K_MODE_11NG_HT20; | 85 | return ATH9K_MODE_11NG_HT20; |
86 | else if (chan->chanmode == CHANNEL_A_HT40PLUS) | 86 | else if (chan->chanmode == CHANNEL_A_HT40PLUS) |
87 | return ATH9K_MODE_11NA_HT40PLUS; | 87 | return ATH9K_MODE_11NA_HT40PLUS; |
88 | else if (chan->chanmode == CHANNEL_A_HT40MINUS) | 88 | else if (chan->chanmode == CHANNEL_A_HT40MINUS) |
89 | return ATH9K_MODE_11NA_HT40MINUS; | 89 | return ATH9K_MODE_11NA_HT40MINUS; |
90 | else if (chan->chanmode == CHANNEL_G_HT40PLUS) | 90 | else if (chan->chanmode == CHANNEL_G_HT40PLUS) |
91 | return ATH9K_MODE_11NG_HT40PLUS; | 91 | return ATH9K_MODE_11NG_HT40PLUS; |
92 | else if (chan->chanmode == CHANNEL_G_HT40MINUS) | 92 | else if (chan->chanmode == CHANNEL_G_HT40MINUS) |
93 | return ATH9K_MODE_11NG_HT40MINUS; | 93 | return ATH9K_MODE_11NG_HT40MINUS; |
94 | 94 | ||
95 | WARN_ON(1); /* should not get here */ | 95 | WARN_ON(1); /* should not get here */ |
96 | 96 | ||
97 | return ATH9K_MODE_11B; | 97 | return ATH9K_MODE_11B; |
98 | } | 98 | } |
99 | 99 | ||
100 | static void ath_update_txpow(struct ath_softc *sc) | 100 | static void ath_update_txpow(struct ath_softc *sc) |
101 | { | 101 | { |
102 | struct ath_hal *ah = sc->sc_ah; | 102 | struct ath_hal *ah = sc->sc_ah; |
103 | u32 txpow; | 103 | u32 txpow; |
104 | 104 | ||
105 | if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { | 105 | if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { |
106 | ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); | 106 | ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); |
107 | /* read back in case value is clamped */ | 107 | /* read back in case value is clamped */ |
108 | ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); | 108 | ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); |
109 | sc->sc_curtxpow = txpow; | 109 | sc->sc_curtxpow = txpow; |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | static u8 parse_mpdudensity(u8 mpdudensity) | 113 | static u8 parse_mpdudensity(u8 mpdudensity) |
114 | { | 114 | { |
115 | /* | 115 | /* |
116 | * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": | 116 | * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": |
117 | * 0 for no restriction | 117 | * 0 for no restriction |
118 | * 1 for 1/4 us | 118 | * 1 for 1/4 us |
119 | * 2 for 1/2 us | 119 | * 2 for 1/2 us |
120 | * 3 for 1 us | 120 | * 3 for 1 us |
121 | * 4 for 2 us | 121 | * 4 for 2 us |
122 | * 5 for 4 us | 122 | * 5 for 4 us |
123 | * 6 for 8 us | 123 | * 6 for 8 us |
124 | * 7 for 16 us | 124 | * 7 for 16 us |
125 | */ | 125 | */ |
126 | switch (mpdudensity) { | 126 | switch (mpdudensity) { |
127 | case 0: | 127 | case 0: |
128 | return 0; | 128 | return 0; |
129 | case 1: | 129 | case 1: |
130 | case 2: | 130 | case 2: |
131 | case 3: | 131 | case 3: |
132 | /* Our lower layer calculations limit our precision to | 132 | /* Our lower layer calculations limit our precision to |
133 | 1 microsecond */ | 133 | 1 microsecond */ |
134 | return 1; | 134 | return 1; |
135 | case 4: | 135 | case 4: |
136 | return 2; | 136 | return 2; |
137 | case 5: | 137 | case 5: |
138 | return 4; | 138 | return 4; |
139 | case 6: | 139 | case 6: |
140 | return 8; | 140 | return 8; |
141 | case 7: | 141 | case 7: |
142 | return 16; | 142 | return 16; |
143 | default: | 143 | default: |
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | } | 146 | } |
147 | 147 | ||
148 | static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) | 148 | static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) |
149 | { | 149 | { |
150 | struct ath_rate_table *rate_table = NULL; | 150 | struct ath_rate_table *rate_table = NULL; |
151 | struct ieee80211_supported_band *sband; | 151 | struct ieee80211_supported_band *sband; |
152 | struct ieee80211_rate *rate; | 152 | struct ieee80211_rate *rate; |
153 | int i, maxrates; | 153 | int i, maxrates; |
154 | 154 | ||
155 | switch (band) { | 155 | switch (band) { |
156 | case IEEE80211_BAND_2GHZ: | 156 | case IEEE80211_BAND_2GHZ: |
157 | rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; | 157 | rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; |
158 | break; | 158 | break; |
159 | case IEEE80211_BAND_5GHZ: | 159 | case IEEE80211_BAND_5GHZ: |
160 | rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; | 160 | rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; |
161 | break; | 161 | break; |
162 | default: | 162 | default: |
163 | break; | 163 | break; |
164 | } | 164 | } |
165 | 165 | ||
166 | if (rate_table == NULL) | 166 | if (rate_table == NULL) |
167 | return; | 167 | return; |
168 | 168 | ||
169 | sband = &sc->sbands[band]; | 169 | sband = &sc->sbands[band]; |
170 | rate = sc->rates[band]; | 170 | rate = sc->rates[band]; |
171 | 171 | ||
172 | if (rate_table->rate_cnt > ATH_RATE_MAX) | 172 | if (rate_table->rate_cnt > ATH_RATE_MAX) |
173 | maxrates = ATH_RATE_MAX; | 173 | maxrates = ATH_RATE_MAX; |
174 | else | 174 | else |
175 | maxrates = rate_table->rate_cnt; | 175 | maxrates = rate_table->rate_cnt; |
176 | 176 | ||
177 | for (i = 0; i < maxrates; i++) { | 177 | for (i = 0; i < maxrates; i++) { |
178 | rate[i].bitrate = rate_table->info[i].ratekbps / 100; | 178 | rate[i].bitrate = rate_table->info[i].ratekbps / 100; |
179 | rate[i].hw_value = rate_table->info[i].ratecode; | 179 | rate[i].hw_value = rate_table->info[i].ratecode; |
180 | sband->n_bitrates++; | 180 | sband->n_bitrates++; |
181 | DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", | 181 | DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", |
182 | rate[i].bitrate / 10, rate[i].hw_value); | 182 | rate[i].bitrate / 10, rate[i].hw_value); |
183 | } | 183 | } |
184 | } | 184 | } |
185 | 185 | ||
186 | static int ath_setup_channels(struct ath_softc *sc) | 186 | static int ath_setup_channels(struct ath_softc *sc) |
187 | { | 187 | { |
188 | struct ath_hal *ah = sc->sc_ah; | 188 | struct ath_hal *ah = sc->sc_ah; |
189 | int nchan, i, a = 0, b = 0; | 189 | int nchan, i, a = 0, b = 0; |
190 | u8 regclassids[ATH_REGCLASSIDS_MAX]; | 190 | u8 regclassids[ATH_REGCLASSIDS_MAX]; |
191 | u32 nregclass = 0; | 191 | u32 nregclass = 0; |
192 | struct ieee80211_supported_band *band_2ghz; | 192 | struct ieee80211_supported_band *band_2ghz; |
193 | struct ieee80211_supported_band *band_5ghz; | 193 | struct ieee80211_supported_band *band_5ghz; |
194 | struct ieee80211_channel *chan_2ghz; | 194 | struct ieee80211_channel *chan_2ghz; |
195 | struct ieee80211_channel *chan_5ghz; | 195 | struct ieee80211_channel *chan_5ghz; |
196 | struct ath9k_channel *c; | 196 | struct ath9k_channel *c; |
197 | 197 | ||
198 | /* Fill in ah->ah_channels */ | 198 | /* Fill in ah->ah_channels */ |
199 | if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, | 199 | if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, |
200 | regclassids, ATH_REGCLASSIDS_MAX, | 200 | regclassids, ATH_REGCLASSIDS_MAX, |
201 | &nregclass, CTRY_DEFAULT, false, 1)) { | 201 | &nregclass, CTRY_DEFAULT, false, 1)) { |
202 | u32 rd = ah->ah_currentRD; | 202 | u32 rd = ah->ah_currentRD; |
203 | DPRINTF(sc, ATH_DBG_FATAL, | 203 | DPRINTF(sc, ATH_DBG_FATAL, |
204 | "Unable to collect channel list; " | 204 | "Unable to collect channel list; " |
205 | "regdomain likely %u country code %u\n", | 205 | "regdomain likely %u country code %u\n", |
206 | rd, CTRY_DEFAULT); | 206 | rd, CTRY_DEFAULT); |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | } | 208 | } |
209 | 209 | ||
210 | band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; | 210 | band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; |
211 | band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; | 211 | band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; |
212 | chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; | 212 | chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; |
213 | chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; | 213 | chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; |
214 | 214 | ||
215 | for (i = 0; i < nchan; i++) { | 215 | for (i = 0; i < nchan; i++) { |
216 | c = &ah->ah_channels[i]; | 216 | c = &ah->ah_channels[i]; |
217 | if (IS_CHAN_2GHZ(c)) { | 217 | if (IS_CHAN_2GHZ(c)) { |
218 | chan_2ghz[a].band = IEEE80211_BAND_2GHZ; | 218 | chan_2ghz[a].band = IEEE80211_BAND_2GHZ; |
219 | chan_2ghz[a].center_freq = c->channel; | 219 | chan_2ghz[a].center_freq = c->channel; |
220 | chan_2ghz[a].max_power = c->maxTxPower; | 220 | chan_2ghz[a].max_power = c->maxTxPower; |
221 | 221 | ||
222 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) | 222 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) |
223 | chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; | 223 | chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; |
224 | if (c->channelFlags & CHANNEL_PASSIVE) | 224 | if (c->channelFlags & CHANNEL_PASSIVE) |
225 | chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; | 225 | chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; |
226 | 226 | ||
227 | band_2ghz->n_channels = ++a; | 227 | band_2ghz->n_channels = ++a; |
228 | 228 | ||
229 | DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " | 229 | DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " |
230 | "channelFlags: 0x%x\n", | 230 | "channelFlags: 0x%x\n", |
231 | c->channel, c->channelFlags); | 231 | c->channel, c->channelFlags); |
232 | } else if (IS_CHAN_5GHZ(c)) { | 232 | } else if (IS_CHAN_5GHZ(c)) { |
233 | chan_5ghz[b].band = IEEE80211_BAND_5GHZ; | 233 | chan_5ghz[b].band = IEEE80211_BAND_5GHZ; |
234 | chan_5ghz[b].center_freq = c->channel; | 234 | chan_5ghz[b].center_freq = c->channel; |
235 | chan_5ghz[b].max_power = c->maxTxPower; | 235 | chan_5ghz[b].max_power = c->maxTxPower; |
236 | 236 | ||
237 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) | 237 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) |
238 | chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; | 238 | chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; |
239 | if (c->channelFlags & CHANNEL_PASSIVE) | 239 | if (c->channelFlags & CHANNEL_PASSIVE) |
240 | chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; | 240 | chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; |
241 | 241 | ||
242 | band_5ghz->n_channels = ++b; | 242 | band_5ghz->n_channels = ++b; |
243 | 243 | ||
244 | DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " | 244 | DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " |
245 | "channelFlags: 0x%x\n", | 245 | "channelFlags: 0x%x\n", |
246 | c->channel, c->channelFlags); | 246 | c->channel, c->channelFlags); |
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | return 0; | 250 | return 0; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * Set/change channels. If the channel is really being changed, it's done | 254 | * Set/change channels. If the channel is really being changed, it's done |
255 | * by reseting the chip. To accomplish this we must first cleanup any pending | 255 | * by reseting the chip. To accomplish this we must first cleanup any pending |
256 | * DMA, then restart stuff. | 256 | * DMA, then restart stuff. |
257 | */ | 257 | */ |
258 | static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) | 258 | static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) |
259 | { | 259 | { |
260 | struct ath_hal *ah = sc->sc_ah; | 260 | struct ath_hal *ah = sc->sc_ah; |
261 | bool fastcc = true, stopped; | 261 | bool fastcc = true, stopped; |
262 | 262 | ||
263 | if (sc->sc_flags & SC_OP_INVALID) | 263 | if (sc->sc_flags & SC_OP_INVALID) |
264 | return -EIO; | 264 | return -EIO; |
265 | 265 | ||
266 | if (hchan->channel != sc->sc_ah->ah_curchan->channel || | 266 | if (hchan->channel != sc->sc_ah->ah_curchan->channel || |
267 | hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || | 267 | hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || |
268 | (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || | 268 | (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || |
269 | (sc->sc_flags & SC_OP_FULL_RESET)) { | 269 | (sc->sc_flags & SC_OP_FULL_RESET)) { |
270 | int status; | 270 | int status; |
271 | /* | 271 | /* |
272 | * This is only performed if the channel settings have | 272 | * This is only performed if the channel settings have |
273 | * actually changed. | 273 | * actually changed. |
274 | * | 274 | * |
275 | * To switch channels clear any pending DMA operations; | 275 | * To switch channels clear any pending DMA operations; |
276 | * wait long enough for the RX fifo to drain, reset the | 276 | * wait long enough for the RX fifo to drain, reset the |
277 | * hardware at the new frequency, and then re-enable | 277 | * hardware at the new frequency, and then re-enable |
278 | * the relevant bits of the h/w. | 278 | * the relevant bits of the h/w. |
279 | */ | 279 | */ |
280 | ath9k_hw_set_interrupts(ah, 0); | 280 | ath9k_hw_set_interrupts(ah, 0); |
281 | ath_draintxq(sc, false); | 281 | ath_draintxq(sc, false); |
282 | stopped = ath_stoprecv(sc); | 282 | stopped = ath_stoprecv(sc); |
283 | 283 | ||
284 | /* XXX: do not flush receive queue here. We don't want | 284 | /* XXX: do not flush receive queue here. We don't want |
285 | * to flush data frames already in queue because of | 285 | * to flush data frames already in queue because of |
286 | * changing channel. */ | 286 | * changing channel. */ |
287 | 287 | ||
288 | if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) | 288 | if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) |
289 | fastcc = false; | 289 | fastcc = false; |
290 | 290 | ||
291 | DPRINTF(sc, ATH_DBG_CONFIG, | 291 | DPRINTF(sc, ATH_DBG_CONFIG, |
292 | "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", | 292 | "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", |
293 | sc->sc_ah->ah_curchan->channel, | 293 | sc->sc_ah->ah_curchan->channel, |
294 | hchan->channel, hchan->channelFlags, sc->tx_chan_width); | 294 | hchan->channel, hchan->channelFlags, sc->tx_chan_width); |
295 | 295 | ||
296 | spin_lock_bh(&sc->sc_resetlock); | 296 | spin_lock_bh(&sc->sc_resetlock); |
297 | if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, | 297 | if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, |
298 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, | 298 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, |
299 | sc->sc_ht_extprotspacing, fastcc, &status)) { | 299 | sc->sc_ht_extprotspacing, fastcc, &status)) { |
300 | DPRINTF(sc, ATH_DBG_FATAL, | 300 | DPRINTF(sc, ATH_DBG_FATAL, |
301 | "Unable to reset channel %u (%uMhz) " | 301 | "Unable to reset channel %u (%uMhz) " |
302 | "flags 0x%x hal status %u\n", | 302 | "flags 0x%x hal status %u\n", |
303 | ath9k_hw_mhz2ieee(ah, hchan->channel, | 303 | ath9k_hw_mhz2ieee(ah, hchan->channel, |
304 | hchan->channelFlags), | 304 | hchan->channelFlags), |
305 | hchan->channel, hchan->channelFlags, status); | 305 | hchan->channel, hchan->channelFlags, status); |
306 | spin_unlock_bh(&sc->sc_resetlock); | 306 | spin_unlock_bh(&sc->sc_resetlock); |
307 | return -EIO; | 307 | return -EIO; |
308 | } | 308 | } |
309 | spin_unlock_bh(&sc->sc_resetlock); | 309 | spin_unlock_bh(&sc->sc_resetlock); |
310 | 310 | ||
311 | sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; | 311 | sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; |
312 | sc->sc_flags &= ~SC_OP_FULL_RESET; | 312 | sc->sc_flags &= ~SC_OP_FULL_RESET; |
313 | 313 | ||
314 | if (ath_startrecv(sc) != 0) { | 314 | if (ath_startrecv(sc) != 0) { |
315 | DPRINTF(sc, ATH_DBG_FATAL, | 315 | DPRINTF(sc, ATH_DBG_FATAL, |
316 | "Unable to restart recv logic\n"); | 316 | "Unable to restart recv logic\n"); |
317 | return -EIO; | 317 | return -EIO; |
318 | } | 318 | } |
319 | 319 | ||
320 | ath_setcurmode(sc, ath_chan2mode(hchan)); | 320 | ath_setcurmode(sc, ath_chan2mode(hchan)); |
321 | ath_update_txpow(sc); | 321 | ath_update_txpow(sc); |
322 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | 322 | ath9k_hw_set_interrupts(ah, sc->sc_imask); |
323 | } | 323 | } |
324 | return 0; | 324 | return 0; |
325 | } | 325 | } |
326 | 326 | ||
327 | /* | 327 | /* |
328 | * This routine performs the periodic noise floor calibration function | 328 | * This routine performs the periodic noise floor calibration function |
329 | * that is used to adjust and optimize the chip performance. This | 329 | * that is used to adjust and optimize the chip performance. This |
330 | * takes environmental changes (location, temperature) into account. | 330 | * takes environmental changes (location, temperature) into account. |
331 | * When the task is complete, it reschedules itself depending on the | 331 | * When the task is complete, it reschedules itself depending on the |
332 | * appropriate interval that was calculated. | 332 | * appropriate interval that was calculated. |
333 | */ | 333 | */ |
334 | static void ath_ani_calibrate(unsigned long data) | 334 | static void ath_ani_calibrate(unsigned long data) |
335 | { | 335 | { |
336 | struct ath_softc *sc; | 336 | struct ath_softc *sc; |
337 | struct ath_hal *ah; | 337 | struct ath_hal *ah; |
338 | bool longcal = false; | 338 | bool longcal = false; |
339 | bool shortcal = false; | 339 | bool shortcal = false; |
340 | bool aniflag = false; | 340 | bool aniflag = false; |
341 | unsigned int timestamp = jiffies_to_msecs(jiffies); | 341 | unsigned int timestamp = jiffies_to_msecs(jiffies); |
342 | u32 cal_interval; | 342 | u32 cal_interval; |
343 | 343 | ||
344 | sc = (struct ath_softc *)data; | 344 | sc = (struct ath_softc *)data; |
345 | ah = sc->sc_ah; | 345 | ah = sc->sc_ah; |
346 | 346 | ||
347 | /* | 347 | /* |
348 | * don't calibrate when we're scanning. | 348 | * don't calibrate when we're scanning. |
349 | * we are most likely not on our home channel. | 349 | * we are most likely not on our home channel. |
350 | */ | 350 | */ |
351 | if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) | 351 | if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) |
352 | return; | 352 | return; |
353 | 353 | ||
354 | /* Long calibration runs independently of short calibration. */ | 354 | /* Long calibration runs independently of short calibration. */ |
355 | if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { | 355 | if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { |
356 | longcal = true; | 356 | longcal = true; |
357 | DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); | 357 | DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); |
358 | sc->sc_ani.sc_longcal_timer = timestamp; | 358 | sc->sc_ani.sc_longcal_timer = timestamp; |
359 | } | 359 | } |
360 | 360 | ||
361 | /* Short calibration applies only while sc_caldone is false */ | 361 | /* Short calibration applies only while sc_caldone is false */ |
362 | if (!sc->sc_ani.sc_caldone) { | 362 | if (!sc->sc_ani.sc_caldone) { |
363 | if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= | 363 | if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= |
364 | ATH_SHORT_CALINTERVAL) { | 364 | ATH_SHORT_CALINTERVAL) { |
365 | shortcal = true; | 365 | shortcal = true; |
366 | DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); | 366 | DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); |
367 | sc->sc_ani.sc_shortcal_timer = timestamp; | 367 | sc->sc_ani.sc_shortcal_timer = timestamp; |
368 | sc->sc_ani.sc_resetcal_timer = timestamp; | 368 | sc->sc_ani.sc_resetcal_timer = timestamp; |
369 | } | 369 | } |
370 | } else { | 370 | } else { |
371 | if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= | 371 | if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= |
372 | ATH_RESTART_CALINTERVAL) { | 372 | ATH_RESTART_CALINTERVAL) { |
373 | ath9k_hw_reset_calvalid(ah, ah->ah_curchan, | 373 | ath9k_hw_reset_calvalid(ah, ah->ah_curchan, |
374 | &sc->sc_ani.sc_caldone); | 374 | &sc->sc_ani.sc_caldone); |
375 | if (sc->sc_ani.sc_caldone) | 375 | if (sc->sc_ani.sc_caldone) |
376 | sc->sc_ani.sc_resetcal_timer = timestamp; | 376 | sc->sc_ani.sc_resetcal_timer = timestamp; |
377 | } | 377 | } |
378 | } | 378 | } |
379 | 379 | ||
380 | /* Verify whether we must check ANI */ | 380 | /* Verify whether we must check ANI */ |
381 | if ((timestamp - sc->sc_ani.sc_checkani_timer) >= | 381 | if ((timestamp - sc->sc_ani.sc_checkani_timer) >= |
382 | ATH_ANI_POLLINTERVAL) { | 382 | ATH_ANI_POLLINTERVAL) { |
383 | aniflag = true; | 383 | aniflag = true; |
384 | sc->sc_ani.sc_checkani_timer = timestamp; | 384 | sc->sc_ani.sc_checkani_timer = timestamp; |
385 | } | 385 | } |
386 | 386 | ||
387 | /* Skip all processing if there's nothing to do. */ | 387 | /* Skip all processing if there's nothing to do. */ |
388 | if (longcal || shortcal || aniflag) { | 388 | if (longcal || shortcal || aniflag) { |
389 | /* Call ANI routine if necessary */ | 389 | /* Call ANI routine if necessary */ |
390 | if (aniflag) | 390 | if (aniflag) |
391 | ath9k_hw_ani_monitor(ah, &sc->sc_halstats, | 391 | ath9k_hw_ani_monitor(ah, &sc->sc_halstats, |
392 | ah->ah_curchan); | 392 | ah->ah_curchan); |
393 | 393 | ||
394 | /* Perform calibration if necessary */ | 394 | /* Perform calibration if necessary */ |
395 | if (longcal || shortcal) { | 395 | if (longcal || shortcal) { |
396 | bool iscaldone = false; | 396 | bool iscaldone = false; |
397 | 397 | ||
398 | if (ath9k_hw_calibrate(ah, ah->ah_curchan, | 398 | if (ath9k_hw_calibrate(ah, ah->ah_curchan, |
399 | sc->sc_rx_chainmask, longcal, | 399 | sc->sc_rx_chainmask, longcal, |
400 | &iscaldone)) { | 400 | &iscaldone)) { |
401 | if (longcal) | 401 | if (longcal) |
402 | sc->sc_ani.sc_noise_floor = | 402 | sc->sc_ani.sc_noise_floor = |
403 | ath9k_hw_getchan_noise(ah, | 403 | ath9k_hw_getchan_noise(ah, |
404 | ah->ah_curchan); | 404 | ah->ah_curchan); |
405 | 405 | ||
406 | DPRINTF(sc, ATH_DBG_ANI, | 406 | DPRINTF(sc, ATH_DBG_ANI, |
407 | "calibrate chan %u/%x nf: %d\n", | 407 | "calibrate chan %u/%x nf: %d\n", |
408 | ah->ah_curchan->channel, | 408 | ah->ah_curchan->channel, |
409 | ah->ah_curchan->channelFlags, | 409 | ah->ah_curchan->channelFlags, |
410 | sc->sc_ani.sc_noise_floor); | 410 | sc->sc_ani.sc_noise_floor); |
411 | } else { | 411 | } else { |
412 | DPRINTF(sc, ATH_DBG_ANY, | 412 | DPRINTF(sc, ATH_DBG_ANY, |
413 | "calibrate chan %u/%x failed\n", | 413 | "calibrate chan %u/%x failed\n", |
414 | ah->ah_curchan->channel, | 414 | ah->ah_curchan->channel, |
415 | ah->ah_curchan->channelFlags); | 415 | ah->ah_curchan->channelFlags); |
416 | } | 416 | } |
417 | sc->sc_ani.sc_caldone = iscaldone; | 417 | sc->sc_ani.sc_caldone = iscaldone; |
418 | } | 418 | } |
419 | } | 419 | } |
420 | 420 | ||
421 | /* | 421 | /* |
422 | * Set timer interval based on previous results. | 422 | * Set timer interval based on previous results. |
423 | * The interval must be the shortest necessary to satisfy ANI, | 423 | * The interval must be the shortest necessary to satisfy ANI, |
424 | * short calibration and long calibration. | 424 | * short calibration and long calibration. |
425 | */ | 425 | */ |
426 | cal_interval = ATH_LONG_CALINTERVAL; | 426 | cal_interval = ATH_LONG_CALINTERVAL; |
427 | if (sc->sc_ah->ah_config.enable_ani) | 427 | if (sc->sc_ah->ah_config.enable_ani) |
428 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | 428 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); |
429 | if (!sc->sc_ani.sc_caldone) | 429 | if (!sc->sc_ani.sc_caldone) |
430 | cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); | 430 | cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); |
431 | 431 | ||
432 | mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 432 | mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
433 | } | 433 | } |
434 | 434 | ||
435 | /* | 435 | /* |
436 | * Update tx/rx chainmask. For legacy association, | 436 | * Update tx/rx chainmask. For legacy association, |
437 | * hard code chainmask to 1x1, for 11n association, use | 437 | * hard code chainmask to 1x1, for 11n association, use |
438 | * the chainmask configuration. | 438 | * the chainmask configuration. |
439 | */ | 439 | */ |
440 | static void ath_update_chainmask(struct ath_softc *sc, int is_ht) | 440 | static void ath_update_chainmask(struct ath_softc *sc, int is_ht) |
441 | { | 441 | { |
442 | sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; | 442 | sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; |
443 | if (is_ht) { | 443 | if (is_ht) { |
444 | sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; | 444 | sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; |
445 | sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; | 445 | sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; |
446 | } else { | 446 | } else { |
447 | sc->sc_tx_chainmask = 1; | 447 | sc->sc_tx_chainmask = 1; |
448 | sc->sc_rx_chainmask = 1; | 448 | sc->sc_rx_chainmask = 1; |
449 | } | 449 | } |
450 | 450 | ||
451 | DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", | 451 | DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", |
452 | sc->sc_tx_chainmask, sc->sc_rx_chainmask); | 452 | sc->sc_tx_chainmask, sc->sc_rx_chainmask); |
453 | } | 453 | } |
454 | 454 | ||
455 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) | 455 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) |
456 | { | 456 | { |
457 | struct ath_node *an; | 457 | struct ath_node *an; |
458 | 458 | ||
459 | an = (struct ath_node *)sta->drv_priv; | 459 | an = (struct ath_node *)sta->drv_priv; |
460 | 460 | ||
461 | if (sc->sc_flags & SC_OP_TXAGGR) | 461 | if (sc->sc_flags & SC_OP_TXAGGR) |
462 | ath_tx_node_init(sc, an); | 462 | ath_tx_node_init(sc, an); |
463 | 463 | ||
464 | an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + | 464 | an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + |
465 | sta->ht_cap.ampdu_factor); | 465 | sta->ht_cap.ampdu_factor); |
466 | an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); | 466 | an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); |
467 | } | 467 | } |
468 | 468 | ||
469 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | 469 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) |
470 | { | 470 | { |
471 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | 471 | struct ath_node *an = (struct ath_node *)sta->drv_priv; |
472 | 472 | ||
473 | if (sc->sc_flags & SC_OP_TXAGGR) | 473 | if (sc->sc_flags & SC_OP_TXAGGR) |
474 | ath_tx_node_cleanup(sc, an); | 474 | ath_tx_node_cleanup(sc, an); |
475 | } | 475 | } |
476 | 476 | ||
477 | static void ath9k_tasklet(unsigned long data) | 477 | static void ath9k_tasklet(unsigned long data) |
478 | { | 478 | { |
479 | struct ath_softc *sc = (struct ath_softc *)data; | 479 | struct ath_softc *sc = (struct ath_softc *)data; |
480 | u32 status = sc->sc_intrstatus; | 480 | u32 status = sc->sc_intrstatus; |
481 | 481 | ||
482 | if (status & ATH9K_INT_FATAL) { | 482 | if (status & ATH9K_INT_FATAL) { |
483 | /* need a chip reset */ | 483 | /* need a chip reset */ |
484 | ath_reset(sc, false); | 484 | ath_reset(sc, false); |
485 | return; | 485 | return; |
486 | } else { | 486 | } else { |
487 | 487 | ||
488 | if (status & | 488 | if (status & |
489 | (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { | 489 | (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { |
490 | spin_lock_bh(&sc->rx.rxflushlock); | 490 | spin_lock_bh(&sc->rx.rxflushlock); |
491 | ath_rx_tasklet(sc, 0); | 491 | ath_rx_tasklet(sc, 0); |
492 | spin_unlock_bh(&sc->rx.rxflushlock); | 492 | spin_unlock_bh(&sc->rx.rxflushlock); |
493 | } | 493 | } |
494 | /* XXX: optimize this */ | 494 | /* XXX: optimize this */ |
495 | if (status & ATH9K_INT_TX) | 495 | if (status & ATH9K_INT_TX) |
496 | ath_tx_tasklet(sc); | 496 | ath_tx_tasklet(sc); |
497 | } | 497 | } |
498 | 498 | ||
499 | /* re-enable hardware interrupt */ | 499 | /* re-enable hardware interrupt */ |
500 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); | 500 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); |
501 | } | 501 | } |
502 | 502 | ||
503 | static irqreturn_t ath_isr(int irq, void *dev) | 503 | static irqreturn_t ath_isr(int irq, void *dev) |
504 | { | 504 | { |
505 | struct ath_softc *sc = dev; | 505 | struct ath_softc *sc = dev; |
506 | struct ath_hal *ah = sc->sc_ah; | 506 | struct ath_hal *ah = sc->sc_ah; |
507 | enum ath9k_int status; | 507 | enum ath9k_int status; |
508 | bool sched = false; | 508 | bool sched = false; |
509 | 509 | ||
510 | do { | 510 | do { |
511 | if (sc->sc_flags & SC_OP_INVALID) { | 511 | if (sc->sc_flags & SC_OP_INVALID) { |
512 | /* | 512 | /* |
513 | * The hardware is not ready/present, don't | 513 | * The hardware is not ready/present, don't |
514 | * touch anything. Note this can happen early | 514 | * touch anything. Note this can happen early |
515 | * on if the IRQ is shared. | 515 | * on if the IRQ is shared. |
516 | */ | 516 | */ |
517 | return IRQ_NONE; | 517 | return IRQ_NONE; |
518 | } | 518 | } |
519 | if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ | 519 | if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ |
520 | return IRQ_NONE; | 520 | return IRQ_NONE; |
521 | } | 521 | } |
522 | 522 | ||
523 | /* | 523 | /* |
524 | * Figure out the reason(s) for the interrupt. Note | 524 | * Figure out the reason(s) for the interrupt. Note |
525 | * that the hal returns a pseudo-ISR that may include | 525 | * that the hal returns a pseudo-ISR that may include |
526 | * bits we haven't explicitly enabled so we mask the | 526 | * bits we haven't explicitly enabled so we mask the |
527 | * value to insure we only process bits we requested. | 527 | * value to insure we only process bits we requested. |
528 | */ | 528 | */ |
529 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ | 529 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ |
530 | 530 | ||
531 | status &= sc->sc_imask; /* discard unasked-for bits */ | 531 | status &= sc->sc_imask; /* discard unasked-for bits */ |
532 | 532 | ||
533 | /* | 533 | /* |
534 | * If there are no status bits set, then this interrupt was not | 534 | * If there are no status bits set, then this interrupt was not |
535 | * for me (should have been caught above). | 535 | * for me (should have been caught above). |
536 | */ | 536 | */ |
537 | if (!status) | 537 | if (!status) |
538 | return IRQ_NONE; | 538 | return IRQ_NONE; |
539 | 539 | ||
540 | sc->sc_intrstatus = status; | 540 | sc->sc_intrstatus = status; |
541 | 541 | ||
542 | if (status & ATH9K_INT_FATAL) { | 542 | if (status & ATH9K_INT_FATAL) { |
543 | /* need a chip reset */ | 543 | /* need a chip reset */ |
544 | sched = true; | 544 | sched = true; |
545 | } else if (status & ATH9K_INT_RXORN) { | 545 | } else if (status & ATH9K_INT_RXORN) { |
546 | /* need a chip reset */ | 546 | /* need a chip reset */ |
547 | sched = true; | 547 | sched = true; |
548 | } else { | 548 | } else { |
549 | if (status & ATH9K_INT_SWBA) { | 549 | if (status & ATH9K_INT_SWBA) { |
550 | /* schedule a tasklet for beacon handling */ | 550 | /* schedule a tasklet for beacon handling */ |
551 | tasklet_schedule(&sc->bcon_tasklet); | 551 | tasklet_schedule(&sc->bcon_tasklet); |
552 | } | 552 | } |
553 | if (status & ATH9K_INT_RXEOL) { | 553 | if (status & ATH9K_INT_RXEOL) { |
554 | /* | 554 | /* |
555 | * NB: the hardware should re-read the link when | 555 | * NB: the hardware should re-read the link when |
556 | * RXE bit is written, but it doesn't work | 556 | * RXE bit is written, but it doesn't work |
557 | * at least on older hardware revs. | 557 | * at least on older hardware revs. |
558 | */ | 558 | */ |
559 | sched = true; | 559 | sched = true; |
560 | } | 560 | } |
561 | 561 | ||
562 | if (status & ATH9K_INT_TXURN) | 562 | if (status & ATH9K_INT_TXURN) |
563 | /* bump tx trigger level */ | 563 | /* bump tx trigger level */ |
564 | ath9k_hw_updatetxtriglevel(ah, true); | 564 | ath9k_hw_updatetxtriglevel(ah, true); |
565 | /* XXX: optimize this */ | 565 | /* XXX: optimize this */ |
566 | if (status & ATH9K_INT_RX) | 566 | if (status & ATH9K_INT_RX) |
567 | sched = true; | 567 | sched = true; |
568 | if (status & ATH9K_INT_TX) | 568 | if (status & ATH9K_INT_TX) |
569 | sched = true; | 569 | sched = true; |
570 | if (status & ATH9K_INT_BMISS) | 570 | if (status & ATH9K_INT_BMISS) |
571 | sched = true; | 571 | sched = true; |
572 | /* carrier sense timeout */ | 572 | /* carrier sense timeout */ |
573 | if (status & ATH9K_INT_CST) | 573 | if (status & ATH9K_INT_CST) |
574 | sched = true; | 574 | sched = true; |
575 | if (status & ATH9K_INT_MIB) { | 575 | if (status & ATH9K_INT_MIB) { |
576 | /* | 576 | /* |
577 | * Disable interrupts until we service the MIB | 577 | * Disable interrupts until we service the MIB |
578 | * interrupt; otherwise it will continue to | 578 | * interrupt; otherwise it will continue to |
579 | * fire. | 579 | * fire. |
580 | */ | 580 | */ |
581 | ath9k_hw_set_interrupts(ah, 0); | 581 | ath9k_hw_set_interrupts(ah, 0); |
582 | /* | 582 | /* |
583 | * Let the hal handle the event. We assume | 583 | * Let the hal handle the event. We assume |
584 | * it will clear whatever condition caused | 584 | * it will clear whatever condition caused |
585 | * the interrupt. | 585 | * the interrupt. |
586 | */ | 586 | */ |
587 | ath9k_hw_procmibevent(ah, &sc->sc_halstats); | 587 | ath9k_hw_procmibevent(ah, &sc->sc_halstats); |
588 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | 588 | ath9k_hw_set_interrupts(ah, sc->sc_imask); |
589 | } | 589 | } |
590 | if (status & ATH9K_INT_TIM_TIMER) { | 590 | if (status & ATH9K_INT_TIM_TIMER) { |
591 | if (!(ah->ah_caps.hw_caps & | 591 | if (!(ah->ah_caps.hw_caps & |
592 | ATH9K_HW_CAP_AUTOSLEEP)) { | 592 | ATH9K_HW_CAP_AUTOSLEEP)) { |
593 | /* Clear RxAbort bit so that we can | 593 | /* Clear RxAbort bit so that we can |
594 | * receive frames */ | 594 | * receive frames */ |
595 | ath9k_hw_setrxabort(ah, 0); | 595 | ath9k_hw_setrxabort(ah, 0); |
596 | sched = true; | 596 | sched = true; |
597 | } | 597 | } |
598 | } | 598 | } |
599 | } | 599 | } |
600 | } while (0); | 600 | } while (0); |
601 | 601 | ||
602 | ath_debug_stat_interrupt(sc, status); | 602 | ath_debug_stat_interrupt(sc, status); |
603 | 603 | ||
604 | if (sched) { | 604 | if (sched) { |
605 | /* turn off every interrupt except SWBA */ | 605 | /* turn off every interrupt except SWBA */ |
606 | ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); | 606 | ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); |
607 | tasklet_schedule(&sc->intr_tq); | 607 | tasklet_schedule(&sc->intr_tq); |
608 | } | 608 | } |
609 | 609 | ||
610 | return IRQ_HANDLED; | 610 | return IRQ_HANDLED; |
611 | } | 611 | } |
612 | 612 | ||
613 | static int ath_get_channel(struct ath_softc *sc, | 613 | static int ath_get_channel(struct ath_softc *sc, |
614 | struct ieee80211_channel *chan) | 614 | struct ieee80211_channel *chan) |
615 | { | 615 | { |
616 | int i; | 616 | int i; |
617 | 617 | ||
618 | for (i = 0; i < sc->sc_ah->ah_nchan; i++) { | 618 | for (i = 0; i < sc->sc_ah->ah_nchan; i++) { |
619 | if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) | 619 | if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) |
620 | return i; | 620 | return i; |
621 | } | 621 | } |
622 | 622 | ||
623 | return -1; | 623 | return -1; |
624 | } | 624 | } |
625 | 625 | ||
626 | /* ext_chan_offset: (-1, 0, 1) (below, none, above) */ | ||
627 | |||
628 | static u32 ath_get_extchanmode(struct ath_softc *sc, | 626 | static u32 ath_get_extchanmode(struct ath_softc *sc, |
629 | struct ieee80211_channel *chan, | 627 | struct ieee80211_channel *chan, |
630 | int ext_chan_offset, | 628 | enum nl80211_channel_type channel_type) |
631 | enum ath9k_ht_macmode tx_chan_width) | ||
632 | { | 629 | { |
633 | u32 chanmode = 0; | 630 | u32 chanmode = 0; |
634 | 631 | ||
635 | switch (chan->band) { | 632 | switch (chan->band) { |
636 | case IEEE80211_BAND_2GHZ: | 633 | case IEEE80211_BAND_2GHZ: |
637 | if ((ext_chan_offset == 0) && | 634 | switch(channel_type) { |
638 | (tx_chan_width == ATH9K_HT_MACMODE_20)) | 635 | case NL80211_CHAN_NO_HT: |
636 | case NL80211_CHAN_HT20: | ||
639 | chanmode = CHANNEL_G_HT20; | 637 | chanmode = CHANNEL_G_HT20; |
640 | if ((ext_chan_offset == 1) && | 638 | break; |
641 | (tx_chan_width == ATH9K_HT_MACMODE_2040)) | 639 | case NL80211_CHAN_HT40PLUS: |
642 | chanmode = CHANNEL_G_HT40PLUS; | 640 | chanmode = CHANNEL_G_HT40PLUS; |
643 | if ((ext_chan_offset == -1) && | 641 | break; |
644 | (tx_chan_width == ATH9K_HT_MACMODE_2040)) | 642 | case NL80211_CHAN_HT40MINUS: |
645 | chanmode = CHANNEL_G_HT40MINUS; | 643 | chanmode = CHANNEL_G_HT40MINUS; |
644 | break; | ||
645 | } | ||
646 | break; | 646 | break; |
647 | case IEEE80211_BAND_5GHZ: | 647 | case IEEE80211_BAND_5GHZ: |
648 | if ((ext_chan_offset == 0) && | 648 | switch(channel_type) { |
649 | (tx_chan_width == ATH9K_HT_MACMODE_20)) | 649 | case NL80211_CHAN_NO_HT: |
650 | case NL80211_CHAN_HT20: | ||
650 | chanmode = CHANNEL_A_HT20; | 651 | chanmode = CHANNEL_A_HT20; |
651 | if ((ext_chan_offset == 1) && | 652 | break; |
652 | (tx_chan_width == ATH9K_HT_MACMODE_2040)) | 653 | case NL80211_CHAN_HT40PLUS: |
653 | chanmode = CHANNEL_A_HT40PLUS; | 654 | chanmode = CHANNEL_A_HT40PLUS; |
654 | if ((ext_chan_offset == -1) && | 655 | break; |
655 | (tx_chan_width == ATH9K_HT_MACMODE_2040)) | 656 | case NL80211_CHAN_HT40MINUS: |
656 | chanmode = CHANNEL_A_HT40MINUS; | 657 | chanmode = CHANNEL_A_HT40MINUS; |
658 | break; | ||
659 | } | ||
657 | break; | 660 | break; |
658 | default: | 661 | default: |
659 | break; | 662 | break; |
660 | } | 663 | } |
661 | 664 | ||
662 | return chanmode; | 665 | return chanmode; |
663 | } | 666 | } |
664 | 667 | ||
665 | static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) | 668 | static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) |
666 | { | 669 | { |
667 | ath9k_hw_keyreset(sc->sc_ah, keyix); | 670 | ath9k_hw_keyreset(sc->sc_ah, keyix); |
668 | if (freeslot) | 671 | if (freeslot) |
669 | clear_bit(keyix, sc->sc_keymap); | 672 | clear_bit(keyix, sc->sc_keymap); |
670 | } | 673 | } |
671 | 674 | ||
672 | static int ath_keyset(struct ath_softc *sc, u16 keyix, | 675 | static int ath_keyset(struct ath_softc *sc, u16 keyix, |
673 | struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) | 676 | struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) |
674 | { | 677 | { |
675 | bool status; | 678 | bool status; |
676 | 679 | ||
677 | status = ath9k_hw_set_keycache_entry(sc->sc_ah, | 680 | status = ath9k_hw_set_keycache_entry(sc->sc_ah, |
678 | keyix, hk, mac, false); | 681 | keyix, hk, mac, false); |
679 | 682 | ||
680 | return status != false; | 683 | return status != false; |
681 | } | 684 | } |
682 | 685 | ||
683 | static int ath_setkey_tkip(struct ath_softc *sc, | 686 | static int ath_setkey_tkip(struct ath_softc *sc, |
684 | struct ieee80211_key_conf *key, | 687 | struct ieee80211_key_conf *key, |
685 | struct ath9k_keyval *hk, | 688 | struct ath9k_keyval *hk, |
686 | const u8 *addr) | 689 | const u8 *addr) |
687 | { | 690 | { |
688 | u8 *key_rxmic = NULL; | 691 | u8 *key_rxmic = NULL; |
689 | u8 *key_txmic = NULL; | 692 | u8 *key_txmic = NULL; |
690 | 693 | ||
691 | key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | 694 | key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; |
692 | key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | 695 | key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; |
693 | 696 | ||
694 | if (addr == NULL) { | 697 | if (addr == NULL) { |
695 | /* Group key installation */ | 698 | /* Group key installation */ |
696 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 699 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
697 | return ath_keyset(sc, key->keyidx, hk, addr); | 700 | return ath_keyset(sc, key->keyidx, hk, addr); |
698 | } | 701 | } |
699 | if (!sc->sc_splitmic) { | 702 | if (!sc->sc_splitmic) { |
700 | /* | 703 | /* |
701 | * data key goes at first index, | 704 | * data key goes at first index, |
702 | * the hal handles the MIC keys at index+64. | 705 | * the hal handles the MIC keys at index+64. |
703 | */ | 706 | */ |
704 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 707 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
705 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | 708 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); |
706 | return ath_keyset(sc, key->keyidx, hk, addr); | 709 | return ath_keyset(sc, key->keyidx, hk, addr); |
707 | } | 710 | } |
708 | /* | 711 | /* |
709 | * TX key goes at first index, RX key at +32. | 712 | * TX key goes at first index, RX key at +32. |
710 | * The hal handles the MIC keys at index+64. | 713 | * The hal handles the MIC keys at index+64. |
711 | */ | 714 | */ |
712 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | 715 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); |
713 | if (!ath_keyset(sc, key->keyidx, hk, NULL)) { | 716 | if (!ath_keyset(sc, key->keyidx, hk, NULL)) { |
714 | /* Txmic entry failed. No need to proceed further */ | 717 | /* Txmic entry failed. No need to proceed further */ |
715 | DPRINTF(sc, ATH_DBG_KEYCACHE, | 718 | DPRINTF(sc, ATH_DBG_KEYCACHE, |
716 | "Setting TX MIC Key Failed\n"); | 719 | "Setting TX MIC Key Failed\n"); |
717 | return 0; | 720 | return 0; |
718 | } | 721 | } |
719 | 722 | ||
720 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 723 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
721 | /* XXX delete tx key on failure? */ | 724 | /* XXX delete tx key on failure? */ |
722 | return ath_keyset(sc, key->keyidx+32, hk, addr); | 725 | return ath_keyset(sc, key->keyidx+32, hk, addr); |
723 | } | 726 | } |
724 | 727 | ||
725 | static int ath_key_config(struct ath_softc *sc, | 728 | static int ath_key_config(struct ath_softc *sc, |
726 | const u8 *addr, | 729 | const u8 *addr, |
727 | struct ieee80211_key_conf *key) | 730 | struct ieee80211_key_conf *key) |
728 | { | 731 | { |
729 | struct ieee80211_vif *vif; | 732 | struct ieee80211_vif *vif; |
730 | struct ath9k_keyval hk; | 733 | struct ath9k_keyval hk; |
731 | const u8 *mac = NULL; | 734 | const u8 *mac = NULL; |
732 | int ret = 0; | 735 | int ret = 0; |
733 | enum nl80211_iftype opmode; | 736 | enum nl80211_iftype opmode; |
734 | 737 | ||
735 | memset(&hk, 0, sizeof(hk)); | 738 | memset(&hk, 0, sizeof(hk)); |
736 | 739 | ||
737 | switch (key->alg) { | 740 | switch (key->alg) { |
738 | case ALG_WEP: | 741 | case ALG_WEP: |
739 | hk.kv_type = ATH9K_CIPHER_WEP; | 742 | hk.kv_type = ATH9K_CIPHER_WEP; |
740 | break; | 743 | break; |
741 | case ALG_TKIP: | 744 | case ALG_TKIP: |
742 | hk.kv_type = ATH9K_CIPHER_TKIP; | 745 | hk.kv_type = ATH9K_CIPHER_TKIP; |
743 | break; | 746 | break; |
744 | case ALG_CCMP: | 747 | case ALG_CCMP: |
745 | hk.kv_type = ATH9K_CIPHER_AES_CCM; | 748 | hk.kv_type = ATH9K_CIPHER_AES_CCM; |
746 | break; | 749 | break; |
747 | default: | 750 | default: |
748 | return -EINVAL; | 751 | return -EINVAL; |
749 | } | 752 | } |
750 | 753 | ||
751 | hk.kv_len = key->keylen; | 754 | hk.kv_len = key->keylen; |
752 | memcpy(hk.kv_val, key->key, key->keylen); | 755 | memcpy(hk.kv_val, key->key, key->keylen); |
753 | 756 | ||
754 | if (!sc->sc_vaps[0]) | 757 | if (!sc->sc_vaps[0]) |
755 | return -EIO; | 758 | return -EIO; |
756 | 759 | ||
757 | vif = sc->sc_vaps[0]; | 760 | vif = sc->sc_vaps[0]; |
758 | opmode = vif->type; | 761 | opmode = vif->type; |
759 | 762 | ||
760 | /* | 763 | /* |
761 | * Strategy: | 764 | * Strategy: |
762 | * For STA mc tx, we will not setup a key at | 765 | * For STA mc tx, we will not setup a key at |
763 | * all since we never tx mc. | 766 | * all since we never tx mc. |
764 | * | 767 | * |
765 | * For STA mc rx, we will use the keyID. | 768 | * For STA mc rx, we will use the keyID. |
766 | * | 769 | * |
767 | * For ADHOC mc tx, we will use the keyID, and no macaddr. | 770 | * For ADHOC mc tx, we will use the keyID, and no macaddr. |
768 | * | 771 | * |
769 | * For ADHOC mc rx, we will alloc a slot and plumb the mac of | 772 | * For ADHOC mc rx, we will alloc a slot and plumb the mac of |
770 | * the peer node. | 773 | * the peer node. |
771 | * BUT we will plumb a cleartext key so that we can do | 774 | * BUT we will plumb a cleartext key so that we can do |
772 | * per-Sta default key table lookup in software. | 775 | * per-Sta default key table lookup in software. |
773 | */ | 776 | */ |
774 | if (is_broadcast_ether_addr(addr)) { | 777 | if (is_broadcast_ether_addr(addr)) { |
775 | switch (opmode) { | 778 | switch (opmode) { |
776 | case NL80211_IFTYPE_STATION: | 779 | case NL80211_IFTYPE_STATION: |
777 | /* default key: could be group WPA key | 780 | /* default key: could be group WPA key |
778 | * or could be static WEP key */ | 781 | * or could be static WEP key */ |
779 | mac = NULL; | 782 | mac = NULL; |
780 | break; | 783 | break; |
781 | case NL80211_IFTYPE_ADHOC: | 784 | case NL80211_IFTYPE_ADHOC: |
782 | break; | 785 | break; |
783 | case NL80211_IFTYPE_AP: | 786 | case NL80211_IFTYPE_AP: |
784 | break; | 787 | break; |
785 | default: | 788 | default: |
786 | ASSERT(0); | 789 | ASSERT(0); |
787 | break; | 790 | break; |
788 | } | 791 | } |
789 | } else { | 792 | } else { |
790 | mac = addr; | 793 | mac = addr; |
791 | } | 794 | } |
792 | 795 | ||
793 | if (key->alg == ALG_TKIP) | 796 | if (key->alg == ALG_TKIP) |
794 | ret = ath_setkey_tkip(sc, key, &hk, mac); | 797 | ret = ath_setkey_tkip(sc, key, &hk, mac); |
795 | else | 798 | else |
796 | ret = ath_keyset(sc, key->keyidx, &hk, mac); | 799 | ret = ath_keyset(sc, key->keyidx, &hk, mac); |
797 | 800 | ||
798 | if (!ret) | 801 | if (!ret) |
799 | return -EIO; | 802 | return -EIO; |
800 | 803 | ||
801 | return 0; | 804 | return 0; |
802 | } | 805 | } |
803 | 806 | ||
804 | static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) | 807 | static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) |
805 | { | 808 | { |
806 | int freeslot; | 809 | int freeslot; |
807 | 810 | ||
808 | freeslot = (key->keyidx >= 4) ? 1 : 0; | 811 | freeslot = (key->keyidx >= 4) ? 1 : 0; |
809 | ath_key_reset(sc, key->keyidx, freeslot); | 812 | ath_key_reset(sc, key->keyidx, freeslot); |
810 | } | 813 | } |
811 | 814 | ||
812 | static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) | 815 | static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) |
813 | { | 816 | { |
814 | #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ | 817 | #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ |
815 | #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ | 818 | #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ |
816 | 819 | ||
817 | ht_info->ht_supported = true; | 820 | ht_info->ht_supported = true; |
818 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 821 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
819 | IEEE80211_HT_CAP_SM_PS | | 822 | IEEE80211_HT_CAP_SM_PS | |
820 | IEEE80211_HT_CAP_SGI_40 | | 823 | IEEE80211_HT_CAP_SGI_40 | |
821 | IEEE80211_HT_CAP_DSSSCCK40; | 824 | IEEE80211_HT_CAP_DSSSCCK40; |
822 | 825 | ||
823 | ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; | 826 | ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; |
824 | ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; | 827 | ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; |
825 | /* set up supported mcs set */ | 828 | /* set up supported mcs set */ |
826 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | 829 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); |
827 | ht_info->mcs.rx_mask[0] = 0xff; | 830 | ht_info->mcs.rx_mask[0] = 0xff; |
828 | ht_info->mcs.rx_mask[1] = 0xff; | 831 | ht_info->mcs.rx_mask[1] = 0xff; |
829 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 832 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
830 | } | 833 | } |
831 | 834 | ||
832 | static void ath9k_ht_conf(struct ath_softc *sc, | ||
833 | struct ieee80211_bss_conf *bss_conf) | ||
834 | { | ||
835 | if (sc->hw->conf.ht.enabled) { | ||
836 | if (bss_conf->ht.width_40_ok) | ||
837 | sc->tx_chan_width = ATH9K_HT_MACMODE_2040; | ||
838 | else | ||
839 | sc->tx_chan_width = ATH9K_HT_MACMODE_20; | ||
840 | |||
841 | ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width); | ||
842 | |||
843 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
844 | "BSS Changed HT, chanwidth: %d\n", sc->tx_chan_width); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | static inline int ath_sec_offset(u8 ext_offset) | ||
849 | { | ||
850 | if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) | ||
851 | return 0; | ||
852 | else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) | ||
853 | return 1; | ||
854 | else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) | ||
855 | return -1; | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static void ath9k_bss_assoc_info(struct ath_softc *sc, | 835 | static void ath9k_bss_assoc_info(struct ath_softc *sc, |
861 | struct ieee80211_vif *vif, | 836 | struct ieee80211_vif *vif, |
862 | struct ieee80211_bss_conf *bss_conf) | 837 | struct ieee80211_bss_conf *bss_conf) |
863 | { | 838 | { |
864 | struct ieee80211_hw *hw = sc->hw; | ||
865 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
866 | struct ath_vap *avp = (void *)vif->drv_priv; | 839 | struct ath_vap *avp = (void *)vif->drv_priv; |
867 | int pos; | ||
868 | 840 | ||
869 | if (bss_conf->assoc) { | 841 | if (bss_conf->assoc) { |
870 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid); | 842 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", |
843 | bss_conf->aid, sc->sc_curbssid); | ||
871 | 844 | ||
872 | /* New association, store aid */ | 845 | /* New association, store aid */ |
873 | if (avp->av_opmode == NL80211_IFTYPE_STATION) { | 846 | if (avp->av_opmode == NL80211_IFTYPE_STATION) { |
874 | sc->sc_curaid = bss_conf->aid; | 847 | sc->sc_curaid = bss_conf->aid; |
875 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, | 848 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, |
876 | sc->sc_curaid); | 849 | sc->sc_curaid); |
877 | } | 850 | } |
878 | 851 | ||
879 | /* Configure the beacon */ | 852 | /* Configure the beacon */ |
880 | ath_beacon_config(sc, 0); | 853 | ath_beacon_config(sc, 0); |
881 | sc->sc_flags |= SC_OP_BEACONS; | 854 | sc->sc_flags |= SC_OP_BEACONS; |
882 | 855 | ||
883 | /* Reset rssi stats */ | 856 | /* Reset rssi stats */ |
884 | sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; | 857 | sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; |
885 | sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; | 858 | sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; |
886 | sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; | 859 | sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; |
887 | sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; | 860 | sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; |
888 | 861 | ||
889 | /* Update chainmask */ | ||
890 | ath_update_chainmask(sc, hw->conf.ht.enabled); | ||
891 | |||
892 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
893 | "bssid %pM aid 0x%x\n", | ||
894 | sc->sc_curbssid, sc->sc_curaid); | ||
895 | |||
896 | pos = ath_get_channel(sc, curchan); | ||
897 | if (pos == -1) { | ||
898 | DPRINTF(sc, ATH_DBG_FATAL, | ||
899 | "Invalid channel: %d\n", curchan->center_freq); | ||
900 | return; | ||
901 | } | ||
902 | |||
903 | if (hw->conf.ht.enabled) { | ||
904 | int offset = | ||
905 | ath_sec_offset(bss_conf->ht.secondary_channel_offset); | ||
906 | sc->tx_chan_width = (bss_conf->ht.width_40_ok) ? | ||
907 | ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; | ||
908 | |||
909 | sc->sc_ah->ah_channels[pos].chanmode = | ||
910 | ath_get_extchanmode(sc, curchan, | ||
911 | offset, sc->tx_chan_width); | ||
912 | } else { | ||
913 | sc->sc_ah->ah_channels[pos].chanmode = | ||
914 | (curchan->band == IEEE80211_BAND_2GHZ) ? | ||
915 | CHANNEL_G : CHANNEL_A; | ||
916 | } | ||
917 | |||
918 | /* set h/w channel */ | ||
919 | if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) | ||
920 | DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel: %d\n", | ||
921 | curchan->center_freq); | ||
922 | |||
923 | /* Start ANI */ | 862 | /* Start ANI */ |
924 | mod_timer(&sc->sc_ani.timer, | 863 | mod_timer(&sc->sc_ani.timer, |
925 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 864 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
926 | 865 | ||
927 | } else { | 866 | } else { |
928 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); | 867 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); |
929 | sc->sc_curaid = 0; | 868 | sc->sc_curaid = 0; |
930 | } | 869 | } |
931 | } | 870 | } |
932 | 871 | ||
933 | /********************************/ | 872 | /********************************/ |
934 | /* LED functions */ | 873 | /* LED functions */ |
935 | /********************************/ | 874 | /********************************/ |
936 | 875 | ||
937 | static void ath_led_brightness(struct led_classdev *led_cdev, | 876 | static void ath_led_brightness(struct led_classdev *led_cdev, |
938 | enum led_brightness brightness) | 877 | enum led_brightness brightness) |
939 | { | 878 | { |
940 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | 879 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); |
941 | struct ath_softc *sc = led->sc; | 880 | struct ath_softc *sc = led->sc; |
942 | 881 | ||
943 | switch (brightness) { | 882 | switch (brightness) { |
944 | case LED_OFF: | 883 | case LED_OFF: |
945 | if (led->led_type == ATH_LED_ASSOC || | 884 | if (led->led_type == ATH_LED_ASSOC || |
946 | led->led_type == ATH_LED_RADIO) | 885 | led->led_type == ATH_LED_RADIO) |
947 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | 886 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; |
948 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | 887 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, |
949 | (led->led_type == ATH_LED_RADIO) ? 1 : | 888 | (led->led_type == ATH_LED_RADIO) ? 1 : |
950 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); | 889 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); |
951 | break; | 890 | break; |
952 | case LED_FULL: | 891 | case LED_FULL: |
953 | if (led->led_type == ATH_LED_ASSOC) | 892 | if (led->led_type == ATH_LED_ASSOC) |
954 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | 893 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; |
955 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | 894 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); |
956 | break; | 895 | break; |
957 | default: | 896 | default: |
958 | break; | 897 | break; |
959 | } | 898 | } |
960 | } | 899 | } |
961 | 900 | ||
962 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | 901 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, |
963 | char *trigger) | 902 | char *trigger) |
964 | { | 903 | { |
965 | int ret; | 904 | int ret; |
966 | 905 | ||
967 | led->sc = sc; | 906 | led->sc = sc; |
968 | led->led_cdev.name = led->name; | 907 | led->led_cdev.name = led->name; |
969 | led->led_cdev.default_trigger = trigger; | 908 | led->led_cdev.default_trigger = trigger; |
970 | led->led_cdev.brightness_set = ath_led_brightness; | 909 | led->led_cdev.brightness_set = ath_led_brightness; |
971 | 910 | ||
972 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | 911 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); |
973 | if (ret) | 912 | if (ret) |
974 | DPRINTF(sc, ATH_DBG_FATAL, | 913 | DPRINTF(sc, ATH_DBG_FATAL, |
975 | "Failed to register led:%s", led->name); | 914 | "Failed to register led:%s", led->name); |
976 | else | 915 | else |
977 | led->registered = 1; | 916 | led->registered = 1; |
978 | return ret; | 917 | return ret; |
979 | } | 918 | } |
980 | 919 | ||
981 | static void ath_unregister_led(struct ath_led *led) | 920 | static void ath_unregister_led(struct ath_led *led) |
982 | { | 921 | { |
983 | if (led->registered) { | 922 | if (led->registered) { |
984 | led_classdev_unregister(&led->led_cdev); | 923 | led_classdev_unregister(&led->led_cdev); |
985 | led->registered = 0; | 924 | led->registered = 0; |
986 | } | 925 | } |
987 | } | 926 | } |
988 | 927 | ||
989 | static void ath_deinit_leds(struct ath_softc *sc) | 928 | static void ath_deinit_leds(struct ath_softc *sc) |
990 | { | 929 | { |
991 | ath_unregister_led(&sc->assoc_led); | 930 | ath_unregister_led(&sc->assoc_led); |
992 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | 931 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; |
993 | ath_unregister_led(&sc->tx_led); | 932 | ath_unregister_led(&sc->tx_led); |
994 | ath_unregister_led(&sc->rx_led); | 933 | ath_unregister_led(&sc->rx_led); |
995 | ath_unregister_led(&sc->radio_led); | 934 | ath_unregister_led(&sc->radio_led); |
996 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 935 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
997 | } | 936 | } |
998 | 937 | ||
999 | static void ath_init_leds(struct ath_softc *sc) | 938 | static void ath_init_leds(struct ath_softc *sc) |
1000 | { | 939 | { |
1001 | char *trigger; | 940 | char *trigger; |
1002 | int ret; | 941 | int ret; |
1003 | 942 | ||
1004 | /* Configure gpio 1 for output */ | 943 | /* Configure gpio 1 for output */ |
1005 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | 944 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, |
1006 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 945 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
1007 | /* LED off, active low */ | 946 | /* LED off, active low */ |
1008 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 947 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
1009 | 948 | ||
1010 | trigger = ieee80211_get_radio_led_name(sc->hw); | 949 | trigger = ieee80211_get_radio_led_name(sc->hw); |
1011 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | 950 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), |
1012 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); | 951 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); |
1013 | ret = ath_register_led(sc, &sc->radio_led, trigger); | 952 | ret = ath_register_led(sc, &sc->radio_led, trigger); |
1014 | sc->radio_led.led_type = ATH_LED_RADIO; | 953 | sc->radio_led.led_type = ATH_LED_RADIO; |
1015 | if (ret) | 954 | if (ret) |
1016 | goto fail; | 955 | goto fail; |
1017 | 956 | ||
1018 | trigger = ieee80211_get_assoc_led_name(sc->hw); | 957 | trigger = ieee80211_get_assoc_led_name(sc->hw); |
1019 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | 958 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), |
1020 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); | 959 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); |
1021 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | 960 | ret = ath_register_led(sc, &sc->assoc_led, trigger); |
1022 | sc->assoc_led.led_type = ATH_LED_ASSOC; | 961 | sc->assoc_led.led_type = ATH_LED_ASSOC; |
1023 | if (ret) | 962 | if (ret) |
1024 | goto fail; | 963 | goto fail; |
1025 | 964 | ||
1026 | trigger = ieee80211_get_tx_led_name(sc->hw); | 965 | trigger = ieee80211_get_tx_led_name(sc->hw); |
1027 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | 966 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), |
1028 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); | 967 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); |
1029 | ret = ath_register_led(sc, &sc->tx_led, trigger); | 968 | ret = ath_register_led(sc, &sc->tx_led, trigger); |
1030 | sc->tx_led.led_type = ATH_LED_TX; | 969 | sc->tx_led.led_type = ATH_LED_TX; |
1031 | if (ret) | 970 | if (ret) |
1032 | goto fail; | 971 | goto fail; |
1033 | 972 | ||
1034 | trigger = ieee80211_get_rx_led_name(sc->hw); | 973 | trigger = ieee80211_get_rx_led_name(sc->hw); |
1035 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | 974 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), |
1036 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); | 975 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); |
1037 | ret = ath_register_led(sc, &sc->rx_led, trigger); | 976 | ret = ath_register_led(sc, &sc->rx_led, trigger); |
1038 | sc->rx_led.led_type = ATH_LED_RX; | 977 | sc->rx_led.led_type = ATH_LED_RX; |
1039 | if (ret) | 978 | if (ret) |
1040 | goto fail; | 979 | goto fail; |
1041 | 980 | ||
1042 | return; | 981 | return; |
1043 | 982 | ||
1044 | fail: | 983 | fail: |
1045 | ath_deinit_leds(sc); | 984 | ath_deinit_leds(sc); |
1046 | } | 985 | } |
1047 | 986 | ||
1048 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 987 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1049 | 988 | ||
1050 | /*******************/ | 989 | /*******************/ |
1051 | /* Rfkill */ | 990 | /* Rfkill */ |
1052 | /*******************/ | 991 | /*******************/ |
1053 | 992 | ||
1054 | static void ath_radio_enable(struct ath_softc *sc) | 993 | static void ath_radio_enable(struct ath_softc *sc) |
1055 | { | 994 | { |
1056 | struct ath_hal *ah = sc->sc_ah; | 995 | struct ath_hal *ah = sc->sc_ah; |
1057 | int status; | 996 | int status; |
1058 | 997 | ||
1059 | spin_lock_bh(&sc->sc_resetlock); | 998 | spin_lock_bh(&sc->sc_resetlock); |
1060 | if (!ath9k_hw_reset(ah, ah->ah_curchan, | 999 | if (!ath9k_hw_reset(ah, ah->ah_curchan, |
1061 | sc->tx_chan_width, | 1000 | sc->tx_chan_width, |
1062 | sc->sc_tx_chainmask, | 1001 | sc->sc_tx_chainmask, |
1063 | sc->sc_rx_chainmask, | 1002 | sc->sc_rx_chainmask, |
1064 | sc->sc_ht_extprotspacing, | 1003 | sc->sc_ht_extprotspacing, |
1065 | false, &status)) { | 1004 | false, &status)) { |
1066 | DPRINTF(sc, ATH_DBG_FATAL, | 1005 | DPRINTF(sc, ATH_DBG_FATAL, |
1067 | "Unable to reset channel %u (%uMhz) " | 1006 | "Unable to reset channel %u (%uMhz) " |
1068 | "flags 0x%x hal status %u\n", | 1007 | "flags 0x%x hal status %u\n", |
1069 | ath9k_hw_mhz2ieee(ah, | 1008 | ath9k_hw_mhz2ieee(ah, |
1070 | ah->ah_curchan->channel, | 1009 | ah->ah_curchan->channel, |
1071 | ah->ah_curchan->channelFlags), | 1010 | ah->ah_curchan->channelFlags), |
1072 | ah->ah_curchan->channel, | 1011 | ah->ah_curchan->channel, |
1073 | ah->ah_curchan->channelFlags, status); | 1012 | ah->ah_curchan->channelFlags, status); |
1074 | } | 1013 | } |
1075 | spin_unlock_bh(&sc->sc_resetlock); | 1014 | spin_unlock_bh(&sc->sc_resetlock); |
1076 | 1015 | ||
1077 | ath_update_txpow(sc); | 1016 | ath_update_txpow(sc); |
1078 | if (ath_startrecv(sc) != 0) { | 1017 | if (ath_startrecv(sc) != 0) { |
1079 | DPRINTF(sc, ATH_DBG_FATAL, | 1018 | DPRINTF(sc, ATH_DBG_FATAL, |
1080 | "Unable to restart recv logic\n"); | 1019 | "Unable to restart recv logic\n"); |
1081 | return; | 1020 | return; |
1082 | } | 1021 | } |
1083 | 1022 | ||
1084 | if (sc->sc_flags & SC_OP_BEACONS) | 1023 | if (sc->sc_flags & SC_OP_BEACONS) |
1085 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ | 1024 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ |
1086 | 1025 | ||
1087 | /* Re-Enable interrupts */ | 1026 | /* Re-Enable interrupts */ |
1088 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | 1027 | ath9k_hw_set_interrupts(ah, sc->sc_imask); |
1089 | 1028 | ||
1090 | /* Enable LED */ | 1029 | /* Enable LED */ |
1091 | ath9k_hw_cfg_output(ah, ATH_LED_PIN, | 1030 | ath9k_hw_cfg_output(ah, ATH_LED_PIN, |
1092 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 1031 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
1093 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); | 1032 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); |
1094 | 1033 | ||
1095 | ieee80211_wake_queues(sc->hw); | 1034 | ieee80211_wake_queues(sc->hw); |
1096 | } | 1035 | } |
1097 | 1036 | ||
1098 | static void ath_radio_disable(struct ath_softc *sc) | 1037 | static void ath_radio_disable(struct ath_softc *sc) |
1099 | { | 1038 | { |
1100 | struct ath_hal *ah = sc->sc_ah; | 1039 | struct ath_hal *ah = sc->sc_ah; |
1101 | int status; | 1040 | int status; |
1102 | 1041 | ||
1103 | 1042 | ||
1104 | ieee80211_stop_queues(sc->hw); | 1043 | ieee80211_stop_queues(sc->hw); |
1105 | 1044 | ||
1106 | /* Disable LED */ | 1045 | /* Disable LED */ |
1107 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); | 1046 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); |
1108 | ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); | 1047 | ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); |
1109 | 1048 | ||
1110 | /* Disable interrupts */ | 1049 | /* Disable interrupts */ |
1111 | ath9k_hw_set_interrupts(ah, 0); | 1050 | ath9k_hw_set_interrupts(ah, 0); |
1112 | 1051 | ||
1113 | ath_draintxq(sc, false); /* clear pending tx frames */ | 1052 | ath_draintxq(sc, false); /* clear pending tx frames */ |
1114 | ath_stoprecv(sc); /* turn off frame recv */ | 1053 | ath_stoprecv(sc); /* turn off frame recv */ |
1115 | ath_flushrecv(sc); /* flush recv queue */ | 1054 | ath_flushrecv(sc); /* flush recv queue */ |
1116 | 1055 | ||
1117 | spin_lock_bh(&sc->sc_resetlock); | 1056 | spin_lock_bh(&sc->sc_resetlock); |
1118 | if (!ath9k_hw_reset(ah, ah->ah_curchan, | 1057 | if (!ath9k_hw_reset(ah, ah->ah_curchan, |
1119 | sc->tx_chan_width, | 1058 | sc->tx_chan_width, |
1120 | sc->sc_tx_chainmask, | 1059 | sc->sc_tx_chainmask, |
1121 | sc->sc_rx_chainmask, | 1060 | sc->sc_rx_chainmask, |
1122 | sc->sc_ht_extprotspacing, | 1061 | sc->sc_ht_extprotspacing, |
1123 | false, &status)) { | 1062 | false, &status)) { |
1124 | DPRINTF(sc, ATH_DBG_FATAL, | 1063 | DPRINTF(sc, ATH_DBG_FATAL, |
1125 | "Unable to reset channel %u (%uMhz) " | 1064 | "Unable to reset channel %u (%uMhz) " |
1126 | "flags 0x%x hal status %u\n", | 1065 | "flags 0x%x hal status %u\n", |
1127 | ath9k_hw_mhz2ieee(ah, | 1066 | ath9k_hw_mhz2ieee(ah, |
1128 | ah->ah_curchan->channel, | 1067 | ah->ah_curchan->channel, |
1129 | ah->ah_curchan->channelFlags), | 1068 | ah->ah_curchan->channelFlags), |
1130 | ah->ah_curchan->channel, | 1069 | ah->ah_curchan->channel, |
1131 | ah->ah_curchan->channelFlags, status); | 1070 | ah->ah_curchan->channelFlags, status); |
1132 | } | 1071 | } |
1133 | spin_unlock_bh(&sc->sc_resetlock); | 1072 | spin_unlock_bh(&sc->sc_resetlock); |
1134 | 1073 | ||
1135 | ath9k_hw_phy_disable(ah); | 1074 | ath9k_hw_phy_disable(ah); |
1136 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | 1075 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); |
1137 | } | 1076 | } |
1138 | 1077 | ||
1139 | static bool ath_is_rfkill_set(struct ath_softc *sc) | 1078 | static bool ath_is_rfkill_set(struct ath_softc *sc) |
1140 | { | 1079 | { |
1141 | struct ath_hal *ah = sc->sc_ah; | 1080 | struct ath_hal *ah = sc->sc_ah; |
1142 | 1081 | ||
1143 | return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == | 1082 | return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == |
1144 | ah->ah_rfkill_polarity; | 1083 | ah->ah_rfkill_polarity; |
1145 | } | 1084 | } |
1146 | 1085 | ||
1147 | /* h/w rfkill poll function */ | 1086 | /* h/w rfkill poll function */ |
1148 | static void ath_rfkill_poll(struct work_struct *work) | 1087 | static void ath_rfkill_poll(struct work_struct *work) |
1149 | { | 1088 | { |
1150 | struct ath_softc *sc = container_of(work, struct ath_softc, | 1089 | struct ath_softc *sc = container_of(work, struct ath_softc, |
1151 | rf_kill.rfkill_poll.work); | 1090 | rf_kill.rfkill_poll.work); |
1152 | bool radio_on; | 1091 | bool radio_on; |
1153 | 1092 | ||
1154 | if (sc->sc_flags & SC_OP_INVALID) | 1093 | if (sc->sc_flags & SC_OP_INVALID) |
1155 | return; | 1094 | return; |
1156 | 1095 | ||
1157 | radio_on = !ath_is_rfkill_set(sc); | 1096 | radio_on = !ath_is_rfkill_set(sc); |
1158 | 1097 | ||
1159 | /* | 1098 | /* |
1160 | * enable/disable radio only when there is a | 1099 | * enable/disable radio only when there is a |
1161 | * state change in RF switch | 1100 | * state change in RF switch |
1162 | */ | 1101 | */ |
1163 | if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { | 1102 | if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { |
1164 | enum rfkill_state state; | 1103 | enum rfkill_state state; |
1165 | 1104 | ||
1166 | if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { | 1105 | if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { |
1167 | state = radio_on ? RFKILL_STATE_SOFT_BLOCKED | 1106 | state = radio_on ? RFKILL_STATE_SOFT_BLOCKED |
1168 | : RFKILL_STATE_HARD_BLOCKED; | 1107 | : RFKILL_STATE_HARD_BLOCKED; |
1169 | } else if (radio_on) { | 1108 | } else if (radio_on) { |
1170 | ath_radio_enable(sc); | 1109 | ath_radio_enable(sc); |
1171 | state = RFKILL_STATE_UNBLOCKED; | 1110 | state = RFKILL_STATE_UNBLOCKED; |
1172 | } else { | 1111 | } else { |
1173 | ath_radio_disable(sc); | 1112 | ath_radio_disable(sc); |
1174 | state = RFKILL_STATE_HARD_BLOCKED; | 1113 | state = RFKILL_STATE_HARD_BLOCKED; |
1175 | } | 1114 | } |
1176 | 1115 | ||
1177 | if (state == RFKILL_STATE_HARD_BLOCKED) | 1116 | if (state == RFKILL_STATE_HARD_BLOCKED) |
1178 | sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; | 1117 | sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; |
1179 | else | 1118 | else |
1180 | sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; | 1119 | sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; |
1181 | 1120 | ||
1182 | rfkill_force_state(sc->rf_kill.rfkill, state); | 1121 | rfkill_force_state(sc->rf_kill.rfkill, state); |
1183 | } | 1122 | } |
1184 | 1123 | ||
1185 | queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, | 1124 | queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, |
1186 | msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); | 1125 | msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); |
1187 | } | 1126 | } |
1188 | 1127 | ||
1189 | /* s/w rfkill handler */ | 1128 | /* s/w rfkill handler */ |
1190 | static int ath_sw_toggle_radio(void *data, enum rfkill_state state) | 1129 | static int ath_sw_toggle_radio(void *data, enum rfkill_state state) |
1191 | { | 1130 | { |
1192 | struct ath_softc *sc = data; | 1131 | struct ath_softc *sc = data; |
1193 | 1132 | ||
1194 | switch (state) { | 1133 | switch (state) { |
1195 | case RFKILL_STATE_SOFT_BLOCKED: | 1134 | case RFKILL_STATE_SOFT_BLOCKED: |
1196 | if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | | 1135 | if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | |
1197 | SC_OP_RFKILL_SW_BLOCKED))) | 1136 | SC_OP_RFKILL_SW_BLOCKED))) |
1198 | ath_radio_disable(sc); | 1137 | ath_radio_disable(sc); |
1199 | sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; | 1138 | sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; |
1200 | return 0; | 1139 | return 0; |
1201 | case RFKILL_STATE_UNBLOCKED: | 1140 | case RFKILL_STATE_UNBLOCKED: |
1202 | if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { | 1141 | if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { |
1203 | sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; | 1142 | sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; |
1204 | if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { | 1143 | if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { |
1205 | DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" | 1144 | DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" |
1206 | "radio as it is disabled by h/w\n"); | 1145 | "radio as it is disabled by h/w\n"); |
1207 | return -EPERM; | 1146 | return -EPERM; |
1208 | } | 1147 | } |
1209 | ath_radio_enable(sc); | 1148 | ath_radio_enable(sc); |
1210 | } | 1149 | } |
1211 | return 0; | 1150 | return 0; |
1212 | default: | 1151 | default: |
1213 | return -EINVAL; | 1152 | return -EINVAL; |
1214 | } | 1153 | } |
1215 | } | 1154 | } |
1216 | 1155 | ||
1217 | /* Init s/w rfkill */ | 1156 | /* Init s/w rfkill */ |
1218 | static int ath_init_sw_rfkill(struct ath_softc *sc) | 1157 | static int ath_init_sw_rfkill(struct ath_softc *sc) |
1219 | { | 1158 | { |
1220 | sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), | 1159 | sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), |
1221 | RFKILL_TYPE_WLAN); | 1160 | RFKILL_TYPE_WLAN); |
1222 | if (!sc->rf_kill.rfkill) { | 1161 | if (!sc->rf_kill.rfkill) { |
1223 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); | 1162 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); |
1224 | return -ENOMEM; | 1163 | return -ENOMEM; |
1225 | } | 1164 | } |
1226 | 1165 | ||
1227 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | 1166 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), |
1228 | "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); | 1167 | "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); |
1229 | sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; | 1168 | sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; |
1230 | sc->rf_kill.rfkill->data = sc; | 1169 | sc->rf_kill.rfkill->data = sc; |
1231 | sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; | 1170 | sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; |
1232 | sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; | 1171 | sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; |
1233 | sc->rf_kill.rfkill->user_claim_unsupported = 1; | 1172 | sc->rf_kill.rfkill->user_claim_unsupported = 1; |
1234 | 1173 | ||
1235 | return 0; | 1174 | return 0; |
1236 | } | 1175 | } |
1237 | 1176 | ||
1238 | /* Deinitialize rfkill */ | 1177 | /* Deinitialize rfkill */ |
1239 | static void ath_deinit_rfkill(struct ath_softc *sc) | 1178 | static void ath_deinit_rfkill(struct ath_softc *sc) |
1240 | { | 1179 | { |
1241 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 1180 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
1242 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | 1181 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); |
1243 | 1182 | ||
1244 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { | 1183 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { |
1245 | rfkill_unregister(sc->rf_kill.rfkill); | 1184 | rfkill_unregister(sc->rf_kill.rfkill); |
1246 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; | 1185 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; |
1247 | sc->rf_kill.rfkill = NULL; | 1186 | sc->rf_kill.rfkill = NULL; |
1248 | } | 1187 | } |
1249 | } | 1188 | } |
1250 | 1189 | ||
1251 | static int ath_start_rfkill_poll(struct ath_softc *sc) | 1190 | static int ath_start_rfkill_poll(struct ath_softc *sc) |
1252 | { | 1191 | { |
1253 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 1192 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
1254 | queue_delayed_work(sc->hw->workqueue, | 1193 | queue_delayed_work(sc->hw->workqueue, |
1255 | &sc->rf_kill.rfkill_poll, 0); | 1194 | &sc->rf_kill.rfkill_poll, 0); |
1256 | 1195 | ||
1257 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | 1196 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { |
1258 | if (rfkill_register(sc->rf_kill.rfkill)) { | 1197 | if (rfkill_register(sc->rf_kill.rfkill)) { |
1259 | DPRINTF(sc, ATH_DBG_FATAL, | 1198 | DPRINTF(sc, ATH_DBG_FATAL, |
1260 | "Unable to register rfkill\n"); | 1199 | "Unable to register rfkill\n"); |
1261 | rfkill_free(sc->rf_kill.rfkill); | 1200 | rfkill_free(sc->rf_kill.rfkill); |
1262 | 1201 | ||
1263 | /* Deinitialize the device */ | 1202 | /* Deinitialize the device */ |
1264 | ath_detach(sc); | 1203 | ath_detach(sc); |
1265 | if (sc->pdev->irq) | 1204 | if (sc->pdev->irq) |
1266 | free_irq(sc->pdev->irq, sc); | 1205 | free_irq(sc->pdev->irq, sc); |
1267 | pci_iounmap(sc->pdev, sc->mem); | 1206 | pci_iounmap(sc->pdev, sc->mem); |
1268 | pci_release_region(sc->pdev, 0); | 1207 | pci_release_region(sc->pdev, 0); |
1269 | pci_disable_device(sc->pdev); | 1208 | pci_disable_device(sc->pdev); |
1270 | ieee80211_free_hw(sc->hw); | 1209 | ieee80211_free_hw(sc->hw); |
1271 | return -EIO; | 1210 | return -EIO; |
1272 | } else { | 1211 | } else { |
1273 | sc->sc_flags |= SC_OP_RFKILL_REGISTERED; | 1212 | sc->sc_flags |= SC_OP_RFKILL_REGISTERED; |
1274 | } | 1213 | } |
1275 | } | 1214 | } |
1276 | 1215 | ||
1277 | return 0; | 1216 | return 0; |
1278 | } | 1217 | } |
1279 | #endif /* CONFIG_RFKILL */ | 1218 | #endif /* CONFIG_RFKILL */ |
1280 | 1219 | ||
1281 | static void ath_detach(struct ath_softc *sc) | 1220 | static void ath_detach(struct ath_softc *sc) |
1282 | { | 1221 | { |
1283 | struct ieee80211_hw *hw = sc->hw; | 1222 | struct ieee80211_hw *hw = sc->hw; |
1284 | int i = 0; | 1223 | int i = 0; |
1285 | 1224 | ||
1286 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); | 1225 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); |
1287 | 1226 | ||
1288 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1227 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1289 | ath_deinit_rfkill(sc); | 1228 | ath_deinit_rfkill(sc); |
1290 | #endif | 1229 | #endif |
1291 | ath_deinit_leds(sc); | 1230 | ath_deinit_leds(sc); |
1292 | 1231 | ||
1293 | ieee80211_unregister_hw(hw); | 1232 | ieee80211_unregister_hw(hw); |
1294 | 1233 | ||
1295 | ath_rate_control_unregister(); | 1234 | ath_rate_control_unregister(); |
1296 | 1235 | ||
1297 | ath_rx_cleanup(sc); | 1236 | ath_rx_cleanup(sc); |
1298 | ath_tx_cleanup(sc); | 1237 | ath_tx_cleanup(sc); |
1299 | 1238 | ||
1300 | tasklet_kill(&sc->intr_tq); | 1239 | tasklet_kill(&sc->intr_tq); |
1301 | tasklet_kill(&sc->bcon_tasklet); | 1240 | tasklet_kill(&sc->bcon_tasklet); |
1302 | 1241 | ||
1303 | if (!(sc->sc_flags & SC_OP_INVALID)) | 1242 | if (!(sc->sc_flags & SC_OP_INVALID)) |
1304 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | 1243 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); |
1305 | 1244 | ||
1306 | /* cleanup tx queues */ | 1245 | /* cleanup tx queues */ |
1307 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | 1246 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) |
1308 | if (ATH_TXQ_SETUP(sc, i)) | 1247 | if (ATH_TXQ_SETUP(sc, i)) |
1309 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | 1248 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); |
1310 | 1249 | ||
1311 | ath9k_hw_detach(sc->sc_ah); | 1250 | ath9k_hw_detach(sc->sc_ah); |
1312 | ath9k_exit_debug(sc); | 1251 | ath9k_exit_debug(sc); |
1313 | } | 1252 | } |
1314 | 1253 | ||
1315 | static int ath_init(u16 devid, struct ath_softc *sc) | 1254 | static int ath_init(u16 devid, struct ath_softc *sc) |
1316 | { | 1255 | { |
1317 | struct ath_hal *ah = NULL; | 1256 | struct ath_hal *ah = NULL; |
1318 | int status; | 1257 | int status; |
1319 | int error = 0, i; | 1258 | int error = 0, i; |
1320 | int csz = 0; | 1259 | int csz = 0; |
1321 | 1260 | ||
1322 | /* XXX: hardware will not be ready until ath_open() being called */ | 1261 | /* XXX: hardware will not be ready until ath_open() being called */ |
1323 | sc->sc_flags |= SC_OP_INVALID; | 1262 | sc->sc_flags |= SC_OP_INVALID; |
1324 | 1263 | ||
1325 | if (ath9k_init_debug(sc) < 0) | 1264 | if (ath9k_init_debug(sc) < 0) |
1326 | printk(KERN_ERR "Unable to create debugfs files\n"); | 1265 | printk(KERN_ERR "Unable to create debugfs files\n"); |
1327 | 1266 | ||
1328 | spin_lock_init(&sc->sc_resetlock); | 1267 | spin_lock_init(&sc->sc_resetlock); |
1329 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 1268 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
1330 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, | 1269 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, |
1331 | (unsigned long)sc); | 1270 | (unsigned long)sc); |
1332 | 1271 | ||
1333 | /* | 1272 | /* |
1334 | * Cache line size is used to size and align various | 1273 | * Cache line size is used to size and align various |
1335 | * structures used to communicate with the hardware. | 1274 | * structures used to communicate with the hardware. |
1336 | */ | 1275 | */ |
1337 | bus_read_cachesize(sc, &csz); | 1276 | bus_read_cachesize(sc, &csz); |
1338 | /* XXX assert csz is non-zero */ | 1277 | /* XXX assert csz is non-zero */ |
1339 | sc->sc_cachelsz = csz << 2; /* convert to bytes */ | 1278 | sc->sc_cachelsz = csz << 2; /* convert to bytes */ |
1340 | 1279 | ||
1341 | ah = ath9k_hw_attach(devid, sc, sc->mem, &status); | 1280 | ah = ath9k_hw_attach(devid, sc, sc->mem, &status); |
1342 | if (ah == NULL) { | 1281 | if (ah == NULL) { |
1343 | DPRINTF(sc, ATH_DBG_FATAL, | 1282 | DPRINTF(sc, ATH_DBG_FATAL, |
1344 | "Unable to attach hardware; HAL status %u\n", status); | 1283 | "Unable to attach hardware; HAL status %u\n", status); |
1345 | error = -ENXIO; | 1284 | error = -ENXIO; |
1346 | goto bad; | 1285 | goto bad; |
1347 | } | 1286 | } |
1348 | sc->sc_ah = ah; | 1287 | sc->sc_ah = ah; |
1349 | 1288 | ||
1350 | /* Get the hardware key cache size. */ | 1289 | /* Get the hardware key cache size. */ |
1351 | sc->sc_keymax = ah->ah_caps.keycache_size; | 1290 | sc->sc_keymax = ah->ah_caps.keycache_size; |
1352 | if (sc->sc_keymax > ATH_KEYMAX) { | 1291 | if (sc->sc_keymax > ATH_KEYMAX) { |
1353 | DPRINTF(sc, ATH_DBG_KEYCACHE, | 1292 | DPRINTF(sc, ATH_DBG_KEYCACHE, |
1354 | "Warning, using only %u entries in %u key cache\n", | 1293 | "Warning, using only %u entries in %u key cache\n", |
1355 | ATH_KEYMAX, sc->sc_keymax); | 1294 | ATH_KEYMAX, sc->sc_keymax); |
1356 | sc->sc_keymax = ATH_KEYMAX; | 1295 | sc->sc_keymax = ATH_KEYMAX; |
1357 | } | 1296 | } |
1358 | 1297 | ||
1359 | /* | 1298 | /* |
1360 | * Reset the key cache since some parts do not | 1299 | * Reset the key cache since some parts do not |
1361 | * reset the contents on initial power up. | 1300 | * reset the contents on initial power up. |
1362 | */ | 1301 | */ |
1363 | for (i = 0; i < sc->sc_keymax; i++) | 1302 | for (i = 0; i < sc->sc_keymax; i++) |
1364 | ath9k_hw_keyreset(ah, (u16) i); | 1303 | ath9k_hw_keyreset(ah, (u16) i); |
1365 | /* | 1304 | /* |
1366 | * Mark key cache slots associated with global keys | 1305 | * Mark key cache slots associated with global keys |
1367 | * as in use. If we knew TKIP was not to be used we | 1306 | * as in use. If we knew TKIP was not to be used we |
1368 | * could leave the +32, +64, and +32+64 slots free. | 1307 | * could leave the +32, +64, and +32+64 slots free. |
1369 | * XXX only for splitmic. | 1308 | * XXX only for splitmic. |
1370 | */ | 1309 | */ |
1371 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { | 1310 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { |
1372 | set_bit(i, sc->sc_keymap); | 1311 | set_bit(i, sc->sc_keymap); |
1373 | set_bit(i + 32, sc->sc_keymap); | 1312 | set_bit(i + 32, sc->sc_keymap); |
1374 | set_bit(i + 64, sc->sc_keymap); | 1313 | set_bit(i + 64, sc->sc_keymap); |
1375 | set_bit(i + 32 + 64, sc->sc_keymap); | 1314 | set_bit(i + 32 + 64, sc->sc_keymap); |
1376 | } | 1315 | } |
1377 | 1316 | ||
1378 | /* Collect the channel list using the default country code */ | 1317 | /* Collect the channel list using the default country code */ |
1379 | 1318 | ||
1380 | error = ath_setup_channels(sc); | 1319 | error = ath_setup_channels(sc); |
1381 | if (error) | 1320 | if (error) |
1382 | goto bad; | 1321 | goto bad; |
1383 | 1322 | ||
1384 | /* default to MONITOR mode */ | 1323 | /* default to MONITOR mode */ |
1385 | sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; | 1324 | sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; |
1386 | 1325 | ||
1387 | 1326 | ||
1388 | /* Setup rate tables */ | 1327 | /* Setup rate tables */ |
1389 | 1328 | ||
1390 | ath_rate_attach(sc); | 1329 | ath_rate_attach(sc); |
1391 | ath_setup_rates(sc, IEEE80211_BAND_2GHZ); | 1330 | ath_setup_rates(sc, IEEE80211_BAND_2GHZ); |
1392 | ath_setup_rates(sc, IEEE80211_BAND_5GHZ); | 1331 | ath_setup_rates(sc, IEEE80211_BAND_5GHZ); |
1393 | 1332 | ||
1394 | /* | 1333 | /* |
1395 | * Allocate hardware transmit queues: one queue for | 1334 | * Allocate hardware transmit queues: one queue for |
1396 | * beacon frames and one data queue for each QoS | 1335 | * beacon frames and one data queue for each QoS |
1397 | * priority. Note that the hal handles reseting | 1336 | * priority. Note that the hal handles reseting |
1398 | * these queues at the needed time. | 1337 | * these queues at the needed time. |
1399 | */ | 1338 | */ |
1400 | sc->beacon.beaconq = ath_beaconq_setup(ah); | 1339 | sc->beacon.beaconq = ath_beaconq_setup(ah); |
1401 | if (sc->beacon.beaconq == -1) { | 1340 | if (sc->beacon.beaconq == -1) { |
1402 | DPRINTF(sc, ATH_DBG_FATAL, | 1341 | DPRINTF(sc, ATH_DBG_FATAL, |
1403 | "Unable to setup a beacon xmit queue\n"); | 1342 | "Unable to setup a beacon xmit queue\n"); |
1404 | error = -EIO; | 1343 | error = -EIO; |
1405 | goto bad2; | 1344 | goto bad2; |
1406 | } | 1345 | } |
1407 | sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); | 1346 | sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); |
1408 | if (sc->beacon.cabq == NULL) { | 1347 | if (sc->beacon.cabq == NULL) { |
1409 | DPRINTF(sc, ATH_DBG_FATAL, | 1348 | DPRINTF(sc, ATH_DBG_FATAL, |
1410 | "Unable to setup CAB xmit queue\n"); | 1349 | "Unable to setup CAB xmit queue\n"); |
1411 | error = -EIO; | 1350 | error = -EIO; |
1412 | goto bad2; | 1351 | goto bad2; |
1413 | } | 1352 | } |
1414 | 1353 | ||
1415 | sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; | 1354 | sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; |
1416 | ath_cabq_update(sc); | 1355 | ath_cabq_update(sc); |
1417 | 1356 | ||
1418 | for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) | 1357 | for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) |
1419 | sc->tx.hwq_map[i] = -1; | 1358 | sc->tx.hwq_map[i] = -1; |
1420 | 1359 | ||
1421 | /* Setup data queues */ | 1360 | /* Setup data queues */ |
1422 | /* NB: ensure BK queue is the lowest priority h/w queue */ | 1361 | /* NB: ensure BK queue is the lowest priority h/w queue */ |
1423 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { | 1362 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { |
1424 | DPRINTF(sc, ATH_DBG_FATAL, | 1363 | DPRINTF(sc, ATH_DBG_FATAL, |
1425 | "Unable to setup xmit queue for BK traffic\n"); | 1364 | "Unable to setup xmit queue for BK traffic\n"); |
1426 | error = -EIO; | 1365 | error = -EIO; |
1427 | goto bad2; | 1366 | goto bad2; |
1428 | } | 1367 | } |
1429 | 1368 | ||
1430 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { | 1369 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { |
1431 | DPRINTF(sc, ATH_DBG_FATAL, | 1370 | DPRINTF(sc, ATH_DBG_FATAL, |
1432 | "Unable to setup xmit queue for BE traffic\n"); | 1371 | "Unable to setup xmit queue for BE traffic\n"); |
1433 | error = -EIO; | 1372 | error = -EIO; |
1434 | goto bad2; | 1373 | goto bad2; |
1435 | } | 1374 | } |
1436 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { | 1375 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { |
1437 | DPRINTF(sc, ATH_DBG_FATAL, | 1376 | DPRINTF(sc, ATH_DBG_FATAL, |
1438 | "Unable to setup xmit queue for VI traffic\n"); | 1377 | "Unable to setup xmit queue for VI traffic\n"); |
1439 | error = -EIO; | 1378 | error = -EIO; |
1440 | goto bad2; | 1379 | goto bad2; |
1441 | } | 1380 | } |
1442 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { | 1381 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { |
1443 | DPRINTF(sc, ATH_DBG_FATAL, | 1382 | DPRINTF(sc, ATH_DBG_FATAL, |
1444 | "Unable to setup xmit queue for VO traffic\n"); | 1383 | "Unable to setup xmit queue for VO traffic\n"); |
1445 | error = -EIO; | 1384 | error = -EIO; |
1446 | goto bad2; | 1385 | goto bad2; |
1447 | } | 1386 | } |
1448 | 1387 | ||
1449 | /* Initializes the noise floor to a reasonable default value. | 1388 | /* Initializes the noise floor to a reasonable default value. |
1450 | * Later on this will be updated during ANI processing. */ | 1389 | * Later on this will be updated during ANI processing. */ |
1451 | 1390 | ||
1452 | sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; | 1391 | sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; |
1453 | setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); | 1392 | setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); |
1454 | 1393 | ||
1455 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | 1394 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, |
1456 | ATH9K_CIPHER_TKIP, NULL)) { | 1395 | ATH9K_CIPHER_TKIP, NULL)) { |
1457 | /* | 1396 | /* |
1458 | * Whether we should enable h/w TKIP MIC. | 1397 | * Whether we should enable h/w TKIP MIC. |
1459 | * XXX: if we don't support WME TKIP MIC, then we wouldn't | 1398 | * XXX: if we don't support WME TKIP MIC, then we wouldn't |
1460 | * report WMM capable, so it's always safe to turn on | 1399 | * report WMM capable, so it's always safe to turn on |
1461 | * TKIP MIC in this case. | 1400 | * TKIP MIC in this case. |
1462 | */ | 1401 | */ |
1463 | ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, | 1402 | ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, |
1464 | 0, 1, NULL); | 1403 | 0, 1, NULL); |
1465 | } | 1404 | } |
1466 | 1405 | ||
1467 | /* | 1406 | /* |
1468 | * Check whether the separate key cache entries | 1407 | * Check whether the separate key cache entries |
1469 | * are required to handle both tx+rx MIC keys. | 1408 | * are required to handle both tx+rx MIC keys. |
1470 | * With split mic keys the number of stations is limited | 1409 | * With split mic keys the number of stations is limited |
1471 | * to 27 otherwise 59. | 1410 | * to 27 otherwise 59. |
1472 | */ | 1411 | */ |
1473 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | 1412 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, |
1474 | ATH9K_CIPHER_TKIP, NULL) | 1413 | ATH9K_CIPHER_TKIP, NULL) |
1475 | && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | 1414 | && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, |
1476 | ATH9K_CIPHER_MIC, NULL) | 1415 | ATH9K_CIPHER_MIC, NULL) |
1477 | && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, | 1416 | && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, |
1478 | 0, NULL)) | 1417 | 0, NULL)) |
1479 | sc->sc_splitmic = 1; | 1418 | sc->sc_splitmic = 1; |
1480 | 1419 | ||
1481 | /* turn on mcast key search if possible */ | 1420 | /* turn on mcast key search if possible */ |
1482 | if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) | 1421 | if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) |
1483 | (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, | 1422 | (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, |
1484 | 1, NULL); | 1423 | 1, NULL); |
1485 | 1424 | ||
1486 | sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; | 1425 | sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; |
1487 | sc->sc_config.txpowlimit_override = 0; | 1426 | sc->sc_config.txpowlimit_override = 0; |
1488 | 1427 | ||
1489 | /* 11n Capabilities */ | 1428 | /* 11n Capabilities */ |
1490 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { | 1429 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { |
1491 | sc->sc_flags |= SC_OP_TXAGGR; | 1430 | sc->sc_flags |= SC_OP_TXAGGR; |
1492 | sc->sc_flags |= SC_OP_RXAGGR; | 1431 | sc->sc_flags |= SC_OP_RXAGGR; |
1493 | } | 1432 | } |
1494 | 1433 | ||
1495 | sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; | 1434 | sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; |
1496 | sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; | 1435 | sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; |
1497 | 1436 | ||
1498 | ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); | 1437 | ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); |
1499 | sc->rx.defant = ath9k_hw_getdefantenna(ah); | 1438 | sc->rx.defant = ath9k_hw_getdefantenna(ah); |
1500 | 1439 | ||
1501 | ath9k_hw_getmac(ah, sc->sc_myaddr); | 1440 | ath9k_hw_getmac(ah, sc->sc_myaddr); |
1502 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { | 1441 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { |
1503 | ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); | 1442 | ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); |
1504 | ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); | 1443 | ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); |
1505 | ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); | 1444 | ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); |
1506 | } | 1445 | } |
1507 | 1446 | ||
1508 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ | 1447 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ |
1509 | 1448 | ||
1510 | /* initialize beacon slots */ | 1449 | /* initialize beacon slots */ |
1511 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) | 1450 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) |
1512 | sc->beacon.bslot[i] = ATH_IF_ID_ANY; | 1451 | sc->beacon.bslot[i] = ATH_IF_ID_ANY; |
1513 | 1452 | ||
1514 | /* save MISC configurations */ | 1453 | /* save MISC configurations */ |
1515 | sc->sc_config.swBeaconProcess = 1; | 1454 | sc->sc_config.swBeaconProcess = 1; |
1516 | 1455 | ||
1517 | /* setup channels and rates */ | 1456 | /* setup channels and rates */ |
1518 | 1457 | ||
1519 | sc->sbands[IEEE80211_BAND_2GHZ].channels = | 1458 | sc->sbands[IEEE80211_BAND_2GHZ].channels = |
1520 | sc->channels[IEEE80211_BAND_2GHZ]; | 1459 | sc->channels[IEEE80211_BAND_2GHZ]; |
1521 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = | 1460 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = |
1522 | sc->rates[IEEE80211_BAND_2GHZ]; | 1461 | sc->rates[IEEE80211_BAND_2GHZ]; |
1523 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | 1462 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; |
1524 | 1463 | ||
1525 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { | 1464 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { |
1526 | sc->sbands[IEEE80211_BAND_5GHZ].channels = | 1465 | sc->sbands[IEEE80211_BAND_5GHZ].channels = |
1527 | sc->channels[IEEE80211_BAND_5GHZ]; | 1466 | sc->channels[IEEE80211_BAND_5GHZ]; |
1528 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | 1467 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = |
1529 | sc->rates[IEEE80211_BAND_5GHZ]; | 1468 | sc->rates[IEEE80211_BAND_5GHZ]; |
1530 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; | 1469 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; |
1531 | } | 1470 | } |
1532 | 1471 | ||
1533 | return 0; | 1472 | return 0; |
1534 | bad2: | 1473 | bad2: |
1535 | /* cleanup tx queues */ | 1474 | /* cleanup tx queues */ |
1536 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | 1475 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) |
1537 | if (ATH_TXQ_SETUP(sc, i)) | 1476 | if (ATH_TXQ_SETUP(sc, i)) |
1538 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | 1477 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); |
1539 | bad: | 1478 | bad: |
1540 | if (ah) | 1479 | if (ah) |
1541 | ath9k_hw_detach(ah); | 1480 | ath9k_hw_detach(ah); |
1542 | 1481 | ||
1543 | return error; | 1482 | return error; |
1544 | } | 1483 | } |
1545 | 1484 | ||
1546 | static int ath_attach(u16 devid, struct ath_softc *sc) | 1485 | static int ath_attach(u16 devid, struct ath_softc *sc) |
1547 | { | 1486 | { |
1548 | struct ieee80211_hw *hw = sc->hw; | 1487 | struct ieee80211_hw *hw = sc->hw; |
1549 | int error = 0; | 1488 | int error = 0; |
1550 | 1489 | ||
1551 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); | 1490 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); |
1552 | 1491 | ||
1553 | error = ath_init(devid, sc); | 1492 | error = ath_init(devid, sc); |
1554 | if (error != 0) | 1493 | if (error != 0) |
1555 | return error; | 1494 | return error; |
1556 | 1495 | ||
1557 | /* get mac address from hardware and set in mac80211 */ | 1496 | /* get mac address from hardware and set in mac80211 */ |
1558 | 1497 | ||
1559 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); | 1498 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); |
1560 | 1499 | ||
1561 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 1500 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
1562 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1501 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1563 | IEEE80211_HW_SIGNAL_DBM | | 1502 | IEEE80211_HW_SIGNAL_DBM | |
1564 | IEEE80211_HW_AMPDU_AGGREGATION; | 1503 | IEEE80211_HW_AMPDU_AGGREGATION; |
1565 | 1504 | ||
1566 | hw->wiphy->interface_modes = | 1505 | hw->wiphy->interface_modes = |
1567 | BIT(NL80211_IFTYPE_AP) | | 1506 | BIT(NL80211_IFTYPE_AP) | |
1568 | BIT(NL80211_IFTYPE_STATION) | | 1507 | BIT(NL80211_IFTYPE_STATION) | |
1569 | BIT(NL80211_IFTYPE_ADHOC); | 1508 | BIT(NL80211_IFTYPE_ADHOC); |
1570 | 1509 | ||
1571 | hw->queues = 4; | 1510 | hw->queues = 4; |
1572 | hw->max_rates = 4; | 1511 | hw->max_rates = 4; |
1573 | hw->max_rate_tries = ATH_11N_TXMAXTRY; | 1512 | hw->max_rate_tries = ATH_11N_TXMAXTRY; |
1574 | hw->sta_data_size = sizeof(struct ath_node); | 1513 | hw->sta_data_size = sizeof(struct ath_node); |
1575 | hw->vif_data_size = sizeof(struct ath_vap); | 1514 | hw->vif_data_size = sizeof(struct ath_vap); |
1576 | 1515 | ||
1577 | /* Register rate control */ | 1516 | /* Register rate control */ |
1578 | hw->rate_control_algorithm = "ath9k_rate_control"; | 1517 | hw->rate_control_algorithm = "ath9k_rate_control"; |
1579 | error = ath_rate_control_register(); | 1518 | error = ath_rate_control_register(); |
1580 | if (error != 0) { | 1519 | if (error != 0) { |
1581 | DPRINTF(sc, ATH_DBG_FATAL, | 1520 | DPRINTF(sc, ATH_DBG_FATAL, |
1582 | "Unable to register rate control algorithm: %d\n", error); | 1521 | "Unable to register rate control algorithm: %d\n", error); |
1583 | ath_rate_control_unregister(); | 1522 | ath_rate_control_unregister(); |
1584 | goto bad; | 1523 | goto bad; |
1585 | } | 1524 | } |
1586 | 1525 | ||
1587 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { | 1526 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { |
1588 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | 1527 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); |
1589 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) | 1528 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) |
1590 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | 1529 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); |
1591 | } | 1530 | } |
1592 | 1531 | ||
1593 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; | 1532 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; |
1594 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) | 1533 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) |
1595 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 1534 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
1596 | &sc->sbands[IEEE80211_BAND_5GHZ]; | 1535 | &sc->sbands[IEEE80211_BAND_5GHZ]; |
1597 | 1536 | ||
1598 | /* initialize tx/rx engine */ | 1537 | /* initialize tx/rx engine */ |
1599 | error = ath_tx_init(sc, ATH_TXBUF); | 1538 | error = ath_tx_init(sc, ATH_TXBUF); |
1600 | if (error != 0) | 1539 | if (error != 0) |
1601 | goto detach; | 1540 | goto detach; |
1602 | 1541 | ||
1603 | error = ath_rx_init(sc, ATH_RXBUF); | 1542 | error = ath_rx_init(sc, ATH_RXBUF); |
1604 | if (error != 0) | 1543 | if (error != 0) |
1605 | goto detach; | 1544 | goto detach; |
1606 | 1545 | ||
1607 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1546 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1608 | /* Initialze h/w Rfkill */ | 1547 | /* Initialze h/w Rfkill */ |
1609 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 1548 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
1610 | INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); | 1549 | INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); |
1611 | 1550 | ||
1612 | /* Initialize s/w rfkill */ | 1551 | /* Initialize s/w rfkill */ |
1613 | if (ath_init_sw_rfkill(sc)) | 1552 | if (ath_init_sw_rfkill(sc)) |
1614 | goto detach; | 1553 | goto detach; |
1615 | #endif | 1554 | #endif |
1616 | 1555 | ||
1617 | error = ieee80211_register_hw(hw); | 1556 | error = ieee80211_register_hw(hw); |
1618 | if (error != 0) { | 1557 | if (error != 0) { |
1619 | ath_rate_control_unregister(); | 1558 | ath_rate_control_unregister(); |
1620 | goto bad; | 1559 | goto bad; |
1621 | } | 1560 | } |
1622 | 1561 | ||
1623 | /* Initialize LED control */ | 1562 | /* Initialize LED control */ |
1624 | ath_init_leds(sc); | 1563 | ath_init_leds(sc); |
1625 | 1564 | ||
1626 | return 0; | 1565 | return 0; |
1627 | detach: | 1566 | detach: |
1628 | ath_detach(sc); | 1567 | ath_detach(sc); |
1629 | bad: | 1568 | bad: |
1630 | return error; | 1569 | return error; |
1631 | } | 1570 | } |
1632 | 1571 | ||
1633 | int ath_reset(struct ath_softc *sc, bool retry_tx) | 1572 | int ath_reset(struct ath_softc *sc, bool retry_tx) |
1634 | { | 1573 | { |
1635 | struct ath_hal *ah = sc->sc_ah; | 1574 | struct ath_hal *ah = sc->sc_ah; |
1636 | int status; | 1575 | int status; |
1637 | int error = 0; | 1576 | int error = 0; |
1638 | 1577 | ||
1639 | ath9k_hw_set_interrupts(ah, 0); | 1578 | ath9k_hw_set_interrupts(ah, 0); |
1640 | ath_draintxq(sc, retry_tx); | 1579 | ath_draintxq(sc, retry_tx); |
1641 | ath_stoprecv(sc); | 1580 | ath_stoprecv(sc); |
1642 | ath_flushrecv(sc); | 1581 | ath_flushrecv(sc); |
1643 | 1582 | ||
1644 | spin_lock_bh(&sc->sc_resetlock); | 1583 | spin_lock_bh(&sc->sc_resetlock); |
1645 | if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, | 1584 | if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, |
1646 | sc->tx_chan_width, | 1585 | sc->tx_chan_width, |
1647 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, | 1586 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, |
1648 | sc->sc_ht_extprotspacing, false, &status)) { | 1587 | sc->sc_ht_extprotspacing, false, &status)) { |
1649 | DPRINTF(sc, ATH_DBG_FATAL, | 1588 | DPRINTF(sc, ATH_DBG_FATAL, |
1650 | "Unable to reset hardware; hal status %u\n", status); | 1589 | "Unable to reset hardware; hal status %u\n", status); |
1651 | error = -EIO; | 1590 | error = -EIO; |
1652 | } | 1591 | } |
1653 | spin_unlock_bh(&sc->sc_resetlock); | 1592 | spin_unlock_bh(&sc->sc_resetlock); |
1654 | 1593 | ||
1655 | if (ath_startrecv(sc) != 0) | 1594 | if (ath_startrecv(sc) != 0) |
1656 | DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); | 1595 | DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); |
1657 | 1596 | ||
1658 | /* | 1597 | /* |
1659 | * We may be doing a reset in response to a request | 1598 | * We may be doing a reset in response to a request |
1660 | * that changes the channel so update any state that | 1599 | * that changes the channel so update any state that |
1661 | * might change as a result. | 1600 | * might change as a result. |
1662 | */ | 1601 | */ |
1663 | ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); | 1602 | ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); |
1664 | 1603 | ||
1665 | ath_update_txpow(sc); | 1604 | ath_update_txpow(sc); |
1666 | 1605 | ||
1667 | if (sc->sc_flags & SC_OP_BEACONS) | 1606 | if (sc->sc_flags & SC_OP_BEACONS) |
1668 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ | 1607 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ |
1669 | 1608 | ||
1670 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | 1609 | ath9k_hw_set_interrupts(ah, sc->sc_imask); |
1671 | 1610 | ||
1672 | if (retry_tx) { | 1611 | if (retry_tx) { |
1673 | int i; | 1612 | int i; |
1674 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 1613 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
1675 | if (ATH_TXQ_SETUP(sc, i)) { | 1614 | if (ATH_TXQ_SETUP(sc, i)) { |
1676 | spin_lock_bh(&sc->tx.txq[i].axq_lock); | 1615 | spin_lock_bh(&sc->tx.txq[i].axq_lock); |
1677 | ath_txq_schedule(sc, &sc->tx.txq[i]); | 1616 | ath_txq_schedule(sc, &sc->tx.txq[i]); |
1678 | spin_unlock_bh(&sc->tx.txq[i].axq_lock); | 1617 | spin_unlock_bh(&sc->tx.txq[i].axq_lock); |
1679 | } | 1618 | } |
1680 | } | 1619 | } |
1681 | } | 1620 | } |
1682 | 1621 | ||
1683 | return error; | 1622 | return error; |
1684 | } | 1623 | } |
1685 | 1624 | ||
1686 | /* | 1625 | /* |
1687 | * This function will allocate both the DMA descriptor structure, and the | 1626 | * This function will allocate both the DMA descriptor structure, and the |
1688 | * buffers it contains. These are used to contain the descriptors used | 1627 | * buffers it contains. These are used to contain the descriptors used |
1689 | * by the system. | 1628 | * by the system. |
1690 | */ | 1629 | */ |
1691 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, | 1630 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, |
1692 | struct list_head *head, const char *name, | 1631 | struct list_head *head, const char *name, |
1693 | int nbuf, int ndesc) | 1632 | int nbuf, int ndesc) |
1694 | { | 1633 | { |
1695 | #define DS2PHYS(_dd, _ds) \ | 1634 | #define DS2PHYS(_dd, _ds) \ |
1696 | ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) | 1635 | ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) |
1697 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) | 1636 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) |
1698 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) | 1637 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) |
1699 | 1638 | ||
1700 | struct ath_desc *ds; | 1639 | struct ath_desc *ds; |
1701 | struct ath_buf *bf; | 1640 | struct ath_buf *bf; |
1702 | int i, bsize, error; | 1641 | int i, bsize, error; |
1703 | 1642 | ||
1704 | DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", | 1643 | DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", |
1705 | name, nbuf, ndesc); | 1644 | name, nbuf, ndesc); |
1706 | 1645 | ||
1707 | /* ath_desc must be a multiple of DWORDs */ | 1646 | /* ath_desc must be a multiple of DWORDs */ |
1708 | if ((sizeof(struct ath_desc) % 4) != 0) { | 1647 | if ((sizeof(struct ath_desc) % 4) != 0) { |
1709 | DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); | 1648 | DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); |
1710 | ASSERT((sizeof(struct ath_desc) % 4) == 0); | 1649 | ASSERT((sizeof(struct ath_desc) % 4) == 0); |
1711 | error = -ENOMEM; | 1650 | error = -ENOMEM; |
1712 | goto fail; | 1651 | goto fail; |
1713 | } | 1652 | } |
1714 | 1653 | ||
1715 | dd->dd_name = name; | 1654 | dd->dd_name = name; |
1716 | dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; | 1655 | dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; |
1717 | 1656 | ||
1718 | /* | 1657 | /* |
1719 | * Need additional DMA memory because we can't use | 1658 | * Need additional DMA memory because we can't use |
1720 | * descriptors that cross the 4K page boundary. Assume | 1659 | * descriptors that cross the 4K page boundary. Assume |
1721 | * one skipped descriptor per 4K page. | 1660 | * one skipped descriptor per 4K page. |
1722 | */ | 1661 | */ |
1723 | if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { | 1662 | if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { |
1724 | u32 ndesc_skipped = | 1663 | u32 ndesc_skipped = |
1725 | ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); | 1664 | ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); |
1726 | u32 dma_len; | 1665 | u32 dma_len; |
1727 | 1666 | ||
1728 | while (ndesc_skipped) { | 1667 | while (ndesc_skipped) { |
1729 | dma_len = ndesc_skipped * sizeof(struct ath_desc); | 1668 | dma_len = ndesc_skipped * sizeof(struct ath_desc); |
1730 | dd->dd_desc_len += dma_len; | 1669 | dd->dd_desc_len += dma_len; |
1731 | 1670 | ||
1732 | ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); | 1671 | ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); |
1733 | }; | 1672 | }; |
1734 | } | 1673 | } |
1735 | 1674 | ||
1736 | /* allocate descriptors */ | 1675 | /* allocate descriptors */ |
1737 | dd->dd_desc = pci_alloc_consistent(sc->pdev, | 1676 | dd->dd_desc = pci_alloc_consistent(sc->pdev, |
1738 | dd->dd_desc_len, | 1677 | dd->dd_desc_len, |
1739 | &dd->dd_desc_paddr); | 1678 | &dd->dd_desc_paddr); |
1740 | if (dd->dd_desc == NULL) { | 1679 | if (dd->dd_desc == NULL) { |
1741 | error = -ENOMEM; | 1680 | error = -ENOMEM; |
1742 | goto fail; | 1681 | goto fail; |
1743 | } | 1682 | } |
1744 | ds = dd->dd_desc; | 1683 | ds = dd->dd_desc; |
1745 | DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", | 1684 | DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", |
1746 | dd->dd_name, ds, (u32) dd->dd_desc_len, | 1685 | dd->dd_name, ds, (u32) dd->dd_desc_len, |
1747 | ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); | 1686 | ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); |
1748 | 1687 | ||
1749 | /* allocate buffers */ | 1688 | /* allocate buffers */ |
1750 | bsize = sizeof(struct ath_buf) * nbuf; | 1689 | bsize = sizeof(struct ath_buf) * nbuf; |
1751 | bf = kmalloc(bsize, GFP_KERNEL); | 1690 | bf = kmalloc(bsize, GFP_KERNEL); |
1752 | if (bf == NULL) { | 1691 | if (bf == NULL) { |
1753 | error = -ENOMEM; | 1692 | error = -ENOMEM; |
1754 | goto fail2; | 1693 | goto fail2; |
1755 | } | 1694 | } |
1756 | memset(bf, 0, bsize); | 1695 | memset(bf, 0, bsize); |
1757 | dd->dd_bufptr = bf; | 1696 | dd->dd_bufptr = bf; |
1758 | 1697 | ||
1759 | INIT_LIST_HEAD(head); | 1698 | INIT_LIST_HEAD(head); |
1760 | for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { | 1699 | for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { |
1761 | bf->bf_desc = ds; | 1700 | bf->bf_desc = ds; |
1762 | bf->bf_daddr = DS2PHYS(dd, ds); | 1701 | bf->bf_daddr = DS2PHYS(dd, ds); |
1763 | 1702 | ||
1764 | if (!(sc->sc_ah->ah_caps.hw_caps & | 1703 | if (!(sc->sc_ah->ah_caps.hw_caps & |
1765 | ATH9K_HW_CAP_4KB_SPLITTRANS)) { | 1704 | ATH9K_HW_CAP_4KB_SPLITTRANS)) { |
1766 | /* | 1705 | /* |
1767 | * Skip descriptor addresses which can cause 4KB | 1706 | * Skip descriptor addresses which can cause 4KB |
1768 | * boundary crossing (addr + length) with a 32 dword | 1707 | * boundary crossing (addr + length) with a 32 dword |
1769 | * descriptor fetch. | 1708 | * descriptor fetch. |
1770 | */ | 1709 | */ |
1771 | while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { | 1710 | while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { |
1772 | ASSERT((caddr_t) bf->bf_desc < | 1711 | ASSERT((caddr_t) bf->bf_desc < |
1773 | ((caddr_t) dd->dd_desc + | 1712 | ((caddr_t) dd->dd_desc + |
1774 | dd->dd_desc_len)); | 1713 | dd->dd_desc_len)); |
1775 | 1714 | ||
1776 | ds += ndesc; | 1715 | ds += ndesc; |
1777 | bf->bf_desc = ds; | 1716 | bf->bf_desc = ds; |
1778 | bf->bf_daddr = DS2PHYS(dd, ds); | 1717 | bf->bf_daddr = DS2PHYS(dd, ds); |
1779 | } | 1718 | } |
1780 | } | 1719 | } |
1781 | list_add_tail(&bf->list, head); | 1720 | list_add_tail(&bf->list, head); |
1782 | } | 1721 | } |
1783 | return 0; | 1722 | return 0; |
1784 | fail2: | 1723 | fail2: |
1785 | pci_free_consistent(sc->pdev, | 1724 | pci_free_consistent(sc->pdev, |
1786 | dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); | 1725 | dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); |
1787 | fail: | 1726 | fail: |
1788 | memset(dd, 0, sizeof(*dd)); | 1727 | memset(dd, 0, sizeof(*dd)); |
1789 | return error; | 1728 | return error; |
1790 | #undef ATH_DESC_4KB_BOUND_CHECK | 1729 | #undef ATH_DESC_4KB_BOUND_CHECK |
1791 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED | 1730 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED |
1792 | #undef DS2PHYS | 1731 | #undef DS2PHYS |
1793 | } | 1732 | } |
1794 | 1733 | ||
1795 | void ath_descdma_cleanup(struct ath_softc *sc, | 1734 | void ath_descdma_cleanup(struct ath_softc *sc, |
1796 | struct ath_descdma *dd, | 1735 | struct ath_descdma *dd, |
1797 | struct list_head *head) | 1736 | struct list_head *head) |
1798 | { | 1737 | { |
1799 | pci_free_consistent(sc->pdev, | 1738 | pci_free_consistent(sc->pdev, |
1800 | dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); | 1739 | dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); |
1801 | 1740 | ||
1802 | INIT_LIST_HEAD(head); | 1741 | INIT_LIST_HEAD(head); |
1803 | kfree(dd->dd_bufptr); | 1742 | kfree(dd->dd_bufptr); |
1804 | memset(dd, 0, sizeof(*dd)); | 1743 | memset(dd, 0, sizeof(*dd)); |
1805 | } | 1744 | } |
1806 | 1745 | ||
1807 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) | 1746 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) |
1808 | { | 1747 | { |
1809 | int qnum; | 1748 | int qnum; |
1810 | 1749 | ||
1811 | switch (queue) { | 1750 | switch (queue) { |
1812 | case 0: | 1751 | case 0: |
1813 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; | 1752 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; |
1814 | break; | 1753 | break; |
1815 | case 1: | 1754 | case 1: |
1816 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; | 1755 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; |
1817 | break; | 1756 | break; |
1818 | case 2: | 1757 | case 2: |
1819 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; | 1758 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; |
1820 | break; | 1759 | break; |
1821 | case 3: | 1760 | case 3: |
1822 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; | 1761 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; |
1823 | break; | 1762 | break; |
1824 | default: | 1763 | default: |
1825 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; | 1764 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; |
1826 | break; | 1765 | break; |
1827 | } | 1766 | } |
1828 | 1767 | ||
1829 | return qnum; | 1768 | return qnum; |
1830 | } | 1769 | } |
1831 | 1770 | ||
1832 | int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) | 1771 | int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) |
1833 | { | 1772 | { |
1834 | int qnum; | 1773 | int qnum; |
1835 | 1774 | ||
1836 | switch (queue) { | 1775 | switch (queue) { |
1837 | case ATH9K_WME_AC_VO: | 1776 | case ATH9K_WME_AC_VO: |
1838 | qnum = 0; | 1777 | qnum = 0; |
1839 | break; | 1778 | break; |
1840 | case ATH9K_WME_AC_VI: | 1779 | case ATH9K_WME_AC_VI: |
1841 | qnum = 1; | 1780 | qnum = 1; |
1842 | break; | 1781 | break; |
1843 | case ATH9K_WME_AC_BE: | 1782 | case ATH9K_WME_AC_BE: |
1844 | qnum = 2; | 1783 | qnum = 2; |
1845 | break; | 1784 | break; |
1846 | case ATH9K_WME_AC_BK: | 1785 | case ATH9K_WME_AC_BK: |
1847 | qnum = 3; | 1786 | qnum = 3; |
1848 | break; | 1787 | break; |
1849 | default: | 1788 | default: |
1850 | qnum = -1; | 1789 | qnum = -1; |
1851 | break; | 1790 | break; |
1852 | } | 1791 | } |
1853 | 1792 | ||
1854 | return qnum; | 1793 | return qnum; |
1855 | } | 1794 | } |
1856 | 1795 | ||
1857 | /**********************/ | 1796 | /**********************/ |
1858 | /* mac80211 callbacks */ | 1797 | /* mac80211 callbacks */ |
1859 | /**********************/ | 1798 | /**********************/ |
1860 | 1799 | ||
1861 | static int ath9k_start(struct ieee80211_hw *hw) | 1800 | static int ath9k_start(struct ieee80211_hw *hw) |
1862 | { | 1801 | { |
1863 | struct ath_softc *sc = hw->priv; | 1802 | struct ath_softc *sc = hw->priv; |
1864 | struct ieee80211_channel *curchan = hw->conf.channel; | 1803 | struct ieee80211_channel *curchan = hw->conf.channel; |
1865 | struct ath9k_channel *init_channel; | 1804 | struct ath9k_channel *init_channel; |
1866 | int error = 0, pos, status; | 1805 | int error = 0, pos, status; |
1867 | 1806 | ||
1868 | DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " | 1807 | DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " |
1869 | "initial channel: %d MHz\n", curchan->center_freq); | 1808 | "initial channel: %d MHz\n", curchan->center_freq); |
1870 | 1809 | ||
1871 | /* setup initial channel */ | 1810 | /* setup initial channel */ |
1872 | 1811 | ||
1873 | pos = ath_get_channel(sc, curchan); | 1812 | pos = ath_get_channel(sc, curchan); |
1874 | if (pos == -1) { | 1813 | if (pos == -1) { |
1875 | DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); | 1814 | DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); |
1876 | error = -EINVAL; | 1815 | error = -EINVAL; |
1877 | goto error; | 1816 | goto error; |
1878 | } | 1817 | } |
1879 | 1818 | ||
1880 | sc->tx_chan_width = ATH9K_HT_MACMODE_20; | 1819 | sc->tx_chan_width = ATH9K_HT_MACMODE_20; |
1881 | sc->sc_ah->ah_channels[pos].chanmode = | 1820 | sc->sc_ah->ah_channels[pos].chanmode = |
1882 | (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; | 1821 | (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; |
1883 | init_channel = &sc->sc_ah->ah_channels[pos]; | 1822 | init_channel = &sc->sc_ah->ah_channels[pos]; |
1884 | 1823 | ||
1885 | /* Reset SERDES registers */ | 1824 | /* Reset SERDES registers */ |
1886 | ath9k_hw_configpcipowersave(sc->sc_ah, 0); | 1825 | ath9k_hw_configpcipowersave(sc->sc_ah, 0); |
1887 | 1826 | ||
1888 | /* | 1827 | /* |
1889 | * The basic interface to setting the hardware in a good | 1828 | * The basic interface to setting the hardware in a good |
1890 | * state is ``reset''. On return the hardware is known to | 1829 | * state is ``reset''. On return the hardware is known to |
1891 | * be powered up and with interrupts disabled. This must | 1830 | * be powered up and with interrupts disabled. This must |
1892 | * be followed by initialization of the appropriate bits | 1831 | * be followed by initialization of the appropriate bits |
1893 | * and then setup of the interrupt mask. | 1832 | * and then setup of the interrupt mask. |
1894 | */ | 1833 | */ |
1895 | spin_lock_bh(&sc->sc_resetlock); | 1834 | spin_lock_bh(&sc->sc_resetlock); |
1896 | if (!ath9k_hw_reset(sc->sc_ah, init_channel, | 1835 | if (!ath9k_hw_reset(sc->sc_ah, init_channel, |
1897 | sc->tx_chan_width, | 1836 | sc->tx_chan_width, |
1898 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, | 1837 | sc->sc_tx_chainmask, sc->sc_rx_chainmask, |
1899 | sc->sc_ht_extprotspacing, false, &status)) { | 1838 | sc->sc_ht_extprotspacing, false, &status)) { |
1900 | DPRINTF(sc, ATH_DBG_FATAL, | 1839 | DPRINTF(sc, ATH_DBG_FATAL, |
1901 | "Unable to reset hardware; hal status %u " | 1840 | "Unable to reset hardware; hal status %u " |
1902 | "(freq %u flags 0x%x)\n", status, | 1841 | "(freq %u flags 0x%x)\n", status, |
1903 | init_channel->channel, init_channel->channelFlags); | 1842 | init_channel->channel, init_channel->channelFlags); |
1904 | error = -EIO; | 1843 | error = -EIO; |
1905 | spin_unlock_bh(&sc->sc_resetlock); | 1844 | spin_unlock_bh(&sc->sc_resetlock); |
1906 | goto error; | 1845 | goto error; |
1907 | } | 1846 | } |
1908 | spin_unlock_bh(&sc->sc_resetlock); | 1847 | spin_unlock_bh(&sc->sc_resetlock); |
1909 | 1848 | ||
1910 | /* | 1849 | /* |
1911 | * This is needed only to setup initial state | 1850 | * This is needed only to setup initial state |
1912 | * but it's best done after a reset. | 1851 | * but it's best done after a reset. |
1913 | */ | 1852 | */ |
1914 | ath_update_txpow(sc); | 1853 | ath_update_txpow(sc); |
1915 | 1854 | ||
1916 | /* | 1855 | /* |
1917 | * Setup the hardware after reset: | 1856 | * Setup the hardware after reset: |
1918 | * The receive engine is set going. | 1857 | * The receive engine is set going. |
1919 | * Frame transmit is handled entirely | 1858 | * Frame transmit is handled entirely |
1920 | * in the frame output path; there's nothing to do | 1859 | * in the frame output path; there's nothing to do |
1921 | * here except setup the interrupt mask. | 1860 | * here except setup the interrupt mask. |
1922 | */ | 1861 | */ |
1923 | if (ath_startrecv(sc) != 0) { | 1862 | if (ath_startrecv(sc) != 0) { |
1924 | DPRINTF(sc, ATH_DBG_FATAL, | 1863 | DPRINTF(sc, ATH_DBG_FATAL, |
1925 | "Unable to start recv logic\n"); | 1864 | "Unable to start recv logic\n"); |
1926 | error = -EIO; | 1865 | error = -EIO; |
1927 | goto error; | 1866 | goto error; |
1928 | } | 1867 | } |
1929 | 1868 | ||
1930 | /* Setup our intr mask. */ | 1869 | /* Setup our intr mask. */ |
1931 | sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX | 1870 | sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX |
1932 | | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | 1871 | | ATH9K_INT_RXEOL | ATH9K_INT_RXORN |
1933 | | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; | 1872 | | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; |
1934 | 1873 | ||
1935 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) | 1874 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) |
1936 | sc->sc_imask |= ATH9K_INT_GTT; | 1875 | sc->sc_imask |= ATH9K_INT_GTT; |
1937 | 1876 | ||
1938 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | 1877 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) |
1939 | sc->sc_imask |= ATH9K_INT_CST; | 1878 | sc->sc_imask |= ATH9K_INT_CST; |
1940 | 1879 | ||
1941 | /* | 1880 | /* |
1942 | * Enable MIB interrupts when there are hardware phy counters. | 1881 | * Enable MIB interrupts when there are hardware phy counters. |
1943 | * Note we only do this (at the moment) for station mode. | 1882 | * Note we only do this (at the moment) for station mode. |
1944 | */ | 1883 | */ |
1945 | if (ath9k_hw_phycounters(sc->sc_ah) && | 1884 | if (ath9k_hw_phycounters(sc->sc_ah) && |
1946 | ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || | 1885 | ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || |
1947 | (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) | 1886 | (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) |
1948 | sc->sc_imask |= ATH9K_INT_MIB; | 1887 | sc->sc_imask |= ATH9K_INT_MIB; |
1949 | /* | 1888 | /* |
1950 | * Some hardware processes the TIM IE and fires an | 1889 | * Some hardware processes the TIM IE and fires an |
1951 | * interrupt when the TIM bit is set. For hardware | 1890 | * interrupt when the TIM bit is set. For hardware |
1952 | * that does, if not overridden by configuration, | 1891 | * that does, if not overridden by configuration, |
1953 | * enable the TIM interrupt when operating as station. | 1892 | * enable the TIM interrupt when operating as station. |
1954 | */ | 1893 | */ |
1955 | if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && | 1894 | if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && |
1956 | (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && | 1895 | (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && |
1957 | !sc->sc_config.swBeaconProcess) | 1896 | !sc->sc_config.swBeaconProcess) |
1958 | sc->sc_imask |= ATH9K_INT_TIM; | 1897 | sc->sc_imask |= ATH9K_INT_TIM; |
1959 | 1898 | ||
1960 | ath_setcurmode(sc, ath_chan2mode(init_channel)); | 1899 | ath_setcurmode(sc, ath_chan2mode(init_channel)); |
1961 | 1900 | ||
1962 | sc->sc_flags &= ~SC_OP_INVALID; | 1901 | sc->sc_flags &= ~SC_OP_INVALID; |
1963 | 1902 | ||
1964 | /* Disable BMISS interrupt when we're not associated */ | 1903 | /* Disable BMISS interrupt when we're not associated */ |
1965 | sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); | 1904 | sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); |
1966 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); | 1905 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); |
1967 | 1906 | ||
1968 | ieee80211_wake_queues(sc->hw); | 1907 | ieee80211_wake_queues(sc->hw); |
1969 | 1908 | ||
1970 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1909 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1971 | error = ath_start_rfkill_poll(sc); | 1910 | error = ath_start_rfkill_poll(sc); |
1972 | #endif | 1911 | #endif |
1973 | 1912 | ||
1974 | error: | 1913 | error: |
1975 | return error; | 1914 | return error; |
1976 | } | 1915 | } |
1977 | 1916 | ||
1978 | static int ath9k_tx(struct ieee80211_hw *hw, | 1917 | static int ath9k_tx(struct ieee80211_hw *hw, |
1979 | struct sk_buff *skb) | 1918 | struct sk_buff *skb) |
1980 | { | 1919 | { |
1981 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1920 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1982 | struct ath_softc *sc = hw->priv; | 1921 | struct ath_softc *sc = hw->priv; |
1983 | struct ath_tx_control txctl; | 1922 | struct ath_tx_control txctl; |
1984 | int hdrlen, padsize; | 1923 | int hdrlen, padsize; |
1985 | 1924 | ||
1986 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | 1925 | memset(&txctl, 0, sizeof(struct ath_tx_control)); |
1987 | 1926 | ||
1988 | /* | 1927 | /* |
1989 | * As a temporary workaround, assign seq# here; this will likely need | 1928 | * As a temporary workaround, assign seq# here; this will likely need |
1990 | * to be cleaned up to work better with Beacon transmission and virtual | 1929 | * to be cleaned up to work better with Beacon transmission and virtual |
1991 | * BSSes. | 1930 | * BSSes. |
1992 | */ | 1931 | */ |
1993 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 1932 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
1994 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1933 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1995 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | 1934 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) |
1996 | sc->tx.seq_no += 0x10; | 1935 | sc->tx.seq_no += 0x10; |
1997 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | 1936 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); |
1998 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); | 1937 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); |
1999 | } | 1938 | } |
2000 | 1939 | ||
2001 | /* Add the padding after the header if this is not already done */ | 1940 | /* Add the padding after the header if this is not already done */ |
2002 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 1941 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
2003 | if (hdrlen & 3) { | 1942 | if (hdrlen & 3) { |
2004 | padsize = hdrlen % 4; | 1943 | padsize = hdrlen % 4; |
2005 | if (skb_headroom(skb) < padsize) | 1944 | if (skb_headroom(skb) < padsize) |
2006 | return -1; | 1945 | return -1; |
2007 | skb_push(skb, padsize); | 1946 | skb_push(skb, padsize); |
2008 | memmove(skb->data, skb->data + padsize, hdrlen); | 1947 | memmove(skb->data, skb->data + padsize, hdrlen); |
2009 | } | 1948 | } |
2010 | 1949 | ||
2011 | /* Check if a tx queue is available */ | 1950 | /* Check if a tx queue is available */ |
2012 | 1951 | ||
2013 | txctl.txq = ath_test_get_txq(sc, skb); | 1952 | txctl.txq = ath_test_get_txq(sc, skb); |
2014 | if (!txctl.txq) | 1953 | if (!txctl.txq) |
2015 | goto exit; | 1954 | goto exit; |
2016 | 1955 | ||
2017 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); | 1956 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); |
2018 | 1957 | ||
2019 | if (ath_tx_start(sc, skb, &txctl) != 0) { | 1958 | if (ath_tx_start(sc, skb, &txctl) != 0) { |
2020 | DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); | 1959 | DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); |
2021 | goto exit; | 1960 | goto exit; |
2022 | } | 1961 | } |
2023 | 1962 | ||
2024 | return 0; | 1963 | return 0; |
2025 | exit: | 1964 | exit: |
2026 | dev_kfree_skb_any(skb); | 1965 | dev_kfree_skb_any(skb); |
2027 | return 0; | 1966 | return 0; |
2028 | } | 1967 | } |
2029 | 1968 | ||
2030 | static void ath9k_stop(struct ieee80211_hw *hw) | 1969 | static void ath9k_stop(struct ieee80211_hw *hw) |
2031 | { | 1970 | { |
2032 | struct ath_softc *sc = hw->priv; | 1971 | struct ath_softc *sc = hw->priv; |
2033 | 1972 | ||
2034 | if (sc->sc_flags & SC_OP_INVALID) { | 1973 | if (sc->sc_flags & SC_OP_INVALID) { |
2035 | DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); | 1974 | DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); |
2036 | return; | 1975 | return; |
2037 | } | 1976 | } |
2038 | 1977 | ||
2039 | DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); | 1978 | DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); |
2040 | 1979 | ||
2041 | ieee80211_stop_queues(sc->hw); | 1980 | ieee80211_stop_queues(sc->hw); |
2042 | 1981 | ||
2043 | /* make sure h/w will not generate any interrupt | 1982 | /* make sure h/w will not generate any interrupt |
2044 | * before setting the invalid flag. */ | 1983 | * before setting the invalid flag. */ |
2045 | ath9k_hw_set_interrupts(sc->sc_ah, 0); | 1984 | ath9k_hw_set_interrupts(sc->sc_ah, 0); |
2046 | 1985 | ||
2047 | if (!(sc->sc_flags & SC_OP_INVALID)) { | 1986 | if (!(sc->sc_flags & SC_OP_INVALID)) { |
2048 | ath_draintxq(sc, false); | 1987 | ath_draintxq(sc, false); |
2049 | ath_stoprecv(sc); | 1988 | ath_stoprecv(sc); |
2050 | ath9k_hw_phy_disable(sc->sc_ah); | 1989 | ath9k_hw_phy_disable(sc->sc_ah); |
2051 | } else | 1990 | } else |
2052 | sc->rx.rxlink = NULL; | 1991 | sc->rx.rxlink = NULL; |
2053 | 1992 | ||
2054 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1993 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
2055 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 1994 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
2056 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | 1995 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); |
2057 | #endif | 1996 | #endif |
2058 | /* disable HAL and put h/w to sleep */ | 1997 | /* disable HAL and put h/w to sleep */ |
2059 | ath9k_hw_disable(sc->sc_ah); | 1998 | ath9k_hw_disable(sc->sc_ah); |
2060 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | 1999 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); |
2061 | 2000 | ||
2062 | sc->sc_flags |= SC_OP_INVALID; | 2001 | sc->sc_flags |= SC_OP_INVALID; |
2063 | 2002 | ||
2064 | DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); | 2003 | DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); |
2065 | } | 2004 | } |
2066 | 2005 | ||
2067 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 2006 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
2068 | struct ieee80211_if_init_conf *conf) | 2007 | struct ieee80211_if_init_conf *conf) |
2069 | { | 2008 | { |
2070 | struct ath_softc *sc = hw->priv; | 2009 | struct ath_softc *sc = hw->priv; |
2071 | struct ath_vap *avp = (void *)conf->vif->drv_priv; | 2010 | struct ath_vap *avp = (void *)conf->vif->drv_priv; |
2072 | enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; | 2011 | enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; |
2073 | 2012 | ||
2074 | /* Support only vap for now */ | 2013 | /* Support only vap for now */ |
2075 | 2014 | ||
2076 | if (sc->sc_nvaps) | 2015 | if (sc->sc_nvaps) |
2077 | return -ENOBUFS; | 2016 | return -ENOBUFS; |
2078 | 2017 | ||
2079 | switch (conf->type) { | 2018 | switch (conf->type) { |
2080 | case NL80211_IFTYPE_STATION: | 2019 | case NL80211_IFTYPE_STATION: |
2081 | ic_opmode = NL80211_IFTYPE_STATION; | 2020 | ic_opmode = NL80211_IFTYPE_STATION; |
2082 | break; | 2021 | break; |
2083 | case NL80211_IFTYPE_ADHOC: | 2022 | case NL80211_IFTYPE_ADHOC: |
2084 | ic_opmode = NL80211_IFTYPE_ADHOC; | 2023 | ic_opmode = NL80211_IFTYPE_ADHOC; |
2085 | break; | 2024 | break; |
2086 | case NL80211_IFTYPE_AP: | 2025 | case NL80211_IFTYPE_AP: |
2087 | ic_opmode = NL80211_IFTYPE_AP; | 2026 | ic_opmode = NL80211_IFTYPE_AP; |
2088 | break; | 2027 | break; |
2089 | default: | 2028 | default: |
2090 | DPRINTF(sc, ATH_DBG_FATAL, | 2029 | DPRINTF(sc, ATH_DBG_FATAL, |
2091 | "Interface type %d not yet supported\n", conf->type); | 2030 | "Interface type %d not yet supported\n", conf->type); |
2092 | return -EOPNOTSUPP; | 2031 | return -EOPNOTSUPP; |
2093 | } | 2032 | } |
2094 | 2033 | ||
2095 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); | 2034 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); |
2096 | 2035 | ||
2097 | /* Set the VAP opmode */ | 2036 | /* Set the VAP opmode */ |
2098 | avp->av_opmode = ic_opmode; | 2037 | avp->av_opmode = ic_opmode; |
2099 | avp->av_bslot = -1; | 2038 | avp->av_bslot = -1; |
2100 | 2039 | ||
2101 | if (ic_opmode == NL80211_IFTYPE_AP) | 2040 | if (ic_opmode == NL80211_IFTYPE_AP) |
2102 | ath9k_hw_set_tsfadjust(sc->sc_ah, 1); | 2041 | ath9k_hw_set_tsfadjust(sc->sc_ah, 1); |
2103 | 2042 | ||
2104 | sc->sc_vaps[0] = conf->vif; | 2043 | sc->sc_vaps[0] = conf->vif; |
2105 | sc->sc_nvaps++; | 2044 | sc->sc_nvaps++; |
2106 | 2045 | ||
2107 | /* Set the device opmode */ | 2046 | /* Set the device opmode */ |
2108 | sc->sc_ah->ah_opmode = ic_opmode; | 2047 | sc->sc_ah->ah_opmode = ic_opmode; |
2109 | 2048 | ||
2110 | if (conf->type == NL80211_IFTYPE_AP) { | 2049 | if (conf->type == NL80211_IFTYPE_AP) { |
2111 | /* TODO: is this a suitable place to start ANI for AP mode? */ | 2050 | /* TODO: is this a suitable place to start ANI for AP mode? */ |
2112 | /* Start ANI */ | 2051 | /* Start ANI */ |
2113 | mod_timer(&sc->sc_ani.timer, | 2052 | mod_timer(&sc->sc_ani.timer, |
2114 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 2053 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
2115 | } | 2054 | } |
2116 | 2055 | ||
2117 | return 0; | 2056 | return 0; |
2118 | } | 2057 | } |
2119 | 2058 | ||
2120 | static void ath9k_remove_interface(struct ieee80211_hw *hw, | 2059 | static void ath9k_remove_interface(struct ieee80211_hw *hw, |
2121 | struct ieee80211_if_init_conf *conf) | 2060 | struct ieee80211_if_init_conf *conf) |
2122 | { | 2061 | { |
2123 | struct ath_softc *sc = hw->priv; | 2062 | struct ath_softc *sc = hw->priv; |
2124 | struct ath_vap *avp = (void *)conf->vif->drv_priv; | 2063 | struct ath_vap *avp = (void *)conf->vif->drv_priv; |
2125 | 2064 | ||
2126 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); | 2065 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); |
2127 | 2066 | ||
2128 | /* Stop ANI */ | 2067 | /* Stop ANI */ |
2129 | del_timer_sync(&sc->sc_ani.timer); | 2068 | del_timer_sync(&sc->sc_ani.timer); |
2130 | 2069 | ||
2131 | /* Reclaim beacon resources */ | 2070 | /* Reclaim beacon resources */ |
2132 | if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || | 2071 | if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || |
2133 | sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { | 2072 | sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { |
2134 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 2073 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
2135 | ath_beacon_return(sc, avp); | 2074 | ath_beacon_return(sc, avp); |
2136 | } | 2075 | } |
2137 | 2076 | ||
2138 | sc->sc_flags &= ~SC_OP_BEACONS; | 2077 | sc->sc_flags &= ~SC_OP_BEACONS; |
2139 | 2078 | ||
2140 | sc->sc_vaps[0] = NULL; | 2079 | sc->sc_vaps[0] = NULL; |
2141 | sc->sc_nvaps--; | 2080 | sc->sc_nvaps--; |
2142 | } | 2081 | } |
2143 | 2082 | ||
2144 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 2083 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |
2145 | { | 2084 | { |
2146 | struct ath_softc *sc = hw->priv; | 2085 | struct ath_softc *sc = hw->priv; |
2147 | struct ieee80211_conf *conf = &hw->conf; | 2086 | struct ieee80211_conf *conf = &hw->conf; |
2148 | 2087 | ||
2149 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 2088 | if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | |
2089 | IEEE80211_CONF_CHANGE_HT)) { | ||
2150 | struct ieee80211_channel *curchan = hw->conf.channel; | 2090 | struct ieee80211_channel *curchan = hw->conf.channel; |
2151 | int pos; | 2091 | int pos; |
2152 | 2092 | ||
2153 | DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", | 2093 | DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", |
2154 | curchan->center_freq); | 2094 | curchan->center_freq); |
2155 | 2095 | ||
2156 | pos = ath_get_channel(sc, curchan); | 2096 | pos = ath_get_channel(sc, curchan); |
2157 | if (pos == -1) { | 2097 | if (pos == -1) { |
2158 | DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", | 2098 | DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", |
2159 | curchan->center_freq); | 2099 | curchan->center_freq); |
2160 | return -EINVAL; | 2100 | return -EINVAL; |
2161 | } | 2101 | } |
2162 | 2102 | ||
2163 | sc->tx_chan_width = ATH9K_HT_MACMODE_20; | 2103 | sc->tx_chan_width = ATH9K_HT_MACMODE_20; |
2164 | sc->sc_ah->ah_channels[pos].chanmode = | 2104 | sc->sc_ah->ah_channels[pos].chanmode = |
2165 | (curchan->band == IEEE80211_BAND_2GHZ) ? | 2105 | (curchan->band == IEEE80211_BAND_2GHZ) ? |
2166 | CHANNEL_G : CHANNEL_A; | 2106 | CHANNEL_G : CHANNEL_A; |
2167 | 2107 | ||
2168 | if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) && | 2108 | if (conf->ht.enabled) { |
2169 | (conf->ht.enabled)) { | 2109 | if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS || |
2170 | sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ? | 2110 | conf->ht.channel_type == NL80211_CHAN_HT40MINUS) |
2171 | ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; | 2111 | sc->tx_chan_width = ATH9K_HT_MACMODE_2040; |
2172 | 2112 | ||
2173 | sc->sc_ah->ah_channels[pos].chanmode = | 2113 | sc->sc_ah->ah_channels[pos].chanmode = |
2174 | ath_get_extchanmode(sc, curchan, | 2114 | ath_get_extchanmode(sc, curchan, |
2175 | conf->ht.sec_chan_offset, | 2115 | conf->ht.channel_type); |
2176 | sc->tx_chan_width); | ||
2177 | } | 2116 | } |
2178 | 2117 | ||
2179 | if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { | 2118 | if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { |
2180 | DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); | 2119 | DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); |
2181 | return -EINVAL; | 2120 | return -EINVAL; |
2182 | } | 2121 | } |
2183 | } | ||
2184 | 2122 | ||
2185 | if (changed & IEEE80211_CONF_CHANGE_HT) | ||
2186 | ath_update_chainmask(sc, conf->ht.enabled); | 2123 | ath_update_chainmask(sc, conf->ht.enabled); |
2124 | } | ||
2187 | 2125 | ||
2188 | if (changed & IEEE80211_CONF_CHANGE_POWER) | 2126 | if (changed & IEEE80211_CONF_CHANGE_POWER) |
2189 | sc->sc_config.txpowlimit = 2 * conf->power_level; | 2127 | sc->sc_config.txpowlimit = 2 * conf->power_level; |
2190 | 2128 | ||
2191 | return 0; | 2129 | return 0; |
2192 | } | 2130 | } |
2193 | 2131 | ||
2194 | static int ath9k_config_interface(struct ieee80211_hw *hw, | 2132 | static int ath9k_config_interface(struct ieee80211_hw *hw, |
2195 | struct ieee80211_vif *vif, | 2133 | struct ieee80211_vif *vif, |
2196 | struct ieee80211_if_conf *conf) | 2134 | struct ieee80211_if_conf *conf) |
2197 | { | 2135 | { |
2198 | struct ath_softc *sc = hw->priv; | 2136 | struct ath_softc *sc = hw->priv; |
2199 | struct ath_hal *ah = sc->sc_ah; | 2137 | struct ath_hal *ah = sc->sc_ah; |
2200 | struct ath_vap *avp = (void *)vif->drv_priv; | 2138 | struct ath_vap *avp = (void *)vif->drv_priv; |
2201 | u32 rfilt = 0; | 2139 | u32 rfilt = 0; |
2202 | int error, i; | 2140 | int error, i; |
2203 | 2141 | ||
2204 | /* TODO: Need to decide which hw opmode to use for multi-interface | 2142 | /* TODO: Need to decide which hw opmode to use for multi-interface |
2205 | * cases */ | 2143 | * cases */ |
2206 | if (vif->type == NL80211_IFTYPE_AP && | 2144 | if (vif->type == NL80211_IFTYPE_AP && |
2207 | ah->ah_opmode != NL80211_IFTYPE_AP) { | 2145 | ah->ah_opmode != NL80211_IFTYPE_AP) { |
2208 | ah->ah_opmode = NL80211_IFTYPE_STATION; | 2146 | ah->ah_opmode = NL80211_IFTYPE_STATION; |
2209 | ath9k_hw_setopmode(ah); | 2147 | ath9k_hw_setopmode(ah); |
2210 | ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); | 2148 | ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); |
2211 | /* Request full reset to get hw opmode changed properly */ | 2149 | /* Request full reset to get hw opmode changed properly */ |
2212 | sc->sc_flags |= SC_OP_FULL_RESET; | 2150 | sc->sc_flags |= SC_OP_FULL_RESET; |
2213 | } | 2151 | } |
2214 | 2152 | ||
2215 | if ((conf->changed & IEEE80211_IFCC_BSSID) && | 2153 | if ((conf->changed & IEEE80211_IFCC_BSSID) && |
2216 | !is_zero_ether_addr(conf->bssid)) { | 2154 | !is_zero_ether_addr(conf->bssid)) { |
2217 | switch (vif->type) { | 2155 | switch (vif->type) { |
2218 | case NL80211_IFTYPE_STATION: | 2156 | case NL80211_IFTYPE_STATION: |
2219 | case NL80211_IFTYPE_ADHOC: | 2157 | case NL80211_IFTYPE_ADHOC: |
2220 | /* Set BSSID */ | 2158 | /* Set BSSID */ |
2221 | memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); | 2159 | memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); |
2222 | sc->sc_curaid = 0; | 2160 | sc->sc_curaid = 0; |
2223 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, | 2161 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, |
2224 | sc->sc_curaid); | 2162 | sc->sc_curaid); |
2225 | 2163 | ||
2226 | /* Set aggregation protection mode parameters */ | 2164 | /* Set aggregation protection mode parameters */ |
2227 | sc->sc_config.ath_aggr_prot = 0; | 2165 | sc->sc_config.ath_aggr_prot = 0; |
2228 | 2166 | ||
2229 | DPRINTF(sc, ATH_DBG_CONFIG, | 2167 | DPRINTF(sc, ATH_DBG_CONFIG, |
2230 | "RX filter 0x%x bssid %pM aid 0x%x\n", | 2168 | "RX filter 0x%x bssid %pM aid 0x%x\n", |
2231 | rfilt, sc->sc_curbssid, sc->sc_curaid); | 2169 | rfilt, sc->sc_curbssid, sc->sc_curaid); |
2232 | 2170 | ||
2233 | /* need to reconfigure the beacon */ | 2171 | /* need to reconfigure the beacon */ |
2234 | sc->sc_flags &= ~SC_OP_BEACONS ; | 2172 | sc->sc_flags &= ~SC_OP_BEACONS ; |
2235 | 2173 | ||
2236 | break; | 2174 | break; |
2237 | default: | 2175 | default: |
2238 | break; | 2176 | break; |
2239 | } | 2177 | } |
2240 | } | 2178 | } |
2241 | 2179 | ||
2242 | if ((conf->changed & IEEE80211_IFCC_BEACON) && | 2180 | if ((conf->changed & IEEE80211_IFCC_BEACON) && |
2243 | ((vif->type == NL80211_IFTYPE_ADHOC) || | 2181 | ((vif->type == NL80211_IFTYPE_ADHOC) || |
2244 | (vif->type == NL80211_IFTYPE_AP))) { | 2182 | (vif->type == NL80211_IFTYPE_AP))) { |
2245 | /* | 2183 | /* |
2246 | * Allocate and setup the beacon frame. | 2184 | * Allocate and setup the beacon frame. |
2247 | * | 2185 | * |
2248 | * Stop any previous beacon DMA. This may be | 2186 | * Stop any previous beacon DMA. This may be |
2249 | * necessary, for example, when an ibss merge | 2187 | * necessary, for example, when an ibss merge |
2250 | * causes reconfiguration; we may be called | 2188 | * causes reconfiguration; we may be called |
2251 | * with beacon transmission active. | 2189 | * with beacon transmission active. |
2252 | */ | 2190 | */ |
2253 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 2191 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
2254 | 2192 | ||
2255 | error = ath_beacon_alloc(sc, 0); | 2193 | error = ath_beacon_alloc(sc, 0); |
2256 | if (error != 0) | 2194 | if (error != 0) |
2257 | return error; | 2195 | return error; |
2258 | 2196 | ||
2259 | ath_beacon_sync(sc, 0); | 2197 | ath_beacon_sync(sc, 0); |
2260 | } | 2198 | } |
2261 | 2199 | ||
2262 | /* Check for WLAN_CAPABILITY_PRIVACY ? */ | 2200 | /* Check for WLAN_CAPABILITY_PRIVACY ? */ |
2263 | if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { | 2201 | if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { |
2264 | for (i = 0; i < IEEE80211_WEP_NKID; i++) | 2202 | for (i = 0; i < IEEE80211_WEP_NKID; i++) |
2265 | if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) | 2203 | if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) |
2266 | ath9k_hw_keysetmac(sc->sc_ah, | 2204 | ath9k_hw_keysetmac(sc->sc_ah, |
2267 | (u16)i, | 2205 | (u16)i, |
2268 | sc->sc_curbssid); | 2206 | sc->sc_curbssid); |
2269 | } | 2207 | } |
2270 | 2208 | ||
2271 | /* Only legacy IBSS for now */ | 2209 | /* Only legacy IBSS for now */ |
2272 | if (vif->type == NL80211_IFTYPE_ADHOC) | 2210 | if (vif->type == NL80211_IFTYPE_ADHOC) |
2273 | ath_update_chainmask(sc, 0); | 2211 | ath_update_chainmask(sc, 0); |
2274 | 2212 | ||
2275 | return 0; | 2213 | return 0; |
2276 | } | 2214 | } |
2277 | 2215 | ||
2278 | #define SUPPORTED_FILTERS \ | 2216 | #define SUPPORTED_FILTERS \ |
2279 | (FIF_PROMISC_IN_BSS | \ | 2217 | (FIF_PROMISC_IN_BSS | \ |
2280 | FIF_ALLMULTI | \ | 2218 | FIF_ALLMULTI | \ |
2281 | FIF_CONTROL | \ | 2219 | FIF_CONTROL | \ |
2282 | FIF_OTHER_BSS | \ | 2220 | FIF_OTHER_BSS | \ |
2283 | FIF_BCN_PRBRESP_PROMISC | \ | 2221 | FIF_BCN_PRBRESP_PROMISC | \ |
2284 | FIF_FCSFAIL) | 2222 | FIF_FCSFAIL) |
2285 | 2223 | ||
2286 | /* FIXME: sc->sc_full_reset ? */ | 2224 | /* FIXME: sc->sc_full_reset ? */ |
2287 | static void ath9k_configure_filter(struct ieee80211_hw *hw, | 2225 | static void ath9k_configure_filter(struct ieee80211_hw *hw, |
2288 | unsigned int changed_flags, | 2226 | unsigned int changed_flags, |
2289 | unsigned int *total_flags, | 2227 | unsigned int *total_flags, |
2290 | int mc_count, | 2228 | int mc_count, |
2291 | struct dev_mc_list *mclist) | 2229 | struct dev_mc_list *mclist) |
2292 | { | 2230 | { |
2293 | struct ath_softc *sc = hw->priv; | 2231 | struct ath_softc *sc = hw->priv; |
2294 | u32 rfilt; | 2232 | u32 rfilt; |
2295 | 2233 | ||
2296 | changed_flags &= SUPPORTED_FILTERS; | 2234 | changed_flags &= SUPPORTED_FILTERS; |
2297 | *total_flags &= SUPPORTED_FILTERS; | 2235 | *total_flags &= SUPPORTED_FILTERS; |
2298 | 2236 | ||
2299 | sc->rx.rxfilter = *total_flags; | 2237 | sc->rx.rxfilter = *total_flags; |
2300 | rfilt = ath_calcrxfilter(sc); | 2238 | rfilt = ath_calcrxfilter(sc); |
2301 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); | 2239 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); |
2302 | 2240 | ||
2303 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { | 2241 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
2304 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) | 2242 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) |
2305 | ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); | 2243 | ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); |
2306 | } | 2244 | } |
2307 | 2245 | ||
2308 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); | 2246 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); |
2309 | } | 2247 | } |
2310 | 2248 | ||
2311 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | 2249 | static void ath9k_sta_notify(struct ieee80211_hw *hw, |
2312 | struct ieee80211_vif *vif, | 2250 | struct ieee80211_vif *vif, |
2313 | enum sta_notify_cmd cmd, | 2251 | enum sta_notify_cmd cmd, |
2314 | struct ieee80211_sta *sta) | 2252 | struct ieee80211_sta *sta) |
2315 | { | 2253 | { |
2316 | struct ath_softc *sc = hw->priv; | 2254 | struct ath_softc *sc = hw->priv; |
2317 | 2255 | ||
2318 | switch (cmd) { | 2256 | switch (cmd) { |
2319 | case STA_NOTIFY_ADD: | 2257 | case STA_NOTIFY_ADD: |
2320 | ath_node_attach(sc, sta); | 2258 | ath_node_attach(sc, sta); |
2321 | break; | 2259 | break; |
2322 | case STA_NOTIFY_REMOVE: | 2260 | case STA_NOTIFY_REMOVE: |
2323 | ath_node_detach(sc, sta); | 2261 | ath_node_detach(sc, sta); |
2324 | break; | 2262 | break; |
2325 | default: | 2263 | default: |
2326 | break; | 2264 | break; |
2327 | } | 2265 | } |
2328 | } | 2266 | } |
2329 | 2267 | ||
2330 | static int ath9k_conf_tx(struct ieee80211_hw *hw, | 2268 | static int ath9k_conf_tx(struct ieee80211_hw *hw, |
2331 | u16 queue, | 2269 | u16 queue, |
2332 | const struct ieee80211_tx_queue_params *params) | 2270 | const struct ieee80211_tx_queue_params *params) |
2333 | { | 2271 | { |
2334 | struct ath_softc *sc = hw->priv; | 2272 | struct ath_softc *sc = hw->priv; |
2335 | struct ath9k_tx_queue_info qi; | 2273 | struct ath9k_tx_queue_info qi; |
2336 | int ret = 0, qnum; | 2274 | int ret = 0, qnum; |
2337 | 2275 | ||
2338 | if (queue >= WME_NUM_AC) | 2276 | if (queue >= WME_NUM_AC) |
2339 | return 0; | 2277 | return 0; |
2340 | 2278 | ||
2341 | qi.tqi_aifs = params->aifs; | 2279 | qi.tqi_aifs = params->aifs; |
2342 | qi.tqi_cwmin = params->cw_min; | 2280 | qi.tqi_cwmin = params->cw_min; |
2343 | qi.tqi_cwmax = params->cw_max; | 2281 | qi.tqi_cwmax = params->cw_max; |
2344 | qi.tqi_burstTime = params->txop; | 2282 | qi.tqi_burstTime = params->txop; |
2345 | qnum = ath_get_hal_qnum(queue, sc); | 2283 | qnum = ath_get_hal_qnum(queue, sc); |
2346 | 2284 | ||
2347 | DPRINTF(sc, ATH_DBG_CONFIG, | 2285 | DPRINTF(sc, ATH_DBG_CONFIG, |
2348 | "Configure tx [queue/halq] [%d/%d], " | 2286 | "Configure tx [queue/halq] [%d/%d], " |
2349 | "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | 2287 | "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", |
2350 | queue, qnum, params->aifs, params->cw_min, | 2288 | queue, qnum, params->aifs, params->cw_min, |
2351 | params->cw_max, params->txop); | 2289 | params->cw_max, params->txop); |
2352 | 2290 | ||
2353 | ret = ath_txq_update(sc, qnum, &qi); | 2291 | ret = ath_txq_update(sc, qnum, &qi); |
2354 | if (ret) | 2292 | if (ret) |
2355 | DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); | 2293 | DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); |
2356 | 2294 | ||
2357 | return ret; | 2295 | return ret; |
2358 | } | 2296 | } |
2359 | 2297 | ||
2360 | static int ath9k_set_key(struct ieee80211_hw *hw, | 2298 | static int ath9k_set_key(struct ieee80211_hw *hw, |
2361 | enum set_key_cmd cmd, | 2299 | enum set_key_cmd cmd, |
2362 | const u8 *local_addr, | 2300 | const u8 *local_addr, |
2363 | const u8 *addr, | 2301 | const u8 *addr, |
2364 | struct ieee80211_key_conf *key) | 2302 | struct ieee80211_key_conf *key) |
2365 | { | 2303 | { |
2366 | struct ath_softc *sc = hw->priv; | 2304 | struct ath_softc *sc = hw->priv; |
2367 | int ret = 0; | 2305 | int ret = 0; |
2368 | 2306 | ||
2369 | DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); | 2307 | DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); |
2370 | 2308 | ||
2371 | switch (cmd) { | 2309 | switch (cmd) { |
2372 | case SET_KEY: | 2310 | case SET_KEY: |
2373 | ret = ath_key_config(sc, addr, key); | 2311 | ret = ath_key_config(sc, addr, key); |
2374 | if (!ret) { | 2312 | if (!ret) { |
2375 | set_bit(key->keyidx, sc->sc_keymap); | 2313 | set_bit(key->keyidx, sc->sc_keymap); |
2376 | key->hw_key_idx = key->keyidx; | 2314 | key->hw_key_idx = key->keyidx; |
2377 | /* push IV and Michael MIC generation to stack */ | 2315 | /* push IV and Michael MIC generation to stack */ |
2378 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 2316 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
2379 | if (key->alg == ALG_TKIP) | 2317 | if (key->alg == ALG_TKIP) |
2380 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 2318 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
2381 | } | 2319 | } |
2382 | break; | 2320 | break; |
2383 | case DISABLE_KEY: | 2321 | case DISABLE_KEY: |
2384 | ath_key_delete(sc, key); | 2322 | ath_key_delete(sc, key); |
2385 | clear_bit(key->keyidx, sc->sc_keymap); | 2323 | clear_bit(key->keyidx, sc->sc_keymap); |
2386 | break; | 2324 | break; |
2387 | default: | 2325 | default: |
2388 | ret = -EINVAL; | 2326 | ret = -EINVAL; |
2389 | } | 2327 | } |
2390 | 2328 | ||
2391 | return ret; | 2329 | return ret; |
2392 | } | 2330 | } |
2393 | 2331 | ||
2394 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | 2332 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, |
2395 | struct ieee80211_vif *vif, | 2333 | struct ieee80211_vif *vif, |
2396 | struct ieee80211_bss_conf *bss_conf, | 2334 | struct ieee80211_bss_conf *bss_conf, |
2397 | u32 changed) | 2335 | u32 changed) |
2398 | { | 2336 | { |
2399 | struct ath_softc *sc = hw->priv; | 2337 | struct ath_softc *sc = hw->priv; |
2400 | 2338 | ||
2401 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 2339 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
2402 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", | 2340 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", |
2403 | bss_conf->use_short_preamble); | 2341 | bss_conf->use_short_preamble); |
2404 | if (bss_conf->use_short_preamble) | 2342 | if (bss_conf->use_short_preamble) |
2405 | sc->sc_flags |= SC_OP_PREAMBLE_SHORT; | 2343 | sc->sc_flags |= SC_OP_PREAMBLE_SHORT; |
2406 | else | 2344 | else |
2407 | sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; | 2345 | sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; |
2408 | } | 2346 | } |
2409 | 2347 | ||
2410 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | 2348 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
2411 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", | 2349 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", |
2412 | bss_conf->use_cts_prot); | 2350 | bss_conf->use_cts_prot); |
2413 | if (bss_conf->use_cts_prot && | 2351 | if (bss_conf->use_cts_prot && |
2414 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) | 2352 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) |
2415 | sc->sc_flags |= SC_OP_PROTECT_ENABLE; | 2353 | sc->sc_flags |= SC_OP_PROTECT_ENABLE; |
2416 | else | 2354 | else |
2417 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; | 2355 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; |
2418 | } | 2356 | } |
2419 | |||
2420 | if (changed & BSS_CHANGED_HT) | ||
2421 | ath9k_ht_conf(sc, bss_conf); | ||
2422 | 2357 | ||
2423 | if (changed & BSS_CHANGED_ASSOC) { | 2358 | if (changed & BSS_CHANGED_ASSOC) { |
2424 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", | 2359 | DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", |
2425 | bss_conf->assoc); | 2360 | bss_conf->assoc); |
2426 | ath9k_bss_assoc_info(sc, vif, bss_conf); | 2361 | ath9k_bss_assoc_info(sc, vif, bss_conf); |
2427 | } | 2362 | } |
2428 | } | 2363 | } |
2429 | 2364 | ||
2430 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw) | 2365 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw) |
2431 | { | 2366 | { |
2432 | u64 tsf; | 2367 | u64 tsf; |
2433 | struct ath_softc *sc = hw->priv; | 2368 | struct ath_softc *sc = hw->priv; |
2434 | struct ath_hal *ah = sc->sc_ah; | 2369 | struct ath_hal *ah = sc->sc_ah; |
2435 | 2370 | ||
2436 | tsf = ath9k_hw_gettsf64(ah); | 2371 | tsf = ath9k_hw_gettsf64(ah); |
2437 | 2372 | ||
2438 | return tsf; | 2373 | return tsf; |
2439 | } | 2374 | } |
2440 | 2375 | ||
2441 | static void ath9k_reset_tsf(struct ieee80211_hw *hw) | 2376 | static void ath9k_reset_tsf(struct ieee80211_hw *hw) |
2442 | { | 2377 | { |
2443 | struct ath_softc *sc = hw->priv; | 2378 | struct ath_softc *sc = hw->priv; |
2444 | struct ath_hal *ah = sc->sc_ah; | 2379 | struct ath_hal *ah = sc->sc_ah; |
2445 | 2380 | ||
2446 | ath9k_hw_reset_tsf(ah); | 2381 | ath9k_hw_reset_tsf(ah); |
2447 | } | 2382 | } |
2448 | 2383 | ||
2449 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, | 2384 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, |
2450 | enum ieee80211_ampdu_mlme_action action, | 2385 | enum ieee80211_ampdu_mlme_action action, |
2451 | struct ieee80211_sta *sta, | 2386 | struct ieee80211_sta *sta, |
2452 | u16 tid, u16 *ssn) | 2387 | u16 tid, u16 *ssn) |
2453 | { | 2388 | { |
2454 | struct ath_softc *sc = hw->priv; | 2389 | struct ath_softc *sc = hw->priv; |
2455 | int ret = 0; | 2390 | int ret = 0; |
2456 | 2391 | ||
2457 | switch (action) { | 2392 | switch (action) { |
2458 | case IEEE80211_AMPDU_RX_START: | 2393 | case IEEE80211_AMPDU_RX_START: |
2459 | if (!(sc->sc_flags & SC_OP_RXAGGR)) | 2394 | if (!(sc->sc_flags & SC_OP_RXAGGR)) |
2460 | ret = -ENOTSUPP; | 2395 | ret = -ENOTSUPP; |
2461 | break; | 2396 | break; |
2462 | case IEEE80211_AMPDU_RX_STOP: | 2397 | case IEEE80211_AMPDU_RX_STOP: |
2463 | break; | 2398 | break; |
2464 | case IEEE80211_AMPDU_TX_START: | 2399 | case IEEE80211_AMPDU_TX_START: |
2465 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); | 2400 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); |
2466 | if (ret < 0) | 2401 | if (ret < 0) |
2467 | DPRINTF(sc, ATH_DBG_FATAL, | 2402 | DPRINTF(sc, ATH_DBG_FATAL, |
2468 | "Unable to start TX aggregation\n"); | 2403 | "Unable to start TX aggregation\n"); |
2469 | else | 2404 | else |
2470 | ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); | 2405 | ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); |
2471 | break; | 2406 | break; |
2472 | case IEEE80211_AMPDU_TX_STOP: | 2407 | case IEEE80211_AMPDU_TX_STOP: |
2473 | ret = ath_tx_aggr_stop(sc, sta, tid); | 2408 | ret = ath_tx_aggr_stop(sc, sta, tid); |
2474 | if (ret < 0) | 2409 | if (ret < 0) |
2475 | DPRINTF(sc, ATH_DBG_FATAL, | 2410 | DPRINTF(sc, ATH_DBG_FATAL, |
2476 | "Unable to stop TX aggregation\n"); | 2411 | "Unable to stop TX aggregation\n"); |
2477 | 2412 | ||
2478 | ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); | 2413 | ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); |
2479 | break; | 2414 | break; |
2480 | case IEEE80211_AMPDU_TX_RESUME: | 2415 | case IEEE80211_AMPDU_TX_RESUME: |
2481 | ath_tx_aggr_resume(sc, sta, tid); | 2416 | ath_tx_aggr_resume(sc, sta, tid); |
2482 | break; | 2417 | break; |
2483 | default: | 2418 | default: |
2484 | DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); | 2419 | DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); |
2485 | } | 2420 | } |
2486 | 2421 | ||
2487 | return ret; | 2422 | return ret; |
2488 | } | 2423 | } |
2489 | 2424 | ||
2490 | static struct ieee80211_ops ath9k_ops = { | 2425 | static struct ieee80211_ops ath9k_ops = { |
2491 | .tx = ath9k_tx, | 2426 | .tx = ath9k_tx, |
2492 | .start = ath9k_start, | 2427 | .start = ath9k_start, |
2493 | .stop = ath9k_stop, | 2428 | .stop = ath9k_stop, |
2494 | .add_interface = ath9k_add_interface, | 2429 | .add_interface = ath9k_add_interface, |
2495 | .remove_interface = ath9k_remove_interface, | 2430 | .remove_interface = ath9k_remove_interface, |
2496 | .config = ath9k_config, | 2431 | .config = ath9k_config, |
2497 | .config_interface = ath9k_config_interface, | 2432 | .config_interface = ath9k_config_interface, |
2498 | .configure_filter = ath9k_configure_filter, | 2433 | .configure_filter = ath9k_configure_filter, |
2499 | .sta_notify = ath9k_sta_notify, | 2434 | .sta_notify = ath9k_sta_notify, |
2500 | .conf_tx = ath9k_conf_tx, | 2435 | .conf_tx = ath9k_conf_tx, |
2501 | .bss_info_changed = ath9k_bss_info_changed, | 2436 | .bss_info_changed = ath9k_bss_info_changed, |
2502 | .set_key = ath9k_set_key, | 2437 | .set_key = ath9k_set_key, |
2503 | .get_tsf = ath9k_get_tsf, | 2438 | .get_tsf = ath9k_get_tsf, |
2504 | .reset_tsf = ath9k_reset_tsf, | 2439 | .reset_tsf = ath9k_reset_tsf, |
2505 | .ampdu_action = ath9k_ampdu_action, | 2440 | .ampdu_action = ath9k_ampdu_action, |
2506 | }; | 2441 | }; |
2507 | 2442 | ||
2508 | static struct { | 2443 | static struct { |
2509 | u32 version; | 2444 | u32 version; |
2510 | const char * name; | 2445 | const char * name; |
2511 | } ath_mac_bb_names[] = { | 2446 | } ath_mac_bb_names[] = { |
2512 | { AR_SREV_VERSION_5416_PCI, "5416" }, | 2447 | { AR_SREV_VERSION_5416_PCI, "5416" }, |
2513 | { AR_SREV_VERSION_5416_PCIE, "5418" }, | 2448 | { AR_SREV_VERSION_5416_PCIE, "5418" }, |
2514 | { AR_SREV_VERSION_9100, "9100" }, | 2449 | { AR_SREV_VERSION_9100, "9100" }, |
2515 | { AR_SREV_VERSION_9160, "9160" }, | 2450 | { AR_SREV_VERSION_9160, "9160" }, |
2516 | { AR_SREV_VERSION_9280, "9280" }, | 2451 | { AR_SREV_VERSION_9280, "9280" }, |
2517 | { AR_SREV_VERSION_9285, "9285" } | 2452 | { AR_SREV_VERSION_9285, "9285" } |
2518 | }; | 2453 | }; |
2519 | 2454 | ||
2520 | static struct { | 2455 | static struct { |
2521 | u16 version; | 2456 | u16 version; |
2522 | const char * name; | 2457 | const char * name; |
2523 | } ath_rf_names[] = { | 2458 | } ath_rf_names[] = { |
2524 | { 0, "5133" }, | 2459 | { 0, "5133" }, |
2525 | { AR_RAD5133_SREV_MAJOR, "5133" }, | 2460 | { AR_RAD5133_SREV_MAJOR, "5133" }, |
2526 | { AR_RAD5122_SREV_MAJOR, "5122" }, | 2461 | { AR_RAD5122_SREV_MAJOR, "5122" }, |
2527 | { AR_RAD2133_SREV_MAJOR, "2133" }, | 2462 | { AR_RAD2133_SREV_MAJOR, "2133" }, |
2528 | { AR_RAD2122_SREV_MAJOR, "2122" } | 2463 | { AR_RAD2122_SREV_MAJOR, "2122" } |
2529 | }; | 2464 | }; |
2530 | 2465 | ||
2531 | /* | 2466 | /* |
2532 | * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. | 2467 | * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. |
2533 | */ | 2468 | */ |
2534 | static const char * | 2469 | static const char * |
2535 | ath_mac_bb_name(u32 mac_bb_version) | 2470 | ath_mac_bb_name(u32 mac_bb_version) |
2536 | { | 2471 | { |
2537 | int i; | 2472 | int i; |
2538 | 2473 | ||
2539 | for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) { | 2474 | for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) { |
2540 | if (ath_mac_bb_names[i].version == mac_bb_version) { | 2475 | if (ath_mac_bb_names[i].version == mac_bb_version) { |
2541 | return ath_mac_bb_names[i].name; | 2476 | return ath_mac_bb_names[i].name; |
2542 | } | 2477 | } |
2543 | } | 2478 | } |
2544 | 2479 | ||
2545 | return "????"; | 2480 | return "????"; |
2546 | } | 2481 | } |
2547 | 2482 | ||
2548 | /* | 2483 | /* |
2549 | * Return the RF name. "????" is returned if the RF is unknown. | 2484 | * Return the RF name. "????" is returned if the RF is unknown. |
2550 | */ | 2485 | */ |
2551 | static const char * | 2486 | static const char * |
2552 | ath_rf_name(u16 rf_version) | 2487 | ath_rf_name(u16 rf_version) |
2553 | { | 2488 | { |
2554 | int i; | 2489 | int i; |
2555 | 2490 | ||
2556 | for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) { | 2491 | for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) { |
2557 | if (ath_rf_names[i].version == rf_version) { | 2492 | if (ath_rf_names[i].version == rf_version) { |
2558 | return ath_rf_names[i].name; | 2493 | return ath_rf_names[i].name; |
2559 | } | 2494 | } |
2560 | } | 2495 | } |
2561 | 2496 | ||
2562 | return "????"; | 2497 | return "????"; |
2563 | } | 2498 | } |
2564 | 2499 | ||
2565 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 2500 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
2566 | { | 2501 | { |
2567 | void __iomem *mem; | 2502 | void __iomem *mem; |
2568 | struct ath_softc *sc; | 2503 | struct ath_softc *sc; |
2569 | struct ieee80211_hw *hw; | 2504 | struct ieee80211_hw *hw; |
2570 | u8 csz; | 2505 | u8 csz; |
2571 | u32 val; | 2506 | u32 val; |
2572 | int ret = 0; | 2507 | int ret = 0; |
2573 | struct ath_hal *ah; | 2508 | struct ath_hal *ah; |
2574 | 2509 | ||
2575 | if (pci_enable_device(pdev)) | 2510 | if (pci_enable_device(pdev)) |
2576 | return -EIO; | 2511 | return -EIO; |
2577 | 2512 | ||
2578 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | 2513 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); |
2579 | 2514 | ||
2580 | if (ret) { | 2515 | if (ret) { |
2581 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); | 2516 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); |
2582 | goto bad; | 2517 | goto bad; |
2583 | } | 2518 | } |
2584 | 2519 | ||
2585 | ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | 2520 | ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); |
2586 | 2521 | ||
2587 | if (ret) { | 2522 | if (ret) { |
2588 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " | 2523 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " |
2589 | "DMA enable failed\n"); | 2524 | "DMA enable failed\n"); |
2590 | goto bad; | 2525 | goto bad; |
2591 | } | 2526 | } |
2592 | 2527 | ||
2593 | /* | 2528 | /* |
2594 | * Cache line size is used to size and align various | 2529 | * Cache line size is used to size and align various |
2595 | * structures used to communicate with the hardware. | 2530 | * structures used to communicate with the hardware. |
2596 | */ | 2531 | */ |
2597 | pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); | 2532 | pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); |
2598 | if (csz == 0) { | 2533 | if (csz == 0) { |
2599 | /* | 2534 | /* |
2600 | * Linux 2.4.18 (at least) writes the cache line size | 2535 | * Linux 2.4.18 (at least) writes the cache line size |
2601 | * register as a 16-bit wide register which is wrong. | 2536 | * register as a 16-bit wide register which is wrong. |
2602 | * We must have this setup properly for rx buffer | 2537 | * We must have this setup properly for rx buffer |
2603 | * DMA to work so force a reasonable value here if it | 2538 | * DMA to work so force a reasonable value here if it |
2604 | * comes up zero. | 2539 | * comes up zero. |
2605 | */ | 2540 | */ |
2606 | csz = L1_CACHE_BYTES / sizeof(u32); | 2541 | csz = L1_CACHE_BYTES / sizeof(u32); |
2607 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); | 2542 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); |
2608 | } | 2543 | } |
2609 | /* | 2544 | /* |
2610 | * The default setting of latency timer yields poor results, | 2545 | * The default setting of latency timer yields poor results, |
2611 | * set it to the value used by other systems. It may be worth | 2546 | * set it to the value used by other systems. It may be worth |
2612 | * tweaking this setting more. | 2547 | * tweaking this setting more. |
2613 | */ | 2548 | */ |
2614 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); | 2549 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); |
2615 | 2550 | ||
2616 | pci_set_master(pdev); | 2551 | pci_set_master(pdev); |
2617 | 2552 | ||
2618 | /* | 2553 | /* |
2619 | * Disable the RETRY_TIMEOUT register (0x41) to keep | 2554 | * Disable the RETRY_TIMEOUT register (0x41) to keep |
2620 | * PCI Tx retries from interfering with C3 CPU state. | 2555 | * PCI Tx retries from interfering with C3 CPU state. |
2621 | */ | 2556 | */ |
2622 | pci_read_config_dword(pdev, 0x40, &val); | 2557 | pci_read_config_dword(pdev, 0x40, &val); |
2623 | if ((val & 0x0000ff00) != 0) | 2558 | if ((val & 0x0000ff00) != 0) |
2624 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 2559 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
2625 | 2560 | ||
2626 | ret = pci_request_region(pdev, 0, "ath9k"); | 2561 | ret = pci_request_region(pdev, 0, "ath9k"); |
2627 | if (ret) { | 2562 | if (ret) { |
2628 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | 2563 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); |
2629 | ret = -ENODEV; | 2564 | ret = -ENODEV; |
2630 | goto bad; | 2565 | goto bad; |
2631 | } | 2566 | } |
2632 | 2567 | ||
2633 | mem = pci_iomap(pdev, 0, 0); | 2568 | mem = pci_iomap(pdev, 0, 0); |
2634 | if (!mem) { | 2569 | if (!mem) { |
2635 | printk(KERN_ERR "PCI memory map error\n") ; | 2570 | printk(KERN_ERR "PCI memory map error\n") ; |
2636 | ret = -EIO; | 2571 | ret = -EIO; |
2637 | goto bad1; | 2572 | goto bad1; |
2638 | } | 2573 | } |
2639 | 2574 | ||
2640 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); | 2575 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
2641 | if (hw == NULL) { | 2576 | if (hw == NULL) { |
2642 | printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); | 2577 | printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); |
2643 | goto bad2; | 2578 | goto bad2; |
2644 | } | 2579 | } |
2645 | 2580 | ||
2646 | SET_IEEE80211_DEV(hw, &pdev->dev); | 2581 | SET_IEEE80211_DEV(hw, &pdev->dev); |
2647 | pci_set_drvdata(pdev, hw); | 2582 | pci_set_drvdata(pdev, hw); |
2648 | 2583 | ||
2649 | sc = hw->priv; | 2584 | sc = hw->priv; |
2650 | sc->hw = hw; | 2585 | sc->hw = hw; |
2651 | sc->pdev = pdev; | 2586 | sc->pdev = pdev; |
2652 | sc->mem = mem; | 2587 | sc->mem = mem; |
2653 | 2588 | ||
2654 | if (ath_attach(id->device, sc) != 0) { | 2589 | if (ath_attach(id->device, sc) != 0) { |
2655 | ret = -ENODEV; | 2590 | ret = -ENODEV; |
2656 | goto bad3; | 2591 | goto bad3; |
2657 | } | 2592 | } |
2658 | 2593 | ||
2659 | /* setup interrupt service routine */ | 2594 | /* setup interrupt service routine */ |
2660 | 2595 | ||
2661 | if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { | 2596 | if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { |
2662 | printk(KERN_ERR "%s: request_irq failed\n", | 2597 | printk(KERN_ERR "%s: request_irq failed\n", |
2663 | wiphy_name(hw->wiphy)); | 2598 | wiphy_name(hw->wiphy)); |
2664 | ret = -EIO; | 2599 | ret = -EIO; |
2665 | goto bad4; | 2600 | goto bad4; |
2666 | } | 2601 | } |
2667 | 2602 | ||
2668 | ah = sc->sc_ah; | 2603 | ah = sc->sc_ah; |
2669 | printk(KERN_INFO | 2604 | printk(KERN_INFO |
2670 | "%s: Atheros AR%s MAC/BB Rev:%x " | 2605 | "%s: Atheros AR%s MAC/BB Rev:%x " |
2671 | "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", | 2606 | "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", |
2672 | wiphy_name(hw->wiphy), | 2607 | wiphy_name(hw->wiphy), |
2673 | ath_mac_bb_name(ah->ah_macVersion), | 2608 | ath_mac_bb_name(ah->ah_macVersion), |
2674 | ah->ah_macRev, | 2609 | ah->ah_macRev, |
2675 | ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), | 2610 | ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), |
2676 | ah->ah_phyRev, | 2611 | ah->ah_phyRev, |
2677 | (unsigned long)mem, pdev->irq); | 2612 | (unsigned long)mem, pdev->irq); |
2678 | 2613 | ||
2679 | return 0; | 2614 | return 0; |
2680 | bad4: | 2615 | bad4: |
2681 | ath_detach(sc); | 2616 | ath_detach(sc); |
2682 | bad3: | 2617 | bad3: |
2683 | ieee80211_free_hw(hw); | 2618 | ieee80211_free_hw(hw); |
2684 | bad2: | 2619 | bad2: |
2685 | pci_iounmap(pdev, mem); | 2620 | pci_iounmap(pdev, mem); |
2686 | bad1: | 2621 | bad1: |
2687 | pci_release_region(pdev, 0); | 2622 | pci_release_region(pdev, 0); |
2688 | bad: | 2623 | bad: |
2689 | pci_disable_device(pdev); | 2624 | pci_disable_device(pdev); |
2690 | return ret; | 2625 | return ret; |
2691 | } | 2626 | } |
2692 | 2627 | ||
2693 | static void ath_pci_remove(struct pci_dev *pdev) | 2628 | static void ath_pci_remove(struct pci_dev *pdev) |
2694 | { | 2629 | { |
2695 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 2630 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
2696 | struct ath_softc *sc = hw->priv; | 2631 | struct ath_softc *sc = hw->priv; |
2697 | 2632 | ||
2698 | ath_detach(sc); | 2633 | ath_detach(sc); |
2699 | if (pdev->irq) | 2634 | if (pdev->irq) |
2700 | free_irq(pdev->irq, sc); | 2635 | free_irq(pdev->irq, sc); |
2701 | pci_iounmap(pdev, sc->mem); | 2636 | pci_iounmap(pdev, sc->mem); |
2702 | pci_release_region(pdev, 0); | 2637 | pci_release_region(pdev, 0); |
2703 | pci_disable_device(pdev); | 2638 | pci_disable_device(pdev); |
2704 | ieee80211_free_hw(hw); | 2639 | ieee80211_free_hw(hw); |
2705 | } | 2640 | } |
2706 | 2641 | ||
2707 | #ifdef CONFIG_PM | 2642 | #ifdef CONFIG_PM |
2708 | 2643 | ||
2709 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 2644 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
2710 | { | 2645 | { |
2711 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 2646 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
2712 | struct ath_softc *sc = hw->priv; | 2647 | struct ath_softc *sc = hw->priv; |
2713 | 2648 | ||
2714 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 2649 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
2715 | 2650 | ||
2716 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 2651 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
2717 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 2652 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
2718 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | 2653 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); |
2719 | #endif | 2654 | #endif |
2720 | 2655 | ||
2721 | pci_save_state(pdev); | 2656 | pci_save_state(pdev); |
2722 | pci_disable_device(pdev); | 2657 | pci_disable_device(pdev); |
2723 | pci_set_power_state(pdev, 3); | 2658 | pci_set_power_state(pdev, 3); |
2724 | 2659 | ||
2725 | return 0; | 2660 | return 0; |
2726 | } | 2661 | } |
2727 | 2662 | ||
2728 | static int ath_pci_resume(struct pci_dev *pdev) | 2663 | static int ath_pci_resume(struct pci_dev *pdev) |
2729 | { | 2664 | { |
2730 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 2665 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
2731 | struct ath_softc *sc = hw->priv; | 2666 | struct ath_softc *sc = hw->priv; |
2732 | u32 val; | 2667 | u32 val; |
2733 | int err; | 2668 | int err; |
2734 | 2669 | ||
2735 | err = pci_enable_device(pdev); | 2670 | err = pci_enable_device(pdev); |
2736 | if (err) | 2671 | if (err) |
2737 | return err; | 2672 | return err; |
2738 | pci_restore_state(pdev); | 2673 | pci_restore_state(pdev); |
2739 | /* | 2674 | /* |
2740 | * Suspend/Resume resets the PCI configuration space, so we have to | 2675 | * Suspend/Resume resets the PCI configuration space, so we have to |
2741 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | 2676 | * re-disable the RETRY_TIMEOUT register (0x41) to keep |
2742 | * PCI Tx retries from interfering with C3 CPU state | 2677 | * PCI Tx retries from interfering with C3 CPU state |
2743 | */ | 2678 | */ |
2744 | pci_read_config_dword(pdev, 0x40, &val); | 2679 | pci_read_config_dword(pdev, 0x40, &val); |
2745 | if ((val & 0x0000ff00) != 0) | 2680 | if ((val & 0x0000ff00) != 0) |
2746 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 2681 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
2747 | 2682 | ||
2748 | /* Enable LED */ | 2683 | /* Enable LED */ |
2749 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | 2684 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, |
2750 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 2685 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
2751 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 2686 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
2752 | 2687 | ||
2753 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 2688 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
2754 | /* | 2689 | /* |
2755 | * check the h/w rfkill state on resume | 2690 | * check the h/w rfkill state on resume |
2756 | * and start the rfkill poll timer | 2691 | * and start the rfkill poll timer |
2757 | */ | 2692 | */ |
2758 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 2693 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
2759 | queue_delayed_work(sc->hw->workqueue, | 2694 | queue_delayed_work(sc->hw->workqueue, |
2760 | &sc->rf_kill.rfkill_poll, 0); | 2695 | &sc->rf_kill.rfkill_poll, 0); |
2761 | #endif | 2696 | #endif |
2762 | 2697 | ||
2763 | return 0; | 2698 | return 0; |
2764 | } | 2699 | } |
2765 | 2700 | ||
2766 | #endif /* CONFIG_PM */ | 2701 | #endif /* CONFIG_PM */ |
2767 | 2702 | ||
2768 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); | 2703 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); |
2769 | 2704 | ||
2770 | static struct pci_driver ath_pci_driver = { | 2705 | static struct pci_driver ath_pci_driver = { |
2771 | .name = "ath9k", | 2706 | .name = "ath9k", |
2772 | .id_table = ath_pci_id_table, | 2707 | .id_table = ath_pci_id_table, |
2773 | .probe = ath_pci_probe, | 2708 | .probe = ath_pci_probe, |
2774 | .remove = ath_pci_remove, | 2709 | .remove = ath_pci_remove, |
2775 | #ifdef CONFIG_PM | 2710 | #ifdef CONFIG_PM |
2776 | .suspend = ath_pci_suspend, | 2711 | .suspend = ath_pci_suspend, |
2777 | .resume = ath_pci_resume, | 2712 | .resume = ath_pci_resume, |
2778 | #endif /* CONFIG_PM */ | 2713 | #endif /* CONFIG_PM */ |
2779 | }; | 2714 | }; |
2780 | 2715 | ||
2781 | static int __init init_ath_pci(void) | 2716 | static int __init init_ath_pci(void) |
2782 | { | 2717 | { |
2783 | printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); | 2718 | printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); |
2784 | 2719 | ||
2785 | if (pci_register_driver(&ath_pci_driver) < 0) { | 2720 | if (pci_register_driver(&ath_pci_driver) < 0) { |
2786 | printk(KERN_ERR | 2721 | printk(KERN_ERR |
2787 | "ath_pci: No devices found, driver not installed.\n"); | 2722 | "ath_pci: No devices found, driver not installed.\n"); |
2788 | pci_unregister_driver(&ath_pci_driver); | 2723 | pci_unregister_driver(&ath_pci_driver); |
2789 | return -ENODEV; | 2724 | return -ENODEV; |
2790 | } | 2725 | } |
2791 | 2726 | ||
2792 | return 0; | 2727 | return 0; |
2793 | } | 2728 | } |
drivers/net/wireless/iwlwifi/iwl-agn.c
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of version 2 of the GNU General Public License as | 9 | * under the terms of version 2 of the GNU General Public License as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | 12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | * more details. | 15 | * more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License along with | 17 | * You should have received a copy of the GNU General Public License along with |
18 | * this program; if not, write to the Free Software Foundation, Inc., | 18 | * this program; if not, write to the Free Software Foundation, Inc., |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
20 | * | 20 | * |
21 | * The full GNU General Public License is included in this distribution in the | 21 | * The full GNU General Public License is included in this distribution in the |
22 | * file called LICENSE. | 22 | * file called LICENSE. |
23 | * | 23 | * |
24 | * Contact Information: | 24 | * Contact Information: |
25 | * Intel Linux Wireless <ilw@linux.intel.com> | 25 | * Intel Linux Wireless <ilw@linux.intel.com> |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
27 | * | 27 | * |
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | 29 | ||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/dma-mapping.h> | 34 | #include <linux/dma-mapping.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/skbuff.h> | 36 | #include <linux/skbuff.h> |
37 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
38 | #include <linux/wireless.h> | 38 | #include <linux/wireless.h> |
39 | #include <linux/firmware.h> | 39 | #include <linux/firmware.h> |
40 | #include <linux/etherdevice.h> | 40 | #include <linux/etherdevice.h> |
41 | #include <linux/if_arp.h> | 41 | #include <linux/if_arp.h> |
42 | 42 | ||
43 | #include <net/mac80211.h> | 43 | #include <net/mac80211.h> |
44 | 44 | ||
45 | #include <asm/div64.h> | 45 | #include <asm/div64.h> |
46 | 46 | ||
47 | #include "iwl-eeprom.h" | 47 | #include "iwl-eeprom.h" |
48 | #include "iwl-dev.h" | 48 | #include "iwl-dev.h" |
49 | #include "iwl-core.h" | 49 | #include "iwl-core.h" |
50 | #include "iwl-io.h" | 50 | #include "iwl-io.h" |
51 | #include "iwl-helpers.h" | 51 | #include "iwl-helpers.h" |
52 | #include "iwl-sta.h" | 52 | #include "iwl-sta.h" |
53 | #include "iwl-calib.h" | 53 | #include "iwl-calib.h" |
54 | 54 | ||
55 | 55 | ||
56 | /****************************************************************************** | 56 | /****************************************************************************** |
57 | * | 57 | * |
58 | * module boiler plate | 58 | * module boiler plate |
59 | * | 59 | * |
60 | ******************************************************************************/ | 60 | ******************************************************************************/ |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * module name, copyright, version, etc. | 63 | * module name, copyright, version, etc. |
64 | * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk | 64 | * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk |
65 | */ | 65 | */ |
66 | 66 | ||
67 | #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" | 67 | #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" |
68 | 68 | ||
69 | #ifdef CONFIG_IWLWIFI_DEBUG | 69 | #ifdef CONFIG_IWLWIFI_DEBUG |
70 | #define VD "d" | 70 | #define VD "d" |
71 | #else | 71 | #else |
72 | #define VD | 72 | #define VD |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT | 75 | #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT |
76 | #define VS "s" | 76 | #define VS "s" |
77 | #else | 77 | #else |
78 | #define VS | 78 | #define VS |
79 | #endif | 79 | #endif |
80 | 80 | ||
81 | #define DRV_VERSION IWLWIFI_VERSION VD VS | 81 | #define DRV_VERSION IWLWIFI_VERSION VD VS |
82 | 82 | ||
83 | 83 | ||
84 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 84 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
85 | MODULE_VERSION(DRV_VERSION); | 85 | MODULE_VERSION(DRV_VERSION); |
86 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | 86 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); |
87 | MODULE_LICENSE("GPL"); | 87 | MODULE_LICENSE("GPL"); |
88 | MODULE_ALIAS("iwl4965"); | 88 | MODULE_ALIAS("iwl4965"); |
89 | 89 | ||
90 | /*************** STATION TABLE MANAGEMENT **** | 90 | /*************** STATION TABLE MANAGEMENT **** |
91 | * mac80211 should be examined to determine if sta_info is duplicating | 91 | * mac80211 should be examined to determine if sta_info is duplicating |
92 | * the functionality provided here | 92 | * the functionality provided here |
93 | */ | 93 | */ |
94 | 94 | ||
95 | /**************************************************************/ | 95 | /**************************************************************/ |
96 | 96 | ||
97 | 97 | ||
98 | 98 | ||
99 | static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) | 99 | static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) |
100 | { | 100 | { |
101 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 101 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
102 | 102 | ||
103 | if (hw_decrypt) | 103 | if (hw_decrypt) |
104 | rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; | 104 | rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; |
105 | else | 105 | else |
106 | rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; | 106 | rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; |
107 | 107 | ||
108 | } | 108 | } |
109 | 109 | ||
110 | /** | 110 | /** |
111 | * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed | 111 | * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed |
112 | * @priv: staging_rxon is compared to active_rxon | 112 | * @priv: staging_rxon is compared to active_rxon |
113 | * | 113 | * |
114 | * If the RXON structure is changing enough to require a new tune, | 114 | * If the RXON structure is changing enough to require a new tune, |
115 | * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that | 115 | * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that |
116 | * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. | 116 | * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. |
117 | */ | 117 | */ |
118 | static int iwl_full_rxon_required(struct iwl_priv *priv) | 118 | static int iwl_full_rxon_required(struct iwl_priv *priv) |
119 | { | 119 | { |
120 | 120 | ||
121 | /* These items are only settable from the full RXON command */ | 121 | /* These items are only settable from the full RXON command */ |
122 | if (!(iwl_is_associated(priv)) || | 122 | if (!(iwl_is_associated(priv)) || |
123 | compare_ether_addr(priv->staging_rxon.bssid_addr, | 123 | compare_ether_addr(priv->staging_rxon.bssid_addr, |
124 | priv->active_rxon.bssid_addr) || | 124 | priv->active_rxon.bssid_addr) || |
125 | compare_ether_addr(priv->staging_rxon.node_addr, | 125 | compare_ether_addr(priv->staging_rxon.node_addr, |
126 | priv->active_rxon.node_addr) || | 126 | priv->active_rxon.node_addr) || |
127 | compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, | 127 | compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, |
128 | priv->active_rxon.wlap_bssid_addr) || | 128 | priv->active_rxon.wlap_bssid_addr) || |
129 | (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || | 129 | (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || |
130 | (priv->staging_rxon.channel != priv->active_rxon.channel) || | 130 | (priv->staging_rxon.channel != priv->active_rxon.channel) || |
131 | (priv->staging_rxon.air_propagation != | 131 | (priv->staging_rxon.air_propagation != |
132 | priv->active_rxon.air_propagation) || | 132 | priv->active_rxon.air_propagation) || |
133 | (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != | 133 | (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != |
134 | priv->active_rxon.ofdm_ht_single_stream_basic_rates) || | 134 | priv->active_rxon.ofdm_ht_single_stream_basic_rates) || |
135 | (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != | 135 | (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != |
136 | priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || | 136 | priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || |
137 | (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) | 137 | (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) |
138 | return 1; | 138 | return 1; |
139 | 139 | ||
140 | /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can | 140 | /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can |
141 | * be updated with the RXON_ASSOC command -- however only some | 141 | * be updated with the RXON_ASSOC command -- however only some |
142 | * flag transitions are allowed using RXON_ASSOC */ | 142 | * flag transitions are allowed using RXON_ASSOC */ |
143 | 143 | ||
144 | /* Check if we are not switching bands */ | 144 | /* Check if we are not switching bands */ |
145 | if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != | 145 | if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != |
146 | (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) | 146 | (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) |
147 | return 1; | 147 | return 1; |
148 | 148 | ||
149 | /* Check if we are switching association toggle */ | 149 | /* Check if we are switching association toggle */ |
150 | if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != | 150 | if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != |
151 | (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) | 151 | (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) |
152 | return 1; | 152 | return 1; |
153 | 153 | ||
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | 156 | ||
157 | /** | 157 | /** |
158 | * iwl_commit_rxon - commit staging_rxon to hardware | 158 | * iwl_commit_rxon - commit staging_rxon to hardware |
159 | * | 159 | * |
160 | * The RXON command in staging_rxon is committed to the hardware and | 160 | * The RXON command in staging_rxon is committed to the hardware and |
161 | * the active_rxon structure is updated with the new data. This | 161 | * the active_rxon structure is updated with the new data. This |
162 | * function correctly transitions out of the RXON_ASSOC_MSK state if | 162 | * function correctly transitions out of the RXON_ASSOC_MSK state if |
163 | * a HW tune is required based on the RXON structure changes. | 163 | * a HW tune is required based on the RXON structure changes. |
164 | */ | 164 | */ |
165 | static int iwl_commit_rxon(struct iwl_priv *priv) | 165 | static int iwl_commit_rxon(struct iwl_priv *priv) |
166 | { | 166 | { |
167 | /* cast away the const for active_rxon in this function */ | 167 | /* cast away the const for active_rxon in this function */ |
168 | struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; | 168 | struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; |
169 | int ret; | 169 | int ret; |
170 | bool new_assoc = | 170 | bool new_assoc = |
171 | !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); | 171 | !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); |
172 | 172 | ||
173 | if (!iwl_is_alive(priv)) | 173 | if (!iwl_is_alive(priv)) |
174 | return -EBUSY; | 174 | return -EBUSY; |
175 | 175 | ||
176 | /* always get timestamp with Rx frame */ | 176 | /* always get timestamp with Rx frame */ |
177 | priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; | 177 | priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; |
178 | /* allow CTS-to-self if possible. this is relevant only for | 178 | /* allow CTS-to-self if possible. this is relevant only for |
179 | * 5000, but will not damage 4965 */ | 179 | * 5000, but will not damage 4965 */ |
180 | priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; | 180 | priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; |
181 | 181 | ||
182 | ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon); | 182 | ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon); |
183 | if (ret) { | 183 | if (ret) { |
184 | IWL_ERROR("Invalid RXON configuration. Not committing.\n"); | 184 | IWL_ERROR("Invalid RXON configuration. Not committing.\n"); |
185 | return -EINVAL; | 185 | return -EINVAL; |
186 | } | 186 | } |
187 | 187 | ||
188 | /* If we don't need to send a full RXON, we can use | 188 | /* If we don't need to send a full RXON, we can use |
189 | * iwl_rxon_assoc_cmd which is used to reconfigure filter | 189 | * iwl_rxon_assoc_cmd which is used to reconfigure filter |
190 | * and other flags for the current radio configuration. */ | 190 | * and other flags for the current radio configuration. */ |
191 | if (!iwl_full_rxon_required(priv)) { | 191 | if (!iwl_full_rxon_required(priv)) { |
192 | ret = iwl_send_rxon_assoc(priv); | 192 | ret = iwl_send_rxon_assoc(priv); |
193 | if (ret) { | 193 | if (ret) { |
194 | IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); | 194 | IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); |
195 | return ret; | 195 | return ret; |
196 | } | 196 | } |
197 | 197 | ||
198 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 198 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
199 | return 0; | 199 | return 0; |
200 | } | 200 | } |
201 | 201 | ||
202 | /* station table will be cleared */ | 202 | /* station table will be cleared */ |
203 | priv->assoc_station_added = 0; | 203 | priv->assoc_station_added = 0; |
204 | 204 | ||
205 | /* If we are currently associated and the new config requires | 205 | /* If we are currently associated and the new config requires |
206 | * an RXON_ASSOC and the new config wants the associated mask enabled, | 206 | * an RXON_ASSOC and the new config wants the associated mask enabled, |
207 | * we must clear the associated from the active configuration | 207 | * we must clear the associated from the active configuration |
208 | * before we apply the new config */ | 208 | * before we apply the new config */ |
209 | if (iwl_is_associated(priv) && new_assoc) { | 209 | if (iwl_is_associated(priv) && new_assoc) { |
210 | IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); | 210 | IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); |
211 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 211 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
212 | 212 | ||
213 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | 213 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, |
214 | sizeof(struct iwl_rxon_cmd), | 214 | sizeof(struct iwl_rxon_cmd), |
215 | &priv->active_rxon); | 215 | &priv->active_rxon); |
216 | 216 | ||
217 | /* If the mask clearing failed then we set | 217 | /* If the mask clearing failed then we set |
218 | * active_rxon back to what it was previously */ | 218 | * active_rxon back to what it was previously */ |
219 | if (ret) { | 219 | if (ret) { |
220 | active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; | 220 | active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; |
221 | IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); | 221 | IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); |
222 | return ret; | 222 | return ret; |
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | IWL_DEBUG_INFO("Sending RXON\n" | 226 | IWL_DEBUG_INFO("Sending RXON\n" |
227 | "* with%s RXON_FILTER_ASSOC_MSK\n" | 227 | "* with%s RXON_FILTER_ASSOC_MSK\n" |
228 | "* channel = %d\n" | 228 | "* channel = %d\n" |
229 | "* bssid = %pM\n", | 229 | "* bssid = %pM\n", |
230 | (new_assoc ? "" : "out"), | 230 | (new_assoc ? "" : "out"), |
231 | le16_to_cpu(priv->staging_rxon.channel), | 231 | le16_to_cpu(priv->staging_rxon.channel), |
232 | priv->staging_rxon.bssid_addr); | 232 | priv->staging_rxon.bssid_addr); |
233 | 233 | ||
234 | iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); | 234 | iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); |
235 | 235 | ||
236 | /* Apply the new configuration | 236 | /* Apply the new configuration |
237 | * RXON unassoc clears the station table in uCode, send it before | 237 | * RXON unassoc clears the station table in uCode, send it before |
238 | * we add the bcast station. If assoc bit is set, we will send RXON | 238 | * we add the bcast station. If assoc bit is set, we will send RXON |
239 | * after having added the bcast and bssid station. | 239 | * after having added the bcast and bssid station. |
240 | */ | 240 | */ |
241 | if (!new_assoc) { | 241 | if (!new_assoc) { |
242 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | 242 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, |
243 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); | 243 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); |
244 | if (ret) { | 244 | if (ret) { |
245 | IWL_ERROR("Error setting new RXON (%d)\n", ret); | 245 | IWL_ERROR("Error setting new RXON (%d)\n", ret); |
246 | return ret; | 246 | return ret; |
247 | } | 247 | } |
248 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 248 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
249 | } | 249 | } |
250 | 250 | ||
251 | iwl_clear_stations_table(priv); | 251 | iwl_clear_stations_table(priv); |
252 | 252 | ||
253 | if (!priv->error_recovering) | 253 | if (!priv->error_recovering) |
254 | priv->start_calib = 0; | 254 | priv->start_calib = 0; |
255 | 255 | ||
256 | /* Add the broadcast address so we can send broadcast frames */ | 256 | /* Add the broadcast address so we can send broadcast frames */ |
257 | if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == | 257 | if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == |
258 | IWL_INVALID_STATION) { | 258 | IWL_INVALID_STATION) { |
259 | IWL_ERROR("Error adding BROADCAST address for transmit.\n"); | 259 | IWL_ERROR("Error adding BROADCAST address for transmit.\n"); |
260 | return -EIO; | 260 | return -EIO; |
261 | } | 261 | } |
262 | 262 | ||
263 | /* If we have set the ASSOC_MSK and we are in BSS mode then | 263 | /* If we have set the ASSOC_MSK and we are in BSS mode then |
264 | * add the IWL_AP_ID to the station rate table */ | 264 | * add the IWL_AP_ID to the station rate table */ |
265 | if (new_assoc) { | 265 | if (new_assoc) { |
266 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { | 266 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { |
267 | ret = iwl_rxon_add_station(priv, | 267 | ret = iwl_rxon_add_station(priv, |
268 | priv->active_rxon.bssid_addr, 1); | 268 | priv->active_rxon.bssid_addr, 1); |
269 | if (ret == IWL_INVALID_STATION) { | 269 | if (ret == IWL_INVALID_STATION) { |
270 | IWL_ERROR("Error adding AP address for TX.\n"); | 270 | IWL_ERROR("Error adding AP address for TX.\n"); |
271 | return -EIO; | 271 | return -EIO; |
272 | } | 272 | } |
273 | priv->assoc_station_added = 1; | 273 | priv->assoc_station_added = 1; |
274 | if (priv->default_wep_key && | 274 | if (priv->default_wep_key && |
275 | iwl_send_static_wepkey_cmd(priv, 0)) | 275 | iwl_send_static_wepkey_cmd(priv, 0)) |
276 | IWL_ERROR("Could not send WEP static key.\n"); | 276 | IWL_ERROR("Could not send WEP static key.\n"); |
277 | } | 277 | } |
278 | 278 | ||
279 | /* Apply the new configuration | 279 | /* Apply the new configuration |
280 | * RXON assoc doesn't clear the station table in uCode, | 280 | * RXON assoc doesn't clear the station table in uCode, |
281 | */ | 281 | */ |
282 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | 282 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, |
283 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); | 283 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); |
284 | if (ret) { | 284 | if (ret) { |
285 | IWL_ERROR("Error setting new RXON (%d)\n", ret); | 285 | IWL_ERROR("Error setting new RXON (%d)\n", ret); |
286 | return ret; | 286 | return ret; |
287 | } | 287 | } |
288 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 288 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
289 | } | 289 | } |
290 | 290 | ||
291 | iwl_init_sensitivity(priv); | 291 | iwl_init_sensitivity(priv); |
292 | 292 | ||
293 | /* If we issue a new RXON command which required a tune then we must | 293 | /* If we issue a new RXON command which required a tune then we must |
294 | * send a new TXPOWER command or we won't be able to Tx any frames */ | 294 | * send a new TXPOWER command or we won't be able to Tx any frames */ |
295 | ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); | 295 | ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); |
296 | if (ret) { | 296 | if (ret) { |
297 | IWL_ERROR("Error sending TX power (%d)\n", ret); | 297 | IWL_ERROR("Error sending TX power (%d)\n", ret); |
298 | return ret; | 298 | return ret; |
299 | } | 299 | } |
300 | 300 | ||
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | 303 | ||
304 | void iwl_update_chain_flags(struct iwl_priv *priv) | 304 | void iwl_update_chain_flags(struct iwl_priv *priv) |
305 | { | 305 | { |
306 | 306 | ||
307 | iwl_set_rxon_chain(priv); | 307 | iwl_set_rxon_chain(priv); |
308 | iwl_commit_rxon(priv); | 308 | iwl_commit_rxon(priv); |
309 | } | 309 | } |
310 | 310 | ||
311 | static int iwl_send_bt_config(struct iwl_priv *priv) | 311 | static int iwl_send_bt_config(struct iwl_priv *priv) |
312 | { | 312 | { |
313 | struct iwl_bt_cmd bt_cmd = { | 313 | struct iwl_bt_cmd bt_cmd = { |
314 | .flags = 3, | 314 | .flags = 3, |
315 | .lead_time = 0xAA, | 315 | .lead_time = 0xAA, |
316 | .max_kill = 1, | 316 | .max_kill = 1, |
317 | .kill_ack_mask = 0, | 317 | .kill_ack_mask = 0, |
318 | .kill_cts_mask = 0, | 318 | .kill_cts_mask = 0, |
319 | }; | 319 | }; |
320 | 320 | ||
321 | return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, | 321 | return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, |
322 | sizeof(struct iwl_bt_cmd), &bt_cmd); | 322 | sizeof(struct iwl_bt_cmd), &bt_cmd); |
323 | } | 323 | } |
324 | 324 | ||
325 | static void iwl_clear_free_frames(struct iwl_priv *priv) | 325 | static void iwl_clear_free_frames(struct iwl_priv *priv) |
326 | { | 326 | { |
327 | struct list_head *element; | 327 | struct list_head *element; |
328 | 328 | ||
329 | IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", | 329 | IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", |
330 | priv->frames_count); | 330 | priv->frames_count); |
331 | 331 | ||
332 | while (!list_empty(&priv->free_frames)) { | 332 | while (!list_empty(&priv->free_frames)) { |
333 | element = priv->free_frames.next; | 333 | element = priv->free_frames.next; |
334 | list_del(element); | 334 | list_del(element); |
335 | kfree(list_entry(element, struct iwl_frame, list)); | 335 | kfree(list_entry(element, struct iwl_frame, list)); |
336 | priv->frames_count--; | 336 | priv->frames_count--; |
337 | } | 337 | } |
338 | 338 | ||
339 | if (priv->frames_count) { | 339 | if (priv->frames_count) { |
340 | IWL_WARNING("%d frames still in use. Did we lose one?\n", | 340 | IWL_WARNING("%d frames still in use. Did we lose one?\n", |
341 | priv->frames_count); | 341 | priv->frames_count); |
342 | priv->frames_count = 0; | 342 | priv->frames_count = 0; |
343 | } | 343 | } |
344 | } | 344 | } |
345 | 345 | ||
346 | static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) | 346 | static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) |
347 | { | 347 | { |
348 | struct iwl_frame *frame; | 348 | struct iwl_frame *frame; |
349 | struct list_head *element; | 349 | struct list_head *element; |
350 | if (list_empty(&priv->free_frames)) { | 350 | if (list_empty(&priv->free_frames)) { |
351 | frame = kzalloc(sizeof(*frame), GFP_KERNEL); | 351 | frame = kzalloc(sizeof(*frame), GFP_KERNEL); |
352 | if (!frame) { | 352 | if (!frame) { |
353 | IWL_ERROR("Could not allocate frame!\n"); | 353 | IWL_ERROR("Could not allocate frame!\n"); |
354 | return NULL; | 354 | return NULL; |
355 | } | 355 | } |
356 | 356 | ||
357 | priv->frames_count++; | 357 | priv->frames_count++; |
358 | return frame; | 358 | return frame; |
359 | } | 359 | } |
360 | 360 | ||
361 | element = priv->free_frames.next; | 361 | element = priv->free_frames.next; |
362 | list_del(element); | 362 | list_del(element); |
363 | return list_entry(element, struct iwl_frame, list); | 363 | return list_entry(element, struct iwl_frame, list); |
364 | } | 364 | } |
365 | 365 | ||
366 | static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) | 366 | static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) |
367 | { | 367 | { |
368 | memset(frame, 0, sizeof(*frame)); | 368 | memset(frame, 0, sizeof(*frame)); |
369 | list_add(&frame->list, &priv->free_frames); | 369 | list_add(&frame->list, &priv->free_frames); |
370 | } | 370 | } |
371 | 371 | ||
372 | static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, | 372 | static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, |
373 | struct ieee80211_hdr *hdr, | 373 | struct ieee80211_hdr *hdr, |
374 | const u8 *dest, int left) | 374 | const u8 *dest, int left) |
375 | { | 375 | { |
376 | if (!iwl_is_associated(priv) || !priv->ibss_beacon || | 376 | if (!iwl_is_associated(priv) || !priv->ibss_beacon || |
377 | ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && | 377 | ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && |
378 | (priv->iw_mode != NL80211_IFTYPE_AP))) | 378 | (priv->iw_mode != NL80211_IFTYPE_AP))) |
379 | return 0; | 379 | return 0; |
380 | 380 | ||
381 | if (priv->ibss_beacon->len > left) | 381 | if (priv->ibss_beacon->len > left) |
382 | return 0; | 382 | return 0; |
383 | 383 | ||
384 | memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); | 384 | memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); |
385 | 385 | ||
386 | return priv->ibss_beacon->len; | 386 | return priv->ibss_beacon->len; |
387 | } | 387 | } |
388 | 388 | ||
389 | static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) | 389 | static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) |
390 | { | 390 | { |
391 | int i; | 391 | int i; |
392 | int rate_mask; | 392 | int rate_mask; |
393 | 393 | ||
394 | /* Set rate mask*/ | 394 | /* Set rate mask*/ |
395 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) | 395 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) |
396 | rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; | 396 | rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; |
397 | else | 397 | else |
398 | rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; | 398 | rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; |
399 | 399 | ||
400 | /* Find lowest valid rate */ | 400 | /* Find lowest valid rate */ |
401 | for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; | 401 | for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; |
402 | i = iwl_rates[i].next_ieee) { | 402 | i = iwl_rates[i].next_ieee) { |
403 | if (rate_mask & (1 << i)) | 403 | if (rate_mask & (1 << i)) |
404 | return iwl_rates[i].plcp; | 404 | return iwl_rates[i].plcp; |
405 | } | 405 | } |
406 | 406 | ||
407 | /* No valid rate was found. Assign the lowest one */ | 407 | /* No valid rate was found. Assign the lowest one */ |
408 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) | 408 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) |
409 | return IWL_RATE_1M_PLCP; | 409 | return IWL_RATE_1M_PLCP; |
410 | else | 410 | else |
411 | return IWL_RATE_6M_PLCP; | 411 | return IWL_RATE_6M_PLCP; |
412 | } | 412 | } |
413 | 413 | ||
414 | static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, | 414 | static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, |
415 | struct iwl_frame *frame, u8 rate) | 415 | struct iwl_frame *frame, u8 rate) |
416 | { | 416 | { |
417 | struct iwl_tx_beacon_cmd *tx_beacon_cmd; | 417 | struct iwl_tx_beacon_cmd *tx_beacon_cmd; |
418 | unsigned int frame_size; | 418 | unsigned int frame_size; |
419 | 419 | ||
420 | tx_beacon_cmd = &frame->u.beacon; | 420 | tx_beacon_cmd = &frame->u.beacon; |
421 | memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); | 421 | memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); |
422 | 422 | ||
423 | tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; | 423 | tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; |
424 | tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; | 424 | tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; |
425 | 425 | ||
426 | frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, | 426 | frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, |
427 | iwl_bcast_addr, | 427 | iwl_bcast_addr, |
428 | sizeof(frame->u) - sizeof(*tx_beacon_cmd)); | 428 | sizeof(frame->u) - sizeof(*tx_beacon_cmd)); |
429 | 429 | ||
430 | BUG_ON(frame_size > MAX_MPDU_SIZE); | 430 | BUG_ON(frame_size > MAX_MPDU_SIZE); |
431 | tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); | 431 | tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); |
432 | 432 | ||
433 | if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) | 433 | if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) |
434 | tx_beacon_cmd->tx.rate_n_flags = | 434 | tx_beacon_cmd->tx.rate_n_flags = |
435 | iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); | 435 | iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); |
436 | else | 436 | else |
437 | tx_beacon_cmd->tx.rate_n_flags = | 437 | tx_beacon_cmd->tx.rate_n_flags = |
438 | iwl_hw_set_rate_n_flags(rate, 0); | 438 | iwl_hw_set_rate_n_flags(rate, 0); |
439 | 439 | ||
440 | tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | | 440 | tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | |
441 | TX_CMD_FLG_TSF_MSK | | 441 | TX_CMD_FLG_TSF_MSK | |
442 | TX_CMD_FLG_STA_RATE_MSK; | 442 | TX_CMD_FLG_STA_RATE_MSK; |
443 | 443 | ||
444 | return sizeof(*tx_beacon_cmd) + frame_size; | 444 | return sizeof(*tx_beacon_cmd) + frame_size; |
445 | } | 445 | } |
446 | static int iwl_send_beacon_cmd(struct iwl_priv *priv) | 446 | static int iwl_send_beacon_cmd(struct iwl_priv *priv) |
447 | { | 447 | { |
448 | struct iwl_frame *frame; | 448 | struct iwl_frame *frame; |
449 | unsigned int frame_size; | 449 | unsigned int frame_size; |
450 | int rc; | 450 | int rc; |
451 | u8 rate; | 451 | u8 rate; |
452 | 452 | ||
453 | frame = iwl_get_free_frame(priv); | 453 | frame = iwl_get_free_frame(priv); |
454 | 454 | ||
455 | if (!frame) { | 455 | if (!frame) { |
456 | IWL_ERROR("Could not obtain free frame buffer for beacon " | 456 | IWL_ERROR("Could not obtain free frame buffer for beacon " |
457 | "command.\n"); | 457 | "command.\n"); |
458 | return -ENOMEM; | 458 | return -ENOMEM; |
459 | } | 459 | } |
460 | 460 | ||
461 | rate = iwl_rate_get_lowest_plcp(priv); | 461 | rate = iwl_rate_get_lowest_plcp(priv); |
462 | 462 | ||
463 | frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); | 463 | frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); |
464 | 464 | ||
465 | rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, | 465 | rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, |
466 | &frame->u.cmd[0]); | 466 | &frame->u.cmd[0]); |
467 | 467 | ||
468 | iwl_free_frame(priv, frame); | 468 | iwl_free_frame(priv, frame); |
469 | 469 | ||
470 | return rc; | 470 | return rc; |
471 | } | 471 | } |
472 | 472 | ||
473 | /****************************************************************************** | 473 | /****************************************************************************** |
474 | * | 474 | * |
475 | * Misc. internal state and helper functions | 475 | * Misc. internal state and helper functions |
476 | * | 476 | * |
477 | ******************************************************************************/ | 477 | ******************************************************************************/ |
478 | 478 | ||
479 | static void iwl_ht_conf(struct iwl_priv *priv, | 479 | static void iwl_ht_conf(struct iwl_priv *priv, |
480 | struct ieee80211_bss_conf *bss_conf) | 480 | struct ieee80211_bss_conf *bss_conf) |
481 | { | 481 | { |
482 | struct ieee80211_sta_ht_cap *ht_conf; | 482 | struct ieee80211_sta_ht_cap *ht_conf; |
483 | struct iwl_ht_info *iwl_conf = &priv->current_ht_config; | 483 | struct iwl_ht_info *iwl_conf = &priv->current_ht_config; |
484 | struct ieee80211_sta *sta; | 484 | struct ieee80211_sta *sta; |
485 | 485 | ||
486 | IWL_DEBUG_MAC80211("enter: \n"); | 486 | IWL_DEBUG_MAC80211("enter: \n"); |
487 | 487 | ||
488 | if (!iwl_conf->is_ht) | 488 | if (!iwl_conf->is_ht) |
489 | return; | 489 | return; |
490 | 490 | ||
491 | 491 | ||
492 | /* | 492 | /* |
493 | * It is totally wrong to base global information on something | 493 | * It is totally wrong to base global information on something |
494 | * that is valid only when associated, alas, this driver works | 494 | * that is valid only when associated, alas, this driver works |
495 | * that way and I don't know how to fix it. | 495 | * that way and I don't know how to fix it. |
496 | */ | 496 | */ |
497 | 497 | ||
498 | rcu_read_lock(); | 498 | rcu_read_lock(); |
499 | sta = ieee80211_find_sta(priv->hw, priv->bssid); | 499 | sta = ieee80211_find_sta(priv->hw, priv->bssid); |
500 | if (!sta) { | 500 | if (!sta) { |
501 | rcu_read_unlock(); | 501 | rcu_read_unlock(); |
502 | return; | 502 | return; |
503 | } | 503 | } |
504 | ht_conf = &sta->ht_cap; | 504 | ht_conf = &sta->ht_cap; |
505 | 505 | ||
506 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) | 506 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) |
507 | iwl_conf->sgf |= HT_SHORT_GI_20MHZ; | 507 | iwl_conf->sgf |= HT_SHORT_GI_20MHZ; |
508 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) | 508 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) |
509 | iwl_conf->sgf |= HT_SHORT_GI_40MHZ; | 509 | iwl_conf->sgf |= HT_SHORT_GI_40MHZ; |
510 | 510 | ||
511 | iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); | 511 | iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); |
512 | iwl_conf->max_amsdu_size = | 512 | iwl_conf->max_amsdu_size = |
513 | !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); | 513 | !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); |
514 | 514 | ||
515 | iwl_conf->supported_chan_width = | 515 | iwl_conf->supported_chan_width = |
516 | !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); | 516 | !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
517 | 517 | ||
518 | iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset; | 518 | /* |
519 | * XXX: The HT configuration needs to be moved into iwl_mac_config() | ||
520 | * to be done there correctly. | ||
521 | */ | ||
522 | |||
523 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
524 | if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS) | ||
525 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
526 | else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS) | ||
527 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
528 | |||
519 | /* If no above or below channel supplied disable FAT channel */ | 529 | /* If no above or below channel supplied disable FAT channel */ |
520 | if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && | 530 | if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && |
521 | iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { | 531 | iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) |
522 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
523 | iwl_conf->supported_chan_width = 0; | 532 | iwl_conf->supported_chan_width = 0; |
524 | } | ||
525 | 533 | ||
526 | iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); | 534 | iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); |
527 | 535 | ||
528 | memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); | 536 | memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); |
529 | 537 | ||
530 | iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok; | 538 | iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; |
531 | iwl_conf->ht_protection = | 539 | iwl_conf->ht_protection = |
532 | bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; | 540 | bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; |
533 | iwl_conf->non_GF_STA_present = | 541 | iwl_conf->non_GF_STA_present = |
534 | !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | 542 | !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
535 | 543 | ||
536 | rcu_read_unlock(); | 544 | rcu_read_unlock(); |
537 | 545 | ||
538 | IWL_DEBUG_MAC80211("leave\n"); | 546 | IWL_DEBUG_MAC80211("leave\n"); |
539 | } | 547 | } |
540 | 548 | ||
541 | /* | 549 | /* |
542 | * QoS support | 550 | * QoS support |
543 | */ | 551 | */ |
544 | static void iwl_activate_qos(struct iwl_priv *priv, u8 force) | 552 | static void iwl_activate_qos(struct iwl_priv *priv, u8 force) |
545 | { | 553 | { |
546 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 554 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
547 | return; | 555 | return; |
548 | 556 | ||
549 | priv->qos_data.def_qos_parm.qos_flags = 0; | 557 | priv->qos_data.def_qos_parm.qos_flags = 0; |
550 | 558 | ||
551 | if (priv->qos_data.qos_cap.q_AP.queue_request && | 559 | if (priv->qos_data.qos_cap.q_AP.queue_request && |
552 | !priv->qos_data.qos_cap.q_AP.txop_request) | 560 | !priv->qos_data.qos_cap.q_AP.txop_request) |
553 | priv->qos_data.def_qos_parm.qos_flags |= | 561 | priv->qos_data.def_qos_parm.qos_flags |= |
554 | QOS_PARAM_FLG_TXOP_TYPE_MSK; | 562 | QOS_PARAM_FLG_TXOP_TYPE_MSK; |
555 | if (priv->qos_data.qos_active) | 563 | if (priv->qos_data.qos_active) |
556 | priv->qos_data.def_qos_parm.qos_flags |= | 564 | priv->qos_data.def_qos_parm.qos_flags |= |
557 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; | 565 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; |
558 | 566 | ||
559 | if (priv->current_ht_config.is_ht) | 567 | if (priv->current_ht_config.is_ht) |
560 | priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; | 568 | priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; |
561 | 569 | ||
562 | if (force || iwl_is_associated(priv)) { | 570 | if (force || iwl_is_associated(priv)) { |
563 | IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", | 571 | IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", |
564 | priv->qos_data.qos_active, | 572 | priv->qos_data.qos_active, |
565 | priv->qos_data.def_qos_parm.qos_flags); | 573 | priv->qos_data.def_qos_parm.qos_flags); |
566 | 574 | ||
567 | iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM, | 575 | iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM, |
568 | sizeof(struct iwl_qosparam_cmd), | 576 | sizeof(struct iwl_qosparam_cmd), |
569 | &priv->qos_data.def_qos_parm, NULL); | 577 | &priv->qos_data.def_qos_parm, NULL); |
570 | } | 578 | } |
571 | } | 579 | } |
572 | 580 | ||
573 | #define MAX_UCODE_BEACON_INTERVAL 4096 | 581 | #define MAX_UCODE_BEACON_INTERVAL 4096 |
574 | 582 | ||
575 | static u16 iwl_adjust_beacon_interval(u16 beacon_val) | 583 | static u16 iwl_adjust_beacon_interval(u16 beacon_val) |
576 | { | 584 | { |
577 | u16 new_val = 0; | 585 | u16 new_val = 0; |
578 | u16 beacon_factor = 0; | 586 | u16 beacon_factor = 0; |
579 | 587 | ||
580 | beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) | 588 | beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) |
581 | / MAX_UCODE_BEACON_INTERVAL; | 589 | / MAX_UCODE_BEACON_INTERVAL; |
582 | new_val = beacon_val / beacon_factor; | 590 | new_val = beacon_val / beacon_factor; |
583 | 591 | ||
584 | return new_val; | 592 | return new_val; |
585 | } | 593 | } |
586 | 594 | ||
587 | static void iwl_setup_rxon_timing(struct iwl_priv *priv) | 595 | static void iwl_setup_rxon_timing(struct iwl_priv *priv) |
588 | { | 596 | { |
589 | u64 tsf; | 597 | u64 tsf; |
590 | s32 interval_tm, rem; | 598 | s32 interval_tm, rem; |
591 | unsigned long flags; | 599 | unsigned long flags; |
592 | struct ieee80211_conf *conf = NULL; | 600 | struct ieee80211_conf *conf = NULL; |
593 | u16 beacon_int = 0; | 601 | u16 beacon_int = 0; |
594 | 602 | ||
595 | conf = ieee80211_get_hw_conf(priv->hw); | 603 | conf = ieee80211_get_hw_conf(priv->hw); |
596 | 604 | ||
597 | spin_lock_irqsave(&priv->lock, flags); | 605 | spin_lock_irqsave(&priv->lock, flags); |
598 | priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); | 606 | priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); |
599 | priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); | 607 | priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); |
600 | 608 | ||
601 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { | 609 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { |
602 | beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); | 610 | beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); |
603 | priv->rxon_timing.atim_window = 0; | 611 | priv->rxon_timing.atim_window = 0; |
604 | } else { | 612 | } else { |
605 | beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); | 613 | beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); |
606 | 614 | ||
607 | /* TODO: we need to get atim_window from upper stack | 615 | /* TODO: we need to get atim_window from upper stack |
608 | * for now we set to 0 */ | 616 | * for now we set to 0 */ |
609 | priv->rxon_timing.atim_window = 0; | 617 | priv->rxon_timing.atim_window = 0; |
610 | } | 618 | } |
611 | 619 | ||
612 | priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); | 620 | priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); |
613 | 621 | ||
614 | tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ | 622 | tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ |
615 | interval_tm = beacon_int * 1024; | 623 | interval_tm = beacon_int * 1024; |
616 | rem = do_div(tsf, interval_tm); | 624 | rem = do_div(tsf, interval_tm); |
617 | priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); | 625 | priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); |
618 | 626 | ||
619 | spin_unlock_irqrestore(&priv->lock, flags); | 627 | spin_unlock_irqrestore(&priv->lock, flags); |
620 | IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", | 628 | IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", |
621 | le16_to_cpu(priv->rxon_timing.beacon_interval), | 629 | le16_to_cpu(priv->rxon_timing.beacon_interval), |
622 | le32_to_cpu(priv->rxon_timing.beacon_init_val), | 630 | le32_to_cpu(priv->rxon_timing.beacon_init_val), |
623 | le16_to_cpu(priv->rxon_timing.atim_window)); | 631 | le16_to_cpu(priv->rxon_timing.atim_window)); |
624 | } | 632 | } |
625 | 633 | ||
626 | static void iwl_set_flags_for_band(struct iwl_priv *priv, | 634 | static void iwl_set_flags_for_band(struct iwl_priv *priv, |
627 | enum ieee80211_band band) | 635 | enum ieee80211_band band) |
628 | { | 636 | { |
629 | if (band == IEEE80211_BAND_5GHZ) { | 637 | if (band == IEEE80211_BAND_5GHZ) { |
630 | priv->staging_rxon.flags &= | 638 | priv->staging_rxon.flags &= |
631 | ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | 639 | ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK |
632 | | RXON_FLG_CCK_MSK); | 640 | | RXON_FLG_CCK_MSK); |
633 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; | 641 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; |
634 | } else { | 642 | } else { |
635 | /* Copied from iwl_post_associate() */ | 643 | /* Copied from iwl_post_associate() */ |
636 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) | 644 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) |
637 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; | 645 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; |
638 | else | 646 | else |
639 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | 647 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; |
640 | 648 | ||
641 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) | 649 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) |
642 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | 650 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; |
643 | 651 | ||
644 | priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; | 652 | priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; |
645 | priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; | 653 | priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; |
646 | priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; | 654 | priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; |
647 | } | 655 | } |
648 | } | 656 | } |
649 | 657 | ||
650 | /* | 658 | /* |
651 | * initialize rxon structure with default values from eeprom | 659 | * initialize rxon structure with default values from eeprom |
652 | */ | 660 | */ |
653 | static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) | 661 | static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) |
654 | { | 662 | { |
655 | const struct iwl_channel_info *ch_info; | 663 | const struct iwl_channel_info *ch_info; |
656 | 664 | ||
657 | memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); | 665 | memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); |
658 | 666 | ||
659 | switch (mode) { | 667 | switch (mode) { |
660 | case NL80211_IFTYPE_AP: | 668 | case NL80211_IFTYPE_AP: |
661 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; | 669 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; |
662 | break; | 670 | break; |
663 | 671 | ||
664 | case NL80211_IFTYPE_STATION: | 672 | case NL80211_IFTYPE_STATION: |
665 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; | 673 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; |
666 | priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; | 674 | priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; |
667 | break; | 675 | break; |
668 | 676 | ||
669 | case NL80211_IFTYPE_ADHOC: | 677 | case NL80211_IFTYPE_ADHOC: |
670 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; | 678 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; |
671 | priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; | 679 | priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; |
672 | priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | | 680 | priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | |
673 | RXON_FILTER_ACCEPT_GRP_MSK; | 681 | RXON_FILTER_ACCEPT_GRP_MSK; |
674 | break; | 682 | break; |
675 | 683 | ||
676 | case NL80211_IFTYPE_MONITOR: | 684 | case NL80211_IFTYPE_MONITOR: |
677 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; | 685 | priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; |
678 | priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | | 686 | priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | |
679 | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; | 687 | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; |
680 | break; | 688 | break; |
681 | default: | 689 | default: |
682 | IWL_ERROR("Unsupported interface type %d\n", mode); | 690 | IWL_ERROR("Unsupported interface type %d\n", mode); |
683 | break; | 691 | break; |
684 | } | 692 | } |
685 | 693 | ||
686 | #if 0 | 694 | #if 0 |
687 | /* TODO: Figure out when short_preamble would be set and cache from | 695 | /* TODO: Figure out when short_preamble would be set and cache from |
688 | * that */ | 696 | * that */ |
689 | if (!hw_to_local(priv->hw)->short_preamble) | 697 | if (!hw_to_local(priv->hw)->short_preamble) |
690 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; | 698 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; |
691 | else | 699 | else |
692 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | 700 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; |
693 | #endif | 701 | #endif |
694 | 702 | ||
695 | ch_info = iwl_get_channel_info(priv, priv->band, | 703 | ch_info = iwl_get_channel_info(priv, priv->band, |
696 | le16_to_cpu(priv->active_rxon.channel)); | 704 | le16_to_cpu(priv->active_rxon.channel)); |
697 | 705 | ||
698 | if (!ch_info) | 706 | if (!ch_info) |
699 | ch_info = &priv->channel_info[0]; | 707 | ch_info = &priv->channel_info[0]; |
700 | 708 | ||
701 | /* | 709 | /* |
702 | * in some case A channels are all non IBSS | 710 | * in some case A channels are all non IBSS |
703 | * in this case force B/G channel | 711 | * in this case force B/G channel |
704 | */ | 712 | */ |
705 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | 713 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && |
706 | !(is_channel_ibss(ch_info))) | 714 | !(is_channel_ibss(ch_info))) |
707 | ch_info = &priv->channel_info[0]; | 715 | ch_info = &priv->channel_info[0]; |
708 | 716 | ||
709 | priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); | 717 | priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); |
710 | priv->band = ch_info->band; | 718 | priv->band = ch_info->band; |
711 | 719 | ||
712 | iwl_set_flags_for_band(priv, priv->band); | 720 | iwl_set_flags_for_band(priv, priv->band); |
713 | 721 | ||
714 | priv->staging_rxon.ofdm_basic_rates = | 722 | priv->staging_rxon.ofdm_basic_rates = |
715 | (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; | 723 | (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; |
716 | priv->staging_rxon.cck_basic_rates = | 724 | priv->staging_rxon.cck_basic_rates = |
717 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; | 725 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; |
718 | 726 | ||
719 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 727 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | |
720 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); | 728 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); |
721 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 729 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
722 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); | 730 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); |
723 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; | 731 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; |
724 | priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; | 732 | priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; |
725 | iwl_set_rxon_chain(priv); | 733 | iwl_set_rxon_chain(priv); |
726 | } | 734 | } |
727 | 735 | ||
728 | static int iwl_set_mode(struct iwl_priv *priv, int mode) | 736 | static int iwl_set_mode(struct iwl_priv *priv, int mode) |
729 | { | 737 | { |
730 | iwl_connection_init_rx_config(priv, mode); | 738 | iwl_connection_init_rx_config(priv, mode); |
731 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 739 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
732 | 740 | ||
733 | iwl_clear_stations_table(priv); | 741 | iwl_clear_stations_table(priv); |
734 | 742 | ||
735 | /* dont commit rxon if rf-kill is on*/ | 743 | /* dont commit rxon if rf-kill is on*/ |
736 | if (!iwl_is_ready_rf(priv)) | 744 | if (!iwl_is_ready_rf(priv)) |
737 | return -EAGAIN; | 745 | return -EAGAIN; |
738 | 746 | ||
739 | cancel_delayed_work(&priv->scan_check); | 747 | cancel_delayed_work(&priv->scan_check); |
740 | if (iwl_scan_cancel_timeout(priv, 100)) { | 748 | if (iwl_scan_cancel_timeout(priv, 100)) { |
741 | IWL_WARNING("Aborted scan still in progress after 100ms\n"); | 749 | IWL_WARNING("Aborted scan still in progress after 100ms\n"); |
742 | IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); | 750 | IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); |
743 | return -EAGAIN; | 751 | return -EAGAIN; |
744 | } | 752 | } |
745 | 753 | ||
746 | iwl_commit_rxon(priv); | 754 | iwl_commit_rxon(priv); |
747 | 755 | ||
748 | return 0; | 756 | return 0; |
749 | } | 757 | } |
750 | 758 | ||
751 | static void iwl_set_rate(struct iwl_priv *priv) | 759 | static void iwl_set_rate(struct iwl_priv *priv) |
752 | { | 760 | { |
753 | const struct ieee80211_supported_band *hw = NULL; | 761 | const struct ieee80211_supported_band *hw = NULL; |
754 | struct ieee80211_rate *rate; | 762 | struct ieee80211_rate *rate; |
755 | int i; | 763 | int i; |
756 | 764 | ||
757 | hw = iwl_get_hw_mode(priv, priv->band); | 765 | hw = iwl_get_hw_mode(priv, priv->band); |
758 | if (!hw) { | 766 | if (!hw) { |
759 | IWL_ERROR("Failed to set rate: unable to get hw mode\n"); | 767 | IWL_ERROR("Failed to set rate: unable to get hw mode\n"); |
760 | return; | 768 | return; |
761 | } | 769 | } |
762 | 770 | ||
763 | priv->active_rate = 0; | 771 | priv->active_rate = 0; |
764 | priv->active_rate_basic = 0; | 772 | priv->active_rate_basic = 0; |
765 | 773 | ||
766 | for (i = 0; i < hw->n_bitrates; i++) { | 774 | for (i = 0; i < hw->n_bitrates; i++) { |
767 | rate = &(hw->bitrates[i]); | 775 | rate = &(hw->bitrates[i]); |
768 | if (rate->hw_value < IWL_RATE_COUNT) | 776 | if (rate->hw_value < IWL_RATE_COUNT) |
769 | priv->active_rate |= (1 << rate->hw_value); | 777 | priv->active_rate |= (1 << rate->hw_value); |
770 | } | 778 | } |
771 | 779 | ||
772 | IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", | 780 | IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", |
773 | priv->active_rate, priv->active_rate_basic); | 781 | priv->active_rate, priv->active_rate_basic); |
774 | 782 | ||
775 | /* | 783 | /* |
776 | * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) | 784 | * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) |
777 | * otherwise set it to the default of all CCK rates and 6, 12, 24 for | 785 | * otherwise set it to the default of all CCK rates and 6, 12, 24 for |
778 | * OFDM | 786 | * OFDM |
779 | */ | 787 | */ |
780 | if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) | 788 | if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) |
781 | priv->staging_rxon.cck_basic_rates = | 789 | priv->staging_rxon.cck_basic_rates = |
782 | ((priv->active_rate_basic & | 790 | ((priv->active_rate_basic & |
783 | IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; | 791 | IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; |
784 | else | 792 | else |
785 | priv->staging_rxon.cck_basic_rates = | 793 | priv->staging_rxon.cck_basic_rates = |
786 | (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; | 794 | (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; |
787 | 795 | ||
788 | if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) | 796 | if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) |
789 | priv->staging_rxon.ofdm_basic_rates = | 797 | priv->staging_rxon.ofdm_basic_rates = |
790 | ((priv->active_rate_basic & | 798 | ((priv->active_rate_basic & |
791 | (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> | 799 | (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> |
792 | IWL_FIRST_OFDM_RATE) & 0xFF; | 800 | IWL_FIRST_OFDM_RATE) & 0xFF; |
793 | else | 801 | else |
794 | priv->staging_rxon.ofdm_basic_rates = | 802 | priv->staging_rxon.ofdm_basic_rates = |
795 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; | 803 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; |
796 | } | 804 | } |
797 | 805 | ||
798 | 806 | ||
799 | /****************************************************************************** | 807 | /****************************************************************************** |
800 | * | 808 | * |
801 | * Generic RX handler implementations | 809 | * Generic RX handler implementations |
802 | * | 810 | * |
803 | ******************************************************************************/ | 811 | ******************************************************************************/ |
804 | static void iwl_rx_reply_alive(struct iwl_priv *priv, | 812 | static void iwl_rx_reply_alive(struct iwl_priv *priv, |
805 | struct iwl_rx_mem_buffer *rxb) | 813 | struct iwl_rx_mem_buffer *rxb) |
806 | { | 814 | { |
807 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 815 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
808 | struct iwl_alive_resp *palive; | 816 | struct iwl_alive_resp *palive; |
809 | struct delayed_work *pwork; | 817 | struct delayed_work *pwork; |
810 | 818 | ||
811 | palive = &pkt->u.alive_frame; | 819 | palive = &pkt->u.alive_frame; |
812 | 820 | ||
813 | IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " | 821 | IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " |
814 | "0x%01X 0x%01X\n", | 822 | "0x%01X 0x%01X\n", |
815 | palive->is_valid, palive->ver_type, | 823 | palive->is_valid, palive->ver_type, |
816 | palive->ver_subtype); | 824 | palive->ver_subtype); |
817 | 825 | ||
818 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { | 826 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { |
819 | IWL_DEBUG_INFO("Initialization Alive received.\n"); | 827 | IWL_DEBUG_INFO("Initialization Alive received.\n"); |
820 | memcpy(&priv->card_alive_init, | 828 | memcpy(&priv->card_alive_init, |
821 | &pkt->u.alive_frame, | 829 | &pkt->u.alive_frame, |
822 | sizeof(struct iwl_init_alive_resp)); | 830 | sizeof(struct iwl_init_alive_resp)); |
823 | pwork = &priv->init_alive_start; | 831 | pwork = &priv->init_alive_start; |
824 | } else { | 832 | } else { |
825 | IWL_DEBUG_INFO("Runtime Alive received.\n"); | 833 | IWL_DEBUG_INFO("Runtime Alive received.\n"); |
826 | memcpy(&priv->card_alive, &pkt->u.alive_frame, | 834 | memcpy(&priv->card_alive, &pkt->u.alive_frame, |
827 | sizeof(struct iwl_alive_resp)); | 835 | sizeof(struct iwl_alive_resp)); |
828 | pwork = &priv->alive_start; | 836 | pwork = &priv->alive_start; |
829 | } | 837 | } |
830 | 838 | ||
831 | /* We delay the ALIVE response by 5ms to | 839 | /* We delay the ALIVE response by 5ms to |
832 | * give the HW RF Kill time to activate... */ | 840 | * give the HW RF Kill time to activate... */ |
833 | if (palive->is_valid == UCODE_VALID_OK) | 841 | if (palive->is_valid == UCODE_VALID_OK) |
834 | queue_delayed_work(priv->workqueue, pwork, | 842 | queue_delayed_work(priv->workqueue, pwork, |
835 | msecs_to_jiffies(5)); | 843 | msecs_to_jiffies(5)); |
836 | else | 844 | else |
837 | IWL_WARNING("uCode did not respond OK.\n"); | 845 | IWL_WARNING("uCode did not respond OK.\n"); |
838 | } | 846 | } |
839 | 847 | ||
840 | static void iwl_rx_reply_error(struct iwl_priv *priv, | 848 | static void iwl_rx_reply_error(struct iwl_priv *priv, |
841 | struct iwl_rx_mem_buffer *rxb) | 849 | struct iwl_rx_mem_buffer *rxb) |
842 | { | 850 | { |
843 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 851 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
844 | 852 | ||
845 | IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " | 853 | IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " |
846 | "seq 0x%04X ser 0x%08X\n", | 854 | "seq 0x%04X ser 0x%08X\n", |
847 | le32_to_cpu(pkt->u.err_resp.error_type), | 855 | le32_to_cpu(pkt->u.err_resp.error_type), |
848 | get_cmd_string(pkt->u.err_resp.cmd_id), | 856 | get_cmd_string(pkt->u.err_resp.cmd_id), |
849 | pkt->u.err_resp.cmd_id, | 857 | pkt->u.err_resp.cmd_id, |
850 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | 858 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), |
851 | le32_to_cpu(pkt->u.err_resp.error_info)); | 859 | le32_to_cpu(pkt->u.err_resp.error_info)); |
852 | } | 860 | } |
853 | 861 | ||
854 | #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x | 862 | #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x |
855 | 863 | ||
856 | static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | 864 | static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) |
857 | { | 865 | { |
858 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 866 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
859 | struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; | 867 | struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; |
860 | struct iwl_csa_notification *csa = &(pkt->u.csa_notif); | 868 | struct iwl_csa_notification *csa = &(pkt->u.csa_notif); |
861 | IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", | 869 | IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", |
862 | le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); | 870 | le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); |
863 | rxon->channel = csa->channel; | 871 | rxon->channel = csa->channel; |
864 | priv->staging_rxon.channel = csa->channel; | 872 | priv->staging_rxon.channel = csa->channel; |
865 | } | 873 | } |
866 | 874 | ||
867 | static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, | 875 | static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, |
868 | struct iwl_rx_mem_buffer *rxb) | 876 | struct iwl_rx_mem_buffer *rxb) |
869 | { | 877 | { |
870 | #ifdef CONFIG_IWLWIFI_DEBUG | 878 | #ifdef CONFIG_IWLWIFI_DEBUG |
871 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 879 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
872 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); | 880 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); |
873 | IWL_DEBUG_RX("sleep mode: %d, src: %d\n", | 881 | IWL_DEBUG_RX("sleep mode: %d, src: %d\n", |
874 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); | 882 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); |
875 | #endif | 883 | #endif |
876 | } | 884 | } |
877 | 885 | ||
878 | static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | 886 | static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, |
879 | struct iwl_rx_mem_buffer *rxb) | 887 | struct iwl_rx_mem_buffer *rxb) |
880 | { | 888 | { |
881 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 889 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
882 | IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " | 890 | IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " |
883 | "notification for %s:\n", | 891 | "notification for %s:\n", |
884 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); | 892 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); |
885 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); | 893 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); |
886 | } | 894 | } |
887 | 895 | ||
888 | static void iwl_bg_beacon_update(struct work_struct *work) | 896 | static void iwl_bg_beacon_update(struct work_struct *work) |
889 | { | 897 | { |
890 | struct iwl_priv *priv = | 898 | struct iwl_priv *priv = |
891 | container_of(work, struct iwl_priv, beacon_update); | 899 | container_of(work, struct iwl_priv, beacon_update); |
892 | struct sk_buff *beacon; | 900 | struct sk_buff *beacon; |
893 | 901 | ||
894 | /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ | 902 | /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ |
895 | beacon = ieee80211_beacon_get(priv->hw, priv->vif); | 903 | beacon = ieee80211_beacon_get(priv->hw, priv->vif); |
896 | 904 | ||
897 | if (!beacon) { | 905 | if (!beacon) { |
898 | IWL_ERROR("update beacon failed\n"); | 906 | IWL_ERROR("update beacon failed\n"); |
899 | return; | 907 | return; |
900 | } | 908 | } |
901 | 909 | ||
902 | mutex_lock(&priv->mutex); | 910 | mutex_lock(&priv->mutex); |
903 | /* new beacon skb is allocated every time; dispose previous.*/ | 911 | /* new beacon skb is allocated every time; dispose previous.*/ |
904 | if (priv->ibss_beacon) | 912 | if (priv->ibss_beacon) |
905 | dev_kfree_skb(priv->ibss_beacon); | 913 | dev_kfree_skb(priv->ibss_beacon); |
906 | 914 | ||
907 | priv->ibss_beacon = beacon; | 915 | priv->ibss_beacon = beacon; |
908 | mutex_unlock(&priv->mutex); | 916 | mutex_unlock(&priv->mutex); |
909 | 917 | ||
910 | iwl_send_beacon_cmd(priv); | 918 | iwl_send_beacon_cmd(priv); |
911 | } | 919 | } |
912 | 920 | ||
913 | /** | 921 | /** |
914 | * iwl_bg_statistics_periodic - Timer callback to queue statistics | 922 | * iwl_bg_statistics_periodic - Timer callback to queue statistics |
915 | * | 923 | * |
916 | * This callback is provided in order to send a statistics request. | 924 | * This callback is provided in order to send a statistics request. |
917 | * | 925 | * |
918 | * This timer function is continually reset to execute within | 926 | * This timer function is continually reset to execute within |
919 | * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION | 927 | * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION |
920 | * was received. We need to ensure we receive the statistics in order | 928 | * was received. We need to ensure we receive the statistics in order |
921 | * to update the temperature used for calibrating the TXPOWER. | 929 | * to update the temperature used for calibrating the TXPOWER. |
922 | */ | 930 | */ |
923 | static void iwl_bg_statistics_periodic(unsigned long data) | 931 | static void iwl_bg_statistics_periodic(unsigned long data) |
924 | { | 932 | { |
925 | struct iwl_priv *priv = (struct iwl_priv *)data; | 933 | struct iwl_priv *priv = (struct iwl_priv *)data; |
926 | 934 | ||
927 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 935 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
928 | return; | 936 | return; |
929 | 937 | ||
930 | /* dont send host command if rf-kill is on */ | 938 | /* dont send host command if rf-kill is on */ |
931 | if (!iwl_is_ready_rf(priv)) | 939 | if (!iwl_is_ready_rf(priv)) |
932 | return; | 940 | return; |
933 | 941 | ||
934 | iwl_send_statistics_request(priv, CMD_ASYNC); | 942 | iwl_send_statistics_request(priv, CMD_ASYNC); |
935 | } | 943 | } |
936 | 944 | ||
937 | static void iwl_rx_beacon_notif(struct iwl_priv *priv, | 945 | static void iwl_rx_beacon_notif(struct iwl_priv *priv, |
938 | struct iwl_rx_mem_buffer *rxb) | 946 | struct iwl_rx_mem_buffer *rxb) |
939 | { | 947 | { |
940 | #ifdef CONFIG_IWLWIFI_DEBUG | 948 | #ifdef CONFIG_IWLWIFI_DEBUG |
941 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 949 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
942 | struct iwl4965_beacon_notif *beacon = | 950 | struct iwl4965_beacon_notif *beacon = |
943 | (struct iwl4965_beacon_notif *)pkt->u.raw; | 951 | (struct iwl4965_beacon_notif *)pkt->u.raw; |
944 | u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); | 952 | u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); |
945 | 953 | ||
946 | IWL_DEBUG_RX("beacon status %x retries %d iss %d " | 954 | IWL_DEBUG_RX("beacon status %x retries %d iss %d " |
947 | "tsf %d %d rate %d\n", | 955 | "tsf %d %d rate %d\n", |
948 | le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, | 956 | le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, |
949 | beacon->beacon_notify_hdr.failure_frame, | 957 | beacon->beacon_notify_hdr.failure_frame, |
950 | le32_to_cpu(beacon->ibss_mgr_status), | 958 | le32_to_cpu(beacon->ibss_mgr_status), |
951 | le32_to_cpu(beacon->high_tsf), | 959 | le32_to_cpu(beacon->high_tsf), |
952 | le32_to_cpu(beacon->low_tsf), rate); | 960 | le32_to_cpu(beacon->low_tsf), rate); |
953 | #endif | 961 | #endif |
954 | 962 | ||
955 | if ((priv->iw_mode == NL80211_IFTYPE_AP) && | 963 | if ((priv->iw_mode == NL80211_IFTYPE_AP) && |
956 | (!test_bit(STATUS_EXIT_PENDING, &priv->status))) | 964 | (!test_bit(STATUS_EXIT_PENDING, &priv->status))) |
957 | queue_work(priv->workqueue, &priv->beacon_update); | 965 | queue_work(priv->workqueue, &priv->beacon_update); |
958 | } | 966 | } |
959 | 967 | ||
960 | /* Handle notification from uCode that card's power state is changing | 968 | /* Handle notification from uCode that card's power state is changing |
961 | * due to software, hardware, or critical temperature RFKILL */ | 969 | * due to software, hardware, or critical temperature RFKILL */ |
962 | static void iwl_rx_card_state_notif(struct iwl_priv *priv, | 970 | static void iwl_rx_card_state_notif(struct iwl_priv *priv, |
963 | struct iwl_rx_mem_buffer *rxb) | 971 | struct iwl_rx_mem_buffer *rxb) |
964 | { | 972 | { |
965 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 973 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
966 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); | 974 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); |
967 | unsigned long status = priv->status; | 975 | unsigned long status = priv->status; |
968 | 976 | ||
969 | IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", | 977 | IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", |
970 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", | 978 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", |
971 | (flags & SW_CARD_DISABLED) ? "Kill" : "On"); | 979 | (flags & SW_CARD_DISABLED) ? "Kill" : "On"); |
972 | 980 | ||
973 | if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | | 981 | if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | |
974 | RF_CARD_DISABLED)) { | 982 | RF_CARD_DISABLED)) { |
975 | 983 | ||
976 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | 984 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, |
977 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 985 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
978 | 986 | ||
979 | if (!iwl_grab_nic_access(priv)) { | 987 | if (!iwl_grab_nic_access(priv)) { |
980 | iwl_write_direct32( | 988 | iwl_write_direct32( |
981 | priv, HBUS_TARG_MBX_C, | 989 | priv, HBUS_TARG_MBX_C, |
982 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | 990 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); |
983 | 991 | ||
984 | iwl_release_nic_access(priv); | 992 | iwl_release_nic_access(priv); |
985 | } | 993 | } |
986 | 994 | ||
987 | if (!(flags & RXON_CARD_DISABLED)) { | 995 | if (!(flags & RXON_CARD_DISABLED)) { |
988 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 996 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
989 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 997 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
990 | if (!iwl_grab_nic_access(priv)) { | 998 | if (!iwl_grab_nic_access(priv)) { |
991 | iwl_write_direct32( | 999 | iwl_write_direct32( |
992 | priv, HBUS_TARG_MBX_C, | 1000 | priv, HBUS_TARG_MBX_C, |
993 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | 1001 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); |
994 | 1002 | ||
995 | iwl_release_nic_access(priv); | 1003 | iwl_release_nic_access(priv); |
996 | } | 1004 | } |
997 | } | 1005 | } |
998 | 1006 | ||
999 | if (flags & RF_CARD_DISABLED) { | 1007 | if (flags & RF_CARD_DISABLED) { |
1000 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | 1008 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, |
1001 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 1009 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
1002 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | 1010 | iwl_read32(priv, CSR_UCODE_DRV_GP1); |
1003 | if (!iwl_grab_nic_access(priv)) | 1011 | if (!iwl_grab_nic_access(priv)) |
1004 | iwl_release_nic_access(priv); | 1012 | iwl_release_nic_access(priv); |
1005 | } | 1013 | } |
1006 | } | 1014 | } |
1007 | 1015 | ||
1008 | if (flags & HW_CARD_DISABLED) | 1016 | if (flags & HW_CARD_DISABLED) |
1009 | set_bit(STATUS_RF_KILL_HW, &priv->status); | 1017 | set_bit(STATUS_RF_KILL_HW, &priv->status); |
1010 | else | 1018 | else |
1011 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 1019 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
1012 | 1020 | ||
1013 | 1021 | ||
1014 | if (flags & SW_CARD_DISABLED) | 1022 | if (flags & SW_CARD_DISABLED) |
1015 | set_bit(STATUS_RF_KILL_SW, &priv->status); | 1023 | set_bit(STATUS_RF_KILL_SW, &priv->status); |
1016 | else | 1024 | else |
1017 | clear_bit(STATUS_RF_KILL_SW, &priv->status); | 1025 | clear_bit(STATUS_RF_KILL_SW, &priv->status); |
1018 | 1026 | ||
1019 | if (!(flags & RXON_CARD_DISABLED)) | 1027 | if (!(flags & RXON_CARD_DISABLED)) |
1020 | iwl_scan_cancel(priv); | 1028 | iwl_scan_cancel(priv); |
1021 | 1029 | ||
1022 | if ((test_bit(STATUS_RF_KILL_HW, &status) != | 1030 | if ((test_bit(STATUS_RF_KILL_HW, &status) != |
1023 | test_bit(STATUS_RF_KILL_HW, &priv->status)) || | 1031 | test_bit(STATUS_RF_KILL_HW, &priv->status)) || |
1024 | (test_bit(STATUS_RF_KILL_SW, &status) != | 1032 | (test_bit(STATUS_RF_KILL_SW, &status) != |
1025 | test_bit(STATUS_RF_KILL_SW, &priv->status))) | 1033 | test_bit(STATUS_RF_KILL_SW, &priv->status))) |
1026 | queue_work(priv->workqueue, &priv->rf_kill); | 1034 | queue_work(priv->workqueue, &priv->rf_kill); |
1027 | else | 1035 | else |
1028 | wake_up_interruptible(&priv->wait_command_queue); | 1036 | wake_up_interruptible(&priv->wait_command_queue); |
1029 | } | 1037 | } |
1030 | 1038 | ||
1031 | int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) | 1039 | int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) |
1032 | { | 1040 | { |
1033 | int ret; | 1041 | int ret; |
1034 | unsigned long flags; | 1042 | unsigned long flags; |
1035 | 1043 | ||
1036 | spin_lock_irqsave(&priv->lock, flags); | 1044 | spin_lock_irqsave(&priv->lock, flags); |
1037 | ret = iwl_grab_nic_access(priv); | 1045 | ret = iwl_grab_nic_access(priv); |
1038 | if (ret) | 1046 | if (ret) |
1039 | goto err; | 1047 | goto err; |
1040 | 1048 | ||
1041 | if (src == IWL_PWR_SRC_VAUX) { | 1049 | if (src == IWL_PWR_SRC_VAUX) { |
1042 | u32 val; | 1050 | u32 val; |
1043 | ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE, | 1051 | ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE, |
1044 | &val); | 1052 | &val); |
1045 | 1053 | ||
1046 | if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) | 1054 | if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) |
1047 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 1055 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
1048 | APMG_PS_CTRL_VAL_PWR_SRC_VAUX, | 1056 | APMG_PS_CTRL_VAL_PWR_SRC_VAUX, |
1049 | ~APMG_PS_CTRL_MSK_PWR_SRC); | 1057 | ~APMG_PS_CTRL_MSK_PWR_SRC); |
1050 | } else { | 1058 | } else { |
1051 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 1059 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
1052 | APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, | 1060 | APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, |
1053 | ~APMG_PS_CTRL_MSK_PWR_SRC); | 1061 | ~APMG_PS_CTRL_MSK_PWR_SRC); |
1054 | } | 1062 | } |
1055 | 1063 | ||
1056 | iwl_release_nic_access(priv); | 1064 | iwl_release_nic_access(priv); |
1057 | err: | 1065 | err: |
1058 | spin_unlock_irqrestore(&priv->lock, flags); | 1066 | spin_unlock_irqrestore(&priv->lock, flags); |
1059 | return ret; | 1067 | return ret; |
1060 | } | 1068 | } |
1061 | 1069 | ||
1062 | /** | 1070 | /** |
1063 | * iwl_setup_rx_handlers - Initialize Rx handler callbacks | 1071 | * iwl_setup_rx_handlers - Initialize Rx handler callbacks |
1064 | * | 1072 | * |
1065 | * Setup the RX handlers for each of the reply types sent from the uCode | 1073 | * Setup the RX handlers for each of the reply types sent from the uCode |
1066 | * to the host. | 1074 | * to the host. |
1067 | * | 1075 | * |
1068 | * This function chains into the hardware specific files for them to setup | 1076 | * This function chains into the hardware specific files for them to setup |
1069 | * any hardware specific handlers as well. | 1077 | * any hardware specific handlers as well. |
1070 | */ | 1078 | */ |
1071 | static void iwl_setup_rx_handlers(struct iwl_priv *priv) | 1079 | static void iwl_setup_rx_handlers(struct iwl_priv *priv) |
1072 | { | 1080 | { |
1073 | priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; | 1081 | priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; |
1074 | priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; | 1082 | priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; |
1075 | priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; | 1083 | priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; |
1076 | priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; | 1084 | priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; |
1077 | priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = | 1085 | priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = |
1078 | iwl_rx_pm_debug_statistics_notif; | 1086 | iwl_rx_pm_debug_statistics_notif; |
1079 | priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; | 1087 | priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; |
1080 | 1088 | ||
1081 | /* | 1089 | /* |
1082 | * The same handler is used for both the REPLY to a discrete | 1090 | * The same handler is used for both the REPLY to a discrete |
1083 | * statistics request from the host as well as for the periodic | 1091 | * statistics request from the host as well as for the periodic |
1084 | * statistics notifications (after received beacons) from the uCode. | 1092 | * statistics notifications (after received beacons) from the uCode. |
1085 | */ | 1093 | */ |
1086 | priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; | 1094 | priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; |
1087 | priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; | 1095 | priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; |
1088 | 1096 | ||
1089 | iwl_setup_spectrum_handlers(priv); | 1097 | iwl_setup_spectrum_handlers(priv); |
1090 | iwl_setup_rx_scan_handlers(priv); | 1098 | iwl_setup_rx_scan_handlers(priv); |
1091 | 1099 | ||
1092 | /* status change handler */ | 1100 | /* status change handler */ |
1093 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; | 1101 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; |
1094 | 1102 | ||
1095 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = | 1103 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = |
1096 | iwl_rx_missed_beacon_notif; | 1104 | iwl_rx_missed_beacon_notif; |
1097 | /* Rx handlers */ | 1105 | /* Rx handlers */ |
1098 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; | 1106 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; |
1099 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; | 1107 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; |
1100 | /* block ack */ | 1108 | /* block ack */ |
1101 | priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; | 1109 | priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; |
1102 | /* Set up hardware specific Rx handlers */ | 1110 | /* Set up hardware specific Rx handlers */ |
1103 | priv->cfg->ops->lib->rx_handler_setup(priv); | 1111 | priv->cfg->ops->lib->rx_handler_setup(priv); |
1104 | } | 1112 | } |
1105 | 1113 | ||
1106 | /* | 1114 | /* |
1107 | * this should be called while priv->lock is locked | 1115 | * this should be called while priv->lock is locked |
1108 | */ | 1116 | */ |
1109 | static void __iwl_rx_replenish(struct iwl_priv *priv) | 1117 | static void __iwl_rx_replenish(struct iwl_priv *priv) |
1110 | { | 1118 | { |
1111 | iwl_rx_allocate(priv); | 1119 | iwl_rx_allocate(priv); |
1112 | iwl_rx_queue_restock(priv); | 1120 | iwl_rx_queue_restock(priv); |
1113 | } | 1121 | } |
1114 | 1122 | ||
1115 | 1123 | ||
1116 | /** | 1124 | /** |
1117 | * iwl_rx_handle - Main entry function for receiving responses from uCode | 1125 | * iwl_rx_handle - Main entry function for receiving responses from uCode |
1118 | * | 1126 | * |
1119 | * Uses the priv->rx_handlers callback function array to invoke | 1127 | * Uses the priv->rx_handlers callback function array to invoke |
1120 | * the appropriate handlers, including command responses, | 1128 | * the appropriate handlers, including command responses, |
1121 | * frame-received notifications, and other notifications. | 1129 | * frame-received notifications, and other notifications. |
1122 | */ | 1130 | */ |
1123 | void iwl_rx_handle(struct iwl_priv *priv) | 1131 | void iwl_rx_handle(struct iwl_priv *priv) |
1124 | { | 1132 | { |
1125 | struct iwl_rx_mem_buffer *rxb; | 1133 | struct iwl_rx_mem_buffer *rxb; |
1126 | struct iwl_rx_packet *pkt; | 1134 | struct iwl_rx_packet *pkt; |
1127 | struct iwl_rx_queue *rxq = &priv->rxq; | 1135 | struct iwl_rx_queue *rxq = &priv->rxq; |
1128 | u32 r, i; | 1136 | u32 r, i; |
1129 | int reclaim; | 1137 | int reclaim; |
1130 | unsigned long flags; | 1138 | unsigned long flags; |
1131 | u8 fill_rx = 0; | 1139 | u8 fill_rx = 0; |
1132 | u32 count = 8; | 1140 | u32 count = 8; |
1133 | 1141 | ||
1134 | /* uCode's read index (stored in shared DRAM) indicates the last Rx | 1142 | /* uCode's read index (stored in shared DRAM) indicates the last Rx |
1135 | * buffer that the driver may process (last buffer filled by ucode). */ | 1143 | * buffer that the driver may process (last buffer filled by ucode). */ |
1136 | r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; | 1144 | r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; |
1137 | i = rxq->read; | 1145 | i = rxq->read; |
1138 | 1146 | ||
1139 | /* Rx interrupt, but nothing sent from uCode */ | 1147 | /* Rx interrupt, but nothing sent from uCode */ |
1140 | if (i == r) | 1148 | if (i == r) |
1141 | IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); | 1149 | IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); |
1142 | 1150 | ||
1143 | if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) | 1151 | if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) |
1144 | fill_rx = 1; | 1152 | fill_rx = 1; |
1145 | 1153 | ||
1146 | while (i != r) { | 1154 | while (i != r) { |
1147 | rxb = rxq->queue[i]; | 1155 | rxb = rxq->queue[i]; |
1148 | 1156 | ||
1149 | /* If an RXB doesn't have a Rx queue slot associated with it, | 1157 | /* If an RXB doesn't have a Rx queue slot associated with it, |
1150 | * then a bug has been introduced in the queue refilling | 1158 | * then a bug has been introduced in the queue refilling |
1151 | * routines -- catch it here */ | 1159 | * routines -- catch it here */ |
1152 | BUG_ON(rxb == NULL); | 1160 | BUG_ON(rxb == NULL); |
1153 | 1161 | ||
1154 | rxq->queue[i] = NULL; | 1162 | rxq->queue[i] = NULL; |
1155 | 1163 | ||
1156 | dma_sync_single_range_for_cpu( | 1164 | dma_sync_single_range_for_cpu( |
1157 | &priv->pci_dev->dev, rxb->real_dma_addr, | 1165 | &priv->pci_dev->dev, rxb->real_dma_addr, |
1158 | rxb->aligned_dma_addr - rxb->real_dma_addr, | 1166 | rxb->aligned_dma_addr - rxb->real_dma_addr, |
1159 | priv->hw_params.rx_buf_size, | 1167 | priv->hw_params.rx_buf_size, |
1160 | PCI_DMA_FROMDEVICE); | 1168 | PCI_DMA_FROMDEVICE); |
1161 | pkt = (struct iwl_rx_packet *)rxb->skb->data; | 1169 | pkt = (struct iwl_rx_packet *)rxb->skb->data; |
1162 | 1170 | ||
1163 | /* Reclaim a command buffer only if this packet is a response | 1171 | /* Reclaim a command buffer only if this packet is a response |
1164 | * to a (driver-originated) command. | 1172 | * to a (driver-originated) command. |
1165 | * If the packet (e.g. Rx frame) originated from uCode, | 1173 | * If the packet (e.g. Rx frame) originated from uCode, |
1166 | * there is no command buffer to reclaim. | 1174 | * there is no command buffer to reclaim. |
1167 | * Ucode should set SEQ_RX_FRAME bit if ucode-originated, | 1175 | * Ucode should set SEQ_RX_FRAME bit if ucode-originated, |
1168 | * but apparently a few don't get set; catch them here. */ | 1176 | * but apparently a few don't get set; catch them here. */ |
1169 | reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && | 1177 | reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && |
1170 | (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && | 1178 | (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && |
1171 | (pkt->hdr.cmd != REPLY_RX) && | 1179 | (pkt->hdr.cmd != REPLY_RX) && |
1172 | (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && | 1180 | (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && |
1173 | (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && | 1181 | (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && |
1174 | (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && | 1182 | (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && |
1175 | (pkt->hdr.cmd != REPLY_TX); | 1183 | (pkt->hdr.cmd != REPLY_TX); |
1176 | 1184 | ||
1177 | /* Based on type of command response or notification, | 1185 | /* Based on type of command response or notification, |
1178 | * handle those that need handling via function in | 1186 | * handle those that need handling via function in |
1179 | * rx_handlers table. See iwl_setup_rx_handlers() */ | 1187 | * rx_handlers table. See iwl_setup_rx_handlers() */ |
1180 | if (priv->rx_handlers[pkt->hdr.cmd]) { | 1188 | if (priv->rx_handlers[pkt->hdr.cmd]) { |
1181 | IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, | 1189 | IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, |
1182 | i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); | 1190 | i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); |
1183 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | 1191 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); |
1184 | } else { | 1192 | } else { |
1185 | /* No handling needed */ | 1193 | /* No handling needed */ |
1186 | IWL_DEBUG(IWL_DL_RX, | 1194 | IWL_DEBUG(IWL_DL_RX, |
1187 | "r %d i %d No handler needed for %s, 0x%02x\n", | 1195 | "r %d i %d No handler needed for %s, 0x%02x\n", |
1188 | r, i, get_cmd_string(pkt->hdr.cmd), | 1196 | r, i, get_cmd_string(pkt->hdr.cmd), |
1189 | pkt->hdr.cmd); | 1197 | pkt->hdr.cmd); |
1190 | } | 1198 | } |
1191 | 1199 | ||
1192 | if (reclaim) { | 1200 | if (reclaim) { |
1193 | /* Invoke any callbacks, transfer the skb to caller, and | 1201 | /* Invoke any callbacks, transfer the skb to caller, and |
1194 | * fire off the (possibly) blocking iwl_send_cmd() | 1202 | * fire off the (possibly) blocking iwl_send_cmd() |
1195 | * as we reclaim the driver command queue */ | 1203 | * as we reclaim the driver command queue */ |
1196 | if (rxb && rxb->skb) | 1204 | if (rxb && rxb->skb) |
1197 | iwl_tx_cmd_complete(priv, rxb); | 1205 | iwl_tx_cmd_complete(priv, rxb); |
1198 | else | 1206 | else |
1199 | IWL_WARNING("Claim null rxb?\n"); | 1207 | IWL_WARNING("Claim null rxb?\n"); |
1200 | } | 1208 | } |
1201 | 1209 | ||
1202 | /* For now we just don't re-use anything. We can tweak this | 1210 | /* For now we just don't re-use anything. We can tweak this |
1203 | * later to try and re-use notification packets and SKBs that | 1211 | * later to try and re-use notification packets and SKBs that |
1204 | * fail to Rx correctly */ | 1212 | * fail to Rx correctly */ |
1205 | if (rxb->skb != NULL) { | 1213 | if (rxb->skb != NULL) { |
1206 | priv->alloc_rxb_skb--; | 1214 | priv->alloc_rxb_skb--; |
1207 | dev_kfree_skb_any(rxb->skb); | 1215 | dev_kfree_skb_any(rxb->skb); |
1208 | rxb->skb = NULL; | 1216 | rxb->skb = NULL; |
1209 | } | 1217 | } |
1210 | 1218 | ||
1211 | pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, | 1219 | pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, |
1212 | priv->hw_params.rx_buf_size + 256, | 1220 | priv->hw_params.rx_buf_size + 256, |
1213 | PCI_DMA_FROMDEVICE); | 1221 | PCI_DMA_FROMDEVICE); |
1214 | spin_lock_irqsave(&rxq->lock, flags); | 1222 | spin_lock_irqsave(&rxq->lock, flags); |
1215 | list_add_tail(&rxb->list, &priv->rxq.rx_used); | 1223 | list_add_tail(&rxb->list, &priv->rxq.rx_used); |
1216 | spin_unlock_irqrestore(&rxq->lock, flags); | 1224 | spin_unlock_irqrestore(&rxq->lock, flags); |
1217 | i = (i + 1) & RX_QUEUE_MASK; | 1225 | i = (i + 1) & RX_QUEUE_MASK; |
1218 | /* If there are a lot of unused frames, | 1226 | /* If there are a lot of unused frames, |
1219 | * restock the Rx queue so ucode wont assert. */ | 1227 | * restock the Rx queue so ucode wont assert. */ |
1220 | if (fill_rx) { | 1228 | if (fill_rx) { |
1221 | count++; | 1229 | count++; |
1222 | if (count >= 8) { | 1230 | if (count >= 8) { |
1223 | priv->rxq.read = i; | 1231 | priv->rxq.read = i; |
1224 | __iwl_rx_replenish(priv); | 1232 | __iwl_rx_replenish(priv); |
1225 | count = 0; | 1233 | count = 0; |
1226 | } | 1234 | } |
1227 | } | 1235 | } |
1228 | } | 1236 | } |
1229 | 1237 | ||
1230 | /* Backtrack one entry */ | 1238 | /* Backtrack one entry */ |
1231 | priv->rxq.read = i; | 1239 | priv->rxq.read = i; |
1232 | iwl_rx_queue_restock(priv); | 1240 | iwl_rx_queue_restock(priv); |
1233 | } | 1241 | } |
1234 | 1242 | ||
1235 | #ifdef CONFIG_IWLWIFI_DEBUG | 1243 | #ifdef CONFIG_IWLWIFI_DEBUG |
1236 | static void iwl_print_rx_config_cmd(struct iwl_priv *priv) | 1244 | static void iwl_print_rx_config_cmd(struct iwl_priv *priv) |
1237 | { | 1245 | { |
1238 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 1246 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
1239 | 1247 | ||
1240 | IWL_DEBUG_RADIO("RX CONFIG:\n"); | 1248 | IWL_DEBUG_RADIO("RX CONFIG:\n"); |
1241 | iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); | 1249 | iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); |
1242 | IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); | 1250 | IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); |
1243 | IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); | 1251 | IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); |
1244 | IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", | 1252 | IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", |
1245 | le32_to_cpu(rxon->filter_flags)); | 1253 | le32_to_cpu(rxon->filter_flags)); |
1246 | IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); | 1254 | IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); |
1247 | IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", | 1255 | IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", |
1248 | rxon->ofdm_basic_rates); | 1256 | rxon->ofdm_basic_rates); |
1249 | IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); | 1257 | IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); |
1250 | IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); | 1258 | IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); |
1251 | IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); | 1259 | IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); |
1252 | IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); | 1260 | IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); |
1253 | } | 1261 | } |
1254 | #endif | 1262 | #endif |
1255 | 1263 | ||
1256 | /* call this function to flush any scheduled tasklet */ | 1264 | /* call this function to flush any scheduled tasklet */ |
1257 | static inline void iwl_synchronize_irq(struct iwl_priv *priv) | 1265 | static inline void iwl_synchronize_irq(struct iwl_priv *priv) |
1258 | { | 1266 | { |
1259 | /* wait to make sure we flush pending tasklet*/ | 1267 | /* wait to make sure we flush pending tasklet*/ |
1260 | synchronize_irq(priv->pci_dev->irq); | 1268 | synchronize_irq(priv->pci_dev->irq); |
1261 | tasklet_kill(&priv->irq_tasklet); | 1269 | tasklet_kill(&priv->irq_tasklet); |
1262 | } | 1270 | } |
1263 | 1271 | ||
1264 | /** | 1272 | /** |
1265 | * iwl_irq_handle_error - called for HW or SW error interrupt from card | 1273 | * iwl_irq_handle_error - called for HW or SW error interrupt from card |
1266 | */ | 1274 | */ |
1267 | static void iwl_irq_handle_error(struct iwl_priv *priv) | 1275 | static void iwl_irq_handle_error(struct iwl_priv *priv) |
1268 | { | 1276 | { |
1269 | /* Set the FW error flag -- cleared on iwl_down */ | 1277 | /* Set the FW error flag -- cleared on iwl_down */ |
1270 | set_bit(STATUS_FW_ERROR, &priv->status); | 1278 | set_bit(STATUS_FW_ERROR, &priv->status); |
1271 | 1279 | ||
1272 | /* Cancel currently queued command. */ | 1280 | /* Cancel currently queued command. */ |
1273 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 1281 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
1274 | 1282 | ||
1275 | #ifdef CONFIG_IWLWIFI_DEBUG | 1283 | #ifdef CONFIG_IWLWIFI_DEBUG |
1276 | if (priv->debug_level & IWL_DL_FW_ERRORS) { | 1284 | if (priv->debug_level & IWL_DL_FW_ERRORS) { |
1277 | iwl_dump_nic_error_log(priv); | 1285 | iwl_dump_nic_error_log(priv); |
1278 | iwl_dump_nic_event_log(priv); | 1286 | iwl_dump_nic_event_log(priv); |
1279 | iwl_print_rx_config_cmd(priv); | 1287 | iwl_print_rx_config_cmd(priv); |
1280 | } | 1288 | } |
1281 | #endif | 1289 | #endif |
1282 | 1290 | ||
1283 | wake_up_interruptible(&priv->wait_command_queue); | 1291 | wake_up_interruptible(&priv->wait_command_queue); |
1284 | 1292 | ||
1285 | /* Keep the restart process from trying to send host | 1293 | /* Keep the restart process from trying to send host |
1286 | * commands by clearing the INIT status bit */ | 1294 | * commands by clearing the INIT status bit */ |
1287 | clear_bit(STATUS_READY, &priv->status); | 1295 | clear_bit(STATUS_READY, &priv->status); |
1288 | 1296 | ||
1289 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { | 1297 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { |
1290 | IWL_DEBUG(IWL_DL_FW_ERRORS, | 1298 | IWL_DEBUG(IWL_DL_FW_ERRORS, |
1291 | "Restarting adapter due to uCode error.\n"); | 1299 | "Restarting adapter due to uCode error.\n"); |
1292 | 1300 | ||
1293 | if (iwl_is_associated(priv)) { | 1301 | if (iwl_is_associated(priv)) { |
1294 | memcpy(&priv->recovery_rxon, &priv->active_rxon, | 1302 | memcpy(&priv->recovery_rxon, &priv->active_rxon, |
1295 | sizeof(priv->recovery_rxon)); | 1303 | sizeof(priv->recovery_rxon)); |
1296 | priv->error_recovering = 1; | 1304 | priv->error_recovering = 1; |
1297 | } | 1305 | } |
1298 | if (priv->cfg->mod_params->restart_fw) | 1306 | if (priv->cfg->mod_params->restart_fw) |
1299 | queue_work(priv->workqueue, &priv->restart); | 1307 | queue_work(priv->workqueue, &priv->restart); |
1300 | } | 1308 | } |
1301 | } | 1309 | } |
1302 | 1310 | ||
1303 | static void iwl_error_recovery(struct iwl_priv *priv) | 1311 | static void iwl_error_recovery(struct iwl_priv *priv) |
1304 | { | 1312 | { |
1305 | unsigned long flags; | 1313 | unsigned long flags; |
1306 | 1314 | ||
1307 | memcpy(&priv->staging_rxon, &priv->recovery_rxon, | 1315 | memcpy(&priv->staging_rxon, &priv->recovery_rxon, |
1308 | sizeof(priv->staging_rxon)); | 1316 | sizeof(priv->staging_rxon)); |
1309 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 1317 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
1310 | iwl_commit_rxon(priv); | 1318 | iwl_commit_rxon(priv); |
1311 | 1319 | ||
1312 | iwl_rxon_add_station(priv, priv->bssid, 1); | 1320 | iwl_rxon_add_station(priv, priv->bssid, 1); |
1313 | 1321 | ||
1314 | spin_lock_irqsave(&priv->lock, flags); | 1322 | spin_lock_irqsave(&priv->lock, flags); |
1315 | priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); | 1323 | priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); |
1316 | priv->error_recovering = 0; | 1324 | priv->error_recovering = 0; |
1317 | spin_unlock_irqrestore(&priv->lock, flags); | 1325 | spin_unlock_irqrestore(&priv->lock, flags); |
1318 | } | 1326 | } |
1319 | 1327 | ||
1320 | static void iwl_irq_tasklet(struct iwl_priv *priv) | 1328 | static void iwl_irq_tasklet(struct iwl_priv *priv) |
1321 | { | 1329 | { |
1322 | u32 inta, handled = 0; | 1330 | u32 inta, handled = 0; |
1323 | u32 inta_fh; | 1331 | u32 inta_fh; |
1324 | unsigned long flags; | 1332 | unsigned long flags; |
1325 | #ifdef CONFIG_IWLWIFI_DEBUG | 1333 | #ifdef CONFIG_IWLWIFI_DEBUG |
1326 | u32 inta_mask; | 1334 | u32 inta_mask; |
1327 | #endif | 1335 | #endif |
1328 | 1336 | ||
1329 | spin_lock_irqsave(&priv->lock, flags); | 1337 | spin_lock_irqsave(&priv->lock, flags); |
1330 | 1338 | ||
1331 | /* Ack/clear/reset pending uCode interrupts. | 1339 | /* Ack/clear/reset pending uCode interrupts. |
1332 | * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, | 1340 | * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, |
1333 | * and will clear only when CSR_FH_INT_STATUS gets cleared. */ | 1341 | * and will clear only when CSR_FH_INT_STATUS gets cleared. */ |
1334 | inta = iwl_read32(priv, CSR_INT); | 1342 | inta = iwl_read32(priv, CSR_INT); |
1335 | iwl_write32(priv, CSR_INT, inta); | 1343 | iwl_write32(priv, CSR_INT, inta); |
1336 | 1344 | ||
1337 | /* Ack/clear/reset pending flow-handler (DMA) interrupts. | 1345 | /* Ack/clear/reset pending flow-handler (DMA) interrupts. |
1338 | * Any new interrupts that happen after this, either while we're | 1346 | * Any new interrupts that happen after this, either while we're |
1339 | * in this tasklet, or later, will show up in next ISR/tasklet. */ | 1347 | * in this tasklet, or later, will show up in next ISR/tasklet. */ |
1340 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1348 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
1341 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); | 1349 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); |
1342 | 1350 | ||
1343 | #ifdef CONFIG_IWLWIFI_DEBUG | 1351 | #ifdef CONFIG_IWLWIFI_DEBUG |
1344 | if (priv->debug_level & IWL_DL_ISR) { | 1352 | if (priv->debug_level & IWL_DL_ISR) { |
1345 | /* just for debug */ | 1353 | /* just for debug */ |
1346 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1354 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1347 | IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | 1355 | IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", |
1348 | inta, inta_mask, inta_fh); | 1356 | inta, inta_mask, inta_fh); |
1349 | } | 1357 | } |
1350 | #endif | 1358 | #endif |
1351 | 1359 | ||
1352 | /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not | 1360 | /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not |
1353 | * atomic, make sure that inta covers all the interrupts that | 1361 | * atomic, make sure that inta covers all the interrupts that |
1354 | * we've discovered, even if FH interrupt came in just after | 1362 | * we've discovered, even if FH interrupt came in just after |
1355 | * reading CSR_INT. */ | 1363 | * reading CSR_INT. */ |
1356 | if (inta_fh & CSR49_FH_INT_RX_MASK) | 1364 | if (inta_fh & CSR49_FH_INT_RX_MASK) |
1357 | inta |= CSR_INT_BIT_FH_RX; | 1365 | inta |= CSR_INT_BIT_FH_RX; |
1358 | if (inta_fh & CSR49_FH_INT_TX_MASK) | 1366 | if (inta_fh & CSR49_FH_INT_TX_MASK) |
1359 | inta |= CSR_INT_BIT_FH_TX; | 1367 | inta |= CSR_INT_BIT_FH_TX; |
1360 | 1368 | ||
1361 | /* Now service all interrupt bits discovered above. */ | 1369 | /* Now service all interrupt bits discovered above. */ |
1362 | if (inta & CSR_INT_BIT_HW_ERR) { | 1370 | if (inta & CSR_INT_BIT_HW_ERR) { |
1363 | IWL_ERROR("Microcode HW error detected. Restarting.\n"); | 1371 | IWL_ERROR("Microcode HW error detected. Restarting.\n"); |
1364 | 1372 | ||
1365 | /* Tell the device to stop sending interrupts */ | 1373 | /* Tell the device to stop sending interrupts */ |
1366 | iwl_disable_interrupts(priv); | 1374 | iwl_disable_interrupts(priv); |
1367 | 1375 | ||
1368 | iwl_irq_handle_error(priv); | 1376 | iwl_irq_handle_error(priv); |
1369 | 1377 | ||
1370 | handled |= CSR_INT_BIT_HW_ERR; | 1378 | handled |= CSR_INT_BIT_HW_ERR; |
1371 | 1379 | ||
1372 | spin_unlock_irqrestore(&priv->lock, flags); | 1380 | spin_unlock_irqrestore(&priv->lock, flags); |
1373 | 1381 | ||
1374 | return; | 1382 | return; |
1375 | } | 1383 | } |
1376 | 1384 | ||
1377 | #ifdef CONFIG_IWLWIFI_DEBUG | 1385 | #ifdef CONFIG_IWLWIFI_DEBUG |
1378 | if (priv->debug_level & (IWL_DL_ISR)) { | 1386 | if (priv->debug_level & (IWL_DL_ISR)) { |
1379 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | 1387 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ |
1380 | if (inta & CSR_INT_BIT_SCD) | 1388 | if (inta & CSR_INT_BIT_SCD) |
1381 | IWL_DEBUG_ISR("Scheduler finished to transmit " | 1389 | IWL_DEBUG_ISR("Scheduler finished to transmit " |
1382 | "the frame/frames.\n"); | 1390 | "the frame/frames.\n"); |
1383 | 1391 | ||
1384 | /* Alive notification via Rx interrupt will do the real work */ | 1392 | /* Alive notification via Rx interrupt will do the real work */ |
1385 | if (inta & CSR_INT_BIT_ALIVE) | 1393 | if (inta & CSR_INT_BIT_ALIVE) |
1386 | IWL_DEBUG_ISR("Alive interrupt\n"); | 1394 | IWL_DEBUG_ISR("Alive interrupt\n"); |
1387 | } | 1395 | } |
1388 | #endif | 1396 | #endif |
1389 | /* Safely ignore these bits for debug checks below */ | 1397 | /* Safely ignore these bits for debug checks below */ |
1390 | inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); | 1398 | inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); |
1391 | 1399 | ||
1392 | /* HW RF KILL switch toggled */ | 1400 | /* HW RF KILL switch toggled */ |
1393 | if (inta & CSR_INT_BIT_RF_KILL) { | 1401 | if (inta & CSR_INT_BIT_RF_KILL) { |
1394 | int hw_rf_kill = 0; | 1402 | int hw_rf_kill = 0; |
1395 | if (!(iwl_read32(priv, CSR_GP_CNTRL) & | 1403 | if (!(iwl_read32(priv, CSR_GP_CNTRL) & |
1396 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) | 1404 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) |
1397 | hw_rf_kill = 1; | 1405 | hw_rf_kill = 1; |
1398 | 1406 | ||
1399 | IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", | 1407 | IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", |
1400 | hw_rf_kill ? "disable radio" : "enable radio"); | 1408 | hw_rf_kill ? "disable radio" : "enable radio"); |
1401 | 1409 | ||
1402 | /* driver only loads ucode once setting the interface up. | 1410 | /* driver only loads ucode once setting the interface up. |
1403 | * the driver as well won't allow loading if RFKILL is set | 1411 | * the driver as well won't allow loading if RFKILL is set |
1404 | * therefore no need to restart the driver from this handler | 1412 | * therefore no need to restart the driver from this handler |
1405 | */ | 1413 | */ |
1406 | if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { | 1414 | if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { |
1407 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 1415 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
1408 | if (priv->is_open && !iwl_is_rfkill(priv)) | 1416 | if (priv->is_open && !iwl_is_rfkill(priv)) |
1409 | queue_work(priv->workqueue, &priv->up); | 1417 | queue_work(priv->workqueue, &priv->up); |
1410 | } | 1418 | } |
1411 | 1419 | ||
1412 | handled |= CSR_INT_BIT_RF_KILL; | 1420 | handled |= CSR_INT_BIT_RF_KILL; |
1413 | } | 1421 | } |
1414 | 1422 | ||
1415 | /* Chip got too hot and stopped itself */ | 1423 | /* Chip got too hot and stopped itself */ |
1416 | if (inta & CSR_INT_BIT_CT_KILL) { | 1424 | if (inta & CSR_INT_BIT_CT_KILL) { |
1417 | IWL_ERROR("Microcode CT kill error detected.\n"); | 1425 | IWL_ERROR("Microcode CT kill error detected.\n"); |
1418 | handled |= CSR_INT_BIT_CT_KILL; | 1426 | handled |= CSR_INT_BIT_CT_KILL; |
1419 | } | 1427 | } |
1420 | 1428 | ||
1421 | /* Error detected by uCode */ | 1429 | /* Error detected by uCode */ |
1422 | if (inta & CSR_INT_BIT_SW_ERR) { | 1430 | if (inta & CSR_INT_BIT_SW_ERR) { |
1423 | IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", | 1431 | IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", |
1424 | inta); | 1432 | inta); |
1425 | iwl_irq_handle_error(priv); | 1433 | iwl_irq_handle_error(priv); |
1426 | handled |= CSR_INT_BIT_SW_ERR; | 1434 | handled |= CSR_INT_BIT_SW_ERR; |
1427 | } | 1435 | } |
1428 | 1436 | ||
1429 | /* uCode wakes up after power-down sleep */ | 1437 | /* uCode wakes up after power-down sleep */ |
1430 | if (inta & CSR_INT_BIT_WAKEUP) { | 1438 | if (inta & CSR_INT_BIT_WAKEUP) { |
1431 | IWL_DEBUG_ISR("Wakeup interrupt\n"); | 1439 | IWL_DEBUG_ISR("Wakeup interrupt\n"); |
1432 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); | 1440 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); |
1433 | iwl_txq_update_write_ptr(priv, &priv->txq[0]); | 1441 | iwl_txq_update_write_ptr(priv, &priv->txq[0]); |
1434 | iwl_txq_update_write_ptr(priv, &priv->txq[1]); | 1442 | iwl_txq_update_write_ptr(priv, &priv->txq[1]); |
1435 | iwl_txq_update_write_ptr(priv, &priv->txq[2]); | 1443 | iwl_txq_update_write_ptr(priv, &priv->txq[2]); |
1436 | iwl_txq_update_write_ptr(priv, &priv->txq[3]); | 1444 | iwl_txq_update_write_ptr(priv, &priv->txq[3]); |
1437 | iwl_txq_update_write_ptr(priv, &priv->txq[4]); | 1445 | iwl_txq_update_write_ptr(priv, &priv->txq[4]); |
1438 | iwl_txq_update_write_ptr(priv, &priv->txq[5]); | 1446 | iwl_txq_update_write_ptr(priv, &priv->txq[5]); |
1439 | 1447 | ||
1440 | handled |= CSR_INT_BIT_WAKEUP; | 1448 | handled |= CSR_INT_BIT_WAKEUP; |
1441 | } | 1449 | } |
1442 | 1450 | ||
1443 | /* All uCode command responses, including Tx command responses, | 1451 | /* All uCode command responses, including Tx command responses, |
1444 | * Rx "responses" (frame-received notification), and other | 1452 | * Rx "responses" (frame-received notification), and other |
1445 | * notifications from uCode come through here*/ | 1453 | * notifications from uCode come through here*/ |
1446 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { | 1454 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { |
1447 | iwl_rx_handle(priv); | 1455 | iwl_rx_handle(priv); |
1448 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); | 1456 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); |
1449 | } | 1457 | } |
1450 | 1458 | ||
1451 | if (inta & CSR_INT_BIT_FH_TX) { | 1459 | if (inta & CSR_INT_BIT_FH_TX) { |
1452 | IWL_DEBUG_ISR("Tx interrupt\n"); | 1460 | IWL_DEBUG_ISR("Tx interrupt\n"); |
1453 | handled |= CSR_INT_BIT_FH_TX; | 1461 | handled |= CSR_INT_BIT_FH_TX; |
1454 | /* FH finished to write, send event */ | 1462 | /* FH finished to write, send event */ |
1455 | priv->ucode_write_complete = 1; | 1463 | priv->ucode_write_complete = 1; |
1456 | wake_up_interruptible(&priv->wait_command_queue); | 1464 | wake_up_interruptible(&priv->wait_command_queue); |
1457 | } | 1465 | } |
1458 | 1466 | ||
1459 | if (inta & ~handled) | 1467 | if (inta & ~handled) |
1460 | IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); | 1468 | IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); |
1461 | 1469 | ||
1462 | if (inta & ~CSR_INI_SET_MASK) { | 1470 | if (inta & ~CSR_INI_SET_MASK) { |
1463 | IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", | 1471 | IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", |
1464 | inta & ~CSR_INI_SET_MASK); | 1472 | inta & ~CSR_INI_SET_MASK); |
1465 | IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); | 1473 | IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); |
1466 | } | 1474 | } |
1467 | 1475 | ||
1468 | /* Re-enable all interrupts */ | 1476 | /* Re-enable all interrupts */ |
1469 | /* only Re-enable if diabled by irq */ | 1477 | /* only Re-enable if diabled by irq */ |
1470 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | 1478 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) |
1471 | iwl_enable_interrupts(priv); | 1479 | iwl_enable_interrupts(priv); |
1472 | 1480 | ||
1473 | #ifdef CONFIG_IWLWIFI_DEBUG | 1481 | #ifdef CONFIG_IWLWIFI_DEBUG |
1474 | if (priv->debug_level & (IWL_DL_ISR)) { | 1482 | if (priv->debug_level & (IWL_DL_ISR)) { |
1475 | inta = iwl_read32(priv, CSR_INT); | 1483 | inta = iwl_read32(priv, CSR_INT); |
1476 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1484 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1477 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1485 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
1478 | IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " | 1486 | IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " |
1479 | "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); | 1487 | "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); |
1480 | } | 1488 | } |
1481 | #endif | 1489 | #endif |
1482 | spin_unlock_irqrestore(&priv->lock, flags); | 1490 | spin_unlock_irqrestore(&priv->lock, flags); |
1483 | } | 1491 | } |
1484 | 1492 | ||
1485 | static irqreturn_t iwl_isr(int irq, void *data) | 1493 | static irqreturn_t iwl_isr(int irq, void *data) |
1486 | { | 1494 | { |
1487 | struct iwl_priv *priv = data; | 1495 | struct iwl_priv *priv = data; |
1488 | u32 inta, inta_mask; | 1496 | u32 inta, inta_mask; |
1489 | u32 inta_fh; | 1497 | u32 inta_fh; |
1490 | if (!priv) | 1498 | if (!priv) |
1491 | return IRQ_NONE; | 1499 | return IRQ_NONE; |
1492 | 1500 | ||
1493 | spin_lock(&priv->lock); | 1501 | spin_lock(&priv->lock); |
1494 | 1502 | ||
1495 | /* Disable (but don't clear!) interrupts here to avoid | 1503 | /* Disable (but don't clear!) interrupts here to avoid |
1496 | * back-to-back ISRs and sporadic interrupts from our NIC. | 1504 | * back-to-back ISRs and sporadic interrupts from our NIC. |
1497 | * If we have something to service, the tasklet will re-enable ints. | 1505 | * If we have something to service, the tasklet will re-enable ints. |
1498 | * If we *don't* have something, we'll re-enable before leaving here. */ | 1506 | * If we *don't* have something, we'll re-enable before leaving here. */ |
1499 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | 1507 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ |
1500 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | 1508 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); |
1501 | 1509 | ||
1502 | /* Discover which interrupts are active/pending */ | 1510 | /* Discover which interrupts are active/pending */ |
1503 | inta = iwl_read32(priv, CSR_INT); | 1511 | inta = iwl_read32(priv, CSR_INT); |
1504 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1512 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
1505 | 1513 | ||
1506 | /* Ignore interrupt if there's nothing in NIC to service. | 1514 | /* Ignore interrupt if there's nothing in NIC to service. |
1507 | * This may be due to IRQ shared with another device, | 1515 | * This may be due to IRQ shared with another device, |
1508 | * or due to sporadic interrupts thrown from our NIC. */ | 1516 | * or due to sporadic interrupts thrown from our NIC. */ |
1509 | if (!inta && !inta_fh) { | 1517 | if (!inta && !inta_fh) { |
1510 | IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); | 1518 | IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); |
1511 | goto none; | 1519 | goto none; |
1512 | } | 1520 | } |
1513 | 1521 | ||
1514 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | 1522 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { |
1515 | /* Hardware disappeared. It might have already raised | 1523 | /* Hardware disappeared. It might have already raised |
1516 | * an interrupt */ | 1524 | * an interrupt */ |
1517 | IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); | 1525 | IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); |
1518 | goto unplugged; | 1526 | goto unplugged; |
1519 | } | 1527 | } |
1520 | 1528 | ||
1521 | IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | 1529 | IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", |
1522 | inta, inta_mask, inta_fh); | 1530 | inta, inta_mask, inta_fh); |
1523 | 1531 | ||
1524 | inta &= ~CSR_INT_BIT_SCD; | 1532 | inta &= ~CSR_INT_BIT_SCD; |
1525 | 1533 | ||
1526 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | 1534 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ |
1527 | if (likely(inta || inta_fh)) | 1535 | if (likely(inta || inta_fh)) |
1528 | tasklet_schedule(&priv->irq_tasklet); | 1536 | tasklet_schedule(&priv->irq_tasklet); |
1529 | 1537 | ||
1530 | unplugged: | 1538 | unplugged: |
1531 | spin_unlock(&priv->lock); | 1539 | spin_unlock(&priv->lock); |
1532 | return IRQ_HANDLED; | 1540 | return IRQ_HANDLED; |
1533 | 1541 | ||
1534 | none: | 1542 | none: |
1535 | /* re-enable interrupts here since we don't have anything to service. */ | 1543 | /* re-enable interrupts here since we don't have anything to service. */ |
1536 | /* only Re-enable if diabled by irq */ | 1544 | /* only Re-enable if diabled by irq */ |
1537 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | 1545 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) |
1538 | iwl_enable_interrupts(priv); | 1546 | iwl_enable_interrupts(priv); |
1539 | spin_unlock(&priv->lock); | 1547 | spin_unlock(&priv->lock); |
1540 | return IRQ_NONE; | 1548 | return IRQ_NONE; |
1541 | } | 1549 | } |
1542 | 1550 | ||
1543 | /****************************************************************************** | 1551 | /****************************************************************************** |
1544 | * | 1552 | * |
1545 | * uCode download functions | 1553 | * uCode download functions |
1546 | * | 1554 | * |
1547 | ******************************************************************************/ | 1555 | ******************************************************************************/ |
1548 | 1556 | ||
1549 | static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) | 1557 | static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) |
1550 | { | 1558 | { |
1551 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); | 1559 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); |
1552 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); | 1560 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); |
1553 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); | 1561 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); |
1554 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); | 1562 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); |
1555 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); | 1563 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); |
1556 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); | 1564 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); |
1557 | } | 1565 | } |
1558 | 1566 | ||
1559 | static void iwl_nic_start(struct iwl_priv *priv) | 1567 | static void iwl_nic_start(struct iwl_priv *priv) |
1560 | { | 1568 | { |
1561 | /* Remove all resets to allow NIC to operate */ | 1569 | /* Remove all resets to allow NIC to operate */ |
1562 | iwl_write32(priv, CSR_RESET, 0); | 1570 | iwl_write32(priv, CSR_RESET, 0); |
1563 | } | 1571 | } |
1564 | 1572 | ||
1565 | 1573 | ||
1566 | /** | 1574 | /** |
1567 | * iwl_read_ucode - Read uCode images from disk file. | 1575 | * iwl_read_ucode - Read uCode images from disk file. |
1568 | * | 1576 | * |
1569 | * Copy into buffers for card to fetch via bus-mastering | 1577 | * Copy into buffers for card to fetch via bus-mastering |
1570 | */ | 1578 | */ |
1571 | static int iwl_read_ucode(struct iwl_priv *priv) | 1579 | static int iwl_read_ucode(struct iwl_priv *priv) |
1572 | { | 1580 | { |
1573 | struct iwl_ucode *ucode; | 1581 | struct iwl_ucode *ucode; |
1574 | int ret = -EINVAL, index; | 1582 | int ret = -EINVAL, index; |
1575 | const struct firmware *ucode_raw; | 1583 | const struct firmware *ucode_raw; |
1576 | const char *name_pre = priv->cfg->fw_name_pre; | 1584 | const char *name_pre = priv->cfg->fw_name_pre; |
1577 | const unsigned int api_max = priv->cfg->ucode_api_max; | 1585 | const unsigned int api_max = priv->cfg->ucode_api_max; |
1578 | const unsigned int api_min = priv->cfg->ucode_api_min; | 1586 | const unsigned int api_min = priv->cfg->ucode_api_min; |
1579 | char buf[25]; | 1587 | char buf[25]; |
1580 | u8 *src; | 1588 | u8 *src; |
1581 | size_t len; | 1589 | size_t len; |
1582 | u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; | 1590 | u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; |
1583 | 1591 | ||
1584 | /* Ask kernel firmware_class module to get the boot firmware off disk. | 1592 | /* Ask kernel firmware_class module to get the boot firmware off disk. |
1585 | * request_firmware() is synchronous, file is in memory on return. */ | 1593 | * request_firmware() is synchronous, file is in memory on return. */ |
1586 | for (index = api_max; index >= api_min; index--) { | 1594 | for (index = api_max; index >= api_min; index--) { |
1587 | sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); | 1595 | sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); |
1588 | ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); | 1596 | ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); |
1589 | if (ret < 0) { | 1597 | if (ret < 0) { |
1590 | IWL_ERROR("%s firmware file req failed: Reason %d\n", | 1598 | IWL_ERROR("%s firmware file req failed: Reason %d\n", |
1591 | buf, ret); | 1599 | buf, ret); |
1592 | if (ret == -ENOENT) | 1600 | if (ret == -ENOENT) |
1593 | continue; | 1601 | continue; |
1594 | else | 1602 | else |
1595 | goto error; | 1603 | goto error; |
1596 | } else { | 1604 | } else { |
1597 | if (index < api_max) | 1605 | if (index < api_max) |
1598 | IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", | 1606 | IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", |
1599 | buf, api_max); | 1607 | buf, api_max); |
1600 | IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", | 1608 | IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", |
1601 | buf, ucode_raw->size); | 1609 | buf, ucode_raw->size); |
1602 | break; | 1610 | break; |
1603 | } | 1611 | } |
1604 | } | 1612 | } |
1605 | 1613 | ||
1606 | if (ret < 0) | 1614 | if (ret < 0) |
1607 | goto error; | 1615 | goto error; |
1608 | 1616 | ||
1609 | /* Make sure that we got at least our header! */ | 1617 | /* Make sure that we got at least our header! */ |
1610 | if (ucode_raw->size < sizeof(*ucode)) { | 1618 | if (ucode_raw->size < sizeof(*ucode)) { |
1611 | IWL_ERROR("File size way too small!\n"); | 1619 | IWL_ERROR("File size way too small!\n"); |
1612 | ret = -EINVAL; | 1620 | ret = -EINVAL; |
1613 | goto err_release; | 1621 | goto err_release; |
1614 | } | 1622 | } |
1615 | 1623 | ||
1616 | /* Data from ucode file: header followed by uCode images */ | 1624 | /* Data from ucode file: header followed by uCode images */ |
1617 | ucode = (void *)ucode_raw->data; | 1625 | ucode = (void *)ucode_raw->data; |
1618 | 1626 | ||
1619 | priv->ucode_ver = le32_to_cpu(ucode->ver); | 1627 | priv->ucode_ver = le32_to_cpu(ucode->ver); |
1620 | api_ver = IWL_UCODE_API(priv->ucode_ver); | 1628 | api_ver = IWL_UCODE_API(priv->ucode_ver); |
1621 | inst_size = le32_to_cpu(ucode->inst_size); | 1629 | inst_size = le32_to_cpu(ucode->inst_size); |
1622 | data_size = le32_to_cpu(ucode->data_size); | 1630 | data_size = le32_to_cpu(ucode->data_size); |
1623 | init_size = le32_to_cpu(ucode->init_size); | 1631 | init_size = le32_to_cpu(ucode->init_size); |
1624 | init_data_size = le32_to_cpu(ucode->init_data_size); | 1632 | init_data_size = le32_to_cpu(ucode->init_data_size); |
1625 | boot_size = le32_to_cpu(ucode->boot_size); | 1633 | boot_size = le32_to_cpu(ucode->boot_size); |
1626 | 1634 | ||
1627 | /* api_ver should match the api version forming part of the | 1635 | /* api_ver should match the api version forming part of the |
1628 | * firmware filename ... but we don't check for that and only rely | 1636 | * firmware filename ... but we don't check for that and only rely |
1629 | * on the API version read from firware header from here on forward */ | 1637 | * on the API version read from firware header from here on forward */ |
1630 | 1638 | ||
1631 | if (api_ver < api_min || api_ver > api_max) { | 1639 | if (api_ver < api_min || api_ver > api_max) { |
1632 | IWL_ERROR("Driver unable to support your firmware API. " | 1640 | IWL_ERROR("Driver unable to support your firmware API. " |
1633 | "Driver supports v%u, firmware is v%u.\n", | 1641 | "Driver supports v%u, firmware is v%u.\n", |
1634 | api_max, api_ver); | 1642 | api_max, api_ver); |
1635 | priv->ucode_ver = 0; | 1643 | priv->ucode_ver = 0; |
1636 | ret = -EINVAL; | 1644 | ret = -EINVAL; |
1637 | goto err_release; | 1645 | goto err_release; |
1638 | } | 1646 | } |
1639 | if (api_ver != api_max) | 1647 | if (api_ver != api_max) |
1640 | IWL_ERROR("Firmware has old API version. Expected v%u, " | 1648 | IWL_ERROR("Firmware has old API version. Expected v%u, " |
1641 | "got v%u. New firmware can be obtained " | 1649 | "got v%u. New firmware can be obtained " |
1642 | "from http://www.intellinuxwireless.org.\n", | 1650 | "from http://www.intellinuxwireless.org.\n", |
1643 | api_max, api_ver); | 1651 | api_max, api_ver); |
1644 | 1652 | ||
1645 | printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", | 1653 | printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", |
1646 | IWL_UCODE_MAJOR(priv->ucode_ver), | 1654 | IWL_UCODE_MAJOR(priv->ucode_ver), |
1647 | IWL_UCODE_MINOR(priv->ucode_ver), | 1655 | IWL_UCODE_MINOR(priv->ucode_ver), |
1648 | IWL_UCODE_API(priv->ucode_ver), | 1656 | IWL_UCODE_API(priv->ucode_ver), |
1649 | IWL_UCODE_SERIAL(priv->ucode_ver)); | 1657 | IWL_UCODE_SERIAL(priv->ucode_ver)); |
1650 | 1658 | ||
1651 | IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", | 1659 | IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", |
1652 | priv->ucode_ver); | 1660 | priv->ucode_ver); |
1653 | IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", | 1661 | IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", |
1654 | inst_size); | 1662 | inst_size); |
1655 | IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", | 1663 | IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", |
1656 | data_size); | 1664 | data_size); |
1657 | IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", | 1665 | IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", |
1658 | init_size); | 1666 | init_size); |
1659 | IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", | 1667 | IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", |
1660 | init_data_size); | 1668 | init_data_size); |
1661 | IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", | 1669 | IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", |
1662 | boot_size); | 1670 | boot_size); |
1663 | 1671 | ||
1664 | /* Verify size of file vs. image size info in file's header */ | 1672 | /* Verify size of file vs. image size info in file's header */ |
1665 | if (ucode_raw->size < sizeof(*ucode) + | 1673 | if (ucode_raw->size < sizeof(*ucode) + |
1666 | inst_size + data_size + init_size + | 1674 | inst_size + data_size + init_size + |
1667 | init_data_size + boot_size) { | 1675 | init_data_size + boot_size) { |
1668 | 1676 | ||
1669 | IWL_DEBUG_INFO("uCode file size %d too small\n", | 1677 | IWL_DEBUG_INFO("uCode file size %d too small\n", |
1670 | (int)ucode_raw->size); | 1678 | (int)ucode_raw->size); |
1671 | ret = -EINVAL; | 1679 | ret = -EINVAL; |
1672 | goto err_release; | 1680 | goto err_release; |
1673 | } | 1681 | } |
1674 | 1682 | ||
1675 | /* Verify that uCode images will fit in card's SRAM */ | 1683 | /* Verify that uCode images will fit in card's SRAM */ |
1676 | if (inst_size > priv->hw_params.max_inst_size) { | 1684 | if (inst_size > priv->hw_params.max_inst_size) { |
1677 | IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", | 1685 | IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", |
1678 | inst_size); | 1686 | inst_size); |
1679 | ret = -EINVAL; | 1687 | ret = -EINVAL; |
1680 | goto err_release; | 1688 | goto err_release; |
1681 | } | 1689 | } |
1682 | 1690 | ||
1683 | if (data_size > priv->hw_params.max_data_size) { | 1691 | if (data_size > priv->hw_params.max_data_size) { |
1684 | IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", | 1692 | IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", |
1685 | data_size); | 1693 | data_size); |
1686 | ret = -EINVAL; | 1694 | ret = -EINVAL; |
1687 | goto err_release; | 1695 | goto err_release; |
1688 | } | 1696 | } |
1689 | if (init_size > priv->hw_params.max_inst_size) { | 1697 | if (init_size > priv->hw_params.max_inst_size) { |
1690 | IWL_DEBUG_INFO | 1698 | IWL_DEBUG_INFO |
1691 | ("uCode init instr len %d too large to fit in\n", | 1699 | ("uCode init instr len %d too large to fit in\n", |
1692 | init_size); | 1700 | init_size); |
1693 | ret = -EINVAL; | 1701 | ret = -EINVAL; |
1694 | goto err_release; | 1702 | goto err_release; |
1695 | } | 1703 | } |
1696 | if (init_data_size > priv->hw_params.max_data_size) { | 1704 | if (init_data_size > priv->hw_params.max_data_size) { |
1697 | IWL_DEBUG_INFO | 1705 | IWL_DEBUG_INFO |
1698 | ("uCode init data len %d too large to fit in\n", | 1706 | ("uCode init data len %d too large to fit in\n", |
1699 | init_data_size); | 1707 | init_data_size); |
1700 | ret = -EINVAL; | 1708 | ret = -EINVAL; |
1701 | goto err_release; | 1709 | goto err_release; |
1702 | } | 1710 | } |
1703 | if (boot_size > priv->hw_params.max_bsm_size) { | 1711 | if (boot_size > priv->hw_params.max_bsm_size) { |
1704 | IWL_DEBUG_INFO | 1712 | IWL_DEBUG_INFO |
1705 | ("uCode boot instr len %d too large to fit in\n", | 1713 | ("uCode boot instr len %d too large to fit in\n", |
1706 | boot_size); | 1714 | boot_size); |
1707 | ret = -EINVAL; | 1715 | ret = -EINVAL; |
1708 | goto err_release; | 1716 | goto err_release; |
1709 | } | 1717 | } |
1710 | 1718 | ||
1711 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1719 | /* Allocate ucode buffers for card's bus-master loading ... */ |
1712 | 1720 | ||
1713 | /* Runtime instructions and 2 copies of data: | 1721 | /* Runtime instructions and 2 copies of data: |
1714 | * 1) unmodified from disk | 1722 | * 1) unmodified from disk |
1715 | * 2) backup cache for save/restore during power-downs */ | 1723 | * 2) backup cache for save/restore during power-downs */ |
1716 | priv->ucode_code.len = inst_size; | 1724 | priv->ucode_code.len = inst_size; |
1717 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); | 1725 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); |
1718 | 1726 | ||
1719 | priv->ucode_data.len = data_size; | 1727 | priv->ucode_data.len = data_size; |
1720 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); | 1728 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); |
1721 | 1729 | ||
1722 | priv->ucode_data_backup.len = data_size; | 1730 | priv->ucode_data_backup.len = data_size; |
1723 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); | 1731 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); |
1724 | 1732 | ||
1725 | /* Initialization instructions and data */ | 1733 | /* Initialization instructions and data */ |
1726 | if (init_size && init_data_size) { | 1734 | if (init_size && init_data_size) { |
1727 | priv->ucode_init.len = init_size; | 1735 | priv->ucode_init.len = init_size; |
1728 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); | 1736 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); |
1729 | 1737 | ||
1730 | priv->ucode_init_data.len = init_data_size; | 1738 | priv->ucode_init_data.len = init_data_size; |
1731 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); | 1739 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); |
1732 | 1740 | ||
1733 | if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) | 1741 | if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) |
1734 | goto err_pci_alloc; | 1742 | goto err_pci_alloc; |
1735 | } | 1743 | } |
1736 | 1744 | ||
1737 | /* Bootstrap (instructions only, no data) */ | 1745 | /* Bootstrap (instructions only, no data) */ |
1738 | if (boot_size) { | 1746 | if (boot_size) { |
1739 | priv->ucode_boot.len = boot_size; | 1747 | priv->ucode_boot.len = boot_size; |
1740 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); | 1748 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); |
1741 | 1749 | ||
1742 | if (!priv->ucode_boot.v_addr) | 1750 | if (!priv->ucode_boot.v_addr) |
1743 | goto err_pci_alloc; | 1751 | goto err_pci_alloc; |
1744 | } | 1752 | } |
1745 | 1753 | ||
1746 | /* Copy images into buffers for card's bus-master reads ... */ | 1754 | /* Copy images into buffers for card's bus-master reads ... */ |
1747 | 1755 | ||
1748 | /* Runtime instructions (first block of data in file) */ | 1756 | /* Runtime instructions (first block of data in file) */ |
1749 | src = &ucode->data[0]; | 1757 | src = &ucode->data[0]; |
1750 | len = priv->ucode_code.len; | 1758 | len = priv->ucode_code.len; |
1751 | IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len); | 1759 | IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len); |
1752 | memcpy(priv->ucode_code.v_addr, src, len); | 1760 | memcpy(priv->ucode_code.v_addr, src, len); |
1753 | IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", | 1761 | IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", |
1754 | priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); | 1762 | priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); |
1755 | 1763 | ||
1756 | /* Runtime data (2nd block) | 1764 | /* Runtime data (2nd block) |
1757 | * NOTE: Copy into backup buffer will be done in iwl_up() */ | 1765 | * NOTE: Copy into backup buffer will be done in iwl_up() */ |
1758 | src = &ucode->data[inst_size]; | 1766 | src = &ucode->data[inst_size]; |
1759 | len = priv->ucode_data.len; | 1767 | len = priv->ucode_data.len; |
1760 | IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); | 1768 | IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); |
1761 | memcpy(priv->ucode_data.v_addr, src, len); | 1769 | memcpy(priv->ucode_data.v_addr, src, len); |
1762 | memcpy(priv->ucode_data_backup.v_addr, src, len); | 1770 | memcpy(priv->ucode_data_backup.v_addr, src, len); |
1763 | 1771 | ||
1764 | /* Initialization instructions (3rd block) */ | 1772 | /* Initialization instructions (3rd block) */ |
1765 | if (init_size) { | 1773 | if (init_size) { |
1766 | src = &ucode->data[inst_size + data_size]; | 1774 | src = &ucode->data[inst_size + data_size]; |
1767 | len = priv->ucode_init.len; | 1775 | len = priv->ucode_init.len; |
1768 | IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", | 1776 | IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", |
1769 | len); | 1777 | len); |
1770 | memcpy(priv->ucode_init.v_addr, src, len); | 1778 | memcpy(priv->ucode_init.v_addr, src, len); |
1771 | } | 1779 | } |
1772 | 1780 | ||
1773 | /* Initialization data (4th block) */ | 1781 | /* Initialization data (4th block) */ |
1774 | if (init_data_size) { | 1782 | if (init_data_size) { |
1775 | src = &ucode->data[inst_size + data_size + init_size]; | 1783 | src = &ucode->data[inst_size + data_size + init_size]; |
1776 | len = priv->ucode_init_data.len; | 1784 | len = priv->ucode_init_data.len; |
1777 | IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n", | 1785 | IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n", |
1778 | len); | 1786 | len); |
1779 | memcpy(priv->ucode_init_data.v_addr, src, len); | 1787 | memcpy(priv->ucode_init_data.v_addr, src, len); |
1780 | } | 1788 | } |
1781 | 1789 | ||
1782 | /* Bootstrap instructions (5th block) */ | 1790 | /* Bootstrap instructions (5th block) */ |
1783 | src = &ucode->data[inst_size + data_size + init_size + init_data_size]; | 1791 | src = &ucode->data[inst_size + data_size + init_size + init_data_size]; |
1784 | len = priv->ucode_boot.len; | 1792 | len = priv->ucode_boot.len; |
1785 | IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len); | 1793 | IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len); |
1786 | memcpy(priv->ucode_boot.v_addr, src, len); | 1794 | memcpy(priv->ucode_boot.v_addr, src, len); |
1787 | 1795 | ||
1788 | /* We have our copies now, allow OS release its copies */ | 1796 | /* We have our copies now, allow OS release its copies */ |
1789 | release_firmware(ucode_raw); | 1797 | release_firmware(ucode_raw); |
1790 | return 0; | 1798 | return 0; |
1791 | 1799 | ||
1792 | err_pci_alloc: | 1800 | err_pci_alloc: |
1793 | IWL_ERROR("failed to allocate pci memory\n"); | 1801 | IWL_ERROR("failed to allocate pci memory\n"); |
1794 | ret = -ENOMEM; | 1802 | ret = -ENOMEM; |
1795 | iwl_dealloc_ucode_pci(priv); | 1803 | iwl_dealloc_ucode_pci(priv); |
1796 | 1804 | ||
1797 | err_release: | 1805 | err_release: |
1798 | release_firmware(ucode_raw); | 1806 | release_firmware(ucode_raw); |
1799 | 1807 | ||
1800 | error: | 1808 | error: |
1801 | return ret; | 1809 | return ret; |
1802 | } | 1810 | } |
1803 | 1811 | ||
1804 | /* temporary */ | 1812 | /* temporary */ |
1805 | static int iwl_mac_beacon_update(struct ieee80211_hw *hw, | 1813 | static int iwl_mac_beacon_update(struct ieee80211_hw *hw, |
1806 | struct sk_buff *skb); | 1814 | struct sk_buff *skb); |
1807 | 1815 | ||
1808 | /** | 1816 | /** |
1809 | * iwl_alive_start - called after REPLY_ALIVE notification received | 1817 | * iwl_alive_start - called after REPLY_ALIVE notification received |
1810 | * from protocol/runtime uCode (initialization uCode's | 1818 | * from protocol/runtime uCode (initialization uCode's |
1811 | * Alive gets handled by iwl_init_alive_start()). | 1819 | * Alive gets handled by iwl_init_alive_start()). |
1812 | */ | 1820 | */ |
1813 | static void iwl_alive_start(struct iwl_priv *priv) | 1821 | static void iwl_alive_start(struct iwl_priv *priv) |
1814 | { | 1822 | { |
1815 | int ret = 0; | 1823 | int ret = 0; |
1816 | 1824 | ||
1817 | IWL_DEBUG_INFO("Runtime Alive received.\n"); | 1825 | IWL_DEBUG_INFO("Runtime Alive received.\n"); |
1818 | 1826 | ||
1819 | if (priv->card_alive.is_valid != UCODE_VALID_OK) { | 1827 | if (priv->card_alive.is_valid != UCODE_VALID_OK) { |
1820 | /* We had an error bringing up the hardware, so take it | 1828 | /* We had an error bringing up the hardware, so take it |
1821 | * all the way back down so we can try again */ | 1829 | * all the way back down so we can try again */ |
1822 | IWL_DEBUG_INFO("Alive failed.\n"); | 1830 | IWL_DEBUG_INFO("Alive failed.\n"); |
1823 | goto restart; | 1831 | goto restart; |
1824 | } | 1832 | } |
1825 | 1833 | ||
1826 | /* Initialize uCode has loaded Runtime uCode ... verify inst image. | 1834 | /* Initialize uCode has loaded Runtime uCode ... verify inst image. |
1827 | * This is a paranoid check, because we would not have gotten the | 1835 | * This is a paranoid check, because we would not have gotten the |
1828 | * "runtime" alive if code weren't properly loaded. */ | 1836 | * "runtime" alive if code weren't properly loaded. */ |
1829 | if (iwl_verify_ucode(priv)) { | 1837 | if (iwl_verify_ucode(priv)) { |
1830 | /* Runtime instruction load was bad; | 1838 | /* Runtime instruction load was bad; |
1831 | * take it all the way back down so we can try again */ | 1839 | * take it all the way back down so we can try again */ |
1832 | IWL_DEBUG_INFO("Bad runtime uCode load.\n"); | 1840 | IWL_DEBUG_INFO("Bad runtime uCode load.\n"); |
1833 | goto restart; | 1841 | goto restart; |
1834 | } | 1842 | } |
1835 | 1843 | ||
1836 | iwl_clear_stations_table(priv); | 1844 | iwl_clear_stations_table(priv); |
1837 | ret = priv->cfg->ops->lib->alive_notify(priv); | 1845 | ret = priv->cfg->ops->lib->alive_notify(priv); |
1838 | if (ret) { | 1846 | if (ret) { |
1839 | IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", | 1847 | IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", |
1840 | ret); | 1848 | ret); |
1841 | goto restart; | 1849 | goto restart; |
1842 | } | 1850 | } |
1843 | 1851 | ||
1844 | /* After the ALIVE response, we can send host commands to the uCode */ | 1852 | /* After the ALIVE response, we can send host commands to the uCode */ |
1845 | set_bit(STATUS_ALIVE, &priv->status); | 1853 | set_bit(STATUS_ALIVE, &priv->status); |
1846 | 1854 | ||
1847 | if (iwl_is_rfkill(priv)) | 1855 | if (iwl_is_rfkill(priv)) |
1848 | return; | 1856 | return; |
1849 | 1857 | ||
1850 | ieee80211_wake_queues(priv->hw); | 1858 | ieee80211_wake_queues(priv->hw); |
1851 | 1859 | ||
1852 | priv->active_rate = priv->rates_mask; | 1860 | priv->active_rate = priv->rates_mask; |
1853 | priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; | 1861 | priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; |
1854 | 1862 | ||
1855 | if (iwl_is_associated(priv)) { | 1863 | if (iwl_is_associated(priv)) { |
1856 | struct iwl_rxon_cmd *active_rxon = | 1864 | struct iwl_rxon_cmd *active_rxon = |
1857 | (struct iwl_rxon_cmd *)&priv->active_rxon; | 1865 | (struct iwl_rxon_cmd *)&priv->active_rxon; |
1858 | 1866 | ||
1859 | memcpy(&priv->staging_rxon, &priv->active_rxon, | 1867 | memcpy(&priv->staging_rxon, &priv->active_rxon, |
1860 | sizeof(priv->staging_rxon)); | 1868 | sizeof(priv->staging_rxon)); |
1861 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 1869 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
1862 | } else { | 1870 | } else { |
1863 | /* Initialize our rx_config data */ | 1871 | /* Initialize our rx_config data */ |
1864 | iwl_connection_init_rx_config(priv, priv->iw_mode); | 1872 | iwl_connection_init_rx_config(priv, priv->iw_mode); |
1865 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 1873 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
1866 | } | 1874 | } |
1867 | 1875 | ||
1868 | /* Configure Bluetooth device coexistence support */ | 1876 | /* Configure Bluetooth device coexistence support */ |
1869 | iwl_send_bt_config(priv); | 1877 | iwl_send_bt_config(priv); |
1870 | 1878 | ||
1871 | iwl_reset_run_time_calib(priv); | 1879 | iwl_reset_run_time_calib(priv); |
1872 | 1880 | ||
1873 | /* Configure the adapter for unassociated operation */ | 1881 | /* Configure the adapter for unassociated operation */ |
1874 | iwl_commit_rxon(priv); | 1882 | iwl_commit_rxon(priv); |
1875 | 1883 | ||
1876 | /* At this point, the NIC is initialized and operational */ | 1884 | /* At this point, the NIC is initialized and operational */ |
1877 | iwl_rf_kill_ct_config(priv); | 1885 | iwl_rf_kill_ct_config(priv); |
1878 | 1886 | ||
1879 | iwl_leds_register(priv); | 1887 | iwl_leds_register(priv); |
1880 | 1888 | ||
1881 | IWL_DEBUG_INFO("ALIVE processing complete.\n"); | 1889 | IWL_DEBUG_INFO("ALIVE processing complete.\n"); |
1882 | set_bit(STATUS_READY, &priv->status); | 1890 | set_bit(STATUS_READY, &priv->status); |
1883 | wake_up_interruptible(&priv->wait_command_queue); | 1891 | wake_up_interruptible(&priv->wait_command_queue); |
1884 | 1892 | ||
1885 | if (priv->error_recovering) | 1893 | if (priv->error_recovering) |
1886 | iwl_error_recovery(priv); | 1894 | iwl_error_recovery(priv); |
1887 | 1895 | ||
1888 | iwl_power_update_mode(priv, 1); | 1896 | iwl_power_update_mode(priv, 1); |
1889 | 1897 | ||
1890 | /* reassociate for ADHOC mode */ | 1898 | /* reassociate for ADHOC mode */ |
1891 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { | 1899 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { |
1892 | struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, | 1900 | struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, |
1893 | priv->vif); | 1901 | priv->vif); |
1894 | if (beacon) | 1902 | if (beacon) |
1895 | iwl_mac_beacon_update(priv->hw, beacon); | 1903 | iwl_mac_beacon_update(priv->hw, beacon); |
1896 | } | 1904 | } |
1897 | 1905 | ||
1898 | 1906 | ||
1899 | if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) | 1907 | if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) |
1900 | iwl_set_mode(priv, priv->iw_mode); | 1908 | iwl_set_mode(priv, priv->iw_mode); |
1901 | 1909 | ||
1902 | return; | 1910 | return; |
1903 | 1911 | ||
1904 | restart: | 1912 | restart: |
1905 | queue_work(priv->workqueue, &priv->restart); | 1913 | queue_work(priv->workqueue, &priv->restart); |
1906 | } | 1914 | } |
1907 | 1915 | ||
1908 | static void iwl_cancel_deferred_work(struct iwl_priv *priv); | 1916 | static void iwl_cancel_deferred_work(struct iwl_priv *priv); |
1909 | 1917 | ||
1910 | static void __iwl_down(struct iwl_priv *priv) | 1918 | static void __iwl_down(struct iwl_priv *priv) |
1911 | { | 1919 | { |
1912 | unsigned long flags; | 1920 | unsigned long flags; |
1913 | int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); | 1921 | int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); |
1914 | 1922 | ||
1915 | IWL_DEBUG_INFO(DRV_NAME " is going down\n"); | 1923 | IWL_DEBUG_INFO(DRV_NAME " is going down\n"); |
1916 | 1924 | ||
1917 | if (!exit_pending) | 1925 | if (!exit_pending) |
1918 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 1926 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
1919 | 1927 | ||
1920 | iwl_leds_unregister(priv); | 1928 | iwl_leds_unregister(priv); |
1921 | 1929 | ||
1922 | iwl_clear_stations_table(priv); | 1930 | iwl_clear_stations_table(priv); |
1923 | 1931 | ||
1924 | /* Unblock any waiting calls */ | 1932 | /* Unblock any waiting calls */ |
1925 | wake_up_interruptible_all(&priv->wait_command_queue); | 1933 | wake_up_interruptible_all(&priv->wait_command_queue); |
1926 | 1934 | ||
1927 | /* Wipe out the EXIT_PENDING status bit if we are not actually | 1935 | /* Wipe out the EXIT_PENDING status bit if we are not actually |
1928 | * exiting the module */ | 1936 | * exiting the module */ |
1929 | if (!exit_pending) | 1937 | if (!exit_pending) |
1930 | clear_bit(STATUS_EXIT_PENDING, &priv->status); | 1938 | clear_bit(STATUS_EXIT_PENDING, &priv->status); |
1931 | 1939 | ||
1932 | /* stop and reset the on-board processor */ | 1940 | /* stop and reset the on-board processor */ |
1933 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | 1941 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); |
1934 | 1942 | ||
1935 | /* tell the device to stop sending interrupts */ | 1943 | /* tell the device to stop sending interrupts */ |
1936 | spin_lock_irqsave(&priv->lock, flags); | 1944 | spin_lock_irqsave(&priv->lock, flags); |
1937 | iwl_disable_interrupts(priv); | 1945 | iwl_disable_interrupts(priv); |
1938 | spin_unlock_irqrestore(&priv->lock, flags); | 1946 | spin_unlock_irqrestore(&priv->lock, flags); |
1939 | iwl_synchronize_irq(priv); | 1947 | iwl_synchronize_irq(priv); |
1940 | 1948 | ||
1941 | if (priv->mac80211_registered) | 1949 | if (priv->mac80211_registered) |
1942 | ieee80211_stop_queues(priv->hw); | 1950 | ieee80211_stop_queues(priv->hw); |
1943 | 1951 | ||
1944 | /* If we have not previously called iwl_init() then | 1952 | /* If we have not previously called iwl_init() then |
1945 | * clear all bits but the RF Kill and SUSPEND bits and return */ | 1953 | * clear all bits but the RF Kill and SUSPEND bits and return */ |
1946 | if (!iwl_is_init(priv)) { | 1954 | if (!iwl_is_init(priv)) { |
1947 | priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << | 1955 | priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << |
1948 | STATUS_RF_KILL_HW | | 1956 | STATUS_RF_KILL_HW | |
1949 | test_bit(STATUS_RF_KILL_SW, &priv->status) << | 1957 | test_bit(STATUS_RF_KILL_SW, &priv->status) << |
1950 | STATUS_RF_KILL_SW | | 1958 | STATUS_RF_KILL_SW | |
1951 | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << | 1959 | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << |
1952 | STATUS_GEO_CONFIGURED | | 1960 | STATUS_GEO_CONFIGURED | |
1953 | test_bit(STATUS_IN_SUSPEND, &priv->status) << | 1961 | test_bit(STATUS_IN_SUSPEND, &priv->status) << |
1954 | STATUS_IN_SUSPEND | | 1962 | STATUS_IN_SUSPEND | |
1955 | test_bit(STATUS_EXIT_PENDING, &priv->status) << | 1963 | test_bit(STATUS_EXIT_PENDING, &priv->status) << |
1956 | STATUS_EXIT_PENDING; | 1964 | STATUS_EXIT_PENDING; |
1957 | goto exit; | 1965 | goto exit; |
1958 | } | 1966 | } |
1959 | 1967 | ||
1960 | /* ...otherwise clear out all the status bits but the RF Kill and | 1968 | /* ...otherwise clear out all the status bits but the RF Kill and |
1961 | * SUSPEND bits and continue taking the NIC down. */ | 1969 | * SUSPEND bits and continue taking the NIC down. */ |
1962 | priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << | 1970 | priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << |
1963 | STATUS_RF_KILL_HW | | 1971 | STATUS_RF_KILL_HW | |
1964 | test_bit(STATUS_RF_KILL_SW, &priv->status) << | 1972 | test_bit(STATUS_RF_KILL_SW, &priv->status) << |
1965 | STATUS_RF_KILL_SW | | 1973 | STATUS_RF_KILL_SW | |
1966 | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << | 1974 | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << |
1967 | STATUS_GEO_CONFIGURED | | 1975 | STATUS_GEO_CONFIGURED | |
1968 | test_bit(STATUS_IN_SUSPEND, &priv->status) << | 1976 | test_bit(STATUS_IN_SUSPEND, &priv->status) << |
1969 | STATUS_IN_SUSPEND | | 1977 | STATUS_IN_SUSPEND | |
1970 | test_bit(STATUS_FW_ERROR, &priv->status) << | 1978 | test_bit(STATUS_FW_ERROR, &priv->status) << |
1971 | STATUS_FW_ERROR | | 1979 | STATUS_FW_ERROR | |
1972 | test_bit(STATUS_EXIT_PENDING, &priv->status) << | 1980 | test_bit(STATUS_EXIT_PENDING, &priv->status) << |
1973 | STATUS_EXIT_PENDING; | 1981 | STATUS_EXIT_PENDING; |
1974 | 1982 | ||
1975 | spin_lock_irqsave(&priv->lock, flags); | 1983 | spin_lock_irqsave(&priv->lock, flags); |
1976 | iwl_clear_bit(priv, CSR_GP_CNTRL, | 1984 | iwl_clear_bit(priv, CSR_GP_CNTRL, |
1977 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1985 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
1978 | spin_unlock_irqrestore(&priv->lock, flags); | 1986 | spin_unlock_irqrestore(&priv->lock, flags); |
1979 | 1987 | ||
1980 | iwl_txq_ctx_stop(priv); | 1988 | iwl_txq_ctx_stop(priv); |
1981 | iwl_rxq_stop(priv); | 1989 | iwl_rxq_stop(priv); |
1982 | 1990 | ||
1983 | spin_lock_irqsave(&priv->lock, flags); | 1991 | spin_lock_irqsave(&priv->lock, flags); |
1984 | if (!iwl_grab_nic_access(priv)) { | 1992 | if (!iwl_grab_nic_access(priv)) { |
1985 | iwl_write_prph(priv, APMG_CLK_DIS_REG, | 1993 | iwl_write_prph(priv, APMG_CLK_DIS_REG, |
1986 | APMG_CLK_VAL_DMA_CLK_RQT); | 1994 | APMG_CLK_VAL_DMA_CLK_RQT); |
1987 | iwl_release_nic_access(priv); | 1995 | iwl_release_nic_access(priv); |
1988 | } | 1996 | } |
1989 | spin_unlock_irqrestore(&priv->lock, flags); | 1997 | spin_unlock_irqrestore(&priv->lock, flags); |
1990 | 1998 | ||
1991 | udelay(5); | 1999 | udelay(5); |
1992 | 2000 | ||
1993 | /* FIXME: apm_ops.suspend(priv) */ | 2001 | /* FIXME: apm_ops.suspend(priv) */ |
1994 | if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) | 2002 | if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) |
1995 | priv->cfg->ops->lib->apm_ops.stop(priv); | 2003 | priv->cfg->ops->lib->apm_ops.stop(priv); |
1996 | else | 2004 | else |
1997 | priv->cfg->ops->lib->apm_ops.reset(priv); | 2005 | priv->cfg->ops->lib->apm_ops.reset(priv); |
1998 | exit: | 2006 | exit: |
1999 | memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); | 2007 | memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); |
2000 | 2008 | ||
2001 | if (priv->ibss_beacon) | 2009 | if (priv->ibss_beacon) |
2002 | dev_kfree_skb(priv->ibss_beacon); | 2010 | dev_kfree_skb(priv->ibss_beacon); |
2003 | priv->ibss_beacon = NULL; | 2011 | priv->ibss_beacon = NULL; |
2004 | 2012 | ||
2005 | /* clear out any free frames */ | 2013 | /* clear out any free frames */ |
2006 | iwl_clear_free_frames(priv); | 2014 | iwl_clear_free_frames(priv); |
2007 | } | 2015 | } |
2008 | 2016 | ||
2009 | static void iwl_down(struct iwl_priv *priv) | 2017 | static void iwl_down(struct iwl_priv *priv) |
2010 | { | 2018 | { |
2011 | mutex_lock(&priv->mutex); | 2019 | mutex_lock(&priv->mutex); |
2012 | __iwl_down(priv); | 2020 | __iwl_down(priv); |
2013 | mutex_unlock(&priv->mutex); | 2021 | mutex_unlock(&priv->mutex); |
2014 | 2022 | ||
2015 | iwl_cancel_deferred_work(priv); | 2023 | iwl_cancel_deferred_work(priv); |
2016 | } | 2024 | } |
2017 | 2025 | ||
2018 | #define MAX_HW_RESTARTS 5 | 2026 | #define MAX_HW_RESTARTS 5 |
2019 | 2027 | ||
2020 | static int __iwl_up(struct iwl_priv *priv) | 2028 | static int __iwl_up(struct iwl_priv *priv) |
2021 | { | 2029 | { |
2022 | int i; | 2030 | int i; |
2023 | int ret; | 2031 | int ret; |
2024 | 2032 | ||
2025 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | 2033 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { |
2026 | IWL_WARNING("Exit pending; will not bring the NIC up\n"); | 2034 | IWL_WARNING("Exit pending; will not bring the NIC up\n"); |
2027 | return -EIO; | 2035 | return -EIO; |
2028 | } | 2036 | } |
2029 | 2037 | ||
2030 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { | 2038 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { |
2031 | IWL_ERROR("ucode not available for device bringup\n"); | 2039 | IWL_ERROR("ucode not available for device bringup\n"); |
2032 | return -EIO; | 2040 | return -EIO; |
2033 | } | 2041 | } |
2034 | 2042 | ||
2035 | /* If platform's RF_KILL switch is NOT set to KILL */ | 2043 | /* If platform's RF_KILL switch is NOT set to KILL */ |
2036 | if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | 2044 | if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) |
2037 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 2045 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
2038 | else | 2046 | else |
2039 | set_bit(STATUS_RF_KILL_HW, &priv->status); | 2047 | set_bit(STATUS_RF_KILL_HW, &priv->status); |
2040 | 2048 | ||
2041 | if (iwl_is_rfkill(priv)) { | 2049 | if (iwl_is_rfkill(priv)) { |
2042 | iwl_enable_interrupts(priv); | 2050 | iwl_enable_interrupts(priv); |
2043 | IWL_WARNING("Radio disabled by %s RF Kill switch\n", | 2051 | IWL_WARNING("Radio disabled by %s RF Kill switch\n", |
2044 | test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); | 2052 | test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); |
2045 | return 0; | 2053 | return 0; |
2046 | } | 2054 | } |
2047 | 2055 | ||
2048 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 2056 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
2049 | 2057 | ||
2050 | ret = iwl_hw_nic_init(priv); | 2058 | ret = iwl_hw_nic_init(priv); |
2051 | if (ret) { | 2059 | if (ret) { |
2052 | IWL_ERROR("Unable to init nic\n"); | 2060 | IWL_ERROR("Unable to init nic\n"); |
2053 | return ret; | 2061 | return ret; |
2054 | } | 2062 | } |
2055 | 2063 | ||
2056 | /* make sure rfkill handshake bits are cleared */ | 2064 | /* make sure rfkill handshake bits are cleared */ |
2057 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 2065 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
2058 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 2066 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
2059 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 2067 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
2060 | 2068 | ||
2061 | /* clear (again), then enable host interrupts */ | 2069 | /* clear (again), then enable host interrupts */ |
2062 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 2070 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
2063 | iwl_enable_interrupts(priv); | 2071 | iwl_enable_interrupts(priv); |
2064 | 2072 | ||
2065 | /* really make sure rfkill handshake bits are cleared */ | 2073 | /* really make sure rfkill handshake bits are cleared */ |
2066 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 2074 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
2067 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 2075 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
2068 | 2076 | ||
2069 | /* Copy original ucode data image from disk into backup cache. | 2077 | /* Copy original ucode data image from disk into backup cache. |
2070 | * This will be used to initialize the on-board processor's | 2078 | * This will be used to initialize the on-board processor's |
2071 | * data SRAM for a clean start when the runtime program first loads. */ | 2079 | * data SRAM for a clean start when the runtime program first loads. */ |
2072 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, | 2080 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, |
2073 | priv->ucode_data.len); | 2081 | priv->ucode_data.len); |
2074 | 2082 | ||
2075 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 2083 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
2076 | 2084 | ||
2077 | iwl_clear_stations_table(priv); | 2085 | iwl_clear_stations_table(priv); |
2078 | 2086 | ||
2079 | /* load bootstrap state machine, | 2087 | /* load bootstrap state machine, |
2080 | * load bootstrap program into processor's memory, | 2088 | * load bootstrap program into processor's memory, |
2081 | * prepare to load the "initialize" uCode */ | 2089 | * prepare to load the "initialize" uCode */ |
2082 | ret = priv->cfg->ops->lib->load_ucode(priv); | 2090 | ret = priv->cfg->ops->lib->load_ucode(priv); |
2083 | 2091 | ||
2084 | if (ret) { | 2092 | if (ret) { |
2085 | IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret); | 2093 | IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret); |
2086 | continue; | 2094 | continue; |
2087 | } | 2095 | } |
2088 | 2096 | ||
2089 | /* Clear out the uCode error bit if it is set */ | 2097 | /* Clear out the uCode error bit if it is set */ |
2090 | clear_bit(STATUS_FW_ERROR, &priv->status); | 2098 | clear_bit(STATUS_FW_ERROR, &priv->status); |
2091 | 2099 | ||
2092 | /* start card; "initialize" will load runtime ucode */ | 2100 | /* start card; "initialize" will load runtime ucode */ |
2093 | iwl_nic_start(priv); | 2101 | iwl_nic_start(priv); |
2094 | 2102 | ||
2095 | IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); | 2103 | IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); |
2096 | 2104 | ||
2097 | return 0; | 2105 | return 0; |
2098 | } | 2106 | } |
2099 | 2107 | ||
2100 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 2108 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
2101 | __iwl_down(priv); | 2109 | __iwl_down(priv); |
2102 | clear_bit(STATUS_EXIT_PENDING, &priv->status); | 2110 | clear_bit(STATUS_EXIT_PENDING, &priv->status); |
2103 | 2111 | ||
2104 | /* tried to restart and config the device for as long as our | 2112 | /* tried to restart and config the device for as long as our |
2105 | * patience could withstand */ | 2113 | * patience could withstand */ |
2106 | IWL_ERROR("Unable to initialize device after %d attempts.\n", i); | 2114 | IWL_ERROR("Unable to initialize device after %d attempts.\n", i); |
2107 | return -EIO; | 2115 | return -EIO; |
2108 | } | 2116 | } |
2109 | 2117 | ||
2110 | 2118 | ||
2111 | /***************************************************************************** | 2119 | /***************************************************************************** |
2112 | * | 2120 | * |
2113 | * Workqueue callbacks | 2121 | * Workqueue callbacks |
2114 | * | 2122 | * |
2115 | *****************************************************************************/ | 2123 | *****************************************************************************/ |
2116 | 2124 | ||
2117 | static void iwl_bg_init_alive_start(struct work_struct *data) | 2125 | static void iwl_bg_init_alive_start(struct work_struct *data) |
2118 | { | 2126 | { |
2119 | struct iwl_priv *priv = | 2127 | struct iwl_priv *priv = |
2120 | container_of(data, struct iwl_priv, init_alive_start.work); | 2128 | container_of(data, struct iwl_priv, init_alive_start.work); |
2121 | 2129 | ||
2122 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2130 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2123 | return; | 2131 | return; |
2124 | 2132 | ||
2125 | mutex_lock(&priv->mutex); | 2133 | mutex_lock(&priv->mutex); |
2126 | priv->cfg->ops->lib->init_alive_start(priv); | 2134 | priv->cfg->ops->lib->init_alive_start(priv); |
2127 | mutex_unlock(&priv->mutex); | 2135 | mutex_unlock(&priv->mutex); |
2128 | } | 2136 | } |
2129 | 2137 | ||
2130 | static void iwl_bg_alive_start(struct work_struct *data) | 2138 | static void iwl_bg_alive_start(struct work_struct *data) |
2131 | { | 2139 | { |
2132 | struct iwl_priv *priv = | 2140 | struct iwl_priv *priv = |
2133 | container_of(data, struct iwl_priv, alive_start.work); | 2141 | container_of(data, struct iwl_priv, alive_start.work); |
2134 | 2142 | ||
2135 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2143 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2136 | return; | 2144 | return; |
2137 | 2145 | ||
2138 | mutex_lock(&priv->mutex); | 2146 | mutex_lock(&priv->mutex); |
2139 | iwl_alive_start(priv); | 2147 | iwl_alive_start(priv); |
2140 | mutex_unlock(&priv->mutex); | 2148 | mutex_unlock(&priv->mutex); |
2141 | } | 2149 | } |
2142 | 2150 | ||
2143 | static void iwl_bg_rf_kill(struct work_struct *work) | 2151 | static void iwl_bg_rf_kill(struct work_struct *work) |
2144 | { | 2152 | { |
2145 | struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); | 2153 | struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); |
2146 | 2154 | ||
2147 | wake_up_interruptible(&priv->wait_command_queue); | 2155 | wake_up_interruptible(&priv->wait_command_queue); |
2148 | 2156 | ||
2149 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2157 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2150 | return; | 2158 | return; |
2151 | 2159 | ||
2152 | mutex_lock(&priv->mutex); | 2160 | mutex_lock(&priv->mutex); |
2153 | 2161 | ||
2154 | if (!iwl_is_rfkill(priv)) { | 2162 | if (!iwl_is_rfkill(priv)) { |
2155 | IWL_DEBUG(IWL_DL_RF_KILL, | 2163 | IWL_DEBUG(IWL_DL_RF_KILL, |
2156 | "HW and/or SW RF Kill no longer active, restarting " | 2164 | "HW and/or SW RF Kill no longer active, restarting " |
2157 | "device\n"); | 2165 | "device\n"); |
2158 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2166 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2159 | queue_work(priv->workqueue, &priv->restart); | 2167 | queue_work(priv->workqueue, &priv->restart); |
2160 | } else { | 2168 | } else { |
2161 | /* make sure mac80211 stop sending Tx frame */ | 2169 | /* make sure mac80211 stop sending Tx frame */ |
2162 | if (priv->mac80211_registered) | 2170 | if (priv->mac80211_registered) |
2163 | ieee80211_stop_queues(priv->hw); | 2171 | ieee80211_stop_queues(priv->hw); |
2164 | 2172 | ||
2165 | if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) | 2173 | if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) |
2166 | IWL_DEBUG_RF_KILL("Can not turn radio back on - " | 2174 | IWL_DEBUG_RF_KILL("Can not turn radio back on - " |
2167 | "disabled by SW switch\n"); | 2175 | "disabled by SW switch\n"); |
2168 | else | 2176 | else |
2169 | IWL_WARNING("Radio Frequency Kill Switch is On:\n" | 2177 | IWL_WARNING("Radio Frequency Kill Switch is On:\n" |
2170 | "Kill switch must be turned off for " | 2178 | "Kill switch must be turned off for " |
2171 | "wireless networking to work.\n"); | 2179 | "wireless networking to work.\n"); |
2172 | } | 2180 | } |
2173 | mutex_unlock(&priv->mutex); | 2181 | mutex_unlock(&priv->mutex); |
2174 | iwl_rfkill_set_hw_state(priv); | 2182 | iwl_rfkill_set_hw_state(priv); |
2175 | } | 2183 | } |
2176 | 2184 | ||
2177 | static void iwl_bg_run_time_calib_work(struct work_struct *work) | 2185 | static void iwl_bg_run_time_calib_work(struct work_struct *work) |
2178 | { | 2186 | { |
2179 | struct iwl_priv *priv = container_of(work, struct iwl_priv, | 2187 | struct iwl_priv *priv = container_of(work, struct iwl_priv, |
2180 | run_time_calib_work); | 2188 | run_time_calib_work); |
2181 | 2189 | ||
2182 | mutex_lock(&priv->mutex); | 2190 | mutex_lock(&priv->mutex); |
2183 | 2191 | ||
2184 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || | 2192 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || |
2185 | test_bit(STATUS_SCANNING, &priv->status)) { | 2193 | test_bit(STATUS_SCANNING, &priv->status)) { |
2186 | mutex_unlock(&priv->mutex); | 2194 | mutex_unlock(&priv->mutex); |
2187 | return; | 2195 | return; |
2188 | } | 2196 | } |
2189 | 2197 | ||
2190 | if (priv->start_calib) { | 2198 | if (priv->start_calib) { |
2191 | iwl_chain_noise_calibration(priv, &priv->statistics); | 2199 | iwl_chain_noise_calibration(priv, &priv->statistics); |
2192 | 2200 | ||
2193 | iwl_sensitivity_calibration(priv, &priv->statistics); | 2201 | iwl_sensitivity_calibration(priv, &priv->statistics); |
2194 | } | 2202 | } |
2195 | 2203 | ||
2196 | mutex_unlock(&priv->mutex); | 2204 | mutex_unlock(&priv->mutex); |
2197 | return; | 2205 | return; |
2198 | } | 2206 | } |
2199 | 2207 | ||
2200 | static void iwl_bg_up(struct work_struct *data) | 2208 | static void iwl_bg_up(struct work_struct *data) |
2201 | { | 2209 | { |
2202 | struct iwl_priv *priv = container_of(data, struct iwl_priv, up); | 2210 | struct iwl_priv *priv = container_of(data, struct iwl_priv, up); |
2203 | 2211 | ||
2204 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2212 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2205 | return; | 2213 | return; |
2206 | 2214 | ||
2207 | mutex_lock(&priv->mutex); | 2215 | mutex_lock(&priv->mutex); |
2208 | __iwl_up(priv); | 2216 | __iwl_up(priv); |
2209 | mutex_unlock(&priv->mutex); | 2217 | mutex_unlock(&priv->mutex); |
2210 | iwl_rfkill_set_hw_state(priv); | 2218 | iwl_rfkill_set_hw_state(priv); |
2211 | } | 2219 | } |
2212 | 2220 | ||
2213 | static void iwl_bg_restart(struct work_struct *data) | 2221 | static void iwl_bg_restart(struct work_struct *data) |
2214 | { | 2222 | { |
2215 | struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); | 2223 | struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); |
2216 | 2224 | ||
2217 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2225 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2218 | return; | 2226 | return; |
2219 | 2227 | ||
2220 | iwl_down(priv); | 2228 | iwl_down(priv); |
2221 | queue_work(priv->workqueue, &priv->up); | 2229 | queue_work(priv->workqueue, &priv->up); |
2222 | } | 2230 | } |
2223 | 2231 | ||
2224 | static void iwl_bg_rx_replenish(struct work_struct *data) | 2232 | static void iwl_bg_rx_replenish(struct work_struct *data) |
2225 | { | 2233 | { |
2226 | struct iwl_priv *priv = | 2234 | struct iwl_priv *priv = |
2227 | container_of(data, struct iwl_priv, rx_replenish); | 2235 | container_of(data, struct iwl_priv, rx_replenish); |
2228 | 2236 | ||
2229 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2237 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2230 | return; | 2238 | return; |
2231 | 2239 | ||
2232 | mutex_lock(&priv->mutex); | 2240 | mutex_lock(&priv->mutex); |
2233 | iwl_rx_replenish(priv); | 2241 | iwl_rx_replenish(priv); |
2234 | mutex_unlock(&priv->mutex); | 2242 | mutex_unlock(&priv->mutex); |
2235 | } | 2243 | } |
2236 | 2244 | ||
2237 | #define IWL_DELAY_NEXT_SCAN (HZ*2) | 2245 | #define IWL_DELAY_NEXT_SCAN (HZ*2) |
2238 | 2246 | ||
2239 | static void iwl_post_associate(struct iwl_priv *priv) | 2247 | static void iwl_post_associate(struct iwl_priv *priv) |
2240 | { | 2248 | { |
2241 | struct ieee80211_conf *conf = NULL; | 2249 | struct ieee80211_conf *conf = NULL; |
2242 | int ret = 0; | 2250 | int ret = 0; |
2243 | unsigned long flags; | 2251 | unsigned long flags; |
2244 | 2252 | ||
2245 | if (priv->iw_mode == NL80211_IFTYPE_AP) { | 2253 | if (priv->iw_mode == NL80211_IFTYPE_AP) { |
2246 | IWL_ERROR("%s Should not be called in AP mode\n", __func__); | 2254 | IWL_ERROR("%s Should not be called in AP mode\n", __func__); |
2247 | return; | 2255 | return; |
2248 | } | 2256 | } |
2249 | 2257 | ||
2250 | IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", | 2258 | IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", |
2251 | priv->assoc_id, priv->active_rxon.bssid_addr); | 2259 | priv->assoc_id, priv->active_rxon.bssid_addr); |
2252 | 2260 | ||
2253 | 2261 | ||
2254 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2262 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2255 | return; | 2263 | return; |
2256 | 2264 | ||
2257 | 2265 | ||
2258 | if (!priv->vif || !priv->is_open) | 2266 | if (!priv->vif || !priv->is_open) |
2259 | return; | 2267 | return; |
2260 | 2268 | ||
2261 | iwl_power_cancel_timeout(priv); | 2269 | iwl_power_cancel_timeout(priv); |
2262 | iwl_scan_cancel_timeout(priv, 200); | 2270 | iwl_scan_cancel_timeout(priv, 200); |
2263 | 2271 | ||
2264 | conf = ieee80211_get_hw_conf(priv->hw); | 2272 | conf = ieee80211_get_hw_conf(priv->hw); |
2265 | 2273 | ||
2266 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 2274 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
2267 | iwl_commit_rxon(priv); | 2275 | iwl_commit_rxon(priv); |
2268 | 2276 | ||
2269 | iwl_setup_rxon_timing(priv); | 2277 | iwl_setup_rxon_timing(priv); |
2270 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, | 2278 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, |
2271 | sizeof(priv->rxon_timing), &priv->rxon_timing); | 2279 | sizeof(priv->rxon_timing), &priv->rxon_timing); |
2272 | if (ret) | 2280 | if (ret) |
2273 | IWL_WARNING("REPLY_RXON_TIMING failed - " | 2281 | IWL_WARNING("REPLY_RXON_TIMING failed - " |
2274 | "Attempting to continue.\n"); | 2282 | "Attempting to continue.\n"); |
2275 | 2283 | ||
2276 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; | 2284 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; |
2277 | 2285 | ||
2278 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | 2286 | iwl_set_rxon_ht(priv, &priv->current_ht_config); |
2279 | 2287 | ||
2280 | iwl_set_rxon_chain(priv); | 2288 | iwl_set_rxon_chain(priv); |
2281 | priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); | 2289 | priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); |
2282 | 2290 | ||
2283 | IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", | 2291 | IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", |
2284 | priv->assoc_id, priv->beacon_int); | 2292 | priv->assoc_id, priv->beacon_int); |
2285 | 2293 | ||
2286 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) | 2294 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) |
2287 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | 2295 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; |
2288 | else | 2296 | else |
2289 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; | 2297 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; |
2290 | 2298 | ||
2291 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { | 2299 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { |
2292 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) | 2300 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) |
2293 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; | 2301 | priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; |
2294 | else | 2302 | else |
2295 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | 2303 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; |
2296 | 2304 | ||
2297 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) | 2305 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) |
2298 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | 2306 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; |
2299 | 2307 | ||
2300 | } | 2308 | } |
2301 | 2309 | ||
2302 | iwl_commit_rxon(priv); | 2310 | iwl_commit_rxon(priv); |
2303 | 2311 | ||
2304 | switch (priv->iw_mode) { | 2312 | switch (priv->iw_mode) { |
2305 | case NL80211_IFTYPE_STATION: | 2313 | case NL80211_IFTYPE_STATION: |
2306 | break; | 2314 | break; |
2307 | 2315 | ||
2308 | case NL80211_IFTYPE_ADHOC: | 2316 | case NL80211_IFTYPE_ADHOC: |
2309 | 2317 | ||
2310 | /* assume default assoc id */ | 2318 | /* assume default assoc id */ |
2311 | priv->assoc_id = 1; | 2319 | priv->assoc_id = 1; |
2312 | 2320 | ||
2313 | iwl_rxon_add_station(priv, priv->bssid, 0); | 2321 | iwl_rxon_add_station(priv, priv->bssid, 0); |
2314 | iwl_send_beacon_cmd(priv); | 2322 | iwl_send_beacon_cmd(priv); |
2315 | 2323 | ||
2316 | break; | 2324 | break; |
2317 | 2325 | ||
2318 | default: | 2326 | default: |
2319 | IWL_ERROR("%s Should not be called in %d mode\n", | 2327 | IWL_ERROR("%s Should not be called in %d mode\n", |
2320 | __func__, priv->iw_mode); | 2328 | __func__, priv->iw_mode); |
2321 | break; | 2329 | break; |
2322 | } | 2330 | } |
2323 | 2331 | ||
2324 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) | 2332 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) |
2325 | priv->assoc_station_added = 1; | 2333 | priv->assoc_station_added = 1; |
2326 | 2334 | ||
2327 | spin_lock_irqsave(&priv->lock, flags); | 2335 | spin_lock_irqsave(&priv->lock, flags); |
2328 | iwl_activate_qos(priv, 0); | 2336 | iwl_activate_qos(priv, 0); |
2329 | spin_unlock_irqrestore(&priv->lock, flags); | 2337 | spin_unlock_irqrestore(&priv->lock, flags); |
2330 | 2338 | ||
2331 | /* the chain noise calibration will enabled PM upon completion | 2339 | /* the chain noise calibration will enabled PM upon completion |
2332 | * If chain noise has already been run, then we need to enable | 2340 | * If chain noise has already been run, then we need to enable |
2333 | * power management here */ | 2341 | * power management here */ |
2334 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) | 2342 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) |
2335 | iwl_power_enable_management(priv); | 2343 | iwl_power_enable_management(priv); |
2336 | 2344 | ||
2337 | /* Enable Rx differential gain and sensitivity calibrations */ | 2345 | /* Enable Rx differential gain and sensitivity calibrations */ |
2338 | iwl_chain_noise_reset(priv); | 2346 | iwl_chain_noise_reset(priv); |
2339 | priv->start_calib = 1; | 2347 | priv->start_calib = 1; |
2340 | 2348 | ||
2341 | } | 2349 | } |
2342 | 2350 | ||
2343 | /***************************************************************************** | 2351 | /***************************************************************************** |
2344 | * | 2352 | * |
2345 | * mac80211 entry point functions | 2353 | * mac80211 entry point functions |
2346 | * | 2354 | * |
2347 | *****************************************************************************/ | 2355 | *****************************************************************************/ |
2348 | 2356 | ||
2349 | #define UCODE_READY_TIMEOUT (4 * HZ) | 2357 | #define UCODE_READY_TIMEOUT (4 * HZ) |
2350 | 2358 | ||
2351 | static int iwl_mac_start(struct ieee80211_hw *hw) | 2359 | static int iwl_mac_start(struct ieee80211_hw *hw) |
2352 | { | 2360 | { |
2353 | struct iwl_priv *priv = hw->priv; | 2361 | struct iwl_priv *priv = hw->priv; |
2354 | int ret; | 2362 | int ret; |
2355 | u16 pci_cmd; | 2363 | u16 pci_cmd; |
2356 | 2364 | ||
2357 | IWL_DEBUG_MAC80211("enter\n"); | 2365 | IWL_DEBUG_MAC80211("enter\n"); |
2358 | 2366 | ||
2359 | if (pci_enable_device(priv->pci_dev)) { | 2367 | if (pci_enable_device(priv->pci_dev)) { |
2360 | IWL_ERROR("Fail to pci_enable_device\n"); | 2368 | IWL_ERROR("Fail to pci_enable_device\n"); |
2361 | return -ENODEV; | 2369 | return -ENODEV; |
2362 | } | 2370 | } |
2363 | pci_restore_state(priv->pci_dev); | 2371 | pci_restore_state(priv->pci_dev); |
2364 | pci_enable_msi(priv->pci_dev); | 2372 | pci_enable_msi(priv->pci_dev); |
2365 | 2373 | ||
2366 | /* enable interrupts if needed: hw bug w/a */ | 2374 | /* enable interrupts if needed: hw bug w/a */ |
2367 | pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); | 2375 | pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); |
2368 | if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { | 2376 | if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { |
2369 | pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; | 2377 | pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; |
2370 | pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); | 2378 | pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); |
2371 | } | 2379 | } |
2372 | 2380 | ||
2373 | ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | 2381 | ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, |
2374 | DRV_NAME, priv); | 2382 | DRV_NAME, priv); |
2375 | if (ret) { | 2383 | if (ret) { |
2376 | IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); | 2384 | IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); |
2377 | goto out_disable_msi; | 2385 | goto out_disable_msi; |
2378 | } | 2386 | } |
2379 | 2387 | ||
2380 | /* we should be verifying the device is ready to be opened */ | 2388 | /* we should be verifying the device is ready to be opened */ |
2381 | mutex_lock(&priv->mutex); | 2389 | mutex_lock(&priv->mutex); |
2382 | 2390 | ||
2383 | memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); | 2391 | memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); |
2384 | /* fetch ucode file from disk, alloc and copy to bus-master buffers ... | 2392 | /* fetch ucode file from disk, alloc and copy to bus-master buffers ... |
2385 | * ucode filename and max sizes are card-specific. */ | 2393 | * ucode filename and max sizes are card-specific. */ |
2386 | 2394 | ||
2387 | if (!priv->ucode_code.len) { | 2395 | if (!priv->ucode_code.len) { |
2388 | ret = iwl_read_ucode(priv); | 2396 | ret = iwl_read_ucode(priv); |
2389 | if (ret) { | 2397 | if (ret) { |
2390 | IWL_ERROR("Could not read microcode: %d\n", ret); | 2398 | IWL_ERROR("Could not read microcode: %d\n", ret); |
2391 | mutex_unlock(&priv->mutex); | 2399 | mutex_unlock(&priv->mutex); |
2392 | goto out_release_irq; | 2400 | goto out_release_irq; |
2393 | } | 2401 | } |
2394 | } | 2402 | } |
2395 | 2403 | ||
2396 | ret = __iwl_up(priv); | 2404 | ret = __iwl_up(priv); |
2397 | 2405 | ||
2398 | mutex_unlock(&priv->mutex); | 2406 | mutex_unlock(&priv->mutex); |
2399 | 2407 | ||
2400 | iwl_rfkill_set_hw_state(priv); | 2408 | iwl_rfkill_set_hw_state(priv); |
2401 | 2409 | ||
2402 | if (ret) | 2410 | if (ret) |
2403 | goto out_release_irq; | 2411 | goto out_release_irq; |
2404 | 2412 | ||
2405 | if (iwl_is_rfkill(priv)) | 2413 | if (iwl_is_rfkill(priv)) |
2406 | goto out; | 2414 | goto out; |
2407 | 2415 | ||
2408 | IWL_DEBUG_INFO("Start UP work done.\n"); | 2416 | IWL_DEBUG_INFO("Start UP work done.\n"); |
2409 | 2417 | ||
2410 | if (test_bit(STATUS_IN_SUSPEND, &priv->status)) | 2418 | if (test_bit(STATUS_IN_SUSPEND, &priv->status)) |
2411 | return 0; | 2419 | return 0; |
2412 | 2420 | ||
2413 | /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from | 2421 | /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from |
2414 | * mac80211 will not be run successfully. */ | 2422 | * mac80211 will not be run successfully. */ |
2415 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | 2423 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, |
2416 | test_bit(STATUS_READY, &priv->status), | 2424 | test_bit(STATUS_READY, &priv->status), |
2417 | UCODE_READY_TIMEOUT); | 2425 | UCODE_READY_TIMEOUT); |
2418 | if (!ret) { | 2426 | if (!ret) { |
2419 | if (!test_bit(STATUS_READY, &priv->status)) { | 2427 | if (!test_bit(STATUS_READY, &priv->status)) { |
2420 | IWL_ERROR("START_ALIVE timeout after %dms.\n", | 2428 | IWL_ERROR("START_ALIVE timeout after %dms.\n", |
2421 | jiffies_to_msecs(UCODE_READY_TIMEOUT)); | 2429 | jiffies_to_msecs(UCODE_READY_TIMEOUT)); |
2422 | ret = -ETIMEDOUT; | 2430 | ret = -ETIMEDOUT; |
2423 | goto out_release_irq; | 2431 | goto out_release_irq; |
2424 | } | 2432 | } |
2425 | } | 2433 | } |
2426 | 2434 | ||
2427 | out: | 2435 | out: |
2428 | priv->is_open = 1; | 2436 | priv->is_open = 1; |
2429 | IWL_DEBUG_MAC80211("leave\n"); | 2437 | IWL_DEBUG_MAC80211("leave\n"); |
2430 | return 0; | 2438 | return 0; |
2431 | 2439 | ||
2432 | out_release_irq: | 2440 | out_release_irq: |
2433 | free_irq(priv->pci_dev->irq, priv); | 2441 | free_irq(priv->pci_dev->irq, priv); |
2434 | out_disable_msi: | 2442 | out_disable_msi: |
2435 | pci_disable_msi(priv->pci_dev); | 2443 | pci_disable_msi(priv->pci_dev); |
2436 | pci_disable_device(priv->pci_dev); | 2444 | pci_disable_device(priv->pci_dev); |
2437 | priv->is_open = 0; | 2445 | priv->is_open = 0; |
2438 | IWL_DEBUG_MAC80211("leave - failed\n"); | 2446 | IWL_DEBUG_MAC80211("leave - failed\n"); |
2439 | return ret; | 2447 | return ret; |
2440 | } | 2448 | } |
2441 | 2449 | ||
2442 | static void iwl_mac_stop(struct ieee80211_hw *hw) | 2450 | static void iwl_mac_stop(struct ieee80211_hw *hw) |
2443 | { | 2451 | { |
2444 | struct iwl_priv *priv = hw->priv; | 2452 | struct iwl_priv *priv = hw->priv; |
2445 | 2453 | ||
2446 | IWL_DEBUG_MAC80211("enter\n"); | 2454 | IWL_DEBUG_MAC80211("enter\n"); |
2447 | 2455 | ||
2448 | if (!priv->is_open) { | 2456 | if (!priv->is_open) { |
2449 | IWL_DEBUG_MAC80211("leave - skip\n"); | 2457 | IWL_DEBUG_MAC80211("leave - skip\n"); |
2450 | return; | 2458 | return; |
2451 | } | 2459 | } |
2452 | 2460 | ||
2453 | priv->is_open = 0; | 2461 | priv->is_open = 0; |
2454 | 2462 | ||
2455 | if (iwl_is_ready_rf(priv)) { | 2463 | if (iwl_is_ready_rf(priv)) { |
2456 | /* stop mac, cancel any scan request and clear | 2464 | /* stop mac, cancel any scan request and clear |
2457 | * RXON_FILTER_ASSOC_MSK BIT | 2465 | * RXON_FILTER_ASSOC_MSK BIT |
2458 | */ | 2466 | */ |
2459 | mutex_lock(&priv->mutex); | 2467 | mutex_lock(&priv->mutex); |
2460 | iwl_scan_cancel_timeout(priv, 100); | 2468 | iwl_scan_cancel_timeout(priv, 100); |
2461 | mutex_unlock(&priv->mutex); | 2469 | mutex_unlock(&priv->mutex); |
2462 | } | 2470 | } |
2463 | 2471 | ||
2464 | iwl_down(priv); | 2472 | iwl_down(priv); |
2465 | 2473 | ||
2466 | flush_workqueue(priv->workqueue); | 2474 | flush_workqueue(priv->workqueue); |
2467 | free_irq(priv->pci_dev->irq, priv); | 2475 | free_irq(priv->pci_dev->irq, priv); |
2468 | pci_disable_msi(priv->pci_dev); | 2476 | pci_disable_msi(priv->pci_dev); |
2469 | pci_save_state(priv->pci_dev); | 2477 | pci_save_state(priv->pci_dev); |
2470 | pci_disable_device(priv->pci_dev); | 2478 | pci_disable_device(priv->pci_dev); |
2471 | 2479 | ||
2472 | IWL_DEBUG_MAC80211("leave\n"); | 2480 | IWL_DEBUG_MAC80211("leave\n"); |
2473 | } | 2481 | } |
2474 | 2482 | ||
2475 | static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 2483 | static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
2476 | { | 2484 | { |
2477 | struct iwl_priv *priv = hw->priv; | 2485 | struct iwl_priv *priv = hw->priv; |
2478 | 2486 | ||
2479 | IWL_DEBUG_MACDUMP("enter\n"); | 2487 | IWL_DEBUG_MACDUMP("enter\n"); |
2480 | 2488 | ||
2481 | IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | 2489 | IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, |
2482 | ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | 2490 | ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); |
2483 | 2491 | ||
2484 | if (iwl_tx_skb(priv, skb)) | 2492 | if (iwl_tx_skb(priv, skb)) |
2485 | dev_kfree_skb_any(skb); | 2493 | dev_kfree_skb_any(skb); |
2486 | 2494 | ||
2487 | IWL_DEBUG_MACDUMP("leave\n"); | 2495 | IWL_DEBUG_MACDUMP("leave\n"); |
2488 | return 0; | 2496 | return 0; |
2489 | } | 2497 | } |
2490 | 2498 | ||
2491 | static int iwl_mac_add_interface(struct ieee80211_hw *hw, | 2499 | static int iwl_mac_add_interface(struct ieee80211_hw *hw, |
2492 | struct ieee80211_if_init_conf *conf) | 2500 | struct ieee80211_if_init_conf *conf) |
2493 | { | 2501 | { |
2494 | struct iwl_priv *priv = hw->priv; | 2502 | struct iwl_priv *priv = hw->priv; |
2495 | unsigned long flags; | 2503 | unsigned long flags; |
2496 | 2504 | ||
2497 | IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); | 2505 | IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); |
2498 | 2506 | ||
2499 | if (priv->vif) { | 2507 | if (priv->vif) { |
2500 | IWL_DEBUG_MAC80211("leave - vif != NULL\n"); | 2508 | IWL_DEBUG_MAC80211("leave - vif != NULL\n"); |
2501 | return -EOPNOTSUPP; | 2509 | return -EOPNOTSUPP; |
2502 | } | 2510 | } |
2503 | 2511 | ||
2504 | spin_lock_irqsave(&priv->lock, flags); | 2512 | spin_lock_irqsave(&priv->lock, flags); |
2505 | priv->vif = conf->vif; | 2513 | priv->vif = conf->vif; |
2506 | priv->iw_mode = conf->type; | 2514 | priv->iw_mode = conf->type; |
2507 | 2515 | ||
2508 | spin_unlock_irqrestore(&priv->lock, flags); | 2516 | spin_unlock_irqrestore(&priv->lock, flags); |
2509 | 2517 | ||
2510 | mutex_lock(&priv->mutex); | 2518 | mutex_lock(&priv->mutex); |
2511 | 2519 | ||
2512 | if (conf->mac_addr) { | 2520 | if (conf->mac_addr) { |
2513 | IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr); | 2521 | IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr); |
2514 | memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); | 2522 | memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); |
2515 | } | 2523 | } |
2516 | 2524 | ||
2517 | if (iwl_set_mode(priv, conf->type) == -EAGAIN) | 2525 | if (iwl_set_mode(priv, conf->type) == -EAGAIN) |
2518 | /* we are not ready, will run again when ready */ | 2526 | /* we are not ready, will run again when ready */ |
2519 | set_bit(STATUS_MODE_PENDING, &priv->status); | 2527 | set_bit(STATUS_MODE_PENDING, &priv->status); |
2520 | 2528 | ||
2521 | mutex_unlock(&priv->mutex); | 2529 | mutex_unlock(&priv->mutex); |
2522 | 2530 | ||
2523 | IWL_DEBUG_MAC80211("leave\n"); | 2531 | IWL_DEBUG_MAC80211("leave\n"); |
2524 | return 0; | 2532 | return 0; |
2525 | } | 2533 | } |
2526 | 2534 | ||
2527 | /** | 2535 | /** |
2528 | * iwl_mac_config - mac80211 config callback | 2536 | * iwl_mac_config - mac80211 config callback |
2529 | * | 2537 | * |
2530 | * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to | 2538 | * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to |
2531 | * be set inappropriately and the driver currently sets the hardware up to | 2539 | * be set inappropriately and the driver currently sets the hardware up to |
2532 | * use it whenever needed. | 2540 | * use it whenever needed. |
2533 | */ | 2541 | */ |
2534 | static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | 2542 | static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) |
2535 | { | 2543 | { |
2536 | struct iwl_priv *priv = hw->priv; | 2544 | struct iwl_priv *priv = hw->priv; |
2537 | const struct iwl_channel_info *ch_info; | 2545 | const struct iwl_channel_info *ch_info; |
2538 | struct ieee80211_conf *conf = &hw->conf; | 2546 | struct ieee80211_conf *conf = &hw->conf; |
2539 | unsigned long flags; | 2547 | unsigned long flags; |
2540 | int ret = 0; | 2548 | int ret = 0; |
2541 | u16 channel; | 2549 | u16 channel; |
2542 | 2550 | ||
2543 | mutex_lock(&priv->mutex); | 2551 | mutex_lock(&priv->mutex); |
2544 | IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); | 2552 | IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); |
2545 | 2553 | ||
2546 | priv->current_ht_config.is_ht = conf->ht.enabled; | 2554 | priv->current_ht_config.is_ht = conf->ht.enabled; |
2547 | 2555 | ||
2548 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { | 2556 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { |
2549 | IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); | 2557 | IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); |
2550 | goto out; | 2558 | goto out; |
2551 | } | 2559 | } |
2552 | 2560 | ||
2553 | if (!conf->radio_enabled) | 2561 | if (!conf->radio_enabled) |
2554 | iwl_radio_kill_sw_disable_radio(priv); | 2562 | iwl_radio_kill_sw_disable_radio(priv); |
2555 | 2563 | ||
2556 | if (!iwl_is_ready(priv)) { | 2564 | if (!iwl_is_ready(priv)) { |
2557 | IWL_DEBUG_MAC80211("leave - not ready\n"); | 2565 | IWL_DEBUG_MAC80211("leave - not ready\n"); |
2558 | ret = -EIO; | 2566 | ret = -EIO; |
2559 | goto out; | 2567 | goto out; |
2560 | } | 2568 | } |
2561 | 2569 | ||
2562 | if (unlikely(!priv->cfg->mod_params->disable_hw_scan && | 2570 | if (unlikely(!priv->cfg->mod_params->disable_hw_scan && |
2563 | test_bit(STATUS_SCANNING, &priv->status))) { | 2571 | test_bit(STATUS_SCANNING, &priv->status))) { |
2564 | IWL_DEBUG_MAC80211("leave - scanning\n"); | 2572 | IWL_DEBUG_MAC80211("leave - scanning\n"); |
2565 | mutex_unlock(&priv->mutex); | 2573 | mutex_unlock(&priv->mutex); |
2566 | return 0; | 2574 | return 0; |
2567 | } | 2575 | } |
2568 | 2576 | ||
2569 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | 2577 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); |
2570 | ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); | 2578 | ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); |
2571 | if (!is_channel_valid(ch_info)) { | 2579 | if (!is_channel_valid(ch_info)) { |
2572 | IWL_DEBUG_MAC80211("leave - invalid channel\n"); | 2580 | IWL_DEBUG_MAC80211("leave - invalid channel\n"); |
2573 | ret = -EINVAL; | 2581 | ret = -EINVAL; |
2574 | goto out; | 2582 | goto out; |
2575 | } | 2583 | } |
2576 | 2584 | ||
2577 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && | 2585 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && |
2578 | !is_channel_ibss(ch_info)) { | 2586 | !is_channel_ibss(ch_info)) { |
2579 | IWL_ERROR("channel %d in band %d not IBSS channel\n", | 2587 | IWL_ERROR("channel %d in band %d not IBSS channel\n", |
2580 | conf->channel->hw_value, conf->channel->band); | 2588 | conf->channel->hw_value, conf->channel->band); |
2581 | ret = -EINVAL; | 2589 | ret = -EINVAL; |
2582 | goto out; | 2590 | goto out; |
2583 | } | 2591 | } |
2584 | 2592 | ||
2585 | spin_lock_irqsave(&priv->lock, flags); | 2593 | spin_lock_irqsave(&priv->lock, flags); |
2586 | 2594 | ||
2587 | 2595 | ||
2588 | /* if we are switching from ht to 2.4 clear flags | 2596 | /* if we are switching from ht to 2.4 clear flags |
2589 | * from any ht related info since 2.4 does not | 2597 | * from any ht related info since 2.4 does not |
2590 | * support ht */ | 2598 | * support ht */ |
2591 | if ((le16_to_cpu(priv->staging_rxon.channel) != channel) | 2599 | if ((le16_to_cpu(priv->staging_rxon.channel) != channel) |
2592 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH | 2600 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH |
2593 | && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) | 2601 | && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) |
2594 | #endif | 2602 | #endif |
2595 | ) | 2603 | ) |
2596 | priv->staging_rxon.flags = 0; | 2604 | priv->staging_rxon.flags = 0; |
2597 | 2605 | ||
2598 | iwl_set_rxon_channel(priv, conf->channel); | 2606 | iwl_set_rxon_channel(priv, conf->channel); |
2599 | 2607 | ||
2600 | iwl_set_flags_for_band(priv, conf->channel->band); | 2608 | iwl_set_flags_for_band(priv, conf->channel->band); |
2601 | 2609 | ||
2602 | /* The list of supported rates and rate mask can be different | 2610 | /* The list of supported rates and rate mask can be different |
2603 | * for each band; since the band may have changed, reset | 2611 | * for each band; since the band may have changed, reset |
2604 | * the rate mask to what mac80211 lists */ | 2612 | * the rate mask to what mac80211 lists */ |
2605 | iwl_set_rate(priv); | 2613 | iwl_set_rate(priv); |
2606 | 2614 | ||
2607 | spin_unlock_irqrestore(&priv->lock, flags); | 2615 | spin_unlock_irqrestore(&priv->lock, flags); |
2608 | 2616 | ||
2609 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH | 2617 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH |
2610 | if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { | 2618 | if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { |
2611 | iwl_hw_channel_switch(priv, conf->channel); | 2619 | iwl_hw_channel_switch(priv, conf->channel); |
2612 | goto out; | 2620 | goto out; |
2613 | } | 2621 | } |
2614 | #endif | 2622 | #endif |
2615 | 2623 | ||
2616 | if (!conf->radio_enabled) { | 2624 | if (!conf->radio_enabled) { |
2617 | IWL_DEBUG_MAC80211("leave - radio disabled\n"); | 2625 | IWL_DEBUG_MAC80211("leave - radio disabled\n"); |
2618 | goto out; | 2626 | goto out; |
2619 | } | 2627 | } |
2620 | 2628 | ||
2621 | if (iwl_is_rfkill(priv)) { | 2629 | if (iwl_is_rfkill(priv)) { |
2622 | IWL_DEBUG_MAC80211("leave - RF kill\n"); | 2630 | IWL_DEBUG_MAC80211("leave - RF kill\n"); |
2623 | ret = -EIO; | 2631 | ret = -EIO; |
2624 | goto out; | 2632 | goto out; |
2625 | } | 2633 | } |
2626 | 2634 | ||
2627 | if (conf->flags & IEEE80211_CONF_PS) | 2635 | if (conf->flags & IEEE80211_CONF_PS) |
2628 | ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); | 2636 | ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); |
2629 | else | 2637 | else |
2630 | ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); | 2638 | ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); |
2631 | if (ret) | 2639 | if (ret) |
2632 | IWL_DEBUG_MAC80211("Error setting power level\n"); | 2640 | IWL_DEBUG_MAC80211("Error setting power level\n"); |
2633 | 2641 | ||
2634 | IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", | 2642 | IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", |
2635 | priv->tx_power_user_lmt, conf->power_level); | 2643 | priv->tx_power_user_lmt, conf->power_level); |
2636 | 2644 | ||
2637 | iwl_set_tx_power(priv, conf->power_level, false); | 2645 | iwl_set_tx_power(priv, conf->power_level, false); |
2638 | 2646 | ||
2639 | iwl_set_rate(priv); | 2647 | iwl_set_rate(priv); |
2640 | 2648 | ||
2641 | if (memcmp(&priv->active_rxon, | 2649 | if (memcmp(&priv->active_rxon, |
2642 | &priv->staging_rxon, sizeof(priv->staging_rxon))) | 2650 | &priv->staging_rxon, sizeof(priv->staging_rxon))) |
2643 | iwl_commit_rxon(priv); | 2651 | iwl_commit_rxon(priv); |
2644 | else | 2652 | else |
2645 | IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); | 2653 | IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); |
2646 | 2654 | ||
2647 | IWL_DEBUG_MAC80211("leave\n"); | 2655 | IWL_DEBUG_MAC80211("leave\n"); |
2648 | 2656 | ||
2649 | out: | 2657 | out: |
2650 | mutex_unlock(&priv->mutex); | 2658 | mutex_unlock(&priv->mutex); |
2651 | return ret; | 2659 | return ret; |
2652 | } | 2660 | } |
2653 | 2661 | ||
2654 | static void iwl_config_ap(struct iwl_priv *priv) | 2662 | static void iwl_config_ap(struct iwl_priv *priv) |
2655 | { | 2663 | { |
2656 | int ret = 0; | 2664 | int ret = 0; |
2657 | unsigned long flags; | 2665 | unsigned long flags; |
2658 | 2666 | ||
2659 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2667 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2660 | return; | 2668 | return; |
2661 | 2669 | ||
2662 | /* The following should be done only at AP bring up */ | 2670 | /* The following should be done only at AP bring up */ |
2663 | if (!iwl_is_associated(priv)) { | 2671 | if (!iwl_is_associated(priv)) { |
2664 | 2672 | ||
2665 | /* RXON - unassoc (to set timing command) */ | 2673 | /* RXON - unassoc (to set timing command) */ |
2666 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 2674 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
2667 | iwl_commit_rxon(priv); | 2675 | iwl_commit_rxon(priv); |
2668 | 2676 | ||
2669 | /* RXON Timing */ | 2677 | /* RXON Timing */ |
2670 | iwl_setup_rxon_timing(priv); | 2678 | iwl_setup_rxon_timing(priv); |
2671 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, | 2679 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, |
2672 | sizeof(priv->rxon_timing), &priv->rxon_timing); | 2680 | sizeof(priv->rxon_timing), &priv->rxon_timing); |
2673 | if (ret) | 2681 | if (ret) |
2674 | IWL_WARNING("REPLY_RXON_TIMING failed - " | 2682 | IWL_WARNING("REPLY_RXON_TIMING failed - " |
2675 | "Attempting to continue.\n"); | 2683 | "Attempting to continue.\n"); |
2676 | 2684 | ||
2677 | iwl_set_rxon_chain(priv); | 2685 | iwl_set_rxon_chain(priv); |
2678 | 2686 | ||
2679 | /* FIXME: what should be the assoc_id for AP? */ | 2687 | /* FIXME: what should be the assoc_id for AP? */ |
2680 | priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); | 2688 | priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); |
2681 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) | 2689 | if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) |
2682 | priv->staging_rxon.flags |= | 2690 | priv->staging_rxon.flags |= |
2683 | RXON_FLG_SHORT_PREAMBLE_MSK; | 2691 | RXON_FLG_SHORT_PREAMBLE_MSK; |
2684 | else | 2692 | else |
2685 | priv->staging_rxon.flags &= | 2693 | priv->staging_rxon.flags &= |
2686 | ~RXON_FLG_SHORT_PREAMBLE_MSK; | 2694 | ~RXON_FLG_SHORT_PREAMBLE_MSK; |
2687 | 2695 | ||
2688 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { | 2696 | if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { |
2689 | if (priv->assoc_capability & | 2697 | if (priv->assoc_capability & |
2690 | WLAN_CAPABILITY_SHORT_SLOT_TIME) | 2698 | WLAN_CAPABILITY_SHORT_SLOT_TIME) |
2691 | priv->staging_rxon.flags |= | 2699 | priv->staging_rxon.flags |= |
2692 | RXON_FLG_SHORT_SLOT_MSK; | 2700 | RXON_FLG_SHORT_SLOT_MSK; |
2693 | else | 2701 | else |
2694 | priv->staging_rxon.flags &= | 2702 | priv->staging_rxon.flags &= |
2695 | ~RXON_FLG_SHORT_SLOT_MSK; | 2703 | ~RXON_FLG_SHORT_SLOT_MSK; |
2696 | 2704 | ||
2697 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) | 2705 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) |
2698 | priv->staging_rxon.flags &= | 2706 | priv->staging_rxon.flags &= |
2699 | ~RXON_FLG_SHORT_SLOT_MSK; | 2707 | ~RXON_FLG_SHORT_SLOT_MSK; |
2700 | } | 2708 | } |
2701 | /* restore RXON assoc */ | 2709 | /* restore RXON assoc */ |
2702 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; | 2710 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; |
2703 | iwl_commit_rxon(priv); | 2711 | iwl_commit_rxon(priv); |
2704 | spin_lock_irqsave(&priv->lock, flags); | 2712 | spin_lock_irqsave(&priv->lock, flags); |
2705 | iwl_activate_qos(priv, 1); | 2713 | iwl_activate_qos(priv, 1); |
2706 | spin_unlock_irqrestore(&priv->lock, flags); | 2714 | spin_unlock_irqrestore(&priv->lock, flags); |
2707 | iwl_rxon_add_station(priv, iwl_bcast_addr, 0); | 2715 | iwl_rxon_add_station(priv, iwl_bcast_addr, 0); |
2708 | } | 2716 | } |
2709 | iwl_send_beacon_cmd(priv); | 2717 | iwl_send_beacon_cmd(priv); |
2710 | 2718 | ||
2711 | /* FIXME - we need to add code here to detect a totally new | 2719 | /* FIXME - we need to add code here to detect a totally new |
2712 | * configuration, reset the AP, unassoc, rxon timing, assoc, | 2720 | * configuration, reset the AP, unassoc, rxon timing, assoc, |
2713 | * clear sta table, add BCAST sta... */ | 2721 | * clear sta table, add BCAST sta... */ |
2714 | } | 2722 | } |
2715 | 2723 | ||
2716 | 2724 | ||
2717 | static int iwl_mac_config_interface(struct ieee80211_hw *hw, | 2725 | static int iwl_mac_config_interface(struct ieee80211_hw *hw, |
2718 | struct ieee80211_vif *vif, | 2726 | struct ieee80211_vif *vif, |
2719 | struct ieee80211_if_conf *conf) | 2727 | struct ieee80211_if_conf *conf) |
2720 | { | 2728 | { |
2721 | struct iwl_priv *priv = hw->priv; | 2729 | struct iwl_priv *priv = hw->priv; |
2722 | int rc; | 2730 | int rc; |
2723 | 2731 | ||
2724 | if (conf == NULL) | 2732 | if (conf == NULL) |
2725 | return -EIO; | 2733 | return -EIO; |
2726 | 2734 | ||
2727 | if (priv->vif != vif) { | 2735 | if (priv->vif != vif) { |
2728 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); | 2736 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); |
2729 | return 0; | 2737 | return 0; |
2730 | } | 2738 | } |
2731 | 2739 | ||
2732 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && | 2740 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && |
2733 | conf->changed & IEEE80211_IFCC_BEACON) { | 2741 | conf->changed & IEEE80211_IFCC_BEACON) { |
2734 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | 2742 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); |
2735 | if (!beacon) | 2743 | if (!beacon) |
2736 | return -ENOMEM; | 2744 | return -ENOMEM; |
2737 | mutex_lock(&priv->mutex); | 2745 | mutex_lock(&priv->mutex); |
2738 | rc = iwl_mac_beacon_update(hw, beacon); | 2746 | rc = iwl_mac_beacon_update(hw, beacon); |
2739 | mutex_unlock(&priv->mutex); | 2747 | mutex_unlock(&priv->mutex); |
2740 | if (rc) | 2748 | if (rc) |
2741 | return rc; | 2749 | return rc; |
2742 | } | 2750 | } |
2743 | 2751 | ||
2744 | if (!iwl_is_alive(priv)) | 2752 | if (!iwl_is_alive(priv)) |
2745 | return -EAGAIN; | 2753 | return -EAGAIN; |
2746 | 2754 | ||
2747 | mutex_lock(&priv->mutex); | 2755 | mutex_lock(&priv->mutex); |
2748 | 2756 | ||
2749 | if (conf->bssid) | 2757 | if (conf->bssid) |
2750 | IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); | 2758 | IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); |
2751 | 2759 | ||
2752 | /* | 2760 | /* |
2753 | * very dubious code was here; the probe filtering flag is never set: | 2761 | * very dubious code was here; the probe filtering flag is never set: |
2754 | * | 2762 | * |
2755 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && | 2763 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && |
2756 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { | 2764 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { |
2757 | */ | 2765 | */ |
2758 | 2766 | ||
2759 | if (priv->iw_mode == NL80211_IFTYPE_AP) { | 2767 | if (priv->iw_mode == NL80211_IFTYPE_AP) { |
2760 | if (!conf->bssid) { | 2768 | if (!conf->bssid) { |
2761 | conf->bssid = priv->mac_addr; | 2769 | conf->bssid = priv->mac_addr; |
2762 | memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); | 2770 | memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); |
2763 | IWL_DEBUG_MAC80211("bssid was set to: %pM\n", | 2771 | IWL_DEBUG_MAC80211("bssid was set to: %pM\n", |
2764 | conf->bssid); | 2772 | conf->bssid); |
2765 | } | 2773 | } |
2766 | if (priv->ibss_beacon) | 2774 | if (priv->ibss_beacon) |
2767 | dev_kfree_skb(priv->ibss_beacon); | 2775 | dev_kfree_skb(priv->ibss_beacon); |
2768 | 2776 | ||
2769 | priv->ibss_beacon = ieee80211_beacon_get(hw, vif); | 2777 | priv->ibss_beacon = ieee80211_beacon_get(hw, vif); |
2770 | } | 2778 | } |
2771 | 2779 | ||
2772 | if (iwl_is_rfkill(priv)) | 2780 | if (iwl_is_rfkill(priv)) |
2773 | goto done; | 2781 | goto done; |
2774 | 2782 | ||
2775 | if (conf->bssid && !is_zero_ether_addr(conf->bssid) && | 2783 | if (conf->bssid && !is_zero_ether_addr(conf->bssid) && |
2776 | !is_multicast_ether_addr(conf->bssid)) { | 2784 | !is_multicast_ether_addr(conf->bssid)) { |
2777 | /* If there is currently a HW scan going on in the background | 2785 | /* If there is currently a HW scan going on in the background |
2778 | * then we need to cancel it else the RXON below will fail. */ | 2786 | * then we need to cancel it else the RXON below will fail. */ |
2779 | if (iwl_scan_cancel_timeout(priv, 100)) { | 2787 | if (iwl_scan_cancel_timeout(priv, 100)) { |
2780 | IWL_WARNING("Aborted scan still in progress " | 2788 | IWL_WARNING("Aborted scan still in progress " |
2781 | "after 100ms\n"); | 2789 | "after 100ms\n"); |
2782 | IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); | 2790 | IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); |
2783 | mutex_unlock(&priv->mutex); | 2791 | mutex_unlock(&priv->mutex); |
2784 | return -EAGAIN; | 2792 | return -EAGAIN; |
2785 | } | 2793 | } |
2786 | memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); | 2794 | memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); |
2787 | 2795 | ||
2788 | /* TODO: Audit driver for usage of these members and see | 2796 | /* TODO: Audit driver for usage of these members and see |
2789 | * if mac80211 deprecates them (priv->bssid looks like it | 2797 | * if mac80211 deprecates them (priv->bssid looks like it |
2790 | * shouldn't be there, but I haven't scanned the IBSS code | 2798 | * shouldn't be there, but I haven't scanned the IBSS code |
2791 | * to verify) - jpk */ | 2799 | * to verify) - jpk */ |
2792 | memcpy(priv->bssid, conf->bssid, ETH_ALEN); | 2800 | memcpy(priv->bssid, conf->bssid, ETH_ALEN); |
2793 | 2801 | ||
2794 | if (priv->iw_mode == NL80211_IFTYPE_AP) | 2802 | if (priv->iw_mode == NL80211_IFTYPE_AP) |
2795 | iwl_config_ap(priv); | 2803 | iwl_config_ap(priv); |
2796 | else { | 2804 | else { |
2797 | rc = iwl_commit_rxon(priv); | 2805 | rc = iwl_commit_rxon(priv); |
2798 | if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) | 2806 | if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) |
2799 | iwl_rxon_add_station( | 2807 | iwl_rxon_add_station( |
2800 | priv, priv->active_rxon.bssid_addr, 1); | 2808 | priv, priv->active_rxon.bssid_addr, 1); |
2801 | } | 2809 | } |
2802 | 2810 | ||
2803 | } else { | 2811 | } else { |
2804 | iwl_scan_cancel_timeout(priv, 100); | 2812 | iwl_scan_cancel_timeout(priv, 100); |
2805 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 2813 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
2806 | iwl_commit_rxon(priv); | 2814 | iwl_commit_rxon(priv); |
2807 | } | 2815 | } |
2808 | 2816 | ||
2809 | done: | 2817 | done: |
2810 | IWL_DEBUG_MAC80211("leave\n"); | 2818 | IWL_DEBUG_MAC80211("leave\n"); |
2811 | mutex_unlock(&priv->mutex); | 2819 | mutex_unlock(&priv->mutex); |
2812 | 2820 | ||
2813 | return 0; | 2821 | return 0; |
2814 | } | 2822 | } |
2815 | 2823 | ||
2816 | static void iwl_configure_filter(struct ieee80211_hw *hw, | 2824 | static void iwl_configure_filter(struct ieee80211_hw *hw, |
2817 | unsigned int changed_flags, | 2825 | unsigned int changed_flags, |
2818 | unsigned int *total_flags, | 2826 | unsigned int *total_flags, |
2819 | int mc_count, struct dev_addr_list *mc_list) | 2827 | int mc_count, struct dev_addr_list *mc_list) |
2820 | { | 2828 | { |
2821 | struct iwl_priv *priv = hw->priv; | 2829 | struct iwl_priv *priv = hw->priv; |
2822 | __le32 *filter_flags = &priv->staging_rxon.filter_flags; | 2830 | __le32 *filter_flags = &priv->staging_rxon.filter_flags; |
2823 | 2831 | ||
2824 | IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", | 2832 | IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", |
2825 | changed_flags, *total_flags); | 2833 | changed_flags, *total_flags); |
2826 | 2834 | ||
2827 | if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { | 2835 | if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { |
2828 | if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) | 2836 | if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) |
2829 | *filter_flags |= RXON_FILTER_PROMISC_MSK; | 2837 | *filter_flags |= RXON_FILTER_PROMISC_MSK; |
2830 | else | 2838 | else |
2831 | *filter_flags &= ~RXON_FILTER_PROMISC_MSK; | 2839 | *filter_flags &= ~RXON_FILTER_PROMISC_MSK; |
2832 | } | 2840 | } |
2833 | if (changed_flags & FIF_ALLMULTI) { | 2841 | if (changed_flags & FIF_ALLMULTI) { |
2834 | if (*total_flags & FIF_ALLMULTI) | 2842 | if (*total_flags & FIF_ALLMULTI) |
2835 | *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; | 2843 | *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; |
2836 | else | 2844 | else |
2837 | *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; | 2845 | *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; |
2838 | } | 2846 | } |
2839 | if (changed_flags & FIF_CONTROL) { | 2847 | if (changed_flags & FIF_CONTROL) { |
2840 | if (*total_flags & FIF_CONTROL) | 2848 | if (*total_flags & FIF_CONTROL) |
2841 | *filter_flags |= RXON_FILTER_CTL2HOST_MSK; | 2849 | *filter_flags |= RXON_FILTER_CTL2HOST_MSK; |
2842 | else | 2850 | else |
2843 | *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; | 2851 | *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; |
2844 | } | 2852 | } |
2845 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { | 2853 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
2846 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) | 2854 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) |
2847 | *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; | 2855 | *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; |
2848 | else | 2856 | else |
2849 | *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; | 2857 | *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; |
2850 | } | 2858 | } |
2851 | 2859 | ||
2852 | /* We avoid iwl_commit_rxon here to commit the new filter flags | 2860 | /* We avoid iwl_commit_rxon here to commit the new filter flags |
2853 | * since mac80211 will call ieee80211_hw_config immediately. | 2861 | * since mac80211 will call ieee80211_hw_config immediately. |
2854 | * (mc_list is not supported at this time). Otherwise, we need to | 2862 | * (mc_list is not supported at this time). Otherwise, we need to |
2855 | * queue a background iwl_commit_rxon work. | 2863 | * queue a background iwl_commit_rxon work. |
2856 | */ | 2864 | */ |
2857 | 2865 | ||
2858 | *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | | 2866 | *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | |
2859 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; | 2867 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; |
2860 | } | 2868 | } |
2861 | 2869 | ||
2862 | static void iwl_mac_remove_interface(struct ieee80211_hw *hw, | 2870 | static void iwl_mac_remove_interface(struct ieee80211_hw *hw, |
2863 | struct ieee80211_if_init_conf *conf) | 2871 | struct ieee80211_if_init_conf *conf) |
2864 | { | 2872 | { |
2865 | struct iwl_priv *priv = hw->priv; | 2873 | struct iwl_priv *priv = hw->priv; |
2866 | 2874 | ||
2867 | IWL_DEBUG_MAC80211("enter\n"); | 2875 | IWL_DEBUG_MAC80211("enter\n"); |
2868 | 2876 | ||
2869 | mutex_lock(&priv->mutex); | 2877 | mutex_lock(&priv->mutex); |
2870 | 2878 | ||
2871 | if (iwl_is_ready_rf(priv)) { | 2879 | if (iwl_is_ready_rf(priv)) { |
2872 | iwl_scan_cancel_timeout(priv, 100); | 2880 | iwl_scan_cancel_timeout(priv, 100); |
2873 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 2881 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
2874 | iwl_commit_rxon(priv); | 2882 | iwl_commit_rxon(priv); |
2875 | } | 2883 | } |
2876 | if (priv->vif == conf->vif) { | 2884 | if (priv->vif == conf->vif) { |
2877 | priv->vif = NULL; | 2885 | priv->vif = NULL; |
2878 | memset(priv->bssid, 0, ETH_ALEN); | 2886 | memset(priv->bssid, 0, ETH_ALEN); |
2879 | } | 2887 | } |
2880 | mutex_unlock(&priv->mutex); | 2888 | mutex_unlock(&priv->mutex); |
2881 | 2889 | ||
2882 | IWL_DEBUG_MAC80211("leave\n"); | 2890 | IWL_DEBUG_MAC80211("leave\n"); |
2883 | 2891 | ||
2884 | } | 2892 | } |
2885 | 2893 | ||
2886 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) | 2894 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) |
2887 | static void iwl_bss_info_changed(struct ieee80211_hw *hw, | 2895 | static void iwl_bss_info_changed(struct ieee80211_hw *hw, |
2888 | struct ieee80211_vif *vif, | 2896 | struct ieee80211_vif *vif, |
2889 | struct ieee80211_bss_conf *bss_conf, | 2897 | struct ieee80211_bss_conf *bss_conf, |
2890 | u32 changes) | 2898 | u32 changes) |
2891 | { | 2899 | { |
2892 | struct iwl_priv *priv = hw->priv; | 2900 | struct iwl_priv *priv = hw->priv; |
2893 | 2901 | ||
2894 | IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); | 2902 | IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); |
2895 | 2903 | ||
2896 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { | 2904 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { |
2897 | IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", | 2905 | IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", |
2898 | bss_conf->use_short_preamble); | 2906 | bss_conf->use_short_preamble); |
2899 | if (bss_conf->use_short_preamble) | 2907 | if (bss_conf->use_short_preamble) |
2900 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | 2908 | priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; |
2901 | else | 2909 | else |
2902 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; | 2910 | priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; |
2903 | } | 2911 | } |
2904 | 2912 | ||
2905 | if (changes & BSS_CHANGED_ERP_CTS_PROT) { | 2913 | if (changes & BSS_CHANGED_ERP_CTS_PROT) { |
2906 | IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); | 2914 | IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); |
2907 | if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) | 2915 | if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) |
2908 | priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; | 2916 | priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; |
2909 | else | 2917 | else |
2910 | priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; | 2918 | priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; |
2911 | } | 2919 | } |
2912 | 2920 | ||
2913 | if (changes & BSS_CHANGED_HT) { | 2921 | if (changes & BSS_CHANGED_HT) { |
2914 | iwl_ht_conf(priv, bss_conf); | 2922 | iwl_ht_conf(priv, bss_conf); |
2915 | iwl_set_rxon_chain(priv); | 2923 | iwl_set_rxon_chain(priv); |
2916 | } | 2924 | } |
2917 | 2925 | ||
2918 | if (changes & BSS_CHANGED_ASSOC) { | 2926 | if (changes & BSS_CHANGED_ASSOC) { |
2919 | IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); | 2927 | IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); |
2920 | /* This should never happen as this function should | 2928 | /* This should never happen as this function should |
2921 | * never be called from interrupt context. */ | 2929 | * never be called from interrupt context. */ |
2922 | if (WARN_ON_ONCE(in_interrupt())) | 2930 | if (WARN_ON_ONCE(in_interrupt())) |
2923 | return; | 2931 | return; |
2924 | if (bss_conf->assoc) { | 2932 | if (bss_conf->assoc) { |
2925 | priv->assoc_id = bss_conf->aid; | 2933 | priv->assoc_id = bss_conf->aid; |
2926 | priv->beacon_int = bss_conf->beacon_int; | 2934 | priv->beacon_int = bss_conf->beacon_int; |
2927 | priv->power_data.dtim_period = bss_conf->dtim_period; | 2935 | priv->power_data.dtim_period = bss_conf->dtim_period; |
2928 | priv->timestamp = bss_conf->timestamp; | 2936 | priv->timestamp = bss_conf->timestamp; |
2929 | priv->assoc_capability = bss_conf->assoc_capability; | 2937 | priv->assoc_capability = bss_conf->assoc_capability; |
2930 | 2938 | ||
2931 | /* we have just associated, don't start scan too early | 2939 | /* we have just associated, don't start scan too early |
2932 | * leave time for EAPOL exchange to complete | 2940 | * leave time for EAPOL exchange to complete |
2933 | */ | 2941 | */ |
2934 | priv->next_scan_jiffies = jiffies + | 2942 | priv->next_scan_jiffies = jiffies + |
2935 | IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; | 2943 | IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; |
2936 | mutex_lock(&priv->mutex); | 2944 | mutex_lock(&priv->mutex); |
2937 | iwl_post_associate(priv); | 2945 | iwl_post_associate(priv); |
2938 | mutex_unlock(&priv->mutex); | 2946 | mutex_unlock(&priv->mutex); |
2939 | } else { | 2947 | } else { |
2940 | priv->assoc_id = 0; | 2948 | priv->assoc_id = 0; |
2941 | IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); | 2949 | IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); |
2942 | } | 2950 | } |
2943 | } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { | 2951 | } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { |
2944 | IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); | 2952 | IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); |
2945 | iwl_send_rxon_assoc(priv); | 2953 | iwl_send_rxon_assoc(priv); |
2946 | } | 2954 | } |
2947 | 2955 | ||
2948 | } | 2956 | } |
2949 | 2957 | ||
2950 | static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) | 2958 | static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) |
2951 | { | 2959 | { |
2952 | unsigned long flags; | 2960 | unsigned long flags; |
2953 | struct iwl_priv *priv = hw->priv; | 2961 | struct iwl_priv *priv = hw->priv; |
2954 | int ret; | 2962 | int ret; |
2955 | 2963 | ||
2956 | IWL_DEBUG_MAC80211("enter\n"); | 2964 | IWL_DEBUG_MAC80211("enter\n"); |
2957 | 2965 | ||
2958 | mutex_lock(&priv->mutex); | 2966 | mutex_lock(&priv->mutex); |
2959 | spin_lock_irqsave(&priv->lock, flags); | 2967 | spin_lock_irqsave(&priv->lock, flags); |
2960 | 2968 | ||
2961 | if (!iwl_is_ready_rf(priv)) { | 2969 | if (!iwl_is_ready_rf(priv)) { |
2962 | ret = -EIO; | 2970 | ret = -EIO; |
2963 | IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); | 2971 | IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); |
2964 | goto out_unlock; | 2972 | goto out_unlock; |
2965 | } | 2973 | } |
2966 | 2974 | ||
2967 | /* We don't schedule scan within next_scan_jiffies period. | 2975 | /* We don't schedule scan within next_scan_jiffies period. |
2968 | * Avoid scanning during possible EAPOL exchange, return | 2976 | * Avoid scanning during possible EAPOL exchange, return |
2969 | * success immediately. | 2977 | * success immediately. |
2970 | */ | 2978 | */ |
2971 | if (priv->next_scan_jiffies && | 2979 | if (priv->next_scan_jiffies && |
2972 | time_after(priv->next_scan_jiffies, jiffies)) { | 2980 | time_after(priv->next_scan_jiffies, jiffies)) { |
2973 | IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); | 2981 | IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); |
2974 | queue_work(priv->workqueue, &priv->scan_completed); | 2982 | queue_work(priv->workqueue, &priv->scan_completed); |
2975 | ret = 0; | 2983 | ret = 0; |
2976 | goto out_unlock; | 2984 | goto out_unlock; |
2977 | } | 2985 | } |
2978 | 2986 | ||
2979 | /* if we just finished scan ask for delay */ | 2987 | /* if we just finished scan ask for delay */ |
2980 | if (iwl_is_associated(priv) && priv->last_scan_jiffies && | 2988 | if (iwl_is_associated(priv) && priv->last_scan_jiffies && |
2981 | time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { | 2989 | time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { |
2982 | IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); | 2990 | IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); |
2983 | queue_work(priv->workqueue, &priv->scan_completed); | 2991 | queue_work(priv->workqueue, &priv->scan_completed); |
2984 | ret = 0; | 2992 | ret = 0; |
2985 | goto out_unlock; | 2993 | goto out_unlock; |
2986 | } | 2994 | } |
2987 | 2995 | ||
2988 | if (ssid_len) { | 2996 | if (ssid_len) { |
2989 | priv->one_direct_scan = 1; | 2997 | priv->one_direct_scan = 1; |
2990 | priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); | 2998 | priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); |
2991 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); | 2999 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); |
2992 | } else { | 3000 | } else { |
2993 | priv->one_direct_scan = 0; | 3001 | priv->one_direct_scan = 0; |
2994 | } | 3002 | } |
2995 | 3003 | ||
2996 | ret = iwl_scan_initiate(priv); | 3004 | ret = iwl_scan_initiate(priv); |
2997 | 3005 | ||
2998 | IWL_DEBUG_MAC80211("leave\n"); | 3006 | IWL_DEBUG_MAC80211("leave\n"); |
2999 | 3007 | ||
3000 | out_unlock: | 3008 | out_unlock: |
3001 | spin_unlock_irqrestore(&priv->lock, flags); | 3009 | spin_unlock_irqrestore(&priv->lock, flags); |
3002 | mutex_unlock(&priv->mutex); | 3010 | mutex_unlock(&priv->mutex); |
3003 | 3011 | ||
3004 | return ret; | 3012 | return ret; |
3005 | } | 3013 | } |
3006 | 3014 | ||
3007 | static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, | 3015 | static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, |
3008 | struct ieee80211_key_conf *keyconf, const u8 *addr, | 3016 | struct ieee80211_key_conf *keyconf, const u8 *addr, |
3009 | u32 iv32, u16 *phase1key) | 3017 | u32 iv32, u16 *phase1key) |
3010 | { | 3018 | { |
3011 | 3019 | ||
3012 | struct iwl_priv *priv = hw->priv; | 3020 | struct iwl_priv *priv = hw->priv; |
3013 | IWL_DEBUG_MAC80211("enter\n"); | 3021 | IWL_DEBUG_MAC80211("enter\n"); |
3014 | 3022 | ||
3015 | iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); | 3023 | iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); |
3016 | 3024 | ||
3017 | IWL_DEBUG_MAC80211("leave\n"); | 3025 | IWL_DEBUG_MAC80211("leave\n"); |
3018 | } | 3026 | } |
3019 | 3027 | ||
3020 | static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 3028 | static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
3021 | const u8 *local_addr, const u8 *addr, | 3029 | const u8 *local_addr, const u8 *addr, |
3022 | struct ieee80211_key_conf *key) | 3030 | struct ieee80211_key_conf *key) |
3023 | { | 3031 | { |
3024 | struct iwl_priv *priv = hw->priv; | 3032 | struct iwl_priv *priv = hw->priv; |
3025 | int ret = 0; | 3033 | int ret = 0; |
3026 | u8 sta_id = IWL_INVALID_STATION; | 3034 | u8 sta_id = IWL_INVALID_STATION; |
3027 | u8 is_default_wep_key = 0; | 3035 | u8 is_default_wep_key = 0; |
3028 | 3036 | ||
3029 | IWL_DEBUG_MAC80211("enter\n"); | 3037 | IWL_DEBUG_MAC80211("enter\n"); |
3030 | 3038 | ||
3031 | if (priv->hw_params.sw_crypto) { | 3039 | if (priv->hw_params.sw_crypto) { |
3032 | IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); | 3040 | IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); |
3033 | return -EOPNOTSUPP; | 3041 | return -EOPNOTSUPP; |
3034 | } | 3042 | } |
3035 | 3043 | ||
3036 | if (is_zero_ether_addr(addr)) | 3044 | if (is_zero_ether_addr(addr)) |
3037 | /* only support pairwise keys */ | 3045 | /* only support pairwise keys */ |
3038 | return -EOPNOTSUPP; | 3046 | return -EOPNOTSUPP; |
3039 | 3047 | ||
3040 | sta_id = iwl_find_station(priv, addr); | 3048 | sta_id = iwl_find_station(priv, addr); |
3041 | if (sta_id == IWL_INVALID_STATION) { | 3049 | if (sta_id == IWL_INVALID_STATION) { |
3042 | IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", | 3050 | IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", |
3043 | addr); | 3051 | addr); |
3044 | return -EINVAL; | 3052 | return -EINVAL; |
3045 | 3053 | ||
3046 | } | 3054 | } |
3047 | 3055 | ||
3048 | mutex_lock(&priv->mutex); | 3056 | mutex_lock(&priv->mutex); |
3049 | iwl_scan_cancel_timeout(priv, 100); | 3057 | iwl_scan_cancel_timeout(priv, 100); |
3050 | mutex_unlock(&priv->mutex); | 3058 | mutex_unlock(&priv->mutex); |
3051 | 3059 | ||
3052 | /* If we are getting WEP group key and we didn't receive any key mapping | 3060 | /* If we are getting WEP group key and we didn't receive any key mapping |
3053 | * so far, we are in legacy wep mode (group key only), otherwise we are | 3061 | * so far, we are in legacy wep mode (group key only), otherwise we are |
3054 | * in 1X mode. | 3062 | * in 1X mode. |
3055 | * In legacy wep mode, we use another host command to the uCode */ | 3063 | * In legacy wep mode, we use another host command to the uCode */ |
3056 | if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && | 3064 | if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && |
3057 | priv->iw_mode != NL80211_IFTYPE_AP) { | 3065 | priv->iw_mode != NL80211_IFTYPE_AP) { |
3058 | if (cmd == SET_KEY) | 3066 | if (cmd == SET_KEY) |
3059 | is_default_wep_key = !priv->key_mapping_key; | 3067 | is_default_wep_key = !priv->key_mapping_key; |
3060 | else | 3068 | else |
3061 | is_default_wep_key = | 3069 | is_default_wep_key = |
3062 | (key->hw_key_idx == HW_KEY_DEFAULT); | 3070 | (key->hw_key_idx == HW_KEY_DEFAULT); |
3063 | } | 3071 | } |
3064 | 3072 | ||
3065 | switch (cmd) { | 3073 | switch (cmd) { |
3066 | case SET_KEY: | 3074 | case SET_KEY: |
3067 | if (is_default_wep_key) | 3075 | if (is_default_wep_key) |
3068 | ret = iwl_set_default_wep_key(priv, key); | 3076 | ret = iwl_set_default_wep_key(priv, key); |
3069 | else | 3077 | else |
3070 | ret = iwl_set_dynamic_key(priv, key, sta_id); | 3078 | ret = iwl_set_dynamic_key(priv, key, sta_id); |
3071 | 3079 | ||
3072 | IWL_DEBUG_MAC80211("enable hwcrypto key\n"); | 3080 | IWL_DEBUG_MAC80211("enable hwcrypto key\n"); |
3073 | break; | 3081 | break; |
3074 | case DISABLE_KEY: | 3082 | case DISABLE_KEY: |
3075 | if (is_default_wep_key) | 3083 | if (is_default_wep_key) |
3076 | ret = iwl_remove_default_wep_key(priv, key); | 3084 | ret = iwl_remove_default_wep_key(priv, key); |
3077 | else | 3085 | else |
3078 | ret = iwl_remove_dynamic_key(priv, key, sta_id); | 3086 | ret = iwl_remove_dynamic_key(priv, key, sta_id); |
3079 | 3087 | ||
3080 | IWL_DEBUG_MAC80211("disable hwcrypto key\n"); | 3088 | IWL_DEBUG_MAC80211("disable hwcrypto key\n"); |
3081 | break; | 3089 | break; |
3082 | default: | 3090 | default: |
3083 | ret = -EINVAL; | 3091 | ret = -EINVAL; |
3084 | } | 3092 | } |
3085 | 3093 | ||
3086 | IWL_DEBUG_MAC80211("leave\n"); | 3094 | IWL_DEBUG_MAC80211("leave\n"); |
3087 | 3095 | ||
3088 | return ret; | 3096 | return ret; |
3089 | } | 3097 | } |
3090 | 3098 | ||
3091 | static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 3099 | static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, |
3092 | const struct ieee80211_tx_queue_params *params) | 3100 | const struct ieee80211_tx_queue_params *params) |
3093 | { | 3101 | { |
3094 | struct iwl_priv *priv = hw->priv; | 3102 | struct iwl_priv *priv = hw->priv; |
3095 | unsigned long flags; | 3103 | unsigned long flags; |
3096 | int q; | 3104 | int q; |
3097 | 3105 | ||
3098 | IWL_DEBUG_MAC80211("enter\n"); | 3106 | IWL_DEBUG_MAC80211("enter\n"); |
3099 | 3107 | ||
3100 | if (!iwl_is_ready_rf(priv)) { | 3108 | if (!iwl_is_ready_rf(priv)) { |
3101 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); | 3109 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); |
3102 | return -EIO; | 3110 | return -EIO; |
3103 | } | 3111 | } |
3104 | 3112 | ||
3105 | if (queue >= AC_NUM) { | 3113 | if (queue >= AC_NUM) { |
3106 | IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); | 3114 | IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); |
3107 | return 0; | 3115 | return 0; |
3108 | } | 3116 | } |
3109 | 3117 | ||
3110 | q = AC_NUM - 1 - queue; | 3118 | q = AC_NUM - 1 - queue; |
3111 | 3119 | ||
3112 | spin_lock_irqsave(&priv->lock, flags); | 3120 | spin_lock_irqsave(&priv->lock, flags); |
3113 | 3121 | ||
3114 | priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); | 3122 | priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); |
3115 | priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); | 3123 | priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); |
3116 | priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; | 3124 | priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; |
3117 | priv->qos_data.def_qos_parm.ac[q].edca_txop = | 3125 | priv->qos_data.def_qos_parm.ac[q].edca_txop = |
3118 | cpu_to_le16((params->txop * 32)); | 3126 | cpu_to_le16((params->txop * 32)); |
3119 | 3127 | ||
3120 | priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; | 3128 | priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; |
3121 | priv->qos_data.qos_active = 1; | 3129 | priv->qos_data.qos_active = 1; |
3122 | 3130 | ||
3123 | if (priv->iw_mode == NL80211_IFTYPE_AP) | 3131 | if (priv->iw_mode == NL80211_IFTYPE_AP) |
3124 | iwl_activate_qos(priv, 1); | 3132 | iwl_activate_qos(priv, 1); |
3125 | else if (priv->assoc_id && iwl_is_associated(priv)) | 3133 | else if (priv->assoc_id && iwl_is_associated(priv)) |
3126 | iwl_activate_qos(priv, 0); | 3134 | iwl_activate_qos(priv, 0); |
3127 | 3135 | ||
3128 | spin_unlock_irqrestore(&priv->lock, flags); | 3136 | spin_unlock_irqrestore(&priv->lock, flags); |
3129 | 3137 | ||
3130 | IWL_DEBUG_MAC80211("leave\n"); | 3138 | IWL_DEBUG_MAC80211("leave\n"); |
3131 | return 0; | 3139 | return 0; |
3132 | } | 3140 | } |
3133 | 3141 | ||
3134 | static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | 3142 | static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, |
3135 | enum ieee80211_ampdu_mlme_action action, | 3143 | enum ieee80211_ampdu_mlme_action action, |
3136 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 3144 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
3137 | { | 3145 | { |
3138 | struct iwl_priv *priv = hw->priv; | 3146 | struct iwl_priv *priv = hw->priv; |
3139 | 3147 | ||
3140 | IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n", | 3148 | IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n", |
3141 | sta->addr, tid); | 3149 | sta->addr, tid); |
3142 | 3150 | ||
3143 | if (!(priv->cfg->sku & IWL_SKU_N)) | 3151 | if (!(priv->cfg->sku & IWL_SKU_N)) |
3144 | return -EACCES; | 3152 | return -EACCES; |
3145 | 3153 | ||
3146 | switch (action) { | 3154 | switch (action) { |
3147 | case IEEE80211_AMPDU_RX_START: | 3155 | case IEEE80211_AMPDU_RX_START: |
3148 | IWL_DEBUG_HT("start Rx\n"); | 3156 | IWL_DEBUG_HT("start Rx\n"); |
3149 | return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); | 3157 | return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); |
3150 | case IEEE80211_AMPDU_RX_STOP: | 3158 | case IEEE80211_AMPDU_RX_STOP: |
3151 | IWL_DEBUG_HT("stop Rx\n"); | 3159 | IWL_DEBUG_HT("stop Rx\n"); |
3152 | return iwl_sta_rx_agg_stop(priv, sta->addr, tid); | 3160 | return iwl_sta_rx_agg_stop(priv, sta->addr, tid); |
3153 | case IEEE80211_AMPDU_TX_START: | 3161 | case IEEE80211_AMPDU_TX_START: |
3154 | IWL_DEBUG_HT("start Tx\n"); | 3162 | IWL_DEBUG_HT("start Tx\n"); |
3155 | return iwl_tx_agg_start(priv, sta->addr, tid, ssn); | 3163 | return iwl_tx_agg_start(priv, sta->addr, tid, ssn); |
3156 | case IEEE80211_AMPDU_TX_STOP: | 3164 | case IEEE80211_AMPDU_TX_STOP: |
3157 | IWL_DEBUG_HT("stop Tx\n"); | 3165 | IWL_DEBUG_HT("stop Tx\n"); |
3158 | return iwl_tx_agg_stop(priv, sta->addr, tid); | 3166 | return iwl_tx_agg_stop(priv, sta->addr, tid); |
3159 | default: | 3167 | default: |
3160 | IWL_DEBUG_HT("unknown\n"); | 3168 | IWL_DEBUG_HT("unknown\n"); |
3161 | return -EINVAL; | 3169 | return -EINVAL; |
3162 | break; | 3170 | break; |
3163 | } | 3171 | } |
3164 | return 0; | 3172 | return 0; |
3165 | } | 3173 | } |
3166 | 3174 | ||
3167 | static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, | 3175 | static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, |
3168 | struct ieee80211_tx_queue_stats *stats) | 3176 | struct ieee80211_tx_queue_stats *stats) |
3169 | { | 3177 | { |
3170 | struct iwl_priv *priv = hw->priv; | 3178 | struct iwl_priv *priv = hw->priv; |
3171 | int i, avail; | 3179 | int i, avail; |
3172 | struct iwl_tx_queue *txq; | 3180 | struct iwl_tx_queue *txq; |
3173 | struct iwl_queue *q; | 3181 | struct iwl_queue *q; |
3174 | unsigned long flags; | 3182 | unsigned long flags; |
3175 | 3183 | ||
3176 | IWL_DEBUG_MAC80211("enter\n"); | 3184 | IWL_DEBUG_MAC80211("enter\n"); |
3177 | 3185 | ||
3178 | if (!iwl_is_ready_rf(priv)) { | 3186 | if (!iwl_is_ready_rf(priv)) { |
3179 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); | 3187 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); |
3180 | return -EIO; | 3188 | return -EIO; |
3181 | } | 3189 | } |
3182 | 3190 | ||
3183 | spin_lock_irqsave(&priv->lock, flags); | 3191 | spin_lock_irqsave(&priv->lock, flags); |
3184 | 3192 | ||
3185 | for (i = 0; i < AC_NUM; i++) { | 3193 | for (i = 0; i < AC_NUM; i++) { |
3186 | txq = &priv->txq[i]; | 3194 | txq = &priv->txq[i]; |
3187 | q = &txq->q; | 3195 | q = &txq->q; |
3188 | avail = iwl_queue_space(q); | 3196 | avail = iwl_queue_space(q); |
3189 | 3197 | ||
3190 | stats[i].len = q->n_window - avail; | 3198 | stats[i].len = q->n_window - avail; |
3191 | stats[i].limit = q->n_window - q->high_mark; | 3199 | stats[i].limit = q->n_window - q->high_mark; |
3192 | stats[i].count = q->n_window; | 3200 | stats[i].count = q->n_window; |
3193 | 3201 | ||
3194 | } | 3202 | } |
3195 | spin_unlock_irqrestore(&priv->lock, flags); | 3203 | spin_unlock_irqrestore(&priv->lock, flags); |
3196 | 3204 | ||
3197 | IWL_DEBUG_MAC80211("leave\n"); | 3205 | IWL_DEBUG_MAC80211("leave\n"); |
3198 | 3206 | ||
3199 | return 0; | 3207 | return 0; |
3200 | } | 3208 | } |
3201 | 3209 | ||
3202 | static int iwl_mac_get_stats(struct ieee80211_hw *hw, | 3210 | static int iwl_mac_get_stats(struct ieee80211_hw *hw, |
3203 | struct ieee80211_low_level_stats *stats) | 3211 | struct ieee80211_low_level_stats *stats) |
3204 | { | 3212 | { |
3205 | struct iwl_priv *priv = hw->priv; | 3213 | struct iwl_priv *priv = hw->priv; |
3206 | 3214 | ||
3207 | priv = hw->priv; | 3215 | priv = hw->priv; |
3208 | IWL_DEBUG_MAC80211("enter\n"); | 3216 | IWL_DEBUG_MAC80211("enter\n"); |
3209 | IWL_DEBUG_MAC80211("leave\n"); | 3217 | IWL_DEBUG_MAC80211("leave\n"); |
3210 | 3218 | ||
3211 | return 0; | 3219 | return 0; |
3212 | } | 3220 | } |
3213 | 3221 | ||
3214 | static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) | 3222 | static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) |
3215 | { | 3223 | { |
3216 | struct iwl_priv *priv = hw->priv; | 3224 | struct iwl_priv *priv = hw->priv; |
3217 | unsigned long flags; | 3225 | unsigned long flags; |
3218 | 3226 | ||
3219 | mutex_lock(&priv->mutex); | 3227 | mutex_lock(&priv->mutex); |
3220 | IWL_DEBUG_MAC80211("enter\n"); | 3228 | IWL_DEBUG_MAC80211("enter\n"); |
3221 | 3229 | ||
3222 | spin_lock_irqsave(&priv->lock, flags); | 3230 | spin_lock_irqsave(&priv->lock, flags); |
3223 | memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); | 3231 | memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); |
3224 | spin_unlock_irqrestore(&priv->lock, flags); | 3232 | spin_unlock_irqrestore(&priv->lock, flags); |
3225 | 3233 | ||
3226 | iwl_reset_qos(priv); | 3234 | iwl_reset_qos(priv); |
3227 | 3235 | ||
3228 | spin_lock_irqsave(&priv->lock, flags); | 3236 | spin_lock_irqsave(&priv->lock, flags); |
3229 | priv->assoc_id = 0; | 3237 | priv->assoc_id = 0; |
3230 | priv->assoc_capability = 0; | 3238 | priv->assoc_capability = 0; |
3231 | priv->assoc_station_added = 0; | 3239 | priv->assoc_station_added = 0; |
3232 | 3240 | ||
3233 | /* new association get rid of ibss beacon skb */ | 3241 | /* new association get rid of ibss beacon skb */ |
3234 | if (priv->ibss_beacon) | 3242 | if (priv->ibss_beacon) |
3235 | dev_kfree_skb(priv->ibss_beacon); | 3243 | dev_kfree_skb(priv->ibss_beacon); |
3236 | 3244 | ||
3237 | priv->ibss_beacon = NULL; | 3245 | priv->ibss_beacon = NULL; |
3238 | 3246 | ||
3239 | priv->beacon_int = priv->hw->conf.beacon_int; | 3247 | priv->beacon_int = priv->hw->conf.beacon_int; |
3240 | priv->timestamp = 0; | 3248 | priv->timestamp = 0; |
3241 | if ((priv->iw_mode == NL80211_IFTYPE_STATION)) | 3249 | if ((priv->iw_mode == NL80211_IFTYPE_STATION)) |
3242 | priv->beacon_int = 0; | 3250 | priv->beacon_int = 0; |
3243 | 3251 | ||
3244 | spin_unlock_irqrestore(&priv->lock, flags); | 3252 | spin_unlock_irqrestore(&priv->lock, flags); |
3245 | 3253 | ||
3246 | if (!iwl_is_ready_rf(priv)) { | 3254 | if (!iwl_is_ready_rf(priv)) { |
3247 | IWL_DEBUG_MAC80211("leave - not ready\n"); | 3255 | IWL_DEBUG_MAC80211("leave - not ready\n"); |
3248 | mutex_unlock(&priv->mutex); | 3256 | mutex_unlock(&priv->mutex); |
3249 | return; | 3257 | return; |
3250 | } | 3258 | } |
3251 | 3259 | ||
3252 | /* we are restarting association process | 3260 | /* we are restarting association process |
3253 | * clear RXON_FILTER_ASSOC_MSK bit | 3261 | * clear RXON_FILTER_ASSOC_MSK bit |
3254 | */ | 3262 | */ |
3255 | if (priv->iw_mode != NL80211_IFTYPE_AP) { | 3263 | if (priv->iw_mode != NL80211_IFTYPE_AP) { |
3256 | iwl_scan_cancel_timeout(priv, 100); | 3264 | iwl_scan_cancel_timeout(priv, 100); |
3257 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 3265 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
3258 | iwl_commit_rxon(priv); | 3266 | iwl_commit_rxon(priv); |
3259 | } | 3267 | } |
3260 | 3268 | ||
3261 | iwl_power_update_mode(priv, 0); | 3269 | iwl_power_update_mode(priv, 0); |
3262 | 3270 | ||
3263 | /* Per mac80211.h: This is only used in IBSS mode... */ | 3271 | /* Per mac80211.h: This is only used in IBSS mode... */ |
3264 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { | 3272 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { |
3265 | 3273 | ||
3266 | /* switch to CAM during association period. | 3274 | /* switch to CAM during association period. |
3267 | * the ucode will block any association/authentication | 3275 | * the ucode will block any association/authentication |
3268 | * frome during assiciation period if it can not hear | 3276 | * frome during assiciation period if it can not hear |
3269 | * the AP because of PM. the timer enable PM back is | 3277 | * the AP because of PM. the timer enable PM back is |
3270 | * association do not complete | 3278 | * association do not complete |
3271 | */ | 3279 | */ |
3272 | if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN | | 3280 | if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN | |
3273 | IEEE80211_CHAN_RADAR)) | 3281 | IEEE80211_CHAN_RADAR)) |
3274 | iwl_power_disable_management(priv, 3000); | 3282 | iwl_power_disable_management(priv, 3000); |
3275 | 3283 | ||
3276 | IWL_DEBUG_MAC80211("leave - not in IBSS\n"); | 3284 | IWL_DEBUG_MAC80211("leave - not in IBSS\n"); |
3277 | mutex_unlock(&priv->mutex); | 3285 | mutex_unlock(&priv->mutex); |
3278 | return; | 3286 | return; |
3279 | } | 3287 | } |
3280 | 3288 | ||
3281 | iwl_set_rate(priv); | 3289 | iwl_set_rate(priv); |
3282 | 3290 | ||
3283 | mutex_unlock(&priv->mutex); | 3291 | mutex_unlock(&priv->mutex); |
3284 | 3292 | ||
3285 | IWL_DEBUG_MAC80211("leave\n"); | 3293 | IWL_DEBUG_MAC80211("leave\n"); |
3286 | } | 3294 | } |
3287 | 3295 | ||
3288 | static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | 3296 | static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) |
3289 | { | 3297 | { |
3290 | struct iwl_priv *priv = hw->priv; | 3298 | struct iwl_priv *priv = hw->priv; |
3291 | unsigned long flags; | 3299 | unsigned long flags; |
3292 | __le64 timestamp; | 3300 | __le64 timestamp; |
3293 | 3301 | ||
3294 | IWL_DEBUG_MAC80211("enter\n"); | 3302 | IWL_DEBUG_MAC80211("enter\n"); |
3295 | 3303 | ||
3296 | if (!iwl_is_ready_rf(priv)) { | 3304 | if (!iwl_is_ready_rf(priv)) { |
3297 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); | 3305 | IWL_DEBUG_MAC80211("leave - RF not ready\n"); |
3298 | return -EIO; | 3306 | return -EIO; |
3299 | } | 3307 | } |
3300 | 3308 | ||
3301 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { | 3309 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { |
3302 | IWL_DEBUG_MAC80211("leave - not IBSS\n"); | 3310 | IWL_DEBUG_MAC80211("leave - not IBSS\n"); |
3303 | return -EIO; | 3311 | return -EIO; |
3304 | } | 3312 | } |
3305 | 3313 | ||
3306 | spin_lock_irqsave(&priv->lock, flags); | 3314 | spin_lock_irqsave(&priv->lock, flags); |
3307 | 3315 | ||
3308 | if (priv->ibss_beacon) | 3316 | if (priv->ibss_beacon) |
3309 | dev_kfree_skb(priv->ibss_beacon); | 3317 | dev_kfree_skb(priv->ibss_beacon); |
3310 | 3318 | ||
3311 | priv->ibss_beacon = skb; | 3319 | priv->ibss_beacon = skb; |
3312 | 3320 | ||
3313 | priv->assoc_id = 0; | 3321 | priv->assoc_id = 0; |
3314 | timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | 3322 | timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; |
3315 | priv->timestamp = le64_to_cpu(timestamp); | 3323 | priv->timestamp = le64_to_cpu(timestamp); |
3316 | 3324 | ||
3317 | IWL_DEBUG_MAC80211("leave\n"); | 3325 | IWL_DEBUG_MAC80211("leave\n"); |
3318 | spin_unlock_irqrestore(&priv->lock, flags); | 3326 | spin_unlock_irqrestore(&priv->lock, flags); |
3319 | 3327 | ||
3320 | iwl_reset_qos(priv); | 3328 | iwl_reset_qos(priv); |
3321 | 3329 | ||
3322 | iwl_post_associate(priv); | 3330 | iwl_post_associate(priv); |
3323 | 3331 | ||
3324 | 3332 | ||
3325 | return 0; | 3333 | return 0; |
3326 | } | 3334 | } |
3327 | 3335 | ||
3328 | /***************************************************************************** | 3336 | /***************************************************************************** |
3329 | * | 3337 | * |
3330 | * sysfs attributes | 3338 | * sysfs attributes |
3331 | * | 3339 | * |
3332 | *****************************************************************************/ | 3340 | *****************************************************************************/ |
3333 | 3341 | ||
3334 | #ifdef CONFIG_IWLWIFI_DEBUG | 3342 | #ifdef CONFIG_IWLWIFI_DEBUG |
3335 | 3343 | ||
3336 | /* | 3344 | /* |
3337 | * The following adds a new attribute to the sysfs representation | 3345 | * The following adds a new attribute to the sysfs representation |
3338 | * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) | 3346 | * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) |
3339 | * used for controlling the debug level. | 3347 | * used for controlling the debug level. |
3340 | * | 3348 | * |
3341 | * See the level definitions in iwl for details. | 3349 | * See the level definitions in iwl for details. |
3342 | */ | 3350 | */ |
3343 | 3351 | ||
3344 | static ssize_t show_debug_level(struct device *d, | 3352 | static ssize_t show_debug_level(struct device *d, |
3345 | struct device_attribute *attr, char *buf) | 3353 | struct device_attribute *attr, char *buf) |
3346 | { | 3354 | { |
3347 | struct iwl_priv *priv = d->driver_data; | 3355 | struct iwl_priv *priv = d->driver_data; |
3348 | 3356 | ||
3349 | return sprintf(buf, "0x%08X\n", priv->debug_level); | 3357 | return sprintf(buf, "0x%08X\n", priv->debug_level); |
3350 | } | 3358 | } |
3351 | static ssize_t store_debug_level(struct device *d, | 3359 | static ssize_t store_debug_level(struct device *d, |
3352 | struct device_attribute *attr, | 3360 | struct device_attribute *attr, |
3353 | const char *buf, size_t count) | 3361 | const char *buf, size_t count) |
3354 | { | 3362 | { |
3355 | struct iwl_priv *priv = d->driver_data; | 3363 | struct iwl_priv *priv = d->driver_data; |
3356 | unsigned long val; | 3364 | unsigned long val; |
3357 | int ret; | 3365 | int ret; |
3358 | 3366 | ||
3359 | ret = strict_strtoul(buf, 0, &val); | 3367 | ret = strict_strtoul(buf, 0, &val); |
3360 | if (ret) | 3368 | if (ret) |
3361 | printk(KERN_INFO DRV_NAME | 3369 | printk(KERN_INFO DRV_NAME |
3362 | ": %s is not in hex or decimal form.\n", buf); | 3370 | ": %s is not in hex or decimal form.\n", buf); |
3363 | else | 3371 | else |
3364 | priv->debug_level = val; | 3372 | priv->debug_level = val; |
3365 | 3373 | ||
3366 | return strnlen(buf, count); | 3374 | return strnlen(buf, count); |
3367 | } | 3375 | } |
3368 | 3376 | ||
3369 | static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, | 3377 | static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, |
3370 | show_debug_level, store_debug_level); | 3378 | show_debug_level, store_debug_level); |
3371 | 3379 | ||
3372 | 3380 | ||
3373 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 3381 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
3374 | 3382 | ||
3375 | 3383 | ||
3376 | static ssize_t show_version(struct device *d, | 3384 | static ssize_t show_version(struct device *d, |
3377 | struct device_attribute *attr, char *buf) | 3385 | struct device_attribute *attr, char *buf) |
3378 | { | 3386 | { |
3379 | struct iwl_priv *priv = d->driver_data; | 3387 | struct iwl_priv *priv = d->driver_data; |
3380 | struct iwl_alive_resp *palive = &priv->card_alive; | 3388 | struct iwl_alive_resp *palive = &priv->card_alive; |
3381 | ssize_t pos = 0; | 3389 | ssize_t pos = 0; |
3382 | u16 eeprom_ver; | 3390 | u16 eeprom_ver; |
3383 | 3391 | ||
3384 | if (palive->is_valid) | 3392 | if (palive->is_valid) |
3385 | pos += sprintf(buf + pos, | 3393 | pos += sprintf(buf + pos, |
3386 | "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" | 3394 | "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" |
3387 | "fw type: 0x%01X 0x%01X\n", | 3395 | "fw type: 0x%01X 0x%01X\n", |
3388 | palive->ucode_major, palive->ucode_minor, | 3396 | palive->ucode_major, palive->ucode_minor, |
3389 | palive->sw_rev[0], palive->sw_rev[1], | 3397 | palive->sw_rev[0], palive->sw_rev[1], |
3390 | palive->ver_type, palive->ver_subtype); | 3398 | palive->ver_type, palive->ver_subtype); |
3391 | else | 3399 | else |
3392 | pos += sprintf(buf + pos, "fw not loaded\n"); | 3400 | pos += sprintf(buf + pos, "fw not loaded\n"); |
3393 | 3401 | ||
3394 | if (priv->eeprom) { | 3402 | if (priv->eeprom) { |
3395 | eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); | 3403 | eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); |
3396 | pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", | 3404 | pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", |
3397 | eeprom_ver); | 3405 | eeprom_ver); |
3398 | } else { | 3406 | } else { |
3399 | pos += sprintf(buf + pos, "EEPROM not initialzed\n"); | 3407 | pos += sprintf(buf + pos, "EEPROM not initialzed\n"); |
3400 | } | 3408 | } |
3401 | 3409 | ||
3402 | return pos; | 3410 | return pos; |
3403 | } | 3411 | } |
3404 | 3412 | ||
3405 | static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); | 3413 | static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); |
3406 | 3414 | ||
3407 | static ssize_t show_temperature(struct device *d, | 3415 | static ssize_t show_temperature(struct device *d, |
3408 | struct device_attribute *attr, char *buf) | 3416 | struct device_attribute *attr, char *buf) |
3409 | { | 3417 | { |
3410 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3418 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3411 | 3419 | ||
3412 | if (!iwl_is_alive(priv)) | 3420 | if (!iwl_is_alive(priv)) |
3413 | return -EAGAIN; | 3421 | return -EAGAIN; |
3414 | 3422 | ||
3415 | return sprintf(buf, "%d\n", priv->temperature); | 3423 | return sprintf(buf, "%d\n", priv->temperature); |
3416 | } | 3424 | } |
3417 | 3425 | ||
3418 | static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); | 3426 | static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); |
3419 | 3427 | ||
3420 | static ssize_t show_tx_power(struct device *d, | 3428 | static ssize_t show_tx_power(struct device *d, |
3421 | struct device_attribute *attr, char *buf) | 3429 | struct device_attribute *attr, char *buf) |
3422 | { | 3430 | { |
3423 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3431 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3424 | return sprintf(buf, "%d\n", priv->tx_power_user_lmt); | 3432 | return sprintf(buf, "%d\n", priv->tx_power_user_lmt); |
3425 | } | 3433 | } |
3426 | 3434 | ||
3427 | static ssize_t store_tx_power(struct device *d, | 3435 | static ssize_t store_tx_power(struct device *d, |
3428 | struct device_attribute *attr, | 3436 | struct device_attribute *attr, |
3429 | const char *buf, size_t count) | 3437 | const char *buf, size_t count) |
3430 | { | 3438 | { |
3431 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3439 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3432 | unsigned long val; | 3440 | unsigned long val; |
3433 | int ret; | 3441 | int ret; |
3434 | 3442 | ||
3435 | ret = strict_strtoul(buf, 10, &val); | 3443 | ret = strict_strtoul(buf, 10, &val); |
3436 | if (ret) | 3444 | if (ret) |
3437 | printk(KERN_INFO DRV_NAME | 3445 | printk(KERN_INFO DRV_NAME |
3438 | ": %s is not in decimal form.\n", buf); | 3446 | ": %s is not in decimal form.\n", buf); |
3439 | else | 3447 | else |
3440 | iwl_set_tx_power(priv, val, false); | 3448 | iwl_set_tx_power(priv, val, false); |
3441 | 3449 | ||
3442 | return count; | 3450 | return count; |
3443 | } | 3451 | } |
3444 | 3452 | ||
3445 | static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); | 3453 | static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); |
3446 | 3454 | ||
3447 | static ssize_t show_flags(struct device *d, | 3455 | static ssize_t show_flags(struct device *d, |
3448 | struct device_attribute *attr, char *buf) | 3456 | struct device_attribute *attr, char *buf) |
3449 | { | 3457 | { |
3450 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3458 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3451 | 3459 | ||
3452 | return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); | 3460 | return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); |
3453 | } | 3461 | } |
3454 | 3462 | ||
3455 | static ssize_t store_flags(struct device *d, | 3463 | static ssize_t store_flags(struct device *d, |
3456 | struct device_attribute *attr, | 3464 | struct device_attribute *attr, |
3457 | const char *buf, size_t count) | 3465 | const char *buf, size_t count) |
3458 | { | 3466 | { |
3459 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3467 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3460 | unsigned long val; | 3468 | unsigned long val; |
3461 | u32 flags; | 3469 | u32 flags; |
3462 | int ret = strict_strtoul(buf, 0, &val); | 3470 | int ret = strict_strtoul(buf, 0, &val); |
3463 | if (ret) | 3471 | if (ret) |
3464 | return ret; | 3472 | return ret; |
3465 | flags = (u32)val; | 3473 | flags = (u32)val; |
3466 | 3474 | ||
3467 | mutex_lock(&priv->mutex); | 3475 | mutex_lock(&priv->mutex); |
3468 | if (le32_to_cpu(priv->staging_rxon.flags) != flags) { | 3476 | if (le32_to_cpu(priv->staging_rxon.flags) != flags) { |
3469 | /* Cancel any currently running scans... */ | 3477 | /* Cancel any currently running scans... */ |
3470 | if (iwl_scan_cancel_timeout(priv, 100)) | 3478 | if (iwl_scan_cancel_timeout(priv, 100)) |
3471 | IWL_WARNING("Could not cancel scan.\n"); | 3479 | IWL_WARNING("Could not cancel scan.\n"); |
3472 | else { | 3480 | else { |
3473 | IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); | 3481 | IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); |
3474 | priv->staging_rxon.flags = cpu_to_le32(flags); | 3482 | priv->staging_rxon.flags = cpu_to_le32(flags); |
3475 | iwl_commit_rxon(priv); | 3483 | iwl_commit_rxon(priv); |
3476 | } | 3484 | } |
3477 | } | 3485 | } |
3478 | mutex_unlock(&priv->mutex); | 3486 | mutex_unlock(&priv->mutex); |
3479 | 3487 | ||
3480 | return count; | 3488 | return count; |
3481 | } | 3489 | } |
3482 | 3490 | ||
3483 | static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); | 3491 | static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); |
3484 | 3492 | ||
3485 | static ssize_t show_filter_flags(struct device *d, | 3493 | static ssize_t show_filter_flags(struct device *d, |
3486 | struct device_attribute *attr, char *buf) | 3494 | struct device_attribute *attr, char *buf) |
3487 | { | 3495 | { |
3488 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3496 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3489 | 3497 | ||
3490 | return sprintf(buf, "0x%04X\n", | 3498 | return sprintf(buf, "0x%04X\n", |
3491 | le32_to_cpu(priv->active_rxon.filter_flags)); | 3499 | le32_to_cpu(priv->active_rxon.filter_flags)); |
3492 | } | 3500 | } |
3493 | 3501 | ||
3494 | static ssize_t store_filter_flags(struct device *d, | 3502 | static ssize_t store_filter_flags(struct device *d, |
3495 | struct device_attribute *attr, | 3503 | struct device_attribute *attr, |
3496 | const char *buf, size_t count) | 3504 | const char *buf, size_t count) |
3497 | { | 3505 | { |
3498 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3506 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3499 | unsigned long val; | 3507 | unsigned long val; |
3500 | u32 filter_flags; | 3508 | u32 filter_flags; |
3501 | int ret = strict_strtoul(buf, 0, &val); | 3509 | int ret = strict_strtoul(buf, 0, &val); |
3502 | if (ret) | 3510 | if (ret) |
3503 | return ret; | 3511 | return ret; |
3504 | filter_flags = (u32)val; | 3512 | filter_flags = (u32)val; |
3505 | 3513 | ||
3506 | mutex_lock(&priv->mutex); | 3514 | mutex_lock(&priv->mutex); |
3507 | if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { | 3515 | if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { |
3508 | /* Cancel any currently running scans... */ | 3516 | /* Cancel any currently running scans... */ |
3509 | if (iwl_scan_cancel_timeout(priv, 100)) | 3517 | if (iwl_scan_cancel_timeout(priv, 100)) |
3510 | IWL_WARNING("Could not cancel scan.\n"); | 3518 | IWL_WARNING("Could not cancel scan.\n"); |
3511 | else { | 3519 | else { |
3512 | IWL_DEBUG_INFO("Committing rxon.filter_flags = " | 3520 | IWL_DEBUG_INFO("Committing rxon.filter_flags = " |
3513 | "0x%04X\n", filter_flags); | 3521 | "0x%04X\n", filter_flags); |
3514 | priv->staging_rxon.filter_flags = | 3522 | priv->staging_rxon.filter_flags = |
3515 | cpu_to_le32(filter_flags); | 3523 | cpu_to_le32(filter_flags); |
3516 | iwl_commit_rxon(priv); | 3524 | iwl_commit_rxon(priv); |
3517 | } | 3525 | } |
3518 | } | 3526 | } |
3519 | mutex_unlock(&priv->mutex); | 3527 | mutex_unlock(&priv->mutex); |
3520 | 3528 | ||
3521 | return count; | 3529 | return count; |
3522 | } | 3530 | } |
3523 | 3531 | ||
3524 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, | 3532 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, |
3525 | store_filter_flags); | 3533 | store_filter_flags); |
3526 | 3534 | ||
3527 | static ssize_t store_retry_rate(struct device *d, | 3535 | static ssize_t store_retry_rate(struct device *d, |
3528 | struct device_attribute *attr, | 3536 | struct device_attribute *attr, |
3529 | const char *buf, size_t count) | 3537 | const char *buf, size_t count) |
3530 | { | 3538 | { |
3531 | struct iwl_priv *priv = dev_get_drvdata(d); | 3539 | struct iwl_priv *priv = dev_get_drvdata(d); |
3532 | long val; | 3540 | long val; |
3533 | int ret = strict_strtol(buf, 10, &val); | 3541 | int ret = strict_strtol(buf, 10, &val); |
3534 | if (!ret) | 3542 | if (!ret) |
3535 | return ret; | 3543 | return ret; |
3536 | 3544 | ||
3537 | priv->retry_rate = (val > 0) ? val : 1; | 3545 | priv->retry_rate = (val > 0) ? val : 1; |
3538 | 3546 | ||
3539 | return count; | 3547 | return count; |
3540 | } | 3548 | } |
3541 | 3549 | ||
3542 | static ssize_t show_retry_rate(struct device *d, | 3550 | static ssize_t show_retry_rate(struct device *d, |
3543 | struct device_attribute *attr, char *buf) | 3551 | struct device_attribute *attr, char *buf) |
3544 | { | 3552 | { |
3545 | struct iwl_priv *priv = dev_get_drvdata(d); | 3553 | struct iwl_priv *priv = dev_get_drvdata(d); |
3546 | return sprintf(buf, "%d", priv->retry_rate); | 3554 | return sprintf(buf, "%d", priv->retry_rate); |
3547 | } | 3555 | } |
3548 | 3556 | ||
3549 | static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, | 3557 | static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, |
3550 | store_retry_rate); | 3558 | store_retry_rate); |
3551 | 3559 | ||
3552 | static ssize_t store_power_level(struct device *d, | 3560 | static ssize_t store_power_level(struct device *d, |
3553 | struct device_attribute *attr, | 3561 | struct device_attribute *attr, |
3554 | const char *buf, size_t count) | 3562 | const char *buf, size_t count) |
3555 | { | 3563 | { |
3556 | struct iwl_priv *priv = dev_get_drvdata(d); | 3564 | struct iwl_priv *priv = dev_get_drvdata(d); |
3557 | int ret; | 3565 | int ret; |
3558 | unsigned long mode; | 3566 | unsigned long mode; |
3559 | 3567 | ||
3560 | 3568 | ||
3561 | mutex_lock(&priv->mutex); | 3569 | mutex_lock(&priv->mutex); |
3562 | 3570 | ||
3563 | if (!iwl_is_ready(priv)) { | 3571 | if (!iwl_is_ready(priv)) { |
3564 | ret = -EAGAIN; | 3572 | ret = -EAGAIN; |
3565 | goto out; | 3573 | goto out; |
3566 | } | 3574 | } |
3567 | 3575 | ||
3568 | ret = strict_strtoul(buf, 10, &mode); | 3576 | ret = strict_strtoul(buf, 10, &mode); |
3569 | if (ret) | 3577 | if (ret) |
3570 | goto out; | 3578 | goto out; |
3571 | 3579 | ||
3572 | ret = iwl_power_set_user_mode(priv, mode); | 3580 | ret = iwl_power_set_user_mode(priv, mode); |
3573 | if (ret) { | 3581 | if (ret) { |
3574 | IWL_DEBUG_MAC80211("failed setting power mode.\n"); | 3582 | IWL_DEBUG_MAC80211("failed setting power mode.\n"); |
3575 | goto out; | 3583 | goto out; |
3576 | } | 3584 | } |
3577 | ret = count; | 3585 | ret = count; |
3578 | 3586 | ||
3579 | out: | 3587 | out: |
3580 | mutex_unlock(&priv->mutex); | 3588 | mutex_unlock(&priv->mutex); |
3581 | return ret; | 3589 | return ret; |
3582 | } | 3590 | } |
3583 | 3591 | ||
3584 | static ssize_t show_power_level(struct device *d, | 3592 | static ssize_t show_power_level(struct device *d, |
3585 | struct device_attribute *attr, char *buf) | 3593 | struct device_attribute *attr, char *buf) |
3586 | { | 3594 | { |
3587 | struct iwl_priv *priv = dev_get_drvdata(d); | 3595 | struct iwl_priv *priv = dev_get_drvdata(d); |
3588 | int mode = priv->power_data.user_power_setting; | 3596 | int mode = priv->power_data.user_power_setting; |
3589 | int system = priv->power_data.system_power_setting; | 3597 | int system = priv->power_data.system_power_setting; |
3590 | int level = priv->power_data.power_mode; | 3598 | int level = priv->power_data.power_mode; |
3591 | char *p = buf; | 3599 | char *p = buf; |
3592 | 3600 | ||
3593 | switch (system) { | 3601 | switch (system) { |
3594 | case IWL_POWER_SYS_AUTO: | 3602 | case IWL_POWER_SYS_AUTO: |
3595 | p += sprintf(p, "SYSTEM:auto"); | 3603 | p += sprintf(p, "SYSTEM:auto"); |
3596 | break; | 3604 | break; |
3597 | case IWL_POWER_SYS_AC: | 3605 | case IWL_POWER_SYS_AC: |
3598 | p += sprintf(p, "SYSTEM:ac"); | 3606 | p += sprintf(p, "SYSTEM:ac"); |
3599 | break; | 3607 | break; |
3600 | case IWL_POWER_SYS_BATTERY: | 3608 | case IWL_POWER_SYS_BATTERY: |
3601 | p += sprintf(p, "SYSTEM:battery"); | 3609 | p += sprintf(p, "SYSTEM:battery"); |
3602 | break; | 3610 | break; |
3603 | } | 3611 | } |
3604 | 3612 | ||
3605 | p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? | 3613 | p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? |
3606 | "fixed" : "auto"); | 3614 | "fixed" : "auto"); |
3607 | p += sprintf(p, "\tINDEX:%d", level); | 3615 | p += sprintf(p, "\tINDEX:%d", level); |
3608 | p += sprintf(p, "\n"); | 3616 | p += sprintf(p, "\n"); |
3609 | return p - buf + 1; | 3617 | return p - buf + 1; |
3610 | } | 3618 | } |
3611 | 3619 | ||
3612 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, | 3620 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, |
3613 | store_power_level); | 3621 | store_power_level); |
3614 | 3622 | ||
3615 | 3623 | ||
3616 | static ssize_t show_statistics(struct device *d, | 3624 | static ssize_t show_statistics(struct device *d, |
3617 | struct device_attribute *attr, char *buf) | 3625 | struct device_attribute *attr, char *buf) |
3618 | { | 3626 | { |
3619 | struct iwl_priv *priv = dev_get_drvdata(d); | 3627 | struct iwl_priv *priv = dev_get_drvdata(d); |
3620 | u32 size = sizeof(struct iwl_notif_statistics); | 3628 | u32 size = sizeof(struct iwl_notif_statistics); |
3621 | u32 len = 0, ofs = 0; | 3629 | u32 len = 0, ofs = 0; |
3622 | u8 *data = (u8 *)&priv->statistics; | 3630 | u8 *data = (u8 *)&priv->statistics; |
3623 | int rc = 0; | 3631 | int rc = 0; |
3624 | 3632 | ||
3625 | if (!iwl_is_alive(priv)) | 3633 | if (!iwl_is_alive(priv)) |
3626 | return -EAGAIN; | 3634 | return -EAGAIN; |
3627 | 3635 | ||
3628 | mutex_lock(&priv->mutex); | 3636 | mutex_lock(&priv->mutex); |
3629 | rc = iwl_send_statistics_request(priv, 0); | 3637 | rc = iwl_send_statistics_request(priv, 0); |
3630 | mutex_unlock(&priv->mutex); | 3638 | mutex_unlock(&priv->mutex); |
3631 | 3639 | ||
3632 | if (rc) { | 3640 | if (rc) { |
3633 | len = sprintf(buf, | 3641 | len = sprintf(buf, |
3634 | "Error sending statistics request: 0x%08X\n", rc); | 3642 | "Error sending statistics request: 0x%08X\n", rc); |
3635 | return len; | 3643 | return len; |
3636 | } | 3644 | } |
3637 | 3645 | ||
3638 | while (size && (PAGE_SIZE - len)) { | 3646 | while (size && (PAGE_SIZE - len)) { |
3639 | hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, | 3647 | hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, |
3640 | PAGE_SIZE - len, 1); | 3648 | PAGE_SIZE - len, 1); |
3641 | len = strlen(buf); | 3649 | len = strlen(buf); |
3642 | if (PAGE_SIZE - len) | 3650 | if (PAGE_SIZE - len) |
3643 | buf[len++] = '\n'; | 3651 | buf[len++] = '\n'; |
3644 | 3652 | ||
3645 | ofs += 16; | 3653 | ofs += 16; |
3646 | size -= min(size, 16U); | 3654 | size -= min(size, 16U); |
3647 | } | 3655 | } |
3648 | 3656 | ||
3649 | return len; | 3657 | return len; |
3650 | } | 3658 | } |
3651 | 3659 | ||
3652 | static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); | 3660 | static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); |
3653 | 3661 | ||
3654 | static ssize_t show_status(struct device *d, | 3662 | static ssize_t show_status(struct device *d, |
3655 | struct device_attribute *attr, char *buf) | 3663 | struct device_attribute *attr, char *buf) |
3656 | { | 3664 | { |
3657 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 3665 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; |
3658 | if (!iwl_is_alive(priv)) | 3666 | if (!iwl_is_alive(priv)) |
3659 | return -EAGAIN; | 3667 | return -EAGAIN; |
3660 | return sprintf(buf, "0x%08x\n", (int)priv->status); | 3668 | return sprintf(buf, "0x%08x\n", (int)priv->status); |
3661 | } | 3669 | } |
3662 | 3670 | ||
3663 | static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | 3671 | static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); |
3664 | 3672 | ||
3665 | /***************************************************************************** | 3673 | /***************************************************************************** |
3666 | * | 3674 | * |
3667 | * driver setup and teardown | 3675 | * driver setup and teardown |
3668 | * | 3676 | * |
3669 | *****************************************************************************/ | 3677 | *****************************************************************************/ |
3670 | 3678 | ||
3671 | static void iwl_setup_deferred_work(struct iwl_priv *priv) | 3679 | static void iwl_setup_deferred_work(struct iwl_priv *priv) |
3672 | { | 3680 | { |
3673 | priv->workqueue = create_workqueue(DRV_NAME); | 3681 | priv->workqueue = create_workqueue(DRV_NAME); |
3674 | 3682 | ||
3675 | init_waitqueue_head(&priv->wait_command_queue); | 3683 | init_waitqueue_head(&priv->wait_command_queue); |
3676 | 3684 | ||
3677 | INIT_WORK(&priv->up, iwl_bg_up); | 3685 | INIT_WORK(&priv->up, iwl_bg_up); |
3678 | INIT_WORK(&priv->restart, iwl_bg_restart); | 3686 | INIT_WORK(&priv->restart, iwl_bg_restart); |
3679 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); | 3687 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); |
3680 | INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); | 3688 | INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); |
3681 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); | 3689 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); |
3682 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); | 3690 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); |
3683 | INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); | 3691 | INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); |
3684 | INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); | 3692 | INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); |
3685 | 3693 | ||
3686 | iwl_setup_scan_deferred_work(priv); | 3694 | iwl_setup_scan_deferred_work(priv); |
3687 | iwl_setup_power_deferred_work(priv); | 3695 | iwl_setup_power_deferred_work(priv); |
3688 | 3696 | ||
3689 | if (priv->cfg->ops->lib->setup_deferred_work) | 3697 | if (priv->cfg->ops->lib->setup_deferred_work) |
3690 | priv->cfg->ops->lib->setup_deferred_work(priv); | 3698 | priv->cfg->ops->lib->setup_deferred_work(priv); |
3691 | 3699 | ||
3692 | init_timer(&priv->statistics_periodic); | 3700 | init_timer(&priv->statistics_periodic); |
3693 | priv->statistics_periodic.data = (unsigned long)priv; | 3701 | priv->statistics_periodic.data = (unsigned long)priv; |
3694 | priv->statistics_periodic.function = iwl_bg_statistics_periodic; | 3702 | priv->statistics_periodic.function = iwl_bg_statistics_periodic; |
3695 | 3703 | ||
3696 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 3704 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
3697 | iwl_irq_tasklet, (unsigned long)priv); | 3705 | iwl_irq_tasklet, (unsigned long)priv); |
3698 | } | 3706 | } |
3699 | 3707 | ||
3700 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) | 3708 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) |
3701 | { | 3709 | { |
3702 | if (priv->cfg->ops->lib->cancel_deferred_work) | 3710 | if (priv->cfg->ops->lib->cancel_deferred_work) |
3703 | priv->cfg->ops->lib->cancel_deferred_work(priv); | 3711 | priv->cfg->ops->lib->cancel_deferred_work(priv); |
3704 | 3712 | ||
3705 | cancel_delayed_work_sync(&priv->init_alive_start); | 3713 | cancel_delayed_work_sync(&priv->init_alive_start); |
3706 | cancel_delayed_work(&priv->scan_check); | 3714 | cancel_delayed_work(&priv->scan_check); |
3707 | cancel_delayed_work_sync(&priv->set_power_save); | 3715 | cancel_delayed_work_sync(&priv->set_power_save); |
3708 | cancel_delayed_work(&priv->alive_start); | 3716 | cancel_delayed_work(&priv->alive_start); |
3709 | cancel_work_sync(&priv->beacon_update); | 3717 | cancel_work_sync(&priv->beacon_update); |
3710 | del_timer_sync(&priv->statistics_periodic); | 3718 | del_timer_sync(&priv->statistics_periodic); |
3711 | } | 3719 | } |
3712 | 3720 | ||
3713 | static struct attribute *iwl_sysfs_entries[] = { | 3721 | static struct attribute *iwl_sysfs_entries[] = { |
3714 | &dev_attr_flags.attr, | 3722 | &dev_attr_flags.attr, |
3715 | &dev_attr_filter_flags.attr, | 3723 | &dev_attr_filter_flags.attr, |
3716 | &dev_attr_power_level.attr, | 3724 | &dev_attr_power_level.attr, |
3717 | &dev_attr_retry_rate.attr, | 3725 | &dev_attr_retry_rate.attr, |
3718 | &dev_attr_statistics.attr, | 3726 | &dev_attr_statistics.attr, |
3719 | &dev_attr_status.attr, | 3727 | &dev_attr_status.attr, |
3720 | &dev_attr_temperature.attr, | 3728 | &dev_attr_temperature.attr, |
3721 | &dev_attr_tx_power.attr, | 3729 | &dev_attr_tx_power.attr, |
3722 | #ifdef CONFIG_IWLWIFI_DEBUG | 3730 | #ifdef CONFIG_IWLWIFI_DEBUG |
3723 | &dev_attr_debug_level.attr, | 3731 | &dev_attr_debug_level.attr, |
3724 | #endif | 3732 | #endif |
3725 | &dev_attr_version.attr, | 3733 | &dev_attr_version.attr, |
3726 | 3734 | ||
3727 | NULL | 3735 | NULL |
3728 | }; | 3736 | }; |
3729 | 3737 | ||
3730 | static struct attribute_group iwl_attribute_group = { | 3738 | static struct attribute_group iwl_attribute_group = { |
3731 | .name = NULL, /* put in device directory */ | 3739 | .name = NULL, /* put in device directory */ |
3732 | .attrs = iwl_sysfs_entries, | 3740 | .attrs = iwl_sysfs_entries, |
3733 | }; | 3741 | }; |
3734 | 3742 | ||
3735 | static struct ieee80211_ops iwl_hw_ops = { | 3743 | static struct ieee80211_ops iwl_hw_ops = { |
3736 | .tx = iwl_mac_tx, | 3744 | .tx = iwl_mac_tx, |
3737 | .start = iwl_mac_start, | 3745 | .start = iwl_mac_start, |
3738 | .stop = iwl_mac_stop, | 3746 | .stop = iwl_mac_stop, |
3739 | .add_interface = iwl_mac_add_interface, | 3747 | .add_interface = iwl_mac_add_interface, |
3740 | .remove_interface = iwl_mac_remove_interface, | 3748 | .remove_interface = iwl_mac_remove_interface, |
3741 | .config = iwl_mac_config, | 3749 | .config = iwl_mac_config, |
3742 | .config_interface = iwl_mac_config_interface, | 3750 | .config_interface = iwl_mac_config_interface, |
3743 | .configure_filter = iwl_configure_filter, | 3751 | .configure_filter = iwl_configure_filter, |
3744 | .set_key = iwl_mac_set_key, | 3752 | .set_key = iwl_mac_set_key, |
3745 | .update_tkip_key = iwl_mac_update_tkip_key, | 3753 | .update_tkip_key = iwl_mac_update_tkip_key, |
3746 | .get_stats = iwl_mac_get_stats, | 3754 | .get_stats = iwl_mac_get_stats, |
3747 | .get_tx_stats = iwl_mac_get_tx_stats, | 3755 | .get_tx_stats = iwl_mac_get_tx_stats, |
3748 | .conf_tx = iwl_mac_conf_tx, | 3756 | .conf_tx = iwl_mac_conf_tx, |
3749 | .reset_tsf = iwl_mac_reset_tsf, | 3757 | .reset_tsf = iwl_mac_reset_tsf, |
3750 | .bss_info_changed = iwl_bss_info_changed, | 3758 | .bss_info_changed = iwl_bss_info_changed, |
3751 | .ampdu_action = iwl_mac_ampdu_action, | 3759 | .ampdu_action = iwl_mac_ampdu_action, |
3752 | .hw_scan = iwl_mac_hw_scan | 3760 | .hw_scan = iwl_mac_hw_scan |
3753 | }; | 3761 | }; |
3754 | 3762 | ||
3755 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 3763 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
3756 | { | 3764 | { |
3757 | int err = 0; | 3765 | int err = 0; |
3758 | struct iwl_priv *priv; | 3766 | struct iwl_priv *priv; |
3759 | struct ieee80211_hw *hw; | 3767 | struct ieee80211_hw *hw; |
3760 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 3768 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
3761 | unsigned long flags; | 3769 | unsigned long flags; |
3762 | 3770 | ||
3763 | /************************ | 3771 | /************************ |
3764 | * 1. Allocating HW data | 3772 | * 1. Allocating HW data |
3765 | ************************/ | 3773 | ************************/ |
3766 | 3774 | ||
3767 | /* Disabling hardware scan means that mac80211 will perform scans | 3775 | /* Disabling hardware scan means that mac80211 will perform scans |
3768 | * "the hard way", rather than using device's scan. */ | 3776 | * "the hard way", rather than using device's scan. */ |
3769 | if (cfg->mod_params->disable_hw_scan) { | 3777 | if (cfg->mod_params->disable_hw_scan) { |
3770 | if (cfg->mod_params->debug & IWL_DL_INFO) | 3778 | if (cfg->mod_params->debug & IWL_DL_INFO) |
3771 | dev_printk(KERN_DEBUG, &(pdev->dev), | 3779 | dev_printk(KERN_DEBUG, &(pdev->dev), |
3772 | "Disabling hw_scan\n"); | 3780 | "Disabling hw_scan\n"); |
3773 | iwl_hw_ops.hw_scan = NULL; | 3781 | iwl_hw_ops.hw_scan = NULL; |
3774 | } | 3782 | } |
3775 | 3783 | ||
3776 | hw = iwl_alloc_all(cfg, &iwl_hw_ops); | 3784 | hw = iwl_alloc_all(cfg, &iwl_hw_ops); |
3777 | if (!hw) { | 3785 | if (!hw) { |
3778 | err = -ENOMEM; | 3786 | err = -ENOMEM; |
3779 | goto out; | 3787 | goto out; |
3780 | } | 3788 | } |
3781 | priv = hw->priv; | 3789 | priv = hw->priv; |
3782 | /* At this point both hw and priv are allocated. */ | 3790 | /* At this point both hw and priv are allocated. */ |
3783 | 3791 | ||
3784 | SET_IEEE80211_DEV(hw, &pdev->dev); | 3792 | SET_IEEE80211_DEV(hw, &pdev->dev); |
3785 | 3793 | ||
3786 | IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); | 3794 | IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); |
3787 | priv->cfg = cfg; | 3795 | priv->cfg = cfg; |
3788 | priv->pci_dev = pdev; | 3796 | priv->pci_dev = pdev; |
3789 | 3797 | ||
3790 | #ifdef CONFIG_IWLWIFI_DEBUG | 3798 | #ifdef CONFIG_IWLWIFI_DEBUG |
3791 | priv->debug_level = priv->cfg->mod_params->debug; | 3799 | priv->debug_level = priv->cfg->mod_params->debug; |
3792 | atomic_set(&priv->restrict_refcnt, 0); | 3800 | atomic_set(&priv->restrict_refcnt, 0); |
3793 | #endif | 3801 | #endif |
3794 | 3802 | ||
3795 | /************************** | 3803 | /************************** |
3796 | * 2. Initializing PCI bus | 3804 | * 2. Initializing PCI bus |
3797 | **************************/ | 3805 | **************************/ |
3798 | if (pci_enable_device(pdev)) { | 3806 | if (pci_enable_device(pdev)) { |
3799 | err = -ENODEV; | 3807 | err = -ENODEV; |
3800 | goto out_ieee80211_free_hw; | 3808 | goto out_ieee80211_free_hw; |
3801 | } | 3809 | } |
3802 | 3810 | ||
3803 | pci_set_master(pdev); | 3811 | pci_set_master(pdev); |
3804 | 3812 | ||
3805 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); | 3813 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); |
3806 | if (!err) | 3814 | if (!err) |
3807 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); | 3815 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); |
3808 | if (err) { | 3816 | if (err) { |
3809 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | 3817 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
3810 | if (!err) | 3818 | if (!err) |
3811 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | 3819 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); |
3812 | /* both attempts failed: */ | 3820 | /* both attempts failed: */ |
3813 | if (err) { | 3821 | if (err) { |
3814 | printk(KERN_WARNING "%s: No suitable DMA available.\n", | 3822 | printk(KERN_WARNING "%s: No suitable DMA available.\n", |
3815 | DRV_NAME); | 3823 | DRV_NAME); |
3816 | goto out_pci_disable_device; | 3824 | goto out_pci_disable_device; |
3817 | } | 3825 | } |
3818 | } | 3826 | } |
3819 | 3827 | ||
3820 | err = pci_request_regions(pdev, DRV_NAME); | 3828 | err = pci_request_regions(pdev, DRV_NAME); |
3821 | if (err) | 3829 | if (err) |
3822 | goto out_pci_disable_device; | 3830 | goto out_pci_disable_device; |
3823 | 3831 | ||
3824 | pci_set_drvdata(pdev, priv); | 3832 | pci_set_drvdata(pdev, priv); |
3825 | 3833 | ||
3826 | 3834 | ||
3827 | /*********************** | 3835 | /*********************** |
3828 | * 3. Read REV register | 3836 | * 3. Read REV register |
3829 | ***********************/ | 3837 | ***********************/ |
3830 | priv->hw_base = pci_iomap(pdev, 0, 0); | 3838 | priv->hw_base = pci_iomap(pdev, 0, 0); |
3831 | if (!priv->hw_base) { | 3839 | if (!priv->hw_base) { |
3832 | err = -ENODEV; | 3840 | err = -ENODEV; |
3833 | goto out_pci_release_regions; | 3841 | goto out_pci_release_regions; |
3834 | } | 3842 | } |
3835 | 3843 | ||
3836 | IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", | 3844 | IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", |
3837 | (unsigned long long) pci_resource_len(pdev, 0)); | 3845 | (unsigned long long) pci_resource_len(pdev, 0)); |
3838 | IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); | 3846 | IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); |
3839 | 3847 | ||
3840 | iwl_hw_detect(priv); | 3848 | iwl_hw_detect(priv); |
3841 | printk(KERN_INFO DRV_NAME | 3849 | printk(KERN_INFO DRV_NAME |
3842 | ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", | 3850 | ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", |
3843 | priv->cfg->name, priv->hw_rev); | 3851 | priv->cfg->name, priv->hw_rev); |
3844 | 3852 | ||
3845 | /* We disable the RETRY_TIMEOUT register (0x41) to keep | 3853 | /* We disable the RETRY_TIMEOUT register (0x41) to keep |
3846 | * PCI Tx retries from interfering with C3 CPU state */ | 3854 | * PCI Tx retries from interfering with C3 CPU state */ |
3847 | pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); | 3855 | pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); |
3848 | 3856 | ||
3849 | /* amp init */ | 3857 | /* amp init */ |
3850 | err = priv->cfg->ops->lib->apm_ops.init(priv); | 3858 | err = priv->cfg->ops->lib->apm_ops.init(priv); |
3851 | if (err < 0) { | 3859 | if (err < 0) { |
3852 | IWL_DEBUG_INFO("Failed to init APMG\n"); | 3860 | IWL_DEBUG_INFO("Failed to init APMG\n"); |
3853 | goto out_iounmap; | 3861 | goto out_iounmap; |
3854 | } | 3862 | } |
3855 | /***************** | 3863 | /***************** |
3856 | * 4. Read EEPROM | 3864 | * 4. Read EEPROM |
3857 | *****************/ | 3865 | *****************/ |
3858 | /* Read the EEPROM */ | 3866 | /* Read the EEPROM */ |
3859 | err = iwl_eeprom_init(priv); | 3867 | err = iwl_eeprom_init(priv); |
3860 | if (err) { | 3868 | if (err) { |
3861 | IWL_ERROR("Unable to init EEPROM\n"); | 3869 | IWL_ERROR("Unable to init EEPROM\n"); |
3862 | goto out_iounmap; | 3870 | goto out_iounmap; |
3863 | } | 3871 | } |
3864 | err = iwl_eeprom_check_version(priv); | 3872 | err = iwl_eeprom_check_version(priv); |
3865 | if (err) | 3873 | if (err) |
3866 | goto out_iounmap; | 3874 | goto out_iounmap; |
3867 | 3875 | ||
3868 | /* extract MAC Address */ | 3876 | /* extract MAC Address */ |
3869 | iwl_eeprom_get_mac(priv, priv->mac_addr); | 3877 | iwl_eeprom_get_mac(priv, priv->mac_addr); |
3870 | IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); | 3878 | IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); |
3871 | SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); | 3879 | SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); |
3872 | 3880 | ||
3873 | /************************ | 3881 | /************************ |
3874 | * 5. Setup HW constants | 3882 | * 5. Setup HW constants |
3875 | ************************/ | 3883 | ************************/ |
3876 | if (iwl_set_hw_params(priv)) { | 3884 | if (iwl_set_hw_params(priv)) { |
3877 | IWL_ERROR("failed to set hw parameters\n"); | 3885 | IWL_ERROR("failed to set hw parameters\n"); |
3878 | goto out_free_eeprom; | 3886 | goto out_free_eeprom; |
3879 | } | 3887 | } |
3880 | 3888 | ||
3881 | /******************* | 3889 | /******************* |
3882 | * 6. Setup priv | 3890 | * 6. Setup priv |
3883 | *******************/ | 3891 | *******************/ |
3884 | 3892 | ||
3885 | err = iwl_init_drv(priv); | 3893 | err = iwl_init_drv(priv); |
3886 | if (err) | 3894 | if (err) |
3887 | goto out_free_eeprom; | 3895 | goto out_free_eeprom; |
3888 | /* At this point both hw and priv are initialized. */ | 3896 | /* At this point both hw and priv are initialized. */ |
3889 | 3897 | ||
3890 | /********************************** | 3898 | /********************************** |
3891 | * 7. Initialize module parameters | 3899 | * 7. Initialize module parameters |
3892 | **********************************/ | 3900 | **********************************/ |
3893 | 3901 | ||
3894 | /* Disable radio (SW RF KILL) via parameter when loading driver */ | 3902 | /* Disable radio (SW RF KILL) via parameter when loading driver */ |
3895 | if (priv->cfg->mod_params->disable) { | 3903 | if (priv->cfg->mod_params->disable) { |
3896 | set_bit(STATUS_RF_KILL_SW, &priv->status); | 3904 | set_bit(STATUS_RF_KILL_SW, &priv->status); |
3897 | IWL_DEBUG_INFO("Radio disabled.\n"); | 3905 | IWL_DEBUG_INFO("Radio disabled.\n"); |
3898 | } | 3906 | } |
3899 | 3907 | ||
3900 | /******************** | 3908 | /******************** |
3901 | * 8. Setup services | 3909 | * 8. Setup services |
3902 | ********************/ | 3910 | ********************/ |
3903 | spin_lock_irqsave(&priv->lock, flags); | 3911 | spin_lock_irqsave(&priv->lock, flags); |
3904 | iwl_disable_interrupts(priv); | 3912 | iwl_disable_interrupts(priv); |
3905 | spin_unlock_irqrestore(&priv->lock, flags); | 3913 | spin_unlock_irqrestore(&priv->lock, flags); |
3906 | 3914 | ||
3907 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); | 3915 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); |
3908 | if (err) { | 3916 | if (err) { |
3909 | IWL_ERROR("failed to create sysfs device attributes\n"); | 3917 | IWL_ERROR("failed to create sysfs device attributes\n"); |
3910 | goto out_uninit_drv; | 3918 | goto out_uninit_drv; |
3911 | } | 3919 | } |
3912 | 3920 | ||
3913 | 3921 | ||
3914 | iwl_setup_deferred_work(priv); | 3922 | iwl_setup_deferred_work(priv); |
3915 | iwl_setup_rx_handlers(priv); | 3923 | iwl_setup_rx_handlers(priv); |
3916 | 3924 | ||
3917 | /******************** | 3925 | /******************** |
3918 | * 9. Conclude | 3926 | * 9. Conclude |
3919 | ********************/ | 3927 | ********************/ |
3920 | pci_save_state(pdev); | 3928 | pci_save_state(pdev); |
3921 | pci_disable_device(pdev); | 3929 | pci_disable_device(pdev); |
3922 | 3930 | ||
3923 | /********************************** | 3931 | /********************************** |
3924 | * 10. Setup and register mac80211 | 3932 | * 10. Setup and register mac80211 |
3925 | **********************************/ | 3933 | **********************************/ |
3926 | 3934 | ||
3927 | err = iwl_setup_mac(priv); | 3935 | err = iwl_setup_mac(priv); |
3928 | if (err) | 3936 | if (err) |
3929 | goto out_remove_sysfs; | 3937 | goto out_remove_sysfs; |
3930 | 3938 | ||
3931 | err = iwl_dbgfs_register(priv, DRV_NAME); | 3939 | err = iwl_dbgfs_register(priv, DRV_NAME); |
3932 | if (err) | 3940 | if (err) |
3933 | IWL_ERROR("failed to create debugfs files\n"); | 3941 | IWL_ERROR("failed to create debugfs files\n"); |
3934 | 3942 | ||
3935 | err = iwl_rfkill_init(priv); | 3943 | err = iwl_rfkill_init(priv); |
3936 | if (err) | 3944 | if (err) |
3937 | IWL_ERROR("Unable to initialize RFKILL system. " | 3945 | IWL_ERROR("Unable to initialize RFKILL system. " |
3938 | "Ignoring error: %d\n", err); | 3946 | "Ignoring error: %d\n", err); |
3939 | iwl_power_initialize(priv); | 3947 | iwl_power_initialize(priv); |
3940 | return 0; | 3948 | return 0; |
3941 | 3949 | ||
3942 | out_remove_sysfs: | 3950 | out_remove_sysfs: |
3943 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | 3951 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); |
3944 | out_uninit_drv: | 3952 | out_uninit_drv: |
3945 | iwl_uninit_drv(priv); | 3953 | iwl_uninit_drv(priv); |
3946 | out_free_eeprom: | 3954 | out_free_eeprom: |
3947 | iwl_eeprom_free(priv); | 3955 | iwl_eeprom_free(priv); |
3948 | out_iounmap: | 3956 | out_iounmap: |
3949 | pci_iounmap(pdev, priv->hw_base); | 3957 | pci_iounmap(pdev, priv->hw_base); |
3950 | out_pci_release_regions: | 3958 | out_pci_release_regions: |
3951 | pci_release_regions(pdev); | 3959 | pci_release_regions(pdev); |
3952 | pci_set_drvdata(pdev, NULL); | 3960 | pci_set_drvdata(pdev, NULL); |
3953 | out_pci_disable_device: | 3961 | out_pci_disable_device: |
3954 | pci_disable_device(pdev); | 3962 | pci_disable_device(pdev); |
3955 | out_ieee80211_free_hw: | 3963 | out_ieee80211_free_hw: |
3956 | ieee80211_free_hw(priv->hw); | 3964 | ieee80211_free_hw(priv->hw); |
3957 | out: | 3965 | out: |
3958 | return err; | 3966 | return err; |
3959 | } | 3967 | } |
3960 | 3968 | ||
3961 | static void __devexit iwl_pci_remove(struct pci_dev *pdev) | 3969 | static void __devexit iwl_pci_remove(struct pci_dev *pdev) |
3962 | { | 3970 | { |
3963 | struct iwl_priv *priv = pci_get_drvdata(pdev); | 3971 | struct iwl_priv *priv = pci_get_drvdata(pdev); |
3964 | unsigned long flags; | 3972 | unsigned long flags; |
3965 | 3973 | ||
3966 | if (!priv) | 3974 | if (!priv) |
3967 | return; | 3975 | return; |
3968 | 3976 | ||
3969 | IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); | 3977 | IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); |
3970 | 3978 | ||
3971 | iwl_dbgfs_unregister(priv); | 3979 | iwl_dbgfs_unregister(priv); |
3972 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | 3980 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); |
3973 | 3981 | ||
3974 | /* ieee80211_unregister_hw call wil cause iwl_mac_stop to | 3982 | /* ieee80211_unregister_hw call wil cause iwl_mac_stop to |
3975 | * to be called and iwl_down since we are removing the device | 3983 | * to be called and iwl_down since we are removing the device |
3976 | * we need to set STATUS_EXIT_PENDING bit. | 3984 | * we need to set STATUS_EXIT_PENDING bit. |
3977 | */ | 3985 | */ |
3978 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 3986 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
3979 | if (priv->mac80211_registered) { | 3987 | if (priv->mac80211_registered) { |
3980 | ieee80211_unregister_hw(priv->hw); | 3988 | ieee80211_unregister_hw(priv->hw); |
3981 | priv->mac80211_registered = 0; | 3989 | priv->mac80211_registered = 0; |
3982 | } else { | 3990 | } else { |
3983 | iwl_down(priv); | 3991 | iwl_down(priv); |
3984 | } | 3992 | } |
3985 | 3993 | ||
3986 | /* make sure we flush any pending irq or | 3994 | /* make sure we flush any pending irq or |
3987 | * tasklet for the driver | 3995 | * tasklet for the driver |
3988 | */ | 3996 | */ |
3989 | spin_lock_irqsave(&priv->lock, flags); | 3997 | spin_lock_irqsave(&priv->lock, flags); |
3990 | iwl_disable_interrupts(priv); | 3998 | iwl_disable_interrupts(priv); |
3991 | spin_unlock_irqrestore(&priv->lock, flags); | 3999 | spin_unlock_irqrestore(&priv->lock, flags); |
3992 | 4000 | ||
3993 | iwl_synchronize_irq(priv); | 4001 | iwl_synchronize_irq(priv); |
3994 | 4002 | ||
3995 | iwl_rfkill_unregister(priv); | 4003 | iwl_rfkill_unregister(priv); |
3996 | iwl_dealloc_ucode_pci(priv); | 4004 | iwl_dealloc_ucode_pci(priv); |
3997 | 4005 | ||
3998 | if (priv->rxq.bd) | 4006 | if (priv->rxq.bd) |
3999 | iwl_rx_queue_free(priv, &priv->rxq); | 4007 | iwl_rx_queue_free(priv, &priv->rxq); |
4000 | iwl_hw_txq_ctx_free(priv); | 4008 | iwl_hw_txq_ctx_free(priv); |
4001 | 4009 | ||
4002 | iwl_clear_stations_table(priv); | 4010 | iwl_clear_stations_table(priv); |
4003 | iwl_eeprom_free(priv); | 4011 | iwl_eeprom_free(priv); |
4004 | 4012 | ||
4005 | 4013 | ||
4006 | /*netif_stop_queue(dev); */ | 4014 | /*netif_stop_queue(dev); */ |
4007 | flush_workqueue(priv->workqueue); | 4015 | flush_workqueue(priv->workqueue); |
4008 | 4016 | ||
4009 | /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes | 4017 | /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes |
4010 | * priv->workqueue... so we can't take down the workqueue | 4018 | * priv->workqueue... so we can't take down the workqueue |
4011 | * until now... */ | 4019 | * until now... */ |
4012 | destroy_workqueue(priv->workqueue); | 4020 | destroy_workqueue(priv->workqueue); |
4013 | priv->workqueue = NULL; | 4021 | priv->workqueue = NULL; |
4014 | 4022 | ||
4015 | pci_iounmap(pdev, priv->hw_base); | 4023 | pci_iounmap(pdev, priv->hw_base); |
4016 | pci_release_regions(pdev); | 4024 | pci_release_regions(pdev); |
4017 | pci_disable_device(pdev); | 4025 | pci_disable_device(pdev); |
4018 | pci_set_drvdata(pdev, NULL); | 4026 | pci_set_drvdata(pdev, NULL); |
4019 | 4027 | ||
4020 | iwl_uninit_drv(priv); | 4028 | iwl_uninit_drv(priv); |
4021 | 4029 | ||
4022 | if (priv->ibss_beacon) | 4030 | if (priv->ibss_beacon) |
4023 | dev_kfree_skb(priv->ibss_beacon); | 4031 | dev_kfree_skb(priv->ibss_beacon); |
4024 | 4032 | ||
4025 | ieee80211_free_hw(priv->hw); | 4033 | ieee80211_free_hw(priv->hw); |
4026 | } | 4034 | } |
4027 | 4035 | ||
4028 | #ifdef CONFIG_PM | 4036 | #ifdef CONFIG_PM |
4029 | 4037 | ||
4030 | static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 4038 | static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
4031 | { | 4039 | { |
4032 | struct iwl_priv *priv = pci_get_drvdata(pdev); | 4040 | struct iwl_priv *priv = pci_get_drvdata(pdev); |
4033 | 4041 | ||
4034 | if (priv->is_open) { | 4042 | if (priv->is_open) { |
4035 | set_bit(STATUS_IN_SUSPEND, &priv->status); | 4043 | set_bit(STATUS_IN_SUSPEND, &priv->status); |
4036 | iwl_mac_stop(priv->hw); | 4044 | iwl_mac_stop(priv->hw); |
4037 | priv->is_open = 1; | 4045 | priv->is_open = 1; |
4038 | } | 4046 | } |
4039 | 4047 | ||
4040 | pci_set_power_state(pdev, PCI_D3hot); | 4048 | pci_set_power_state(pdev, PCI_D3hot); |
4041 | 4049 | ||
4042 | return 0; | 4050 | return 0; |
4043 | } | 4051 | } |
4044 | 4052 | ||
4045 | static int iwl_pci_resume(struct pci_dev *pdev) | 4053 | static int iwl_pci_resume(struct pci_dev *pdev) |
4046 | { | 4054 | { |
4047 | struct iwl_priv *priv = pci_get_drvdata(pdev); | 4055 | struct iwl_priv *priv = pci_get_drvdata(pdev); |
4048 | 4056 | ||
4049 | pci_set_power_state(pdev, PCI_D0); | 4057 | pci_set_power_state(pdev, PCI_D0); |
4050 | 4058 | ||
4051 | if (priv->is_open) | 4059 | if (priv->is_open) |
4052 | iwl_mac_start(priv->hw); | 4060 | iwl_mac_start(priv->hw); |
4053 | 4061 | ||
4054 | clear_bit(STATUS_IN_SUSPEND, &priv->status); | 4062 | clear_bit(STATUS_IN_SUSPEND, &priv->status); |
4055 | return 0; | 4063 | return 0; |
4056 | } | 4064 | } |
4057 | 4065 | ||
4058 | #endif /* CONFIG_PM */ | 4066 | #endif /* CONFIG_PM */ |
4059 | 4067 | ||
4060 | /***************************************************************************** | 4068 | /***************************************************************************** |
4061 | * | 4069 | * |
4062 | * driver and module entry point | 4070 | * driver and module entry point |
4063 | * | 4071 | * |
4064 | *****************************************************************************/ | 4072 | *****************************************************************************/ |
4065 | 4073 | ||
4066 | /* Hardware specific file defines the PCI IDs table for that hardware module */ | 4074 | /* Hardware specific file defines the PCI IDs table for that hardware module */ |
4067 | static struct pci_device_id iwl_hw_card_ids[] = { | 4075 | static struct pci_device_id iwl_hw_card_ids[] = { |
4068 | #ifdef CONFIG_IWL4965 | 4076 | #ifdef CONFIG_IWL4965 |
4069 | {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, | 4077 | {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, |
4070 | {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, | 4078 | {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, |
4071 | #endif /* CONFIG_IWL4965 */ | 4079 | #endif /* CONFIG_IWL4965 */ |
4072 | #ifdef CONFIG_IWL5000 | 4080 | #ifdef CONFIG_IWL5000 |
4073 | {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, | 4081 | {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, |
4074 | {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, | 4082 | {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, |
4075 | {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, | 4083 | {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, |
4076 | {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, | 4084 | {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, |
4077 | {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, | 4085 | {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, |
4078 | {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, | 4086 | {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, |
4079 | {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, | 4087 | {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, |
4080 | {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, | 4088 | {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, |
4081 | {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, | 4089 | {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, |
4082 | {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, | 4090 | {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, |
4083 | /* 5350 WiFi/WiMax */ | 4091 | /* 5350 WiFi/WiMax */ |
4084 | {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, | 4092 | {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, |
4085 | {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, | 4093 | {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, |
4086 | {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, | 4094 | {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, |
4087 | /* 5150 Wifi/WiMax */ | 4095 | /* 5150 Wifi/WiMax */ |
4088 | {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, | 4096 | {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, |
4089 | {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, | 4097 | {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, |
4090 | #endif /* CONFIG_IWL5000 */ | 4098 | #endif /* CONFIG_IWL5000 */ |
4091 | 4099 | ||
4092 | {0} | 4100 | {0} |
4093 | }; | 4101 | }; |
4094 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | 4102 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); |
4095 | 4103 | ||
4096 | static struct pci_driver iwl_driver = { | 4104 | static struct pci_driver iwl_driver = { |
4097 | .name = DRV_NAME, | 4105 | .name = DRV_NAME, |
4098 | .id_table = iwl_hw_card_ids, | 4106 | .id_table = iwl_hw_card_ids, |
4099 | .probe = iwl_pci_probe, | 4107 | .probe = iwl_pci_probe, |
4100 | .remove = __devexit_p(iwl_pci_remove), | 4108 | .remove = __devexit_p(iwl_pci_remove), |
4101 | #ifdef CONFIG_PM | 4109 | #ifdef CONFIG_PM |
4102 | .suspend = iwl_pci_suspend, | 4110 | .suspend = iwl_pci_suspend, |
4103 | .resume = iwl_pci_resume, | 4111 | .resume = iwl_pci_resume, |
4104 | #endif | 4112 | #endif |
4105 | }; | 4113 | }; |
4106 | 4114 | ||
4107 | static int __init iwl_init(void) | 4115 | static int __init iwl_init(void) |
4108 | { | 4116 | { |
4109 | 4117 | ||
4110 | int ret; | 4118 | int ret; |
4111 | printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); | 4119 | printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); |
4112 | printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); | 4120 | printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); |
4113 | 4121 | ||
4114 | ret = iwlagn_rate_control_register(); | 4122 | ret = iwlagn_rate_control_register(); |
4115 | if (ret) { | 4123 | if (ret) { |
4116 | IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); | 4124 | IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); |
4117 | return ret; | 4125 | return ret; |
4118 | } | 4126 | } |
4119 | 4127 | ||
4120 | ret = pci_register_driver(&iwl_driver); | 4128 | ret = pci_register_driver(&iwl_driver); |
4121 | if (ret) { | 4129 | if (ret) { |
4122 | IWL_ERROR("Unable to initialize PCI module\n"); | 4130 | IWL_ERROR("Unable to initialize PCI module\n"); |
4123 | goto error_register; | 4131 | goto error_register; |
4124 | } | 4132 | } |
4125 | 4133 | ||
4126 | return ret; | 4134 | return ret; |
4127 | 4135 | ||
4128 | error_register: | 4136 | error_register: |
4129 | iwlagn_rate_control_unregister(); | 4137 | iwlagn_rate_control_unregister(); |
4130 | return ret; | 4138 | return ret; |
4131 | } | 4139 | } |
4132 | 4140 | ||
4133 | static void __exit iwl_exit(void) | 4141 | static void __exit iwl_exit(void) |
4134 | { | 4142 | { |
4135 | pci_unregister_driver(&iwl_driver); | 4143 | pci_unregister_driver(&iwl_driver); |
4136 | iwlagn_rate_control_unregister(); | 4144 | iwlagn_rate_control_unregister(); |
4137 | } | 4145 | } |
4138 | 4146 | ||
4139 | module_exit(iwl_exit); | 4147 | module_exit(iwl_exit); |
drivers/net/wireless/mac80211_hwsim.c
1 | /* | 1 | /* |
2 | * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 | 2 | * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 |
3 | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> | 3 | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* | 10 | /* |
11 | * TODO: | 11 | * TODO: |
12 | * - IBSS mode simulation (Beacon transmission with competition for "air time") | 12 | * - IBSS mode simulation (Beacon transmission with competition for "air time") |
13 | * - IEEE 802.11a and 802.11n modes | 13 | * - IEEE 802.11a and 802.11n modes |
14 | * - RX filtering based on filter configuration (data->rx_filter) | 14 | * - RX filtering based on filter configuration (data->rx_filter) |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | #include <net/mac80211.h> | 19 | #include <net/mac80211.h> |
20 | #include <net/ieee80211_radiotap.h> | 20 | #include <net/ieee80211_radiotap.h> |
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/etherdevice.h> | 23 | #include <linux/etherdevice.h> |
24 | #include <linux/debugfs.h> | 24 | #include <linux/debugfs.h> |
25 | 25 | ||
26 | MODULE_AUTHOR("Jouni Malinen"); | 26 | MODULE_AUTHOR("Jouni Malinen"); |
27 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); | 27 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); |
28 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
29 | 29 | ||
30 | static int radios = 2; | 30 | static int radios = 2; |
31 | module_param(radios, int, 0444); | 31 | module_param(radios, int, 0444); |
32 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 32 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
33 | 33 | ||
34 | struct hwsim_vif_priv { | 34 | struct hwsim_vif_priv { |
35 | u32 magic; | 35 | u32 magic; |
36 | u8 bssid[ETH_ALEN]; | 36 | u8 bssid[ETH_ALEN]; |
37 | bool assoc; | 37 | bool assoc; |
38 | u16 aid; | 38 | u16 aid; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | #define HWSIM_VIF_MAGIC 0x69537748 | 41 | #define HWSIM_VIF_MAGIC 0x69537748 |
42 | 42 | ||
43 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) | 43 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) |
44 | { | 44 | { |
45 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 45 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
46 | WARN_ON(vp->magic != HWSIM_VIF_MAGIC); | 46 | WARN_ON(vp->magic != HWSIM_VIF_MAGIC); |
47 | } | 47 | } |
48 | 48 | ||
49 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) | 49 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) |
50 | { | 50 | { |
51 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 51 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
52 | vp->magic = HWSIM_VIF_MAGIC; | 52 | vp->magic = HWSIM_VIF_MAGIC; |
53 | } | 53 | } |
54 | 54 | ||
55 | static inline void hwsim_clear_magic(struct ieee80211_vif *vif) | 55 | static inline void hwsim_clear_magic(struct ieee80211_vif *vif) |
56 | { | 56 | { |
57 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 57 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
58 | vp->magic = 0; | 58 | vp->magic = 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | struct hwsim_sta_priv { | 61 | struct hwsim_sta_priv { |
62 | u32 magic; | 62 | u32 magic; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | #define HWSIM_STA_MAGIC 0x6d537748 | 65 | #define HWSIM_STA_MAGIC 0x6d537748 |
66 | 66 | ||
67 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) | 67 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) |
68 | { | 68 | { |
69 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; | 69 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; |
70 | WARN_ON(sp->magic != HWSIM_STA_MAGIC); | 70 | WARN_ON(sp->magic != HWSIM_STA_MAGIC); |
71 | } | 71 | } |
72 | 72 | ||
73 | static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) | 73 | static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) |
74 | { | 74 | { |
75 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; | 75 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; |
76 | sp->magic = HWSIM_STA_MAGIC; | 76 | sp->magic = HWSIM_STA_MAGIC; |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) | 79 | static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) |
80 | { | 80 | { |
81 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; | 81 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; |
82 | sp->magic = 0; | 82 | sp->magic = 0; |
83 | } | 83 | } |
84 | 84 | ||
85 | static struct class *hwsim_class; | 85 | static struct class *hwsim_class; |
86 | 86 | ||
87 | static struct net_device *hwsim_mon; /* global monitor netdev */ | 87 | static struct net_device *hwsim_mon; /* global monitor netdev */ |
88 | 88 | ||
89 | 89 | ||
90 | static const struct ieee80211_channel hwsim_channels[] = { | 90 | static const struct ieee80211_channel hwsim_channels[] = { |
91 | { .center_freq = 2412 }, | 91 | { .center_freq = 2412 }, |
92 | { .center_freq = 2417 }, | 92 | { .center_freq = 2417 }, |
93 | { .center_freq = 2422 }, | 93 | { .center_freq = 2422 }, |
94 | { .center_freq = 2427 }, | 94 | { .center_freq = 2427 }, |
95 | { .center_freq = 2432 }, | 95 | { .center_freq = 2432 }, |
96 | { .center_freq = 2437 }, | 96 | { .center_freq = 2437 }, |
97 | { .center_freq = 2442 }, | 97 | { .center_freq = 2442 }, |
98 | { .center_freq = 2447 }, | 98 | { .center_freq = 2447 }, |
99 | { .center_freq = 2452 }, | 99 | { .center_freq = 2452 }, |
100 | { .center_freq = 2457 }, | 100 | { .center_freq = 2457 }, |
101 | { .center_freq = 2462 }, | 101 | { .center_freq = 2462 }, |
102 | { .center_freq = 2467 }, | 102 | { .center_freq = 2467 }, |
103 | { .center_freq = 2472 }, | 103 | { .center_freq = 2472 }, |
104 | { .center_freq = 2484 }, | 104 | { .center_freq = 2484 }, |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static const struct ieee80211_rate hwsim_rates[] = { | 107 | static const struct ieee80211_rate hwsim_rates[] = { |
108 | { .bitrate = 10 }, | 108 | { .bitrate = 10 }, |
109 | { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 109 | { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
110 | { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 110 | { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
111 | { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 111 | { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
112 | { .bitrate = 60 }, | 112 | { .bitrate = 60 }, |
113 | { .bitrate = 90 }, | 113 | { .bitrate = 90 }, |
114 | { .bitrate = 120 }, | 114 | { .bitrate = 120 }, |
115 | { .bitrate = 180 }, | 115 | { .bitrate = 180 }, |
116 | { .bitrate = 240 }, | 116 | { .bitrate = 240 }, |
117 | { .bitrate = 360 }, | 117 | { .bitrate = 360 }, |
118 | { .bitrate = 480 }, | 118 | { .bitrate = 480 }, |
119 | { .bitrate = 540 } | 119 | { .bitrate = 540 } |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static spinlock_t hwsim_radio_lock; | 122 | static spinlock_t hwsim_radio_lock; |
123 | static struct list_head hwsim_radios; | 123 | static struct list_head hwsim_radios; |
124 | 124 | ||
125 | struct mac80211_hwsim_data { | 125 | struct mac80211_hwsim_data { |
126 | struct list_head list; | 126 | struct list_head list; |
127 | struct ieee80211_hw *hw; | 127 | struct ieee80211_hw *hw; |
128 | struct device *dev; | 128 | struct device *dev; |
129 | struct ieee80211_supported_band band; | 129 | struct ieee80211_supported_band band; |
130 | struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; | 130 | struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; |
131 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; | 131 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; |
132 | 132 | ||
133 | struct ieee80211_channel *channel; | 133 | struct ieee80211_channel *channel; |
134 | int radio_enabled; | 134 | int radio_enabled; |
135 | unsigned long beacon_int; /* in jiffies unit */ | 135 | unsigned long beacon_int; /* in jiffies unit */ |
136 | unsigned int rx_filter; | 136 | unsigned int rx_filter; |
137 | int started; | 137 | int started; |
138 | struct timer_list beacon_timer; | 138 | struct timer_list beacon_timer; |
139 | enum ps_mode { | 139 | enum ps_mode { |
140 | PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL | 140 | PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL |
141 | } ps; | 141 | } ps; |
142 | bool ps_poll_pending; | 142 | bool ps_poll_pending; |
143 | struct dentry *debugfs; | 143 | struct dentry *debugfs; |
144 | struct dentry *debugfs_ps; | 144 | struct dentry *debugfs_ps; |
145 | }; | 145 | }; |
146 | 146 | ||
147 | 147 | ||
148 | struct hwsim_radiotap_hdr { | 148 | struct hwsim_radiotap_hdr { |
149 | struct ieee80211_radiotap_header hdr; | 149 | struct ieee80211_radiotap_header hdr; |
150 | u8 rt_flags; | 150 | u8 rt_flags; |
151 | u8 rt_rate; | 151 | u8 rt_rate; |
152 | __le16 rt_channel; | 152 | __le16 rt_channel; |
153 | __le16 rt_chbitmask; | 153 | __le16 rt_chbitmask; |
154 | } __attribute__ ((packed)); | 154 | } __attribute__ ((packed)); |
155 | 155 | ||
156 | 156 | ||
157 | static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) | 157 | static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) |
158 | { | 158 | { |
159 | /* TODO: allow packet injection */ | 159 | /* TODO: allow packet injection */ |
160 | dev_kfree_skb(skb); | 160 | dev_kfree_skb(skb); |
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
164 | 164 | ||
165 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | 165 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, |
166 | struct sk_buff *tx_skb) | 166 | struct sk_buff *tx_skb) |
167 | { | 167 | { |
168 | struct mac80211_hwsim_data *data = hw->priv; | 168 | struct mac80211_hwsim_data *data = hw->priv; |
169 | struct sk_buff *skb; | 169 | struct sk_buff *skb; |
170 | struct hwsim_radiotap_hdr *hdr; | 170 | struct hwsim_radiotap_hdr *hdr; |
171 | u16 flags; | 171 | u16 flags; |
172 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); | 172 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); |
173 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); | 173 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); |
174 | 174 | ||
175 | if (!netif_running(hwsim_mon)) | 175 | if (!netif_running(hwsim_mon)) |
176 | return; | 176 | return; |
177 | 177 | ||
178 | skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); | 178 | skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); |
179 | if (skb == NULL) | 179 | if (skb == NULL) |
180 | return; | 180 | return; |
181 | 181 | ||
182 | hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); | 182 | hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); |
183 | hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; | 183 | hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; |
184 | hdr->hdr.it_pad = 0; | 184 | hdr->hdr.it_pad = 0; |
185 | hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); | 185 | hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); |
186 | hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | 186 | hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | |
187 | (1 << IEEE80211_RADIOTAP_RATE) | | 187 | (1 << IEEE80211_RADIOTAP_RATE) | |
188 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | 188 | (1 << IEEE80211_RADIOTAP_CHANNEL)); |
189 | hdr->rt_flags = 0; | 189 | hdr->rt_flags = 0; |
190 | hdr->rt_rate = txrate->bitrate / 5; | 190 | hdr->rt_rate = txrate->bitrate / 5; |
191 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | 191 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); |
192 | flags = IEEE80211_CHAN_2GHZ; | 192 | flags = IEEE80211_CHAN_2GHZ; |
193 | if (txrate->flags & IEEE80211_RATE_ERP_G) | 193 | if (txrate->flags & IEEE80211_RATE_ERP_G) |
194 | flags |= IEEE80211_CHAN_OFDM; | 194 | flags |= IEEE80211_CHAN_OFDM; |
195 | else | 195 | else |
196 | flags |= IEEE80211_CHAN_CCK; | 196 | flags |= IEEE80211_CHAN_CCK; |
197 | hdr->rt_chbitmask = cpu_to_le16(flags); | 197 | hdr->rt_chbitmask = cpu_to_le16(flags); |
198 | 198 | ||
199 | skb->dev = hwsim_mon; | 199 | skb->dev = hwsim_mon; |
200 | skb_set_mac_header(skb, 0); | 200 | skb_set_mac_header(skb, 0); |
201 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 201 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
202 | skb->pkt_type = PACKET_OTHERHOST; | 202 | skb->pkt_type = PACKET_OTHERHOST; |
203 | skb->protocol = htons(ETH_P_802_2); | 203 | skb->protocol = htons(ETH_P_802_2); |
204 | memset(skb->cb, 0, sizeof(skb->cb)); | 204 | memset(skb->cb, 0, sizeof(skb->cb)); |
205 | netif_rx(skb); | 205 | netif_rx(skb); |
206 | } | 206 | } |
207 | 207 | ||
208 | 208 | ||
209 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | 209 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, |
210 | struct sk_buff *skb) | 210 | struct sk_buff *skb) |
211 | { | 211 | { |
212 | switch (data->ps) { | 212 | switch (data->ps) { |
213 | case PS_DISABLED: | 213 | case PS_DISABLED: |
214 | return true; | 214 | return true; |
215 | case PS_ENABLED: | 215 | case PS_ENABLED: |
216 | return false; | 216 | return false; |
217 | case PS_AUTO_POLL: | 217 | case PS_AUTO_POLL: |
218 | /* TODO: accept (some) Beacons by default and other frames only | 218 | /* TODO: accept (some) Beacons by default and other frames only |
219 | * if pending PS-Poll has been sent */ | 219 | * if pending PS-Poll has been sent */ |
220 | return true; | 220 | return true; |
221 | case PS_MANUAL_POLL: | 221 | case PS_MANUAL_POLL: |
222 | /* Allow unicast frames to own address if there is a pending | 222 | /* Allow unicast frames to own address if there is a pending |
223 | * PS-Poll */ | 223 | * PS-Poll */ |
224 | if (data->ps_poll_pending && | 224 | if (data->ps_poll_pending && |
225 | memcmp(data->hw->wiphy->perm_addr, skb->data + 4, | 225 | memcmp(data->hw->wiphy->perm_addr, skb->data + 4, |
226 | ETH_ALEN) == 0) { | 226 | ETH_ALEN) == 0) { |
227 | data->ps_poll_pending = false; | 227 | data->ps_poll_pending = false; |
228 | return true; | 228 | return true; |
229 | } | 229 | } |
230 | return false; | 230 | return false; |
231 | } | 231 | } |
232 | 232 | ||
233 | return true; | 233 | return true; |
234 | } | 234 | } |
235 | 235 | ||
236 | 236 | ||
237 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 237 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, |
238 | struct sk_buff *skb) | 238 | struct sk_buff *skb) |
239 | { | 239 | { |
240 | struct mac80211_hwsim_data *data = hw->priv, *data2; | 240 | struct mac80211_hwsim_data *data = hw->priv, *data2; |
241 | bool ack = false; | 241 | bool ack = false; |
242 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 242 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
243 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 243 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
244 | struct ieee80211_rx_status rx_status; | 244 | struct ieee80211_rx_status rx_status; |
245 | 245 | ||
246 | memset(&rx_status, 0, sizeof(rx_status)); | 246 | memset(&rx_status, 0, sizeof(rx_status)); |
247 | /* TODO: set mactime */ | 247 | /* TODO: set mactime */ |
248 | rx_status.freq = data->channel->center_freq; | 248 | rx_status.freq = data->channel->center_freq; |
249 | rx_status.band = data->channel->band; | 249 | rx_status.band = data->channel->band; |
250 | rx_status.rate_idx = info->control.rates[0].idx; | 250 | rx_status.rate_idx = info->control.rates[0].idx; |
251 | /* TODO: simulate signal strength (and optional packet drop) */ | 251 | /* TODO: simulate signal strength (and optional packet drop) */ |
252 | 252 | ||
253 | if (data->ps != PS_DISABLED) | 253 | if (data->ps != PS_DISABLED) |
254 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 254 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
255 | 255 | ||
256 | /* Copy skb to all enabled radios that are on the current frequency */ | 256 | /* Copy skb to all enabled radios that are on the current frequency */ |
257 | spin_lock(&hwsim_radio_lock); | 257 | spin_lock(&hwsim_radio_lock); |
258 | list_for_each_entry(data2, &hwsim_radios, list) { | 258 | list_for_each_entry(data2, &hwsim_radios, list) { |
259 | struct sk_buff *nskb; | 259 | struct sk_buff *nskb; |
260 | 260 | ||
261 | if (data == data2) | 261 | if (data == data2) |
262 | continue; | 262 | continue; |
263 | 263 | ||
264 | if (!data2->started || !data2->radio_enabled || | 264 | if (!data2->started || !data2->radio_enabled || |
265 | !hwsim_ps_rx_ok(data2, skb) || | 265 | !hwsim_ps_rx_ok(data2, skb) || |
266 | data->channel->center_freq != data2->channel->center_freq) | 266 | data->channel->center_freq != data2->channel->center_freq) |
267 | continue; | 267 | continue; |
268 | 268 | ||
269 | nskb = skb_copy(skb, GFP_ATOMIC); | 269 | nskb = skb_copy(skb, GFP_ATOMIC); |
270 | if (nskb == NULL) | 270 | if (nskb == NULL) |
271 | continue; | 271 | continue; |
272 | 272 | ||
273 | if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, | 273 | if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, |
274 | ETH_ALEN) == 0) | 274 | ETH_ALEN) == 0) |
275 | ack = true; | 275 | ack = true; |
276 | ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); | 276 | ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); |
277 | } | 277 | } |
278 | spin_unlock(&hwsim_radio_lock); | 278 | spin_unlock(&hwsim_radio_lock); |
279 | 279 | ||
280 | return ack; | 280 | return ack; |
281 | } | 281 | } |
282 | 282 | ||
283 | 283 | ||
284 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 284 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
285 | { | 285 | { |
286 | struct mac80211_hwsim_data *data = hw->priv; | 286 | struct mac80211_hwsim_data *data = hw->priv; |
287 | bool ack; | 287 | bool ack; |
288 | struct ieee80211_tx_info *txi; | 288 | struct ieee80211_tx_info *txi; |
289 | 289 | ||
290 | mac80211_hwsim_monitor_rx(hw, skb); | 290 | mac80211_hwsim_monitor_rx(hw, skb); |
291 | 291 | ||
292 | if (skb->len < 10) { | 292 | if (skb->len < 10) { |
293 | /* Should not happen; just a sanity check for addr1 use */ | 293 | /* Should not happen; just a sanity check for addr1 use */ |
294 | dev_kfree_skb(skb); | 294 | dev_kfree_skb(skb); |
295 | return NETDEV_TX_OK; | 295 | return NETDEV_TX_OK; |
296 | } | 296 | } |
297 | 297 | ||
298 | if (!data->radio_enabled) { | 298 | if (!data->radio_enabled) { |
299 | printk(KERN_DEBUG "%s: dropped TX frame since radio " | 299 | printk(KERN_DEBUG "%s: dropped TX frame since radio " |
300 | "disabled\n", wiphy_name(hw->wiphy)); | 300 | "disabled\n", wiphy_name(hw->wiphy)); |
301 | dev_kfree_skb(skb); | 301 | dev_kfree_skb(skb); |
302 | return NETDEV_TX_OK; | 302 | return NETDEV_TX_OK; |
303 | } | 303 | } |
304 | 304 | ||
305 | ack = mac80211_hwsim_tx_frame(hw, skb); | 305 | ack = mac80211_hwsim_tx_frame(hw, skb); |
306 | 306 | ||
307 | txi = IEEE80211_SKB_CB(skb); | 307 | txi = IEEE80211_SKB_CB(skb); |
308 | 308 | ||
309 | if (txi->control.vif) | 309 | if (txi->control.vif) |
310 | hwsim_check_magic(txi->control.vif); | 310 | hwsim_check_magic(txi->control.vif); |
311 | if (txi->control.sta) | 311 | if (txi->control.sta) |
312 | hwsim_check_sta_magic(txi->control.sta); | 312 | hwsim_check_sta_magic(txi->control.sta); |
313 | 313 | ||
314 | ieee80211_tx_info_clear_status(txi); | 314 | ieee80211_tx_info_clear_status(txi); |
315 | if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) | 315 | if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) |
316 | txi->flags |= IEEE80211_TX_STAT_ACK; | 316 | txi->flags |= IEEE80211_TX_STAT_ACK; |
317 | ieee80211_tx_status_irqsafe(hw, skb); | 317 | ieee80211_tx_status_irqsafe(hw, skb); |
318 | return NETDEV_TX_OK; | 318 | return NETDEV_TX_OK; |
319 | } | 319 | } |
320 | 320 | ||
321 | 321 | ||
322 | static int mac80211_hwsim_start(struct ieee80211_hw *hw) | 322 | static int mac80211_hwsim_start(struct ieee80211_hw *hw) |
323 | { | 323 | { |
324 | struct mac80211_hwsim_data *data = hw->priv; | 324 | struct mac80211_hwsim_data *data = hw->priv; |
325 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); | 325 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); |
326 | data->started = 1; | 326 | data->started = 1; |
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | 330 | ||
331 | static void mac80211_hwsim_stop(struct ieee80211_hw *hw) | 331 | static void mac80211_hwsim_stop(struct ieee80211_hw *hw) |
332 | { | 332 | { |
333 | struct mac80211_hwsim_data *data = hw->priv; | 333 | struct mac80211_hwsim_data *data = hw->priv; |
334 | data->started = 0; | 334 | data->started = 0; |
335 | del_timer(&data->beacon_timer); | 335 | del_timer(&data->beacon_timer); |
336 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); | 336 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); |
337 | } | 337 | } |
338 | 338 | ||
339 | 339 | ||
340 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | 340 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, |
341 | struct ieee80211_if_init_conf *conf) | 341 | struct ieee80211_if_init_conf *conf) |
342 | { | 342 | { |
343 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | 343 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
344 | wiphy_name(hw->wiphy), __func__, conf->type, | 344 | wiphy_name(hw->wiphy), __func__, conf->type, |
345 | conf->mac_addr); | 345 | conf->mac_addr); |
346 | hwsim_set_magic(conf->vif); | 346 | hwsim_set_magic(conf->vif); |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | 350 | ||
351 | static void mac80211_hwsim_remove_interface( | 351 | static void mac80211_hwsim_remove_interface( |
352 | struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) | 352 | struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) |
353 | { | 353 | { |
354 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | 354 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
355 | wiphy_name(hw->wiphy), __func__, conf->type, | 355 | wiphy_name(hw->wiphy), __func__, conf->type, |
356 | conf->mac_addr); | 356 | conf->mac_addr); |
357 | hwsim_check_magic(conf->vif); | 357 | hwsim_check_magic(conf->vif); |
358 | hwsim_clear_magic(conf->vif); | 358 | hwsim_clear_magic(conf->vif); |
359 | } | 359 | } |
360 | 360 | ||
361 | 361 | ||
362 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | 362 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, |
363 | struct ieee80211_vif *vif) | 363 | struct ieee80211_vif *vif) |
364 | { | 364 | { |
365 | struct ieee80211_hw *hw = arg; | 365 | struct ieee80211_hw *hw = arg; |
366 | struct sk_buff *skb; | 366 | struct sk_buff *skb; |
367 | struct ieee80211_tx_info *info; | 367 | struct ieee80211_tx_info *info; |
368 | 368 | ||
369 | hwsim_check_magic(vif); | 369 | hwsim_check_magic(vif); |
370 | 370 | ||
371 | if (vif->type != NL80211_IFTYPE_AP && | 371 | if (vif->type != NL80211_IFTYPE_AP && |
372 | vif->type != NL80211_IFTYPE_MESH_POINT) | 372 | vif->type != NL80211_IFTYPE_MESH_POINT) |
373 | return; | 373 | return; |
374 | 374 | ||
375 | skb = ieee80211_beacon_get(hw, vif); | 375 | skb = ieee80211_beacon_get(hw, vif); |
376 | if (skb == NULL) | 376 | if (skb == NULL) |
377 | return; | 377 | return; |
378 | info = IEEE80211_SKB_CB(skb); | 378 | info = IEEE80211_SKB_CB(skb); |
379 | 379 | ||
380 | mac80211_hwsim_monitor_rx(hw, skb); | 380 | mac80211_hwsim_monitor_rx(hw, skb); |
381 | mac80211_hwsim_tx_frame(hw, skb); | 381 | mac80211_hwsim_tx_frame(hw, skb); |
382 | dev_kfree_skb(skb); | 382 | dev_kfree_skb(skb); |
383 | } | 383 | } |
384 | 384 | ||
385 | 385 | ||
386 | static void mac80211_hwsim_beacon(unsigned long arg) | 386 | static void mac80211_hwsim_beacon(unsigned long arg) |
387 | { | 387 | { |
388 | struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; | 388 | struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; |
389 | struct mac80211_hwsim_data *data = hw->priv; | 389 | struct mac80211_hwsim_data *data = hw->priv; |
390 | 390 | ||
391 | if (!data->started || !data->radio_enabled) | 391 | if (!data->started || !data->radio_enabled) |
392 | return; | 392 | return; |
393 | 393 | ||
394 | ieee80211_iterate_active_interfaces_atomic( | 394 | ieee80211_iterate_active_interfaces_atomic( |
395 | hw, mac80211_hwsim_beacon_tx, hw); | 395 | hw, mac80211_hwsim_beacon_tx, hw); |
396 | 396 | ||
397 | data->beacon_timer.expires = jiffies + data->beacon_int; | 397 | data->beacon_timer.expires = jiffies + data->beacon_int; |
398 | add_timer(&data->beacon_timer); | 398 | add_timer(&data->beacon_timer); |
399 | } | 399 | } |
400 | 400 | ||
401 | 401 | ||
402 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | 402 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) |
403 | { | 403 | { |
404 | struct mac80211_hwsim_data *data = hw->priv; | 404 | struct mac80211_hwsim_data *data = hw->priv; |
405 | struct ieee80211_conf *conf = &hw->conf; | 405 | struct ieee80211_conf *conf = &hw->conf; |
406 | 406 | ||
407 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", | 407 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", |
408 | wiphy_name(hw->wiphy), __func__, | 408 | wiphy_name(hw->wiphy), __func__, |
409 | conf->channel->center_freq, conf->radio_enabled, | 409 | conf->channel->center_freq, conf->radio_enabled, |
410 | conf->beacon_int); | 410 | conf->beacon_int); |
411 | 411 | ||
412 | data->channel = conf->channel; | 412 | data->channel = conf->channel; |
413 | data->radio_enabled = conf->radio_enabled; | 413 | data->radio_enabled = conf->radio_enabled; |
414 | data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000; | 414 | data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000; |
415 | if (data->beacon_int < 1) | 415 | if (data->beacon_int < 1) |
416 | data->beacon_int = 1; | 416 | data->beacon_int = 1; |
417 | 417 | ||
418 | if (!data->started || !data->radio_enabled) | 418 | if (!data->started || !data->radio_enabled) |
419 | del_timer(&data->beacon_timer); | 419 | del_timer(&data->beacon_timer); |
420 | else | 420 | else |
421 | mod_timer(&data->beacon_timer, jiffies + data->beacon_int); | 421 | mod_timer(&data->beacon_timer, jiffies + data->beacon_int); |
422 | 422 | ||
423 | return 0; | 423 | return 0; |
424 | } | 424 | } |
425 | 425 | ||
426 | 426 | ||
427 | static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, | 427 | static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, |
428 | unsigned int changed_flags, | 428 | unsigned int changed_flags, |
429 | unsigned int *total_flags, | 429 | unsigned int *total_flags, |
430 | int mc_count, | 430 | int mc_count, |
431 | struct dev_addr_list *mc_list) | 431 | struct dev_addr_list *mc_list) |
432 | { | 432 | { |
433 | struct mac80211_hwsim_data *data = hw->priv; | 433 | struct mac80211_hwsim_data *data = hw->priv; |
434 | 434 | ||
435 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); | 435 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); |
436 | 436 | ||
437 | data->rx_filter = 0; | 437 | data->rx_filter = 0; |
438 | if (*total_flags & FIF_PROMISC_IN_BSS) | 438 | if (*total_flags & FIF_PROMISC_IN_BSS) |
439 | data->rx_filter |= FIF_PROMISC_IN_BSS; | 439 | data->rx_filter |= FIF_PROMISC_IN_BSS; |
440 | if (*total_flags & FIF_ALLMULTI) | 440 | if (*total_flags & FIF_ALLMULTI) |
441 | data->rx_filter |= FIF_ALLMULTI; | 441 | data->rx_filter |= FIF_ALLMULTI; |
442 | 442 | ||
443 | *total_flags = data->rx_filter; | 443 | *total_flags = data->rx_filter; |
444 | } | 444 | } |
445 | 445 | ||
446 | static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, | 446 | static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, |
447 | struct ieee80211_vif *vif, | 447 | struct ieee80211_vif *vif, |
448 | struct ieee80211_if_conf *conf) | 448 | struct ieee80211_if_conf *conf) |
449 | { | 449 | { |
450 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 450 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
451 | 451 | ||
452 | hwsim_check_magic(vif); | 452 | hwsim_check_magic(vif); |
453 | if (conf->changed & IEEE80211_IFCC_BSSID) { | 453 | if (conf->changed & IEEE80211_IFCC_BSSID) { |
454 | DECLARE_MAC_BUF(mac); | 454 | DECLARE_MAC_BUF(mac); |
455 | printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", | 455 | printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", |
456 | wiphy_name(hw->wiphy), __func__, | 456 | wiphy_name(hw->wiphy), __func__, |
457 | conf->bssid); | 457 | conf->bssid); |
458 | memcpy(vp->bssid, conf->bssid, ETH_ALEN); | 458 | memcpy(vp->bssid, conf->bssid, ETH_ALEN); |
459 | } | 459 | } |
460 | return 0; | 460 | return 0; |
461 | } | 461 | } |
462 | 462 | ||
463 | static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | 463 | static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, |
464 | struct ieee80211_vif *vif, | 464 | struct ieee80211_vif *vif, |
465 | struct ieee80211_bss_conf *info, | 465 | struct ieee80211_bss_conf *info, |
466 | u32 changed) | 466 | u32 changed) |
467 | { | 467 | { |
468 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 468 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
469 | 469 | ||
470 | hwsim_check_magic(vif); | 470 | hwsim_check_magic(vif); |
471 | 471 | ||
472 | printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", | 472 | printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", |
473 | wiphy_name(hw->wiphy), __func__, changed); | 473 | wiphy_name(hw->wiphy), __func__, changed); |
474 | 474 | ||
475 | if (changed & BSS_CHANGED_ASSOC) { | 475 | if (changed & BSS_CHANGED_ASSOC) { |
476 | printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", | 476 | printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", |
477 | wiphy_name(hw->wiphy), info->assoc, info->aid); | 477 | wiphy_name(hw->wiphy), info->assoc, info->aid); |
478 | vp->assoc = info->assoc; | 478 | vp->assoc = info->assoc; |
479 | vp->aid = info->aid; | 479 | vp->aid = info->aid; |
480 | } | 480 | } |
481 | 481 | ||
482 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | 482 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
483 | printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", | 483 | printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", |
484 | wiphy_name(hw->wiphy), info->use_cts_prot); | 484 | wiphy_name(hw->wiphy), info->use_cts_prot); |
485 | } | 485 | } |
486 | 486 | ||
487 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 487 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
488 | printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", | 488 | printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", |
489 | wiphy_name(hw->wiphy), info->use_short_preamble); | 489 | wiphy_name(hw->wiphy), info->use_short_preamble); |
490 | } | 490 | } |
491 | 491 | ||
492 | if (changed & BSS_CHANGED_ERP_SLOT) { | 492 | if (changed & BSS_CHANGED_ERP_SLOT) { |
493 | printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", | 493 | printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", |
494 | wiphy_name(hw->wiphy), info->use_short_slot); | 494 | wiphy_name(hw->wiphy), info->use_short_slot); |
495 | } | 495 | } |
496 | 496 | ||
497 | if (changed & BSS_CHANGED_HT) { | 497 | if (changed & BSS_CHANGED_HT) { |
498 | printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d " | 498 | printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", |
499 | "op_mode=%d\n", | ||
500 | wiphy_name(hw->wiphy), | 499 | wiphy_name(hw->wiphy), |
501 | info->ht.secondary_channel_offset, | 500 | info->ht.operation_mode); |
502 | info->ht.width_40_ok, info->ht.operation_mode); | ||
503 | } | 501 | } |
504 | 502 | ||
505 | if (changed & BSS_CHANGED_BASIC_RATES) { | 503 | if (changed & BSS_CHANGED_BASIC_RATES) { |
506 | printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", | 504 | printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", |
507 | wiphy_name(hw->wiphy), | 505 | wiphy_name(hw->wiphy), |
508 | (unsigned long long) info->basic_rates); | 506 | (unsigned long long) info->basic_rates); |
509 | } | 507 | } |
510 | } | 508 | } |
511 | 509 | ||
512 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, | 510 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, |
513 | struct ieee80211_vif *vif, | 511 | struct ieee80211_vif *vif, |
514 | enum sta_notify_cmd cmd, | 512 | enum sta_notify_cmd cmd, |
515 | struct ieee80211_sta *sta) | 513 | struct ieee80211_sta *sta) |
516 | { | 514 | { |
517 | hwsim_check_magic(vif); | 515 | hwsim_check_magic(vif); |
518 | switch (cmd) { | 516 | switch (cmd) { |
519 | case STA_NOTIFY_ADD: | 517 | case STA_NOTIFY_ADD: |
520 | hwsim_set_sta_magic(sta); | 518 | hwsim_set_sta_magic(sta); |
521 | break; | 519 | break; |
522 | case STA_NOTIFY_REMOVE: | 520 | case STA_NOTIFY_REMOVE: |
523 | hwsim_clear_sta_magic(sta); | 521 | hwsim_clear_sta_magic(sta); |
524 | break; | 522 | break; |
525 | case STA_NOTIFY_SLEEP: | 523 | case STA_NOTIFY_SLEEP: |
526 | case STA_NOTIFY_AWAKE: | 524 | case STA_NOTIFY_AWAKE: |
527 | /* TODO: make good use of these flags */ | 525 | /* TODO: make good use of these flags */ |
528 | break; | 526 | break; |
529 | } | 527 | } |
530 | } | 528 | } |
531 | 529 | ||
532 | static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, | 530 | static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, |
533 | struct ieee80211_sta *sta, | 531 | struct ieee80211_sta *sta, |
534 | bool set) | 532 | bool set) |
535 | { | 533 | { |
536 | hwsim_check_sta_magic(sta); | 534 | hwsim_check_sta_magic(sta); |
537 | return 0; | 535 | return 0; |
538 | } | 536 | } |
539 | 537 | ||
540 | static int mac80211_hwsim_conf_tx( | 538 | static int mac80211_hwsim_conf_tx( |
541 | struct ieee80211_hw *hw, u16 queue, | 539 | struct ieee80211_hw *hw, u16 queue, |
542 | const struct ieee80211_tx_queue_params *params) | 540 | const struct ieee80211_tx_queue_params *params) |
543 | { | 541 | { |
544 | printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " | 542 | printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " |
545 | "aifs=%d)\n", | 543 | "aifs=%d)\n", |
546 | wiphy_name(hw->wiphy), __func__, queue, | 544 | wiphy_name(hw->wiphy), __func__, queue, |
547 | params->txop, params->cw_min, params->cw_max, params->aifs); | 545 | params->txop, params->cw_min, params->cw_max, params->aifs); |
548 | return 0; | 546 | return 0; |
549 | } | 547 | } |
550 | 548 | ||
551 | static const struct ieee80211_ops mac80211_hwsim_ops = | 549 | static const struct ieee80211_ops mac80211_hwsim_ops = |
552 | { | 550 | { |
553 | .tx = mac80211_hwsim_tx, | 551 | .tx = mac80211_hwsim_tx, |
554 | .start = mac80211_hwsim_start, | 552 | .start = mac80211_hwsim_start, |
555 | .stop = mac80211_hwsim_stop, | 553 | .stop = mac80211_hwsim_stop, |
556 | .add_interface = mac80211_hwsim_add_interface, | 554 | .add_interface = mac80211_hwsim_add_interface, |
557 | .remove_interface = mac80211_hwsim_remove_interface, | 555 | .remove_interface = mac80211_hwsim_remove_interface, |
558 | .config = mac80211_hwsim_config, | 556 | .config = mac80211_hwsim_config, |
559 | .configure_filter = mac80211_hwsim_configure_filter, | 557 | .configure_filter = mac80211_hwsim_configure_filter, |
560 | .config_interface = mac80211_hwsim_config_interface, | 558 | .config_interface = mac80211_hwsim_config_interface, |
561 | .bss_info_changed = mac80211_hwsim_bss_info_changed, | 559 | .bss_info_changed = mac80211_hwsim_bss_info_changed, |
562 | .sta_notify = mac80211_hwsim_sta_notify, | 560 | .sta_notify = mac80211_hwsim_sta_notify, |
563 | .set_tim = mac80211_hwsim_set_tim, | 561 | .set_tim = mac80211_hwsim_set_tim, |
564 | .conf_tx = mac80211_hwsim_conf_tx, | 562 | .conf_tx = mac80211_hwsim_conf_tx, |
565 | }; | 563 | }; |
566 | 564 | ||
567 | 565 | ||
568 | static void mac80211_hwsim_free(void) | 566 | static void mac80211_hwsim_free(void) |
569 | { | 567 | { |
570 | struct list_head tmplist, *i, *tmp; | 568 | struct list_head tmplist, *i, *tmp; |
571 | struct mac80211_hwsim_data *data; | 569 | struct mac80211_hwsim_data *data; |
572 | 570 | ||
573 | INIT_LIST_HEAD(&tmplist); | 571 | INIT_LIST_HEAD(&tmplist); |
574 | 572 | ||
575 | spin_lock_bh(&hwsim_radio_lock); | 573 | spin_lock_bh(&hwsim_radio_lock); |
576 | list_for_each_safe(i, tmp, &hwsim_radios) | 574 | list_for_each_safe(i, tmp, &hwsim_radios) |
577 | list_move(i, &tmplist); | 575 | list_move(i, &tmplist); |
578 | spin_unlock_bh(&hwsim_radio_lock); | 576 | spin_unlock_bh(&hwsim_radio_lock); |
579 | 577 | ||
580 | list_for_each_entry(data, &tmplist, list) { | 578 | list_for_each_entry(data, &tmplist, list) { |
581 | debugfs_remove(data->debugfs_ps); | 579 | debugfs_remove(data->debugfs_ps); |
582 | debugfs_remove(data->debugfs); | 580 | debugfs_remove(data->debugfs); |
583 | ieee80211_unregister_hw(data->hw); | 581 | ieee80211_unregister_hw(data->hw); |
584 | device_unregister(data->dev); | 582 | device_unregister(data->dev); |
585 | ieee80211_free_hw(data->hw); | 583 | ieee80211_free_hw(data->hw); |
586 | } | 584 | } |
587 | class_destroy(hwsim_class); | 585 | class_destroy(hwsim_class); |
588 | } | 586 | } |
589 | 587 | ||
590 | 588 | ||
591 | static struct device_driver mac80211_hwsim_driver = { | 589 | static struct device_driver mac80211_hwsim_driver = { |
592 | .name = "mac80211_hwsim" | 590 | .name = "mac80211_hwsim" |
593 | }; | 591 | }; |
594 | 592 | ||
595 | 593 | ||
596 | static void hwsim_mon_setup(struct net_device *dev) | 594 | static void hwsim_mon_setup(struct net_device *dev) |
597 | { | 595 | { |
598 | dev->hard_start_xmit = hwsim_mon_xmit; | 596 | dev->hard_start_xmit = hwsim_mon_xmit; |
599 | dev->destructor = free_netdev; | 597 | dev->destructor = free_netdev; |
600 | ether_setup(dev); | 598 | ether_setup(dev); |
601 | dev->tx_queue_len = 0; | 599 | dev->tx_queue_len = 0; |
602 | dev->type = ARPHRD_IEEE80211_RADIOTAP; | 600 | dev->type = ARPHRD_IEEE80211_RADIOTAP; |
603 | memset(dev->dev_addr, 0, ETH_ALEN); | 601 | memset(dev->dev_addr, 0, ETH_ALEN); |
604 | dev->dev_addr[0] = 0x12; | 602 | dev->dev_addr[0] = 0x12; |
605 | } | 603 | } |
606 | 604 | ||
607 | 605 | ||
608 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | 606 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) |
609 | { | 607 | { |
610 | struct mac80211_hwsim_data *data = dat; | 608 | struct mac80211_hwsim_data *data = dat; |
611 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 609 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
612 | DECLARE_MAC_BUF(buf); | 610 | DECLARE_MAC_BUF(buf); |
613 | struct sk_buff *skb; | 611 | struct sk_buff *skb; |
614 | struct ieee80211_pspoll *pspoll; | 612 | struct ieee80211_pspoll *pspoll; |
615 | 613 | ||
616 | if (!vp->assoc) | 614 | if (!vp->assoc) |
617 | return; | 615 | return; |
618 | 616 | ||
619 | printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", | 617 | printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", |
620 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); | 618 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); |
621 | 619 | ||
622 | skb = dev_alloc_skb(sizeof(*pspoll)); | 620 | skb = dev_alloc_skb(sizeof(*pspoll)); |
623 | if (!skb) | 621 | if (!skb) |
624 | return; | 622 | return; |
625 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); | 623 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); |
626 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | 624 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | |
627 | IEEE80211_STYPE_PSPOLL | | 625 | IEEE80211_STYPE_PSPOLL | |
628 | IEEE80211_FCTL_PM); | 626 | IEEE80211_FCTL_PM); |
629 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | 627 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); |
630 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | 628 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); |
631 | memcpy(pspoll->ta, mac, ETH_ALEN); | 629 | memcpy(pspoll->ta, mac, ETH_ALEN); |
632 | if (data->radio_enabled && | 630 | if (data->radio_enabled && |
633 | !mac80211_hwsim_tx_frame(data->hw, skb)) | 631 | !mac80211_hwsim_tx_frame(data->hw, skb)) |
634 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); | 632 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); |
635 | dev_kfree_skb(skb); | 633 | dev_kfree_skb(skb); |
636 | } | 634 | } |
637 | 635 | ||
638 | 636 | ||
639 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | 637 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, |
640 | struct ieee80211_vif *vif, int ps) | 638 | struct ieee80211_vif *vif, int ps) |
641 | { | 639 | { |
642 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 640 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
643 | DECLARE_MAC_BUF(buf); | 641 | DECLARE_MAC_BUF(buf); |
644 | struct sk_buff *skb; | 642 | struct sk_buff *skb; |
645 | struct ieee80211_hdr *hdr; | 643 | struct ieee80211_hdr *hdr; |
646 | 644 | ||
647 | if (!vp->assoc) | 645 | if (!vp->assoc) |
648 | return; | 646 | return; |
649 | 647 | ||
650 | printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", | 648 | printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", |
651 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); | 649 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); |
652 | 650 | ||
653 | skb = dev_alloc_skb(sizeof(*hdr)); | 651 | skb = dev_alloc_skb(sizeof(*hdr)); |
654 | if (!skb) | 652 | if (!skb) |
655 | return; | 653 | return; |
656 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); | 654 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); |
657 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | 655 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | |
658 | IEEE80211_STYPE_NULLFUNC | | 656 | IEEE80211_STYPE_NULLFUNC | |
659 | (ps ? IEEE80211_FCTL_PM : 0)); | 657 | (ps ? IEEE80211_FCTL_PM : 0)); |
660 | hdr->duration_id = cpu_to_le16(0); | 658 | hdr->duration_id = cpu_to_le16(0); |
661 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | 659 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); |
662 | memcpy(hdr->addr2, mac, ETH_ALEN); | 660 | memcpy(hdr->addr2, mac, ETH_ALEN); |
663 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | 661 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); |
664 | if (data->radio_enabled && | 662 | if (data->radio_enabled && |
665 | !mac80211_hwsim_tx_frame(data->hw, skb)) | 663 | !mac80211_hwsim_tx_frame(data->hw, skb)) |
666 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | 664 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); |
667 | dev_kfree_skb(skb); | 665 | dev_kfree_skb(skb); |
668 | } | 666 | } |
669 | 667 | ||
670 | 668 | ||
671 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, | 669 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, |
672 | struct ieee80211_vif *vif) | 670 | struct ieee80211_vif *vif) |
673 | { | 671 | { |
674 | struct mac80211_hwsim_data *data = dat; | 672 | struct mac80211_hwsim_data *data = dat; |
675 | hwsim_send_nullfunc(data, mac, vif, 1); | 673 | hwsim_send_nullfunc(data, mac, vif, 1); |
676 | } | 674 | } |
677 | 675 | ||
678 | 676 | ||
679 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, | 677 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, |
680 | struct ieee80211_vif *vif) | 678 | struct ieee80211_vif *vif) |
681 | { | 679 | { |
682 | struct mac80211_hwsim_data *data = dat; | 680 | struct mac80211_hwsim_data *data = dat; |
683 | hwsim_send_nullfunc(data, mac, vif, 0); | 681 | hwsim_send_nullfunc(data, mac, vif, 0); |
684 | } | 682 | } |
685 | 683 | ||
686 | 684 | ||
687 | static int hwsim_fops_ps_read(void *dat, u64 *val) | 685 | static int hwsim_fops_ps_read(void *dat, u64 *val) |
688 | { | 686 | { |
689 | struct mac80211_hwsim_data *data = dat; | 687 | struct mac80211_hwsim_data *data = dat; |
690 | *val = data->ps; | 688 | *val = data->ps; |
691 | return 0; | 689 | return 0; |
692 | } | 690 | } |
693 | 691 | ||
694 | static int hwsim_fops_ps_write(void *dat, u64 val) | 692 | static int hwsim_fops_ps_write(void *dat, u64 val) |
695 | { | 693 | { |
696 | struct mac80211_hwsim_data *data = dat; | 694 | struct mac80211_hwsim_data *data = dat; |
697 | enum ps_mode old_ps; | 695 | enum ps_mode old_ps; |
698 | 696 | ||
699 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && | 697 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && |
700 | val != PS_MANUAL_POLL) | 698 | val != PS_MANUAL_POLL) |
701 | return -EINVAL; | 699 | return -EINVAL; |
702 | 700 | ||
703 | old_ps = data->ps; | 701 | old_ps = data->ps; |
704 | data->ps = val; | 702 | data->ps = val; |
705 | 703 | ||
706 | if (val == PS_MANUAL_POLL) { | 704 | if (val == PS_MANUAL_POLL) { |
707 | ieee80211_iterate_active_interfaces(data->hw, | 705 | ieee80211_iterate_active_interfaces(data->hw, |
708 | hwsim_send_ps_poll, data); | 706 | hwsim_send_ps_poll, data); |
709 | data->ps_poll_pending = true; | 707 | data->ps_poll_pending = true; |
710 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | 708 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { |
711 | ieee80211_iterate_active_interfaces(data->hw, | 709 | ieee80211_iterate_active_interfaces(data->hw, |
712 | hwsim_send_nullfunc_ps, | 710 | hwsim_send_nullfunc_ps, |
713 | data); | 711 | data); |
714 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | 712 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { |
715 | ieee80211_iterate_active_interfaces(data->hw, | 713 | ieee80211_iterate_active_interfaces(data->hw, |
716 | hwsim_send_nullfunc_no_ps, | 714 | hwsim_send_nullfunc_no_ps, |
717 | data); | 715 | data); |
718 | } | 716 | } |
719 | 717 | ||
720 | return 0; | 718 | return 0; |
721 | } | 719 | } |
722 | 720 | ||
723 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | 721 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, |
724 | "%llu\n"); | 722 | "%llu\n"); |
725 | 723 | ||
726 | 724 | ||
727 | static int __init init_mac80211_hwsim(void) | 725 | static int __init init_mac80211_hwsim(void) |
728 | { | 726 | { |
729 | int i, err = 0; | 727 | int i, err = 0; |
730 | u8 addr[ETH_ALEN]; | 728 | u8 addr[ETH_ALEN]; |
731 | struct mac80211_hwsim_data *data; | 729 | struct mac80211_hwsim_data *data; |
732 | struct ieee80211_hw *hw; | 730 | struct ieee80211_hw *hw; |
733 | 731 | ||
734 | if (radios < 1 || radios > 100) | 732 | if (radios < 1 || radios > 100) |
735 | return -EINVAL; | 733 | return -EINVAL; |
736 | 734 | ||
737 | spin_lock_init(&hwsim_radio_lock); | 735 | spin_lock_init(&hwsim_radio_lock); |
738 | INIT_LIST_HEAD(&hwsim_radios); | 736 | INIT_LIST_HEAD(&hwsim_radios); |
739 | 737 | ||
740 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); | 738 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); |
741 | if (IS_ERR(hwsim_class)) | 739 | if (IS_ERR(hwsim_class)) |
742 | return PTR_ERR(hwsim_class); | 740 | return PTR_ERR(hwsim_class); |
743 | 741 | ||
744 | memset(addr, 0, ETH_ALEN); | 742 | memset(addr, 0, ETH_ALEN); |
745 | addr[0] = 0x02; | 743 | addr[0] = 0x02; |
746 | 744 | ||
747 | for (i = 0; i < radios; i++) { | 745 | for (i = 0; i < radios; i++) { |
748 | printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", | 746 | printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", |
749 | i); | 747 | i); |
750 | hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); | 748 | hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); |
751 | if (!hw) { | 749 | if (!hw) { |
752 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " | 750 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " |
753 | "failed\n"); | 751 | "failed\n"); |
754 | err = -ENOMEM; | 752 | err = -ENOMEM; |
755 | goto failed; | 753 | goto failed; |
756 | } | 754 | } |
757 | data = hw->priv; | 755 | data = hw->priv; |
758 | data->hw = hw; | 756 | data->hw = hw; |
759 | 757 | ||
760 | data->dev = device_create(hwsim_class, NULL, 0, hw, | 758 | data->dev = device_create(hwsim_class, NULL, 0, hw, |
761 | "hwsim%d", i); | 759 | "hwsim%d", i); |
762 | if (IS_ERR(data->dev)) { | 760 | if (IS_ERR(data->dev)) { |
763 | printk(KERN_DEBUG | 761 | printk(KERN_DEBUG |
764 | "mac80211_hwsim: device_create " | 762 | "mac80211_hwsim: device_create " |
765 | "failed (%ld)\n", PTR_ERR(data->dev)); | 763 | "failed (%ld)\n", PTR_ERR(data->dev)); |
766 | err = -ENOMEM; | 764 | err = -ENOMEM; |
767 | goto failed_drvdata; | 765 | goto failed_drvdata; |
768 | } | 766 | } |
769 | data->dev->driver = &mac80211_hwsim_driver; | 767 | data->dev->driver = &mac80211_hwsim_driver; |
770 | 768 | ||
771 | SET_IEEE80211_DEV(hw, data->dev); | 769 | SET_IEEE80211_DEV(hw, data->dev); |
772 | addr[3] = i >> 8; | 770 | addr[3] = i >> 8; |
773 | addr[4] = i; | 771 | addr[4] = i; |
774 | SET_IEEE80211_PERM_ADDR(hw, addr); | 772 | SET_IEEE80211_PERM_ADDR(hw, addr); |
775 | 773 | ||
776 | hw->channel_change_time = 1; | 774 | hw->channel_change_time = 1; |
777 | hw->queues = 4; | 775 | hw->queues = 4; |
778 | hw->wiphy->interface_modes = | 776 | hw->wiphy->interface_modes = |
779 | BIT(NL80211_IFTYPE_STATION) | | 777 | BIT(NL80211_IFTYPE_STATION) | |
780 | BIT(NL80211_IFTYPE_AP) | | 778 | BIT(NL80211_IFTYPE_AP) | |
781 | BIT(NL80211_IFTYPE_MESH_POINT); | 779 | BIT(NL80211_IFTYPE_MESH_POINT); |
782 | hw->ampdu_queues = 1; | 780 | hw->ampdu_queues = 1; |
783 | 781 | ||
784 | /* ask mac80211 to reserve space for magic */ | 782 | /* ask mac80211 to reserve space for magic */ |
785 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 783 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
786 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); | 784 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); |
787 | 785 | ||
788 | memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); | 786 | memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); |
789 | memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); | 787 | memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); |
790 | data->band.channels = data->channels; | 788 | data->band.channels = data->channels; |
791 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); | 789 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); |
792 | data->band.bitrates = data->rates; | 790 | data->band.bitrates = data->rates; |
793 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); | 791 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); |
794 | data->band.ht_cap.ht_supported = true; | 792 | data->band.ht_cap.ht_supported = true; |
795 | data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 793 | data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
796 | IEEE80211_HT_CAP_GRN_FLD | | 794 | IEEE80211_HT_CAP_GRN_FLD | |
797 | IEEE80211_HT_CAP_SGI_40 | | 795 | IEEE80211_HT_CAP_SGI_40 | |
798 | IEEE80211_HT_CAP_DSSSCCK40; | 796 | IEEE80211_HT_CAP_DSSSCCK40; |
799 | data->band.ht_cap.ampdu_factor = 0x3; | 797 | data->band.ht_cap.ampdu_factor = 0x3; |
800 | data->band.ht_cap.ampdu_density = 0x6; | 798 | data->band.ht_cap.ampdu_density = 0x6; |
801 | memset(&data->band.ht_cap.mcs, 0, | 799 | memset(&data->band.ht_cap.mcs, 0, |
802 | sizeof(data->band.ht_cap.mcs)); | 800 | sizeof(data->band.ht_cap.mcs)); |
803 | data->band.ht_cap.mcs.rx_mask[0] = 0xff; | 801 | data->band.ht_cap.mcs.rx_mask[0] = 0xff; |
804 | data->band.ht_cap.mcs.rx_mask[1] = 0xff; | 802 | data->band.ht_cap.mcs.rx_mask[1] = 0xff; |
805 | data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 803 | data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
806 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; | 804 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; |
807 | 805 | ||
808 | err = ieee80211_register_hw(hw); | 806 | err = ieee80211_register_hw(hw); |
809 | if (err < 0) { | 807 | if (err < 0) { |
810 | printk(KERN_DEBUG "mac80211_hwsim: " | 808 | printk(KERN_DEBUG "mac80211_hwsim: " |
811 | "ieee80211_register_hw failed (%d)\n", err); | 809 | "ieee80211_register_hw failed (%d)\n", err); |
812 | goto failed_hw; | 810 | goto failed_hw; |
813 | } | 811 | } |
814 | 812 | ||
815 | printk(KERN_DEBUG "%s: hwaddr %pM registered\n", | 813 | printk(KERN_DEBUG "%s: hwaddr %pM registered\n", |
816 | wiphy_name(hw->wiphy), | 814 | wiphy_name(hw->wiphy), |
817 | hw->wiphy->perm_addr); | 815 | hw->wiphy->perm_addr); |
818 | 816 | ||
819 | data->debugfs = debugfs_create_dir("hwsim", | 817 | data->debugfs = debugfs_create_dir("hwsim", |
820 | hw->wiphy->debugfsdir); | 818 | hw->wiphy->debugfsdir); |
821 | data->debugfs_ps = debugfs_create_file("ps", 0666, | 819 | data->debugfs_ps = debugfs_create_file("ps", 0666, |
822 | data->debugfs, data, | 820 | data->debugfs, data, |
823 | &hwsim_fops_ps); | 821 | &hwsim_fops_ps); |
824 | 822 | ||
825 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, | 823 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, |
826 | (unsigned long) hw); | 824 | (unsigned long) hw); |
827 | 825 | ||
828 | list_add_tail(&data->list, &hwsim_radios); | 826 | list_add_tail(&data->list, &hwsim_radios); |
829 | } | 827 | } |
830 | 828 | ||
831 | hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); | 829 | hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); |
832 | if (hwsim_mon == NULL) | 830 | if (hwsim_mon == NULL) |
833 | goto failed; | 831 | goto failed; |
834 | 832 | ||
835 | rtnl_lock(); | 833 | rtnl_lock(); |
836 | 834 | ||
837 | err = dev_alloc_name(hwsim_mon, hwsim_mon->name); | 835 | err = dev_alloc_name(hwsim_mon, hwsim_mon->name); |
838 | if (err < 0) | 836 | if (err < 0) |
839 | goto failed_mon; | 837 | goto failed_mon; |
840 | 838 | ||
841 | 839 | ||
842 | err = register_netdevice(hwsim_mon); | 840 | err = register_netdevice(hwsim_mon); |
843 | if (err < 0) | 841 | if (err < 0) |
844 | goto failed_mon; | 842 | goto failed_mon; |
845 | 843 | ||
846 | rtnl_unlock(); | 844 | rtnl_unlock(); |
847 | 845 | ||
848 | return 0; | 846 | return 0; |
849 | 847 | ||
850 | failed_mon: | 848 | failed_mon: |
851 | rtnl_unlock(); | 849 | rtnl_unlock(); |
852 | free_netdev(hwsim_mon); | 850 | free_netdev(hwsim_mon); |
853 | mac80211_hwsim_free(); | 851 | mac80211_hwsim_free(); |
854 | return err; | 852 | return err; |
855 | 853 | ||
856 | failed_hw: | 854 | failed_hw: |
857 | device_unregister(data->dev); | 855 | device_unregister(data->dev); |
858 | failed_drvdata: | 856 | failed_drvdata: |
859 | ieee80211_free_hw(hw); | 857 | ieee80211_free_hw(hw); |
860 | failed: | 858 | failed: |
861 | mac80211_hwsim_free(); | 859 | mac80211_hwsim_free(); |
862 | return err; | 860 | return err; |
863 | } | 861 | } |
864 | 862 | ||
865 | 863 | ||
866 | static void __exit exit_mac80211_hwsim(void) | 864 | static void __exit exit_mac80211_hwsim(void) |
867 | { | 865 | { |
868 | printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); | 866 | printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); |
869 | 867 | ||
870 | unregister_netdev(hwsim_mon); | 868 | unregister_netdev(hwsim_mon); |
871 | mac80211_hwsim_free(); | 869 | mac80211_hwsim_free(); |
872 | } | 870 | } |
873 | 871 | ||
874 | 872 | ||
875 | module_init(init_mac80211_hwsim); | 873 | module_init(init_mac80211_hwsim); |
876 | module_exit(exit_mac80211_hwsim); | 874 | module_exit(exit_mac80211_hwsim); |
877 | 875 |
include/linux/nl80211.h
1 | #ifndef __LINUX_NL80211_H | 1 | #ifndef __LINUX_NL80211_H |
2 | #define __LINUX_NL80211_H | 2 | #define __LINUX_NL80211_H |
3 | /* | 3 | /* |
4 | * 802.11 netlink interface public header | 4 | * 802.11 netlink interface public header |
5 | * | 5 | * |
6 | * Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net> |
7 | * Copyright 2008 Michael Wu <flamingice@sourmilk.net> | 7 | * Copyright 2008 Michael Wu <flamingice@sourmilk.net> |
8 | * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com> | 8 | * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com> |
9 | * Copyright 2008 Michael Buesch <mb@bu3sch.de> | 9 | * Copyright 2008 Michael Buesch <mb@bu3sch.de> |
10 | * Copyright 2008 Luis R. Rodriguez <lrodriguez@atheros.com> | 10 | * Copyright 2008 Luis R. Rodriguez <lrodriguez@atheros.com> |
11 | * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> | 11 | * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> |
12 | * Copyright 2008 Colin McCabe <colin@cozybit.com> | 12 | * Copyright 2008 Colin McCabe <colin@cozybit.com> |
13 | * | 13 | * |
14 | * Permission to use, copy, modify, and/or distribute this software for any | 14 | * Permission to use, copy, modify, and/or distribute this software for any |
15 | * purpose with or without fee is hereby granted, provided that the above | 15 | * purpose with or without fee is hereby granted, provided that the above |
16 | * copyright notice and this permission notice appear in all copies. | 16 | * copyright notice and this permission notice appear in all copies. |
17 | * | 17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 18 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
19 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 19 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
20 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 20 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
21 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 21 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
22 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 22 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
23 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 23 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
24 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 24 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * DOC: Station handling | 29 | * DOC: Station handling |
30 | * | 30 | * |
31 | * Stations are added per interface, but a special case exists with VLAN | 31 | * Stations are added per interface, but a special case exists with VLAN |
32 | * interfaces. When a station is bound to an AP interface, it may be moved | 32 | * interfaces. When a station is bound to an AP interface, it may be moved |
33 | * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). | 33 | * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). |
34 | * The station is still assumed to belong to the AP interface it was added | 34 | * The station is still assumed to belong to the AP interface it was added |
35 | * to. | 35 | * to. |
36 | * | 36 | * |
37 | * TODO: need more info? | 37 | * TODO: need more info? |
38 | */ | 38 | */ |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * enum nl80211_commands - supported nl80211 commands | 41 | * enum nl80211_commands - supported nl80211 commands |
42 | * | 42 | * |
43 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors | 43 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors |
44 | * | 44 | * |
45 | * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request | 45 | * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request |
46 | * to get a list of all present wiphys. | 46 | * to get a list of all present wiphys. |
47 | * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or | 47 | * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or |
48 | * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, | 48 | * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, |
49 | * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or | 49 | * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or |
50 | * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET. | 50 | * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET. |
51 | * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request | 51 | * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request |
52 | * or rename notification. Has attributes %NL80211_ATTR_WIPHY and | 52 | * or rename notification. Has attributes %NL80211_ATTR_WIPHY and |
53 | * %NL80211_ATTR_WIPHY_NAME. | 53 | * %NL80211_ATTR_WIPHY_NAME. |
54 | * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes | 54 | * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes |
55 | * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. | 55 | * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. |
56 | * | 56 | * |
57 | * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; | 57 | * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; |
58 | * either a dump request on a %NL80211_ATTR_WIPHY or a specific get | 58 | * either a dump request on a %NL80211_ATTR_WIPHY or a specific get |
59 | * on an %NL80211_ATTR_IFINDEX is supported. | 59 | * on an %NL80211_ATTR_IFINDEX is supported. |
60 | * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires | 60 | * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires |
61 | * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. | 61 | * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. |
62 | * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response | 62 | * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response |
63 | * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, | 63 | * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, |
64 | * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also | 64 | * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also |
65 | * be sent from userspace to request creation of a new virtual interface, | 65 | * be sent from userspace to request creation of a new virtual interface, |
66 | * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and | 66 | * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and |
67 | * %NL80211_ATTR_IFNAME. | 67 | * %NL80211_ATTR_IFNAME. |
68 | * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes | 68 | * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes |
69 | * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from | 69 | * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from |
70 | * userspace to request deletion of a virtual interface, then requires | 70 | * userspace to request deletion of a virtual interface, then requires |
71 | * attribute %NL80211_ATTR_IFINDEX. | 71 | * attribute %NL80211_ATTR_IFINDEX. |
72 | * | 72 | * |
73 | * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified | 73 | * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified |
74 | * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. | 74 | * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. |
75 | * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or | 75 | * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or |
76 | * %NL80211_ATTR_KEY_THRESHOLD. | 76 | * %NL80211_ATTR_KEY_THRESHOLD. |
77 | * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, | 77 | * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, |
78 | * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER | 78 | * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER |
79 | * attributes. | 79 | * attributes. |
80 | * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX | 80 | * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX |
81 | * or %NL80211_ATTR_MAC. | 81 | * or %NL80211_ATTR_MAC. |
82 | * | 82 | * |
83 | * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a | 83 | * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a |
84 | * %NL80222_CMD_NEW_BEACON message) | 84 | * %NL80222_CMD_NEW_BEACON message) |
85 | * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface | 85 | * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface |
86 | * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, | 86 | * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, |
87 | * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. | 87 | * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. |
88 | * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, | 88 | * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, |
89 | * parameters are like for %NL80211_CMD_SET_BEACON. | 89 | * parameters are like for %NL80211_CMD_SET_BEACON. |
90 | * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it | 90 | * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it |
91 | * | 91 | * |
92 | * @NL80211_CMD_GET_STATION: Get station attributes for station identified by | 92 | * @NL80211_CMD_GET_STATION: Get station attributes for station identified by |
93 | * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. | 93 | * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. |
94 | * @NL80211_CMD_SET_STATION: Set station attributes for station identified by | 94 | * @NL80211_CMD_SET_STATION: Set station attributes for station identified by |
95 | * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. | 95 | * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. |
96 | * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the | 96 | * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the |
97 | * the interface identified by %NL80211_ATTR_IFINDEX. | 97 | * the interface identified by %NL80211_ATTR_IFINDEX. |
98 | * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC | 98 | * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC |
99 | * or, if no MAC address given, all stations, on the interface identified | 99 | * or, if no MAC address given, all stations, on the interface identified |
100 | * by %NL80211_ATTR_IFINDEX. | 100 | * by %NL80211_ATTR_IFINDEX. |
101 | * | 101 | * |
102 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to | 102 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to |
103 | * destination %NL80211_ATTR_MAC on the interface identified by | 103 | * destination %NL80211_ATTR_MAC on the interface identified by |
104 | * %NL80211_ATTR_IFINDEX. | 104 | * %NL80211_ATTR_IFINDEX. |
105 | * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to | 105 | * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to |
106 | * destination %NL80211_ATTR_MAC on the interface identified by | 106 | * destination %NL80211_ATTR_MAC on the interface identified by |
107 | * %NL80211_ATTR_IFINDEX. | 107 | * %NL80211_ATTR_IFINDEX. |
108 | * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the | 108 | * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the |
109 | * the interface identified by %NL80211_ATTR_IFINDEX. | 109 | * the interface identified by %NL80211_ATTR_IFINDEX. |
110 | * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC | 110 | * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC |
111 | * or, if no MAC address given, all mesh paths, on the interface identified | 111 | * or, if no MAC address given, all mesh paths, on the interface identified |
112 | * by %NL80211_ATTR_IFINDEX. | 112 | * by %NL80211_ATTR_IFINDEX. |
113 | * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by | 113 | * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by |
114 | * %NL80211_ATTR_IFINDEX. | 114 | * %NL80211_ATTR_IFINDEX. |
115 | * | 115 | * |
116 | * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command | 116 | * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command |
117 | * after being queried by the kernel. CRDA replies by sending a regulatory | 117 | * after being queried by the kernel. CRDA replies by sending a regulatory |
118 | * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our | 118 | * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our |
119 | * current alpha2 if it found a match. It also provides | 119 | * current alpha2 if it found a match. It also provides |
120 | * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each | 120 | * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each |
121 | * regulatory rule is a nested set of attributes given by | 121 | * regulatory rule is a nested set of attributes given by |
122 | * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and | 122 | * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and |
123 | * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by | 123 | * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by |
124 | * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and | 124 | * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and |
125 | * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. | 125 | * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. |
126 | * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain | 126 | * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain |
127 | * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will | 127 | * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will |
128 | * store this as a valid request and then query userspace for it. | 128 | * store this as a valid request and then query userspace for it. |
129 | * | 129 | * |
130 | * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the | 130 | * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the |
131 | * interface identified by %NL80211_ATTR_IFINDEX | 131 | * interface identified by %NL80211_ATTR_IFINDEX |
132 | * | 132 | * |
133 | * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the | 133 | * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the |
134 | * interface identified by %NL80211_ATTR_IFINDEX | 134 | * interface identified by %NL80211_ATTR_IFINDEX |
135 | * | 135 | * |
136 | * @NL80211_CMD_MAX: highest used command number | 136 | * @NL80211_CMD_MAX: highest used command number |
137 | * @__NL80211_CMD_AFTER_LAST: internal use | 137 | * @__NL80211_CMD_AFTER_LAST: internal use |
138 | */ | 138 | */ |
139 | enum nl80211_commands { | 139 | enum nl80211_commands { |
140 | /* don't change the order or add anything inbetween, this is ABI! */ | 140 | /* don't change the order or add anything inbetween, this is ABI! */ |
141 | NL80211_CMD_UNSPEC, | 141 | NL80211_CMD_UNSPEC, |
142 | 142 | ||
143 | NL80211_CMD_GET_WIPHY, /* can dump */ | 143 | NL80211_CMD_GET_WIPHY, /* can dump */ |
144 | NL80211_CMD_SET_WIPHY, | 144 | NL80211_CMD_SET_WIPHY, |
145 | NL80211_CMD_NEW_WIPHY, | 145 | NL80211_CMD_NEW_WIPHY, |
146 | NL80211_CMD_DEL_WIPHY, | 146 | NL80211_CMD_DEL_WIPHY, |
147 | 147 | ||
148 | NL80211_CMD_GET_INTERFACE, /* can dump */ | 148 | NL80211_CMD_GET_INTERFACE, /* can dump */ |
149 | NL80211_CMD_SET_INTERFACE, | 149 | NL80211_CMD_SET_INTERFACE, |
150 | NL80211_CMD_NEW_INTERFACE, | 150 | NL80211_CMD_NEW_INTERFACE, |
151 | NL80211_CMD_DEL_INTERFACE, | 151 | NL80211_CMD_DEL_INTERFACE, |
152 | 152 | ||
153 | NL80211_CMD_GET_KEY, | 153 | NL80211_CMD_GET_KEY, |
154 | NL80211_CMD_SET_KEY, | 154 | NL80211_CMD_SET_KEY, |
155 | NL80211_CMD_NEW_KEY, | 155 | NL80211_CMD_NEW_KEY, |
156 | NL80211_CMD_DEL_KEY, | 156 | NL80211_CMD_DEL_KEY, |
157 | 157 | ||
158 | NL80211_CMD_GET_BEACON, | 158 | NL80211_CMD_GET_BEACON, |
159 | NL80211_CMD_SET_BEACON, | 159 | NL80211_CMD_SET_BEACON, |
160 | NL80211_CMD_NEW_BEACON, | 160 | NL80211_CMD_NEW_BEACON, |
161 | NL80211_CMD_DEL_BEACON, | 161 | NL80211_CMD_DEL_BEACON, |
162 | 162 | ||
163 | NL80211_CMD_GET_STATION, | 163 | NL80211_CMD_GET_STATION, |
164 | NL80211_CMD_SET_STATION, | 164 | NL80211_CMD_SET_STATION, |
165 | NL80211_CMD_NEW_STATION, | 165 | NL80211_CMD_NEW_STATION, |
166 | NL80211_CMD_DEL_STATION, | 166 | NL80211_CMD_DEL_STATION, |
167 | 167 | ||
168 | NL80211_CMD_GET_MPATH, | 168 | NL80211_CMD_GET_MPATH, |
169 | NL80211_CMD_SET_MPATH, | 169 | NL80211_CMD_SET_MPATH, |
170 | NL80211_CMD_NEW_MPATH, | 170 | NL80211_CMD_NEW_MPATH, |
171 | NL80211_CMD_DEL_MPATH, | 171 | NL80211_CMD_DEL_MPATH, |
172 | 172 | ||
173 | NL80211_CMD_SET_BSS, | 173 | NL80211_CMD_SET_BSS, |
174 | 174 | ||
175 | NL80211_CMD_SET_REG, | 175 | NL80211_CMD_SET_REG, |
176 | NL80211_CMD_REQ_SET_REG, | 176 | NL80211_CMD_REQ_SET_REG, |
177 | 177 | ||
178 | NL80211_CMD_GET_MESH_PARAMS, | 178 | NL80211_CMD_GET_MESH_PARAMS, |
179 | NL80211_CMD_SET_MESH_PARAMS, | 179 | NL80211_CMD_SET_MESH_PARAMS, |
180 | 180 | ||
181 | /* add new commands above here */ | 181 | /* add new commands above here */ |
182 | 182 | ||
183 | /* used to define NL80211_CMD_MAX below */ | 183 | /* used to define NL80211_CMD_MAX below */ |
184 | __NL80211_CMD_AFTER_LAST, | 184 | __NL80211_CMD_AFTER_LAST, |
185 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 | 185 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 |
186 | }; | 186 | }; |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Allow user space programs to use #ifdef on new commands by defining them | 189 | * Allow user space programs to use #ifdef on new commands by defining them |
190 | * here | 190 | * here |
191 | */ | 191 | */ |
192 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS | 192 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS |
193 | 193 | ||
194 | /** | 194 | /** |
195 | * enum nl80211_attrs - nl80211 netlink attributes | 195 | * enum nl80211_attrs - nl80211 netlink attributes |
196 | * | 196 | * |
197 | * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors | 197 | * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors |
198 | * | 198 | * |
199 | * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. | 199 | * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. |
200 | * /sys/class/ieee80211/<phyname>/index | 200 | * /sys/class/ieee80211/<phyname>/index |
201 | * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) | 201 | * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) |
202 | * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters | 202 | * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters |
203 | * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz | 203 | * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz |
204 | * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ | 204 | * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ |
205 | * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): | 205 | * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): |
206 | * NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including | 206 | * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including |
207 | * this attribute) | 207 | * this attribute) |
208 | * NL80211_SEC_CHAN_DISABLED = HT20 only | 208 | * NL80211_CHAN_HT20 = HT20 only |
209 | * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel | 209 | * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel |
210 | * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel | 210 | * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel |
211 | * | 211 | * |
212 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on | 212 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on |
213 | * @NL80211_ATTR_IFNAME: network interface name | 213 | * @NL80211_ATTR_IFNAME: network interface name |
214 | * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype | 214 | * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype |
215 | * | 215 | * |
216 | * @NL80211_ATTR_MAC: MAC address (various uses) | 216 | * @NL80211_ATTR_MAC: MAC address (various uses) |
217 | * | 217 | * |
218 | * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of | 218 | * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of |
219 | * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC | 219 | * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC |
220 | * keys | 220 | * keys |
221 | * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) | 221 | * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) |
222 | * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 | 222 | * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 |
223 | * section 7.3.2.25.1, e.g. 0x000FAC04) | 223 | * section 7.3.2.25.1, e.g. 0x000FAC04) |
224 | * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and | 224 | * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and |
225 | * CCMP keys, each six bytes in little endian | 225 | * CCMP keys, each six bytes in little endian |
226 | * | 226 | * |
227 | * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU | 227 | * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU |
228 | * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing | 228 | * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing |
229 | * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE | 229 | * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE |
230 | * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE | 230 | * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE |
231 | * | 231 | * |
232 | * @NL80211_ATTR_STA_AID: Association ID for the station (u16) | 232 | * @NL80211_ATTR_STA_AID: Association ID for the station (u16) |
233 | * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of | 233 | * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of |
234 | * &enum nl80211_sta_flags. | 234 | * &enum nl80211_sta_flags. |
235 | * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by | 235 | * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by |
236 | * IEEE 802.11 7.3.1.6 (u16). | 236 | * IEEE 802.11 7.3.1.6 (u16). |
237 | * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported | 237 | * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported |
238 | * rates as defined by IEEE 802.11 7.3.2.2 but without the length | 238 | * rates as defined by IEEE 802.11 7.3.2.2 but without the length |
239 | * restriction (at most %NL80211_MAX_SUPP_RATES). | 239 | * restriction (at most %NL80211_MAX_SUPP_RATES). |
240 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station | 240 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station |
241 | * to, or the AP interface the station was originally added to to. | 241 | * to, or the AP interface the station was originally added to to. |
242 | * @NL80211_ATTR_STA_INFO: information about a station, part of station info | 242 | * @NL80211_ATTR_STA_INFO: information about a station, part of station info |
243 | * given for %NL80211_CMD_GET_STATION, nested attribute containing | 243 | * given for %NL80211_CMD_GET_STATION, nested attribute containing |
244 | * info as possible, see &enum nl80211_sta_info. | 244 | * info as possible, see &enum nl80211_sta_info. |
245 | * | 245 | * |
246 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, | 246 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, |
247 | * consisting of a nested array. | 247 | * consisting of a nested array. |
248 | * | 248 | * |
249 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). | 249 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). |
250 | * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. | 250 | * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. |
251 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. | 251 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. |
252 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path | 252 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path |
253 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at | 253 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at |
254 | * &enum nl80211_mpath_info. | 254 | * &enum nl80211_mpath_info. |
255 | * | 255 | * |
256 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of | 256 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of |
257 | * &enum nl80211_mntr_flags. | 257 | * &enum nl80211_mntr_flags. |
258 | * | 258 | * |
259 | * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the | 259 | * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the |
260 | * current regulatory domain should be set to or is already set to. | 260 | * current regulatory domain should be set to or is already set to. |
261 | * For example, 'CR', for Costa Rica. This attribute is used by the kernel | 261 | * For example, 'CR', for Costa Rica. This attribute is used by the kernel |
262 | * to query the CRDA to retrieve one regulatory domain. This attribute can | 262 | * to query the CRDA to retrieve one regulatory domain. This attribute can |
263 | * also be used by userspace to query the kernel for the currently set | 263 | * also be used by userspace to query the kernel for the currently set |
264 | * regulatory domain. We chose an alpha2 as that is also used by the | 264 | * regulatory domain. We chose an alpha2 as that is also used by the |
265 | * IEEE-802.11d country information element to identify a country. | 265 | * IEEE-802.11d country information element to identify a country. |
266 | * Users can also simply ask the wireless core to set regulatory domain | 266 | * Users can also simply ask the wireless core to set regulatory domain |
267 | * to a specific alpha2. | 267 | * to a specific alpha2. |
268 | * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory | 268 | * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory |
269 | * rules. | 269 | * rules. |
270 | * | 270 | * |
271 | * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) | 271 | * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) |
272 | * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled | 272 | * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled |
273 | * (u8, 0 or 1) | 273 | * (u8, 0 or 1) |
274 | * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled | 274 | * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled |
275 | * (u8, 0 or 1) | 275 | * (u8, 0 or 1) |
276 | * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic | 276 | * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic |
277 | * rates in format defined by IEEE 802.11 7.3.2.2 but without the length | 277 | * rates in format defined by IEEE 802.11 7.3.2.2 but without the length |
278 | * restriction (at most %NL80211_MAX_SUPP_RATES). | 278 | * restriction (at most %NL80211_MAX_SUPP_RATES). |
279 | * | 279 | * |
280 | * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from | 280 | * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from |
281 | * association request when used with NL80211_CMD_NEW_STATION) | 281 | * association request when used with NL80211_CMD_NEW_STATION) |
282 | * | 282 | * |
283 | * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all | 283 | * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all |
284 | * supported interface types, each a flag attribute with the number | 284 | * supported interface types, each a flag attribute with the number |
285 | * of the interface mode. | 285 | * of the interface mode. |
286 | * | 286 | * |
287 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 287 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
288 | * @__NL80211_ATTR_AFTER_LAST: internal use | 288 | * @__NL80211_ATTR_AFTER_LAST: internal use |
289 | */ | 289 | */ |
290 | enum nl80211_attrs { | 290 | enum nl80211_attrs { |
291 | /* don't change the order or add anything inbetween, this is ABI! */ | 291 | /* don't change the order or add anything inbetween, this is ABI! */ |
292 | NL80211_ATTR_UNSPEC, | 292 | NL80211_ATTR_UNSPEC, |
293 | 293 | ||
294 | NL80211_ATTR_WIPHY, | 294 | NL80211_ATTR_WIPHY, |
295 | NL80211_ATTR_WIPHY_NAME, | 295 | NL80211_ATTR_WIPHY_NAME, |
296 | 296 | ||
297 | NL80211_ATTR_IFINDEX, | 297 | NL80211_ATTR_IFINDEX, |
298 | NL80211_ATTR_IFNAME, | 298 | NL80211_ATTR_IFNAME, |
299 | NL80211_ATTR_IFTYPE, | 299 | NL80211_ATTR_IFTYPE, |
300 | 300 | ||
301 | NL80211_ATTR_MAC, | 301 | NL80211_ATTR_MAC, |
302 | 302 | ||
303 | NL80211_ATTR_KEY_DATA, | 303 | NL80211_ATTR_KEY_DATA, |
304 | NL80211_ATTR_KEY_IDX, | 304 | NL80211_ATTR_KEY_IDX, |
305 | NL80211_ATTR_KEY_CIPHER, | 305 | NL80211_ATTR_KEY_CIPHER, |
306 | NL80211_ATTR_KEY_SEQ, | 306 | NL80211_ATTR_KEY_SEQ, |
307 | NL80211_ATTR_KEY_DEFAULT, | 307 | NL80211_ATTR_KEY_DEFAULT, |
308 | 308 | ||
309 | NL80211_ATTR_BEACON_INTERVAL, | 309 | NL80211_ATTR_BEACON_INTERVAL, |
310 | NL80211_ATTR_DTIM_PERIOD, | 310 | NL80211_ATTR_DTIM_PERIOD, |
311 | NL80211_ATTR_BEACON_HEAD, | 311 | NL80211_ATTR_BEACON_HEAD, |
312 | NL80211_ATTR_BEACON_TAIL, | 312 | NL80211_ATTR_BEACON_TAIL, |
313 | 313 | ||
314 | NL80211_ATTR_STA_AID, | 314 | NL80211_ATTR_STA_AID, |
315 | NL80211_ATTR_STA_FLAGS, | 315 | NL80211_ATTR_STA_FLAGS, |
316 | NL80211_ATTR_STA_LISTEN_INTERVAL, | 316 | NL80211_ATTR_STA_LISTEN_INTERVAL, |
317 | NL80211_ATTR_STA_SUPPORTED_RATES, | 317 | NL80211_ATTR_STA_SUPPORTED_RATES, |
318 | NL80211_ATTR_STA_VLAN, | 318 | NL80211_ATTR_STA_VLAN, |
319 | NL80211_ATTR_STA_INFO, | 319 | NL80211_ATTR_STA_INFO, |
320 | 320 | ||
321 | NL80211_ATTR_WIPHY_BANDS, | 321 | NL80211_ATTR_WIPHY_BANDS, |
322 | 322 | ||
323 | NL80211_ATTR_MNTR_FLAGS, | 323 | NL80211_ATTR_MNTR_FLAGS, |
324 | 324 | ||
325 | NL80211_ATTR_MESH_ID, | 325 | NL80211_ATTR_MESH_ID, |
326 | NL80211_ATTR_STA_PLINK_ACTION, | 326 | NL80211_ATTR_STA_PLINK_ACTION, |
327 | NL80211_ATTR_MPATH_NEXT_HOP, | 327 | NL80211_ATTR_MPATH_NEXT_HOP, |
328 | NL80211_ATTR_MPATH_INFO, | 328 | NL80211_ATTR_MPATH_INFO, |
329 | 329 | ||
330 | NL80211_ATTR_BSS_CTS_PROT, | 330 | NL80211_ATTR_BSS_CTS_PROT, |
331 | NL80211_ATTR_BSS_SHORT_PREAMBLE, | 331 | NL80211_ATTR_BSS_SHORT_PREAMBLE, |
332 | NL80211_ATTR_BSS_SHORT_SLOT_TIME, | 332 | NL80211_ATTR_BSS_SHORT_SLOT_TIME, |
333 | 333 | ||
334 | NL80211_ATTR_HT_CAPABILITY, | 334 | NL80211_ATTR_HT_CAPABILITY, |
335 | 335 | ||
336 | NL80211_ATTR_SUPPORTED_IFTYPES, | 336 | NL80211_ATTR_SUPPORTED_IFTYPES, |
337 | 337 | ||
338 | NL80211_ATTR_REG_ALPHA2, | 338 | NL80211_ATTR_REG_ALPHA2, |
339 | NL80211_ATTR_REG_RULES, | 339 | NL80211_ATTR_REG_RULES, |
340 | 340 | ||
341 | NL80211_ATTR_MESH_PARAMS, | 341 | NL80211_ATTR_MESH_PARAMS, |
342 | 342 | ||
343 | NL80211_ATTR_BSS_BASIC_RATES, | 343 | NL80211_ATTR_BSS_BASIC_RATES, |
344 | 344 | ||
345 | NL80211_ATTR_WIPHY_TXQ_PARAMS, | 345 | NL80211_ATTR_WIPHY_TXQ_PARAMS, |
346 | NL80211_ATTR_WIPHY_FREQ, | 346 | NL80211_ATTR_WIPHY_FREQ, |
347 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET, | 347 | NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
348 | 348 | ||
349 | /* add attributes here, update the policy in nl80211.c */ | 349 | /* add attributes here, update the policy in nl80211.c */ |
350 | 350 | ||
351 | __NL80211_ATTR_AFTER_LAST, | 351 | __NL80211_ATTR_AFTER_LAST, |
352 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 352 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
353 | }; | 353 | }; |
354 | 354 | ||
355 | /* | 355 | /* |
356 | * Allow user space programs to use #ifdef on new attributes by defining them | 356 | * Allow user space programs to use #ifdef on new attributes by defining them |
357 | * here | 357 | * here |
358 | */ | 358 | */ |
359 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY | 359 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY |
360 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES | 360 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES |
361 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS | 361 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS |
362 | #define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ | 362 | #define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ |
363 | #define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET | 363 | #define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET |
364 | 364 | ||
365 | #define NL80211_MAX_SUPP_RATES 32 | 365 | #define NL80211_MAX_SUPP_RATES 32 |
366 | #define NL80211_MAX_SUPP_REG_RULES 32 | 366 | #define NL80211_MAX_SUPP_REG_RULES 32 |
367 | #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 | 367 | #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 |
368 | #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 | 368 | #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 |
369 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 | 369 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 |
370 | #define NL80211_HT_CAPABILITY_LEN 26 | 370 | #define NL80211_HT_CAPABILITY_LEN 26 |
371 | 371 | ||
372 | /** | 372 | /** |
373 | * enum nl80211_iftype - (virtual) interface types | 373 | * enum nl80211_iftype - (virtual) interface types |
374 | * | 374 | * |
375 | * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides | 375 | * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides |
376 | * @NL80211_IFTYPE_ADHOC: independent BSS member | 376 | * @NL80211_IFTYPE_ADHOC: independent BSS member |
377 | * @NL80211_IFTYPE_STATION: managed BSS member | 377 | * @NL80211_IFTYPE_STATION: managed BSS member |
378 | * @NL80211_IFTYPE_AP: access point | 378 | * @NL80211_IFTYPE_AP: access point |
379 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points | 379 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points |
380 | * @NL80211_IFTYPE_WDS: wireless distribution interface | 380 | * @NL80211_IFTYPE_WDS: wireless distribution interface |
381 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames | 381 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames |
382 | * @NL80211_IFTYPE_MESH_POINT: mesh point | 382 | * @NL80211_IFTYPE_MESH_POINT: mesh point |
383 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 383 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
384 | * @__NL80211_IFTYPE_AFTER_LAST: internal use | 384 | * @__NL80211_IFTYPE_AFTER_LAST: internal use |
385 | * | 385 | * |
386 | * These values are used with the %NL80211_ATTR_IFTYPE | 386 | * These values are used with the %NL80211_ATTR_IFTYPE |
387 | * to set the type of an interface. | 387 | * to set the type of an interface. |
388 | * | 388 | * |
389 | */ | 389 | */ |
390 | enum nl80211_iftype { | 390 | enum nl80211_iftype { |
391 | NL80211_IFTYPE_UNSPECIFIED, | 391 | NL80211_IFTYPE_UNSPECIFIED, |
392 | NL80211_IFTYPE_ADHOC, | 392 | NL80211_IFTYPE_ADHOC, |
393 | NL80211_IFTYPE_STATION, | 393 | NL80211_IFTYPE_STATION, |
394 | NL80211_IFTYPE_AP, | 394 | NL80211_IFTYPE_AP, |
395 | NL80211_IFTYPE_AP_VLAN, | 395 | NL80211_IFTYPE_AP_VLAN, |
396 | NL80211_IFTYPE_WDS, | 396 | NL80211_IFTYPE_WDS, |
397 | NL80211_IFTYPE_MONITOR, | 397 | NL80211_IFTYPE_MONITOR, |
398 | NL80211_IFTYPE_MESH_POINT, | 398 | NL80211_IFTYPE_MESH_POINT, |
399 | 399 | ||
400 | /* keep last */ | 400 | /* keep last */ |
401 | __NL80211_IFTYPE_AFTER_LAST, | 401 | __NL80211_IFTYPE_AFTER_LAST, |
402 | NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 | 402 | NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 |
403 | }; | 403 | }; |
404 | 404 | ||
405 | /** | 405 | /** |
406 | * enum nl80211_sta_flags - station flags | 406 | * enum nl80211_sta_flags - station flags |
407 | * | 407 | * |
408 | * Station flags. When a station is added to an AP interface, it is | 408 | * Station flags. When a station is added to an AP interface, it is |
409 | * assumed to be already associated (and hence authenticated.) | 409 | * assumed to be already associated (and hence authenticated.) |
410 | * | 410 | * |
411 | * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) | 411 | * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) |
412 | * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames | 412 | * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames |
413 | * with short barker preamble | 413 | * with short barker preamble |
414 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable | 414 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable |
415 | */ | 415 | */ |
416 | enum nl80211_sta_flags { | 416 | enum nl80211_sta_flags { |
417 | __NL80211_STA_FLAG_INVALID, | 417 | __NL80211_STA_FLAG_INVALID, |
418 | NL80211_STA_FLAG_AUTHORIZED, | 418 | NL80211_STA_FLAG_AUTHORIZED, |
419 | NL80211_STA_FLAG_SHORT_PREAMBLE, | 419 | NL80211_STA_FLAG_SHORT_PREAMBLE, |
420 | NL80211_STA_FLAG_WME, | 420 | NL80211_STA_FLAG_WME, |
421 | 421 | ||
422 | /* keep last */ | 422 | /* keep last */ |
423 | __NL80211_STA_FLAG_AFTER_LAST, | 423 | __NL80211_STA_FLAG_AFTER_LAST, |
424 | NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 | 424 | NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 |
425 | }; | 425 | }; |
426 | 426 | ||
427 | /** | 427 | /** |
428 | * enum nl80211_rate_info - bitrate information | 428 | * enum nl80211_rate_info - bitrate information |
429 | * | 429 | * |
430 | * These attribute types are used with %NL80211_STA_INFO_TXRATE | 430 | * These attribute types are used with %NL80211_STA_INFO_TXRATE |
431 | * when getting information about the bitrate of a station. | 431 | * when getting information about the bitrate of a station. |
432 | * | 432 | * |
433 | * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved | 433 | * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved |
434 | * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) | 434 | * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) |
435 | * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) | 435 | * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) |
436 | * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate | 436 | * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate |
437 | * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval | 437 | * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval |
438 | * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined | 438 | * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined |
439 | * @__NL80211_RATE_INFO_AFTER_LAST: internal use | 439 | * @__NL80211_RATE_INFO_AFTER_LAST: internal use |
440 | */ | 440 | */ |
441 | enum nl80211_rate_info { | 441 | enum nl80211_rate_info { |
442 | __NL80211_RATE_INFO_INVALID, | 442 | __NL80211_RATE_INFO_INVALID, |
443 | NL80211_RATE_INFO_BITRATE, | 443 | NL80211_RATE_INFO_BITRATE, |
444 | NL80211_RATE_INFO_MCS, | 444 | NL80211_RATE_INFO_MCS, |
445 | NL80211_RATE_INFO_40_MHZ_WIDTH, | 445 | NL80211_RATE_INFO_40_MHZ_WIDTH, |
446 | NL80211_RATE_INFO_SHORT_GI, | 446 | NL80211_RATE_INFO_SHORT_GI, |
447 | 447 | ||
448 | /* keep last */ | 448 | /* keep last */ |
449 | __NL80211_RATE_INFO_AFTER_LAST, | 449 | __NL80211_RATE_INFO_AFTER_LAST, |
450 | NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 | 450 | NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 |
451 | }; | 451 | }; |
452 | 452 | ||
453 | /** | 453 | /** |
454 | * enum nl80211_sta_info - station information | 454 | * enum nl80211_sta_info - station information |
455 | * | 455 | * |
456 | * These attribute types are used with %NL80211_ATTR_STA_INFO | 456 | * These attribute types are used with %NL80211_ATTR_STA_INFO |
457 | * when getting information about a station. | 457 | * when getting information about a station. |
458 | * | 458 | * |
459 | * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved | 459 | * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved |
460 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) | 460 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) |
461 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) | 461 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) |
462 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) | 462 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) |
463 | * @__NL80211_STA_INFO_AFTER_LAST: internal | 463 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
464 | * @NL80211_STA_INFO_MAX: highest possible station info attribute | 464 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
465 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) | 465 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) |
466 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute | 466 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute |
467 | * containing info as possible, see &enum nl80211_sta_info_txrate. | 467 | * containing info as possible, see &enum nl80211_sta_info_txrate. |
468 | */ | 468 | */ |
469 | enum nl80211_sta_info { | 469 | enum nl80211_sta_info { |
470 | __NL80211_STA_INFO_INVALID, | 470 | __NL80211_STA_INFO_INVALID, |
471 | NL80211_STA_INFO_INACTIVE_TIME, | 471 | NL80211_STA_INFO_INACTIVE_TIME, |
472 | NL80211_STA_INFO_RX_BYTES, | 472 | NL80211_STA_INFO_RX_BYTES, |
473 | NL80211_STA_INFO_TX_BYTES, | 473 | NL80211_STA_INFO_TX_BYTES, |
474 | NL80211_STA_INFO_LLID, | 474 | NL80211_STA_INFO_LLID, |
475 | NL80211_STA_INFO_PLID, | 475 | NL80211_STA_INFO_PLID, |
476 | NL80211_STA_INFO_PLINK_STATE, | 476 | NL80211_STA_INFO_PLINK_STATE, |
477 | NL80211_STA_INFO_SIGNAL, | 477 | NL80211_STA_INFO_SIGNAL, |
478 | NL80211_STA_INFO_TX_BITRATE, | 478 | NL80211_STA_INFO_TX_BITRATE, |
479 | 479 | ||
480 | /* keep last */ | 480 | /* keep last */ |
481 | __NL80211_STA_INFO_AFTER_LAST, | 481 | __NL80211_STA_INFO_AFTER_LAST, |
482 | NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 | 482 | NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 |
483 | }; | 483 | }; |
484 | 484 | ||
485 | /** | 485 | /** |
486 | * enum nl80211_mpath_flags - nl80211 mesh path flags | 486 | * enum nl80211_mpath_flags - nl80211 mesh path flags |
487 | * | 487 | * |
488 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active | 488 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active |
489 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running | 489 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running |
490 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN | 490 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN |
491 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set | 491 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set |
492 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded | 492 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded |
493 | */ | 493 | */ |
494 | enum nl80211_mpath_flags { | 494 | enum nl80211_mpath_flags { |
495 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, | 495 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, |
496 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, | 496 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, |
497 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, | 497 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, |
498 | NL80211_MPATH_FLAG_FIXED = 1<<3, | 498 | NL80211_MPATH_FLAG_FIXED = 1<<3, |
499 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, | 499 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, |
500 | }; | 500 | }; |
501 | 501 | ||
502 | /** | 502 | /** |
503 | * enum nl80211_mpath_info - mesh path information | 503 | * enum nl80211_mpath_info - mesh path information |
504 | * | 504 | * |
505 | * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting | 505 | * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting |
506 | * information about a mesh path. | 506 | * information about a mesh path. |
507 | * | 507 | * |
508 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved | 508 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved |
509 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination | 509 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination |
510 | * @NL80211_ATTR_MPATH_DSN: destination sequence number | 510 | * @NL80211_ATTR_MPATH_DSN: destination sequence number |
511 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path | 511 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path |
512 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now | 512 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now |
513 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in | 513 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in |
514 | * &enum nl80211_mpath_flags; | 514 | * &enum nl80211_mpath_flags; |
515 | * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec | 515 | * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec |
516 | * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries | 516 | * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries |
517 | */ | 517 | */ |
518 | enum nl80211_mpath_info { | 518 | enum nl80211_mpath_info { |
519 | __NL80211_MPATH_INFO_INVALID, | 519 | __NL80211_MPATH_INFO_INVALID, |
520 | NL80211_MPATH_INFO_FRAME_QLEN, | 520 | NL80211_MPATH_INFO_FRAME_QLEN, |
521 | NL80211_MPATH_INFO_DSN, | 521 | NL80211_MPATH_INFO_DSN, |
522 | NL80211_MPATH_INFO_METRIC, | 522 | NL80211_MPATH_INFO_METRIC, |
523 | NL80211_MPATH_INFO_EXPTIME, | 523 | NL80211_MPATH_INFO_EXPTIME, |
524 | NL80211_MPATH_INFO_FLAGS, | 524 | NL80211_MPATH_INFO_FLAGS, |
525 | NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | 525 | NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, |
526 | NL80211_MPATH_INFO_DISCOVERY_RETRIES, | 526 | NL80211_MPATH_INFO_DISCOVERY_RETRIES, |
527 | 527 | ||
528 | /* keep last */ | 528 | /* keep last */ |
529 | __NL80211_MPATH_INFO_AFTER_LAST, | 529 | __NL80211_MPATH_INFO_AFTER_LAST, |
530 | NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 | 530 | NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 |
531 | }; | 531 | }; |
532 | 532 | ||
533 | /** | 533 | /** |
534 | * enum nl80211_band_attr - band attributes | 534 | * enum nl80211_band_attr - band attributes |
535 | * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved | 535 | * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved |
536 | * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, | 536 | * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, |
537 | * an array of nested frequency attributes | 537 | * an array of nested frequency attributes |
538 | * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, | 538 | * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, |
539 | * an array of nested bitrate attributes | 539 | * an array of nested bitrate attributes |
540 | * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as | 540 | * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as |
541 | * defined in 802.11n | 541 | * defined in 802.11n |
542 | * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE | 542 | * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE |
543 | * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n | 543 | * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n |
544 | * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n | 544 | * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n |
545 | */ | 545 | */ |
546 | enum nl80211_band_attr { | 546 | enum nl80211_band_attr { |
547 | __NL80211_BAND_ATTR_INVALID, | 547 | __NL80211_BAND_ATTR_INVALID, |
548 | NL80211_BAND_ATTR_FREQS, | 548 | NL80211_BAND_ATTR_FREQS, |
549 | NL80211_BAND_ATTR_RATES, | 549 | NL80211_BAND_ATTR_RATES, |
550 | 550 | ||
551 | NL80211_BAND_ATTR_HT_MCS_SET, | 551 | NL80211_BAND_ATTR_HT_MCS_SET, |
552 | NL80211_BAND_ATTR_HT_CAPA, | 552 | NL80211_BAND_ATTR_HT_CAPA, |
553 | NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 553 | NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
554 | NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 554 | NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
555 | 555 | ||
556 | /* keep last */ | 556 | /* keep last */ |
557 | __NL80211_BAND_ATTR_AFTER_LAST, | 557 | __NL80211_BAND_ATTR_AFTER_LAST, |
558 | NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 | 558 | NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 |
559 | }; | 559 | }; |
560 | 560 | ||
561 | #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA | 561 | #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA |
562 | 562 | ||
563 | /** | 563 | /** |
564 | * enum nl80211_frequency_attr - frequency attributes | 564 | * enum nl80211_frequency_attr - frequency attributes |
565 | * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz | 565 | * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz |
566 | * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current | 566 | * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current |
567 | * regulatory domain. | 567 | * regulatory domain. |
568 | * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is | 568 | * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is |
569 | * permitted on this channel in current regulatory domain. | 569 | * permitted on this channel in current regulatory domain. |
570 | * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted | 570 | * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted |
571 | * on this channel in current regulatory domain. | 571 | * on this channel in current regulatory domain. |
572 | * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory | 572 | * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory |
573 | * on this channel in current regulatory domain. | 573 | * on this channel in current regulatory domain. |
574 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm | 574 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm |
575 | * (100 * dBm). | 575 | * (100 * dBm). |
576 | */ | 576 | */ |
577 | enum nl80211_frequency_attr { | 577 | enum nl80211_frequency_attr { |
578 | __NL80211_FREQUENCY_ATTR_INVALID, | 578 | __NL80211_FREQUENCY_ATTR_INVALID, |
579 | NL80211_FREQUENCY_ATTR_FREQ, | 579 | NL80211_FREQUENCY_ATTR_FREQ, |
580 | NL80211_FREQUENCY_ATTR_DISABLED, | 580 | NL80211_FREQUENCY_ATTR_DISABLED, |
581 | NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, | 581 | NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, |
582 | NL80211_FREQUENCY_ATTR_NO_IBSS, | 582 | NL80211_FREQUENCY_ATTR_NO_IBSS, |
583 | NL80211_FREQUENCY_ATTR_RADAR, | 583 | NL80211_FREQUENCY_ATTR_RADAR, |
584 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 584 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
585 | 585 | ||
586 | /* keep last */ | 586 | /* keep last */ |
587 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, | 587 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, |
588 | NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 | 588 | NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 |
589 | }; | 589 | }; |
590 | 590 | ||
591 | #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER | 591 | #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER |
592 | 592 | ||
593 | /** | 593 | /** |
594 | * enum nl80211_bitrate_attr - bitrate attributes | 594 | * enum nl80211_bitrate_attr - bitrate attributes |
595 | * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps | 595 | * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps |
596 | * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported | 596 | * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported |
597 | * in 2.4 GHz band. | 597 | * in 2.4 GHz band. |
598 | */ | 598 | */ |
599 | enum nl80211_bitrate_attr { | 599 | enum nl80211_bitrate_attr { |
600 | __NL80211_BITRATE_ATTR_INVALID, | 600 | __NL80211_BITRATE_ATTR_INVALID, |
601 | NL80211_BITRATE_ATTR_RATE, | 601 | NL80211_BITRATE_ATTR_RATE, |
602 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, | 602 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, |
603 | 603 | ||
604 | /* keep last */ | 604 | /* keep last */ |
605 | __NL80211_BITRATE_ATTR_AFTER_LAST, | 605 | __NL80211_BITRATE_ATTR_AFTER_LAST, |
606 | NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 | 606 | NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 |
607 | }; | 607 | }; |
608 | 608 | ||
609 | /** | 609 | /** |
610 | * enum nl80211_reg_rule_attr - regulatory rule attributes | 610 | * enum nl80211_reg_rule_attr - regulatory rule attributes |
611 | * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional | 611 | * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional |
612 | * considerations for a given frequency range. These are the | 612 | * considerations for a given frequency range. These are the |
613 | * &enum nl80211_reg_rule_flags. | 613 | * &enum nl80211_reg_rule_flags. |
614 | * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory | 614 | * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory |
615 | * rule in KHz. This is not a center of frequency but an actual regulatory | 615 | * rule in KHz. This is not a center of frequency but an actual regulatory |
616 | * band edge. | 616 | * band edge. |
617 | * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule | 617 | * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule |
618 | * in KHz. This is not a center a frequency but an actual regulatory | 618 | * in KHz. This is not a center a frequency but an actual regulatory |
619 | * band edge. | 619 | * band edge. |
620 | * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this | 620 | * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this |
621 | * frequency range, in KHz. | 621 | * frequency range, in KHz. |
622 | * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain | 622 | * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain |
623 | * for a given frequency range. The value is in mBi (100 * dBi). | 623 | * for a given frequency range. The value is in mBi (100 * dBi). |
624 | * If you don't have one then don't send this. | 624 | * If you don't have one then don't send this. |
625 | * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for | 625 | * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for |
626 | * a given frequency range. The value is in mBm (100 * dBm). | 626 | * a given frequency range. The value is in mBm (100 * dBm). |
627 | */ | 627 | */ |
628 | enum nl80211_reg_rule_attr { | 628 | enum nl80211_reg_rule_attr { |
629 | __NL80211_REG_RULE_ATTR_INVALID, | 629 | __NL80211_REG_RULE_ATTR_INVALID, |
630 | NL80211_ATTR_REG_RULE_FLAGS, | 630 | NL80211_ATTR_REG_RULE_FLAGS, |
631 | 631 | ||
632 | NL80211_ATTR_FREQ_RANGE_START, | 632 | NL80211_ATTR_FREQ_RANGE_START, |
633 | NL80211_ATTR_FREQ_RANGE_END, | 633 | NL80211_ATTR_FREQ_RANGE_END, |
634 | NL80211_ATTR_FREQ_RANGE_MAX_BW, | 634 | NL80211_ATTR_FREQ_RANGE_MAX_BW, |
635 | 635 | ||
636 | NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, | 636 | NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
637 | NL80211_ATTR_POWER_RULE_MAX_EIRP, | 637 | NL80211_ATTR_POWER_RULE_MAX_EIRP, |
638 | 638 | ||
639 | /* keep last */ | 639 | /* keep last */ |
640 | __NL80211_REG_RULE_ATTR_AFTER_LAST, | 640 | __NL80211_REG_RULE_ATTR_AFTER_LAST, |
641 | NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 | 641 | NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 |
642 | }; | 642 | }; |
643 | 643 | ||
644 | /** | 644 | /** |
645 | * enum nl80211_reg_rule_flags - regulatory rule flags | 645 | * enum nl80211_reg_rule_flags - regulatory rule flags |
646 | * | 646 | * |
647 | * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed | 647 | * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed |
648 | * @NL80211_RRF_NO_CCK: CCK modulation not allowed | 648 | * @NL80211_RRF_NO_CCK: CCK modulation not allowed |
649 | * @NL80211_RRF_NO_INDOOR: indoor operation not allowed | 649 | * @NL80211_RRF_NO_INDOOR: indoor operation not allowed |
650 | * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed | 650 | * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed |
651 | * @NL80211_RRF_DFS: DFS support is required to be used | 651 | * @NL80211_RRF_DFS: DFS support is required to be used |
652 | * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links | 652 | * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links |
653 | * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links | 653 | * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links |
654 | * @NL80211_RRF_PASSIVE_SCAN: passive scan is required | 654 | * @NL80211_RRF_PASSIVE_SCAN: passive scan is required |
655 | * @NL80211_RRF_NO_IBSS: no IBSS is allowed | 655 | * @NL80211_RRF_NO_IBSS: no IBSS is allowed |
656 | */ | 656 | */ |
657 | enum nl80211_reg_rule_flags { | 657 | enum nl80211_reg_rule_flags { |
658 | NL80211_RRF_NO_OFDM = 1<<0, | 658 | NL80211_RRF_NO_OFDM = 1<<0, |
659 | NL80211_RRF_NO_CCK = 1<<1, | 659 | NL80211_RRF_NO_CCK = 1<<1, |
660 | NL80211_RRF_NO_INDOOR = 1<<2, | 660 | NL80211_RRF_NO_INDOOR = 1<<2, |
661 | NL80211_RRF_NO_OUTDOOR = 1<<3, | 661 | NL80211_RRF_NO_OUTDOOR = 1<<3, |
662 | NL80211_RRF_DFS = 1<<4, | 662 | NL80211_RRF_DFS = 1<<4, |
663 | NL80211_RRF_PTP_ONLY = 1<<5, | 663 | NL80211_RRF_PTP_ONLY = 1<<5, |
664 | NL80211_RRF_PTMP_ONLY = 1<<6, | 664 | NL80211_RRF_PTMP_ONLY = 1<<6, |
665 | NL80211_RRF_PASSIVE_SCAN = 1<<7, | 665 | NL80211_RRF_PASSIVE_SCAN = 1<<7, |
666 | NL80211_RRF_NO_IBSS = 1<<8, | 666 | NL80211_RRF_NO_IBSS = 1<<8, |
667 | }; | 667 | }; |
668 | 668 | ||
669 | /** | 669 | /** |
670 | * enum nl80211_mntr_flags - monitor configuration flags | 670 | * enum nl80211_mntr_flags - monitor configuration flags |
671 | * | 671 | * |
672 | * Monitor configuration flags. | 672 | * Monitor configuration flags. |
673 | * | 673 | * |
674 | * @__NL80211_MNTR_FLAG_INVALID: reserved | 674 | * @__NL80211_MNTR_FLAG_INVALID: reserved |
675 | * | 675 | * |
676 | * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS | 676 | * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS |
677 | * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP | 677 | * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP |
678 | * @NL80211_MNTR_FLAG_CONTROL: pass control frames | 678 | * @NL80211_MNTR_FLAG_CONTROL: pass control frames |
679 | * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering | 679 | * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering |
680 | * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. | 680 | * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. |
681 | * overrides all other flags. | 681 | * overrides all other flags. |
682 | * | 682 | * |
683 | * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use | 683 | * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use |
684 | * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag | 684 | * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag |
685 | */ | 685 | */ |
686 | enum nl80211_mntr_flags { | 686 | enum nl80211_mntr_flags { |
687 | __NL80211_MNTR_FLAG_INVALID, | 687 | __NL80211_MNTR_FLAG_INVALID, |
688 | NL80211_MNTR_FLAG_FCSFAIL, | 688 | NL80211_MNTR_FLAG_FCSFAIL, |
689 | NL80211_MNTR_FLAG_PLCPFAIL, | 689 | NL80211_MNTR_FLAG_PLCPFAIL, |
690 | NL80211_MNTR_FLAG_CONTROL, | 690 | NL80211_MNTR_FLAG_CONTROL, |
691 | NL80211_MNTR_FLAG_OTHER_BSS, | 691 | NL80211_MNTR_FLAG_OTHER_BSS, |
692 | NL80211_MNTR_FLAG_COOK_FRAMES, | 692 | NL80211_MNTR_FLAG_COOK_FRAMES, |
693 | 693 | ||
694 | /* keep last */ | 694 | /* keep last */ |
695 | __NL80211_MNTR_FLAG_AFTER_LAST, | 695 | __NL80211_MNTR_FLAG_AFTER_LAST, |
696 | NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 | 696 | NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 |
697 | }; | 697 | }; |
698 | 698 | ||
699 | /** | 699 | /** |
700 | * enum nl80211_meshconf_params - mesh configuration parameters | 700 | * enum nl80211_meshconf_params - mesh configuration parameters |
701 | * | 701 | * |
702 | * Mesh configuration parameters | 702 | * Mesh configuration parameters |
703 | * | 703 | * |
704 | * @__NL80211_MESHCONF_INVALID: internal use | 704 | * @__NL80211_MESHCONF_INVALID: internal use |
705 | * | 705 | * |
706 | * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in | 706 | * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in |
707 | * millisecond units, used by the Peer Link Open message | 707 | * millisecond units, used by the Peer Link Open message |
708 | * | 708 | * |
709 | * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in | 709 | * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in |
710 | * millisecond units, used by the peer link management to close a peer link | 710 | * millisecond units, used by the peer link management to close a peer link |
711 | * | 711 | * |
712 | * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in | 712 | * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in |
713 | * millisecond units | 713 | * millisecond units |
714 | * | 714 | * |
715 | * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed | 715 | * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed |
716 | * on this mesh interface | 716 | * on this mesh interface |
717 | * | 717 | * |
718 | * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link | 718 | * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link |
719 | * open retries that can be sent to establish a new peer link instance in a | 719 | * open retries that can be sent to establish a new peer link instance in a |
720 | * mesh | 720 | * mesh |
721 | * | 721 | * |
722 | * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh | 722 | * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh |
723 | * point. | 723 | * point. |
724 | * | 724 | * |
725 | * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically | 725 | * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically |
726 | * open peer links when we detect compatible mesh peers. | 726 | * open peer links when we detect compatible mesh peers. |
727 | * | 727 | * |
728 | * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames | 728 | * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames |
729 | * containing a PREQ that an MP can send to a particular destination (path | 729 | * containing a PREQ that an MP can send to a particular destination (path |
730 | * target) | 730 | * target) |
731 | * | 731 | * |
732 | * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths | 732 | * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths |
733 | * (in milliseconds) | 733 | * (in milliseconds) |
734 | * | 734 | * |
735 | * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait | 735 | * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait |
736 | * until giving up on a path discovery (in milliseconds) | 736 | * until giving up on a path discovery (in milliseconds) |
737 | * | 737 | * |
738 | * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh | 738 | * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh |
739 | * points receiving a PREQ shall consider the forwarding information from the | 739 | * points receiving a PREQ shall consider the forwarding information from the |
740 | * root to be valid. (TU = time unit) | 740 | * root to be valid. (TU = time unit) |
741 | * | 741 | * |
742 | * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in | 742 | * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in |
743 | * TUs) during which an MP can send only one action frame containing a PREQ | 743 | * TUs) during which an MP can send only one action frame containing a PREQ |
744 | * reference element | 744 | * reference element |
745 | * | 745 | * |
746 | * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) | 746 | * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) |
747 | * that it takes for an HWMP information element to propagate across the mesh | 747 | * that it takes for an HWMP information element to propagate across the mesh |
748 | * | 748 | * |
749 | * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute | 749 | * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute |
750 | * | 750 | * |
751 | * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use | 751 | * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use |
752 | */ | 752 | */ |
753 | enum nl80211_meshconf_params { | 753 | enum nl80211_meshconf_params { |
754 | __NL80211_MESHCONF_INVALID, | 754 | __NL80211_MESHCONF_INVALID, |
755 | NL80211_MESHCONF_RETRY_TIMEOUT, | 755 | NL80211_MESHCONF_RETRY_TIMEOUT, |
756 | NL80211_MESHCONF_CONFIRM_TIMEOUT, | 756 | NL80211_MESHCONF_CONFIRM_TIMEOUT, |
757 | NL80211_MESHCONF_HOLDING_TIMEOUT, | 757 | NL80211_MESHCONF_HOLDING_TIMEOUT, |
758 | NL80211_MESHCONF_MAX_PEER_LINKS, | 758 | NL80211_MESHCONF_MAX_PEER_LINKS, |
759 | NL80211_MESHCONF_MAX_RETRIES, | 759 | NL80211_MESHCONF_MAX_RETRIES, |
760 | NL80211_MESHCONF_TTL, | 760 | NL80211_MESHCONF_TTL, |
761 | NL80211_MESHCONF_AUTO_OPEN_PLINKS, | 761 | NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
762 | NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 762 | NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
763 | NL80211_MESHCONF_PATH_REFRESH_TIME, | 763 | NL80211_MESHCONF_PATH_REFRESH_TIME, |
764 | NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 764 | NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
765 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 765 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
766 | NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 766 | NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
767 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 767 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
768 | 768 | ||
769 | /* keep last */ | 769 | /* keep last */ |
770 | __NL80211_MESHCONF_ATTR_AFTER_LAST, | 770 | __NL80211_MESHCONF_ATTR_AFTER_LAST, |
771 | NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 | 771 | NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 |
772 | }; | 772 | }; |
773 | 773 | ||
774 | /** | 774 | /** |
775 | * enum nl80211_txq_attr - TX queue parameter attributes | 775 | * enum nl80211_txq_attr - TX queue parameter attributes |
776 | * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved | 776 | * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved |
777 | * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) | 777 | * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) |
778 | * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning | 778 | * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning |
779 | * disabled | 779 | * disabled |
780 | * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form | 780 | * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form |
781 | * 2^n-1 in the range 1..32767] | 781 | * 2^n-1 in the range 1..32767] |
782 | * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form | 782 | * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form |
783 | * 2^n-1 in the range 1..32767] | 783 | * 2^n-1 in the range 1..32767] |
784 | * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] | 784 | * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] |
785 | * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal | 785 | * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal |
786 | * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number | 786 | * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number |
787 | */ | 787 | */ |
788 | enum nl80211_txq_attr { | 788 | enum nl80211_txq_attr { |
789 | __NL80211_TXQ_ATTR_INVALID, | 789 | __NL80211_TXQ_ATTR_INVALID, |
790 | NL80211_TXQ_ATTR_QUEUE, | 790 | NL80211_TXQ_ATTR_QUEUE, |
791 | NL80211_TXQ_ATTR_TXOP, | 791 | NL80211_TXQ_ATTR_TXOP, |
792 | NL80211_TXQ_ATTR_CWMIN, | 792 | NL80211_TXQ_ATTR_CWMIN, |
793 | NL80211_TXQ_ATTR_CWMAX, | 793 | NL80211_TXQ_ATTR_CWMAX, |
794 | NL80211_TXQ_ATTR_AIFS, | 794 | NL80211_TXQ_ATTR_AIFS, |
795 | 795 | ||
796 | /* keep last */ | 796 | /* keep last */ |
797 | __NL80211_TXQ_ATTR_AFTER_LAST, | 797 | __NL80211_TXQ_ATTR_AFTER_LAST, |
798 | NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 | 798 | NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 |
799 | }; | 799 | }; |
800 | 800 | ||
801 | enum nl80211_txq_q { | 801 | enum nl80211_txq_q { |
802 | NL80211_TXQ_Q_VO, | 802 | NL80211_TXQ_Q_VO, |
803 | NL80211_TXQ_Q_VI, | 803 | NL80211_TXQ_Q_VI, |
804 | NL80211_TXQ_Q_BE, | 804 | NL80211_TXQ_Q_BE, |
805 | NL80211_TXQ_Q_BK | 805 | NL80211_TXQ_Q_BK |
806 | }; | 806 | }; |
807 | 807 | ||
808 | enum nl80211_sec_chan_offset { | 808 | enum nl80211_channel_type { |
809 | NL80211_SEC_CHAN_NO_HT /* No HT */, | 809 | NL80211_CHAN_NO_HT, |
810 | NL80211_SEC_CHAN_DISABLED /* HT20 only */, | 810 | NL80211_CHAN_HT20, |
811 | NL80211_SEC_CHAN_BELOW /* HT40- */, | 811 | NL80211_CHAN_HT40MINUS, |
812 | NL80211_SEC_CHAN_ABOVE /* HT40+ */ | 812 | NL80211_CHAN_HT40PLUS |
813 | }; | 813 | }; |
814 | #endif /* __LINUX_NL80211_H */ | 814 | #endif /* __LINUX_NL80211_H */ |
815 | 815 |
include/net/cfg80211.h
1 | #ifndef __NET_CFG80211_H | 1 | #ifndef __NET_CFG80211_H |
2 | #define __NET_CFG80211_H | 2 | #define __NET_CFG80211_H |
3 | 3 | ||
4 | #include <linux/netlink.h> | 4 | #include <linux/netlink.h> |
5 | #include <linux/skbuff.h> | 5 | #include <linux/skbuff.h> |
6 | #include <linux/nl80211.h> | 6 | #include <linux/nl80211.h> |
7 | #include <net/genetlink.h> | 7 | #include <net/genetlink.h> |
8 | /* remove once we remove the wext stuff */ | 8 | /* remove once we remove the wext stuff */ |
9 | #include <net/iw_handler.h> | 9 | #include <net/iw_handler.h> |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * 802.11 configuration in-kernel interface | 12 | * 802.11 configuration in-kernel interface |
13 | * | 13 | * |
14 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 14 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /** | 17 | /** |
18 | * struct vif_params - describes virtual interface parameters | 18 | * struct vif_params - describes virtual interface parameters |
19 | * @mesh_id: mesh ID to use | 19 | * @mesh_id: mesh ID to use |
20 | * @mesh_id_len: length of the mesh ID | 20 | * @mesh_id_len: length of the mesh ID |
21 | */ | 21 | */ |
22 | struct vif_params { | 22 | struct vif_params { |
23 | u8 *mesh_id; | 23 | u8 *mesh_id; |
24 | int mesh_id_len; | 24 | int mesh_id_len; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | /* Radiotap header iteration | 27 | /* Radiotap header iteration |
28 | * implemented in net/wireless/radiotap.c | 28 | * implemented in net/wireless/radiotap.c |
29 | * docs in Documentation/networking/radiotap-headers.txt | 29 | * docs in Documentation/networking/radiotap-headers.txt |
30 | */ | 30 | */ |
31 | /** | 31 | /** |
32 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args | 32 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args |
33 | * @rtheader: pointer to the radiotap header we are walking through | 33 | * @rtheader: pointer to the radiotap header we are walking through |
34 | * @max_length: length of radiotap header in cpu byte ordering | 34 | * @max_length: length of radiotap header in cpu byte ordering |
35 | * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg | 35 | * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg |
36 | * @this_arg: pointer to current radiotap arg | 36 | * @this_arg: pointer to current radiotap arg |
37 | * @arg_index: internal next argument index | 37 | * @arg_index: internal next argument index |
38 | * @arg: internal next argument pointer | 38 | * @arg: internal next argument pointer |
39 | * @next_bitmap: internal pointer to next present u32 | 39 | * @next_bitmap: internal pointer to next present u32 |
40 | * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present | 40 | * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present |
41 | */ | 41 | */ |
42 | 42 | ||
43 | struct ieee80211_radiotap_iterator { | 43 | struct ieee80211_radiotap_iterator { |
44 | struct ieee80211_radiotap_header *rtheader; | 44 | struct ieee80211_radiotap_header *rtheader; |
45 | int max_length; | 45 | int max_length; |
46 | int this_arg_index; | 46 | int this_arg_index; |
47 | u8 *this_arg; | 47 | u8 *this_arg; |
48 | 48 | ||
49 | int arg_index; | 49 | int arg_index; |
50 | u8 *arg; | 50 | u8 *arg; |
51 | __le32 *next_bitmap; | 51 | __le32 *next_bitmap; |
52 | u32 bitmap_shifter; | 52 | u32 bitmap_shifter; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | extern int ieee80211_radiotap_iterator_init( | 55 | extern int ieee80211_radiotap_iterator_init( |
56 | struct ieee80211_radiotap_iterator *iterator, | 56 | struct ieee80211_radiotap_iterator *iterator, |
57 | struct ieee80211_radiotap_header *radiotap_header, | 57 | struct ieee80211_radiotap_header *radiotap_header, |
58 | int max_length); | 58 | int max_length); |
59 | 59 | ||
60 | extern int ieee80211_radiotap_iterator_next( | 60 | extern int ieee80211_radiotap_iterator_next( |
61 | struct ieee80211_radiotap_iterator *iterator); | 61 | struct ieee80211_radiotap_iterator *iterator); |
62 | 62 | ||
63 | 63 | ||
64 | /** | 64 | /** |
65 | * struct key_params - key information | 65 | * struct key_params - key information |
66 | * | 66 | * |
67 | * Information about a key | 67 | * Information about a key |
68 | * | 68 | * |
69 | * @key: key material | 69 | * @key: key material |
70 | * @key_len: length of key material | 70 | * @key_len: length of key material |
71 | * @cipher: cipher suite selector | 71 | * @cipher: cipher suite selector |
72 | * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used | 72 | * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used |
73 | * with the get_key() callback, must be in little endian, | 73 | * with the get_key() callback, must be in little endian, |
74 | * length given by @seq_len. | 74 | * length given by @seq_len. |
75 | */ | 75 | */ |
76 | struct key_params { | 76 | struct key_params { |
77 | u8 *key; | 77 | u8 *key; |
78 | u8 *seq; | 78 | u8 *seq; |
79 | int key_len; | 79 | int key_len; |
80 | int seq_len; | 80 | int seq_len; |
81 | u32 cipher; | 81 | u32 cipher; |
82 | }; | 82 | }; |
83 | 83 | ||
84 | /** | 84 | /** |
85 | * struct beacon_parameters - beacon parameters | 85 | * struct beacon_parameters - beacon parameters |
86 | * | 86 | * |
87 | * Used to configure the beacon for an interface. | 87 | * Used to configure the beacon for an interface. |
88 | * | 88 | * |
89 | * @head: head portion of beacon (before TIM IE) | 89 | * @head: head portion of beacon (before TIM IE) |
90 | * or %NULL if not changed | 90 | * or %NULL if not changed |
91 | * @tail: tail portion of beacon (after TIM IE) | 91 | * @tail: tail portion of beacon (after TIM IE) |
92 | * or %NULL if not changed | 92 | * or %NULL if not changed |
93 | * @interval: beacon interval or zero if not changed | 93 | * @interval: beacon interval or zero if not changed |
94 | * @dtim_period: DTIM period or zero if not changed | 94 | * @dtim_period: DTIM period or zero if not changed |
95 | * @head_len: length of @head | 95 | * @head_len: length of @head |
96 | * @tail_len: length of @tail | 96 | * @tail_len: length of @tail |
97 | */ | 97 | */ |
98 | struct beacon_parameters { | 98 | struct beacon_parameters { |
99 | u8 *head, *tail; | 99 | u8 *head, *tail; |
100 | int interval, dtim_period; | 100 | int interval, dtim_period; |
101 | int head_len, tail_len; | 101 | int head_len, tail_len; |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /** | 104 | /** |
105 | * enum station_flags - station flags | 105 | * enum station_flags - station flags |
106 | * | 106 | * |
107 | * Station capability flags. Note that these must be the bits | 107 | * Station capability flags. Note that these must be the bits |
108 | * according to the nl80211 flags. | 108 | * according to the nl80211 flags. |
109 | * | 109 | * |
110 | * @STATION_FLAG_CHANGED: station flags were changed | 110 | * @STATION_FLAG_CHANGED: station flags were changed |
111 | * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) | 111 | * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) |
112 | * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames | 112 | * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames |
113 | * with short preambles | 113 | * with short preambles |
114 | * @STATION_FLAG_WME: station is WME/QoS capable | 114 | * @STATION_FLAG_WME: station is WME/QoS capable |
115 | */ | 115 | */ |
116 | enum station_flags { | 116 | enum station_flags { |
117 | STATION_FLAG_CHANGED = 1<<0, | 117 | STATION_FLAG_CHANGED = 1<<0, |
118 | STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, | 118 | STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, |
119 | STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, | 119 | STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, |
120 | STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, | 120 | STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, |
121 | }; | 121 | }; |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * enum plink_action - actions to perform in mesh peers | 124 | * enum plink_action - actions to perform in mesh peers |
125 | * | 125 | * |
126 | * @PLINK_ACTION_INVALID: action 0 is reserved | 126 | * @PLINK_ACTION_INVALID: action 0 is reserved |
127 | * @PLINK_ACTION_OPEN: start mesh peer link establishment | 127 | * @PLINK_ACTION_OPEN: start mesh peer link establishment |
128 | * @PLINK_ACTION_BLOCL: block traffic from this mesh peer | 128 | * @PLINK_ACTION_BLOCL: block traffic from this mesh peer |
129 | */ | 129 | */ |
130 | enum plink_actions { | 130 | enum plink_actions { |
131 | PLINK_ACTION_INVALID, | 131 | PLINK_ACTION_INVALID, |
132 | PLINK_ACTION_OPEN, | 132 | PLINK_ACTION_OPEN, |
133 | PLINK_ACTION_BLOCK, | 133 | PLINK_ACTION_BLOCK, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | /** | 136 | /** |
137 | * struct station_parameters - station parameters | 137 | * struct station_parameters - station parameters |
138 | * | 138 | * |
139 | * Used to change and create a new station. | 139 | * Used to change and create a new station. |
140 | * | 140 | * |
141 | * @vlan: vlan interface station should belong to | 141 | * @vlan: vlan interface station should belong to |
142 | * @supported_rates: supported rates in IEEE 802.11 format | 142 | * @supported_rates: supported rates in IEEE 802.11 format |
143 | * (or NULL for no change) | 143 | * (or NULL for no change) |
144 | * @supported_rates_len: number of supported rates | 144 | * @supported_rates_len: number of supported rates |
145 | * @station_flags: station flags (see &enum station_flags) | 145 | * @station_flags: station flags (see &enum station_flags) |
146 | * @listen_interval: listen interval or -1 for no change | 146 | * @listen_interval: listen interval or -1 for no change |
147 | * @aid: AID or zero for no change | 147 | * @aid: AID or zero for no change |
148 | */ | 148 | */ |
149 | struct station_parameters { | 149 | struct station_parameters { |
150 | u8 *supported_rates; | 150 | u8 *supported_rates; |
151 | struct net_device *vlan; | 151 | struct net_device *vlan; |
152 | u32 station_flags; | 152 | u32 station_flags; |
153 | int listen_interval; | 153 | int listen_interval; |
154 | u16 aid; | 154 | u16 aid; |
155 | u8 supported_rates_len; | 155 | u8 supported_rates_len; |
156 | u8 plink_action; | 156 | u8 plink_action; |
157 | struct ieee80211_ht_cap *ht_capa; | 157 | struct ieee80211_ht_cap *ht_capa; |
158 | }; | 158 | }; |
159 | 159 | ||
160 | /** | 160 | /** |
161 | * enum station_info_flags - station information flags | 161 | * enum station_info_flags - station information flags |
162 | * | 162 | * |
163 | * Used by the driver to indicate which info in &struct station_info | 163 | * Used by the driver to indicate which info in &struct station_info |
164 | * it has filled in during get_station() or dump_station(). | 164 | * it has filled in during get_station() or dump_station(). |
165 | * | 165 | * |
166 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled | 166 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled |
167 | * @STATION_INFO_RX_BYTES: @rx_bytes filled | 167 | * @STATION_INFO_RX_BYTES: @rx_bytes filled |
168 | * @STATION_INFO_TX_BYTES: @tx_bytes filled | 168 | * @STATION_INFO_TX_BYTES: @tx_bytes filled |
169 | * @STATION_INFO_LLID: @llid filled | 169 | * @STATION_INFO_LLID: @llid filled |
170 | * @STATION_INFO_PLID: @plid filled | 170 | * @STATION_INFO_PLID: @plid filled |
171 | * @STATION_INFO_PLINK_STATE: @plink_state filled | 171 | * @STATION_INFO_PLINK_STATE: @plink_state filled |
172 | * @STATION_INFO_SIGNAL: @signal filled | 172 | * @STATION_INFO_SIGNAL: @signal filled |
173 | * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled | 173 | * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled |
174 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) | 174 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) |
175 | */ | 175 | */ |
176 | enum station_info_flags { | 176 | enum station_info_flags { |
177 | STATION_INFO_INACTIVE_TIME = 1<<0, | 177 | STATION_INFO_INACTIVE_TIME = 1<<0, |
178 | STATION_INFO_RX_BYTES = 1<<1, | 178 | STATION_INFO_RX_BYTES = 1<<1, |
179 | STATION_INFO_TX_BYTES = 1<<2, | 179 | STATION_INFO_TX_BYTES = 1<<2, |
180 | STATION_INFO_LLID = 1<<3, | 180 | STATION_INFO_LLID = 1<<3, |
181 | STATION_INFO_PLID = 1<<4, | 181 | STATION_INFO_PLID = 1<<4, |
182 | STATION_INFO_PLINK_STATE = 1<<5, | 182 | STATION_INFO_PLINK_STATE = 1<<5, |
183 | STATION_INFO_SIGNAL = 1<<6, | 183 | STATION_INFO_SIGNAL = 1<<6, |
184 | STATION_INFO_TX_BITRATE = 1<<7, | 184 | STATION_INFO_TX_BITRATE = 1<<7, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /** | 187 | /** |
188 | * enum station_info_rate_flags - bitrate info flags | 188 | * enum station_info_rate_flags - bitrate info flags |
189 | * | 189 | * |
190 | * Used by the driver to indicate the specific rate transmission | 190 | * Used by the driver to indicate the specific rate transmission |
191 | * type for 802.11n transmissions. | 191 | * type for 802.11n transmissions. |
192 | * | 192 | * |
193 | * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled | 193 | * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled |
194 | * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission | 194 | * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission |
195 | * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval | 195 | * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval |
196 | */ | 196 | */ |
197 | enum rate_info_flags { | 197 | enum rate_info_flags { |
198 | RATE_INFO_FLAGS_MCS = 1<<0, | 198 | RATE_INFO_FLAGS_MCS = 1<<0, |
199 | RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, | 199 | RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, |
200 | RATE_INFO_FLAGS_SHORT_GI = 1<<2, | 200 | RATE_INFO_FLAGS_SHORT_GI = 1<<2, |
201 | }; | 201 | }; |
202 | 202 | ||
203 | /** | 203 | /** |
204 | * struct rate_info - bitrate information | 204 | * struct rate_info - bitrate information |
205 | * | 205 | * |
206 | * Information about a receiving or transmitting bitrate | 206 | * Information about a receiving or transmitting bitrate |
207 | * | 207 | * |
208 | * @flags: bitflag of flags from &enum rate_info_flags | 208 | * @flags: bitflag of flags from &enum rate_info_flags |
209 | * @mcs: mcs index if struct describes a 802.11n bitrate | 209 | * @mcs: mcs index if struct describes a 802.11n bitrate |
210 | * @legacy: bitrate in 100kbit/s for 802.11abg | 210 | * @legacy: bitrate in 100kbit/s for 802.11abg |
211 | */ | 211 | */ |
212 | struct rate_info { | 212 | struct rate_info { |
213 | u8 flags; | 213 | u8 flags; |
214 | u8 mcs; | 214 | u8 mcs; |
215 | u16 legacy; | 215 | u16 legacy; |
216 | }; | 216 | }; |
217 | 217 | ||
218 | /** | 218 | /** |
219 | * struct station_info - station information | 219 | * struct station_info - station information |
220 | * | 220 | * |
221 | * Station information filled by driver for get_station() and dump_station. | 221 | * Station information filled by driver for get_station() and dump_station. |
222 | * | 222 | * |
223 | * @filled: bitflag of flags from &enum station_info_flags | 223 | * @filled: bitflag of flags from &enum station_info_flags |
224 | * @inactive_time: time since last station activity (tx/rx) in milliseconds | 224 | * @inactive_time: time since last station activity (tx/rx) in milliseconds |
225 | * @rx_bytes: bytes received from this station | 225 | * @rx_bytes: bytes received from this station |
226 | * @tx_bytes: bytes transmitted to this station | 226 | * @tx_bytes: bytes transmitted to this station |
227 | * @llid: mesh local link id | 227 | * @llid: mesh local link id |
228 | * @plid: mesh peer link id | 228 | * @plid: mesh peer link id |
229 | * @plink_state: mesh peer link state | 229 | * @plink_state: mesh peer link state |
230 | * @signal: signal strength of last received packet in dBm | 230 | * @signal: signal strength of last received packet in dBm |
231 | * @txrate: current unicast bitrate to this station | 231 | * @txrate: current unicast bitrate to this station |
232 | */ | 232 | */ |
233 | struct station_info { | 233 | struct station_info { |
234 | u32 filled; | 234 | u32 filled; |
235 | u32 inactive_time; | 235 | u32 inactive_time; |
236 | u32 rx_bytes; | 236 | u32 rx_bytes; |
237 | u32 tx_bytes; | 237 | u32 tx_bytes; |
238 | u16 llid; | 238 | u16 llid; |
239 | u16 plid; | 239 | u16 plid; |
240 | u8 plink_state; | 240 | u8 plink_state; |
241 | s8 signal; | 241 | s8 signal; |
242 | struct rate_info txrate; | 242 | struct rate_info txrate; |
243 | }; | 243 | }; |
244 | 244 | ||
245 | /** | 245 | /** |
246 | * enum monitor_flags - monitor flags | 246 | * enum monitor_flags - monitor flags |
247 | * | 247 | * |
248 | * Monitor interface configuration flags. Note that these must be the bits | 248 | * Monitor interface configuration flags. Note that these must be the bits |
249 | * according to the nl80211 flags. | 249 | * according to the nl80211 flags. |
250 | * | 250 | * |
251 | * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS | 251 | * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS |
252 | * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP | 252 | * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP |
253 | * @MONITOR_FLAG_CONTROL: pass control frames | 253 | * @MONITOR_FLAG_CONTROL: pass control frames |
254 | * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering | 254 | * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering |
255 | * @MONITOR_FLAG_COOK_FRAMES: report frames after processing | 255 | * @MONITOR_FLAG_COOK_FRAMES: report frames after processing |
256 | */ | 256 | */ |
257 | enum monitor_flags { | 257 | enum monitor_flags { |
258 | MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, | 258 | MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, |
259 | MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL, | 259 | MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL, |
260 | MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, | 260 | MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, |
261 | MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, | 261 | MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, |
262 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, | 262 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | /** | 265 | /** |
266 | * enum mpath_info_flags - mesh path information flags | 266 | * enum mpath_info_flags - mesh path information flags |
267 | * | 267 | * |
268 | * Used by the driver to indicate which info in &struct mpath_info it has filled | 268 | * Used by the driver to indicate which info in &struct mpath_info it has filled |
269 | * in during get_station() or dump_station(). | 269 | * in during get_station() or dump_station(). |
270 | * | 270 | * |
271 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled | 271 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled |
272 | * MPATH_INFO_DSN: @dsn filled | 272 | * MPATH_INFO_DSN: @dsn filled |
273 | * MPATH_INFO_METRIC: @metric filled | 273 | * MPATH_INFO_METRIC: @metric filled |
274 | * MPATH_INFO_EXPTIME: @exptime filled | 274 | * MPATH_INFO_EXPTIME: @exptime filled |
275 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled | 275 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled |
276 | * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled | 276 | * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled |
277 | * MPATH_INFO_FLAGS: @flags filled | 277 | * MPATH_INFO_FLAGS: @flags filled |
278 | */ | 278 | */ |
279 | enum mpath_info_flags { | 279 | enum mpath_info_flags { |
280 | MPATH_INFO_FRAME_QLEN = BIT(0), | 280 | MPATH_INFO_FRAME_QLEN = BIT(0), |
281 | MPATH_INFO_DSN = BIT(1), | 281 | MPATH_INFO_DSN = BIT(1), |
282 | MPATH_INFO_METRIC = BIT(2), | 282 | MPATH_INFO_METRIC = BIT(2), |
283 | MPATH_INFO_EXPTIME = BIT(3), | 283 | MPATH_INFO_EXPTIME = BIT(3), |
284 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), | 284 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), |
285 | MPATH_INFO_DISCOVERY_RETRIES = BIT(5), | 285 | MPATH_INFO_DISCOVERY_RETRIES = BIT(5), |
286 | MPATH_INFO_FLAGS = BIT(6), | 286 | MPATH_INFO_FLAGS = BIT(6), |
287 | }; | 287 | }; |
288 | 288 | ||
289 | /** | 289 | /** |
290 | * struct mpath_info - mesh path information | 290 | * struct mpath_info - mesh path information |
291 | * | 291 | * |
292 | * Mesh path information filled by driver for get_mpath() and dump_mpath(). | 292 | * Mesh path information filled by driver for get_mpath() and dump_mpath(). |
293 | * | 293 | * |
294 | * @filled: bitfield of flags from &enum mpath_info_flags | 294 | * @filled: bitfield of flags from &enum mpath_info_flags |
295 | * @frame_qlen: number of queued frames for this destination | 295 | * @frame_qlen: number of queued frames for this destination |
296 | * @dsn: destination sequence number | 296 | * @dsn: destination sequence number |
297 | * @metric: metric (cost) of this mesh path | 297 | * @metric: metric (cost) of this mesh path |
298 | * @exptime: expiration time for the mesh path from now, in msecs | 298 | * @exptime: expiration time for the mesh path from now, in msecs |
299 | * @flags: mesh path flags | 299 | * @flags: mesh path flags |
300 | * @discovery_timeout: total mesh path discovery timeout, in msecs | 300 | * @discovery_timeout: total mesh path discovery timeout, in msecs |
301 | * @discovery_retries: mesh path discovery retries | 301 | * @discovery_retries: mesh path discovery retries |
302 | */ | 302 | */ |
303 | struct mpath_info { | 303 | struct mpath_info { |
304 | u32 filled; | 304 | u32 filled; |
305 | u32 frame_qlen; | 305 | u32 frame_qlen; |
306 | u32 dsn; | 306 | u32 dsn; |
307 | u32 metric; | 307 | u32 metric; |
308 | u32 exptime; | 308 | u32 exptime; |
309 | u32 discovery_timeout; | 309 | u32 discovery_timeout; |
310 | u8 discovery_retries; | 310 | u8 discovery_retries; |
311 | u8 flags; | 311 | u8 flags; |
312 | }; | 312 | }; |
313 | 313 | ||
314 | /** | 314 | /** |
315 | * struct bss_parameters - BSS parameters | 315 | * struct bss_parameters - BSS parameters |
316 | * | 316 | * |
317 | * Used to change BSS parameters (mainly for AP mode). | 317 | * Used to change BSS parameters (mainly for AP mode). |
318 | * | 318 | * |
319 | * @use_cts_prot: Whether to use CTS protection | 319 | * @use_cts_prot: Whether to use CTS protection |
320 | * (0 = no, 1 = yes, -1 = do not change) | 320 | * (0 = no, 1 = yes, -1 = do not change) |
321 | * @use_short_preamble: Whether the use of short preambles is allowed | 321 | * @use_short_preamble: Whether the use of short preambles is allowed |
322 | * (0 = no, 1 = yes, -1 = do not change) | 322 | * (0 = no, 1 = yes, -1 = do not change) |
323 | * @use_short_slot_time: Whether the use of short slot time is allowed | 323 | * @use_short_slot_time: Whether the use of short slot time is allowed |
324 | * (0 = no, 1 = yes, -1 = do not change) | 324 | * (0 = no, 1 = yes, -1 = do not change) |
325 | * @basic_rates: basic rates in IEEE 802.11 format | 325 | * @basic_rates: basic rates in IEEE 802.11 format |
326 | * (or NULL for no change) | 326 | * (or NULL for no change) |
327 | * @basic_rates_len: number of basic rates | 327 | * @basic_rates_len: number of basic rates |
328 | */ | 328 | */ |
329 | struct bss_parameters { | 329 | struct bss_parameters { |
330 | int use_cts_prot; | 330 | int use_cts_prot; |
331 | int use_short_preamble; | 331 | int use_short_preamble; |
332 | int use_short_slot_time; | 332 | int use_short_slot_time; |
333 | u8 *basic_rates; | 333 | u8 *basic_rates; |
334 | u8 basic_rates_len; | 334 | u8 basic_rates_len; |
335 | }; | 335 | }; |
336 | 336 | ||
337 | /** | 337 | /** |
338 | * enum reg_set_by - Indicates who is trying to set the regulatory domain | 338 | * enum reg_set_by - Indicates who is trying to set the regulatory domain |
339 | * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be | 339 | * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be |
340 | * using a static world regulatory domain by default. | 340 | * using a static world regulatory domain by default. |
341 | * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain. | 341 | * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain. |
342 | * @REGDOM_SET_BY_USER: User asked the wireless core to set the | 342 | * @REGDOM_SET_BY_USER: User asked the wireless core to set the |
343 | * regulatory domain. | 343 | * regulatory domain. |
344 | * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core | 344 | * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core |
345 | * it thinks its knows the regulatory domain we should be in. | 345 | * it thinks its knows the regulatory domain we should be in. |
346 | * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country | 346 | * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country |
347 | * information element with regulatory information it thinks we | 347 | * information element with regulatory information it thinks we |
348 | * should consider. | 348 | * should consider. |
349 | */ | 349 | */ |
350 | enum reg_set_by { | 350 | enum reg_set_by { |
351 | REGDOM_SET_BY_INIT, | 351 | REGDOM_SET_BY_INIT, |
352 | REGDOM_SET_BY_CORE, | 352 | REGDOM_SET_BY_CORE, |
353 | REGDOM_SET_BY_USER, | 353 | REGDOM_SET_BY_USER, |
354 | REGDOM_SET_BY_DRIVER, | 354 | REGDOM_SET_BY_DRIVER, |
355 | REGDOM_SET_BY_COUNTRY_IE, | 355 | REGDOM_SET_BY_COUNTRY_IE, |
356 | }; | 356 | }; |
357 | 357 | ||
358 | struct ieee80211_freq_range { | 358 | struct ieee80211_freq_range { |
359 | u32 start_freq_khz; | 359 | u32 start_freq_khz; |
360 | u32 end_freq_khz; | 360 | u32 end_freq_khz; |
361 | u32 max_bandwidth_khz; | 361 | u32 max_bandwidth_khz; |
362 | }; | 362 | }; |
363 | 363 | ||
364 | struct ieee80211_power_rule { | 364 | struct ieee80211_power_rule { |
365 | u32 max_antenna_gain; | 365 | u32 max_antenna_gain; |
366 | u32 max_eirp; | 366 | u32 max_eirp; |
367 | }; | 367 | }; |
368 | 368 | ||
369 | struct ieee80211_reg_rule { | 369 | struct ieee80211_reg_rule { |
370 | struct ieee80211_freq_range freq_range; | 370 | struct ieee80211_freq_range freq_range; |
371 | struct ieee80211_power_rule power_rule; | 371 | struct ieee80211_power_rule power_rule; |
372 | u32 flags; | 372 | u32 flags; |
373 | }; | 373 | }; |
374 | 374 | ||
375 | struct ieee80211_regdomain { | 375 | struct ieee80211_regdomain { |
376 | u32 n_reg_rules; | 376 | u32 n_reg_rules; |
377 | char alpha2[2]; | 377 | char alpha2[2]; |
378 | struct ieee80211_reg_rule reg_rules[]; | 378 | struct ieee80211_reg_rule reg_rules[]; |
379 | }; | 379 | }; |
380 | 380 | ||
381 | #define MHZ_TO_KHZ(freq) ((freq) * 1000) | 381 | #define MHZ_TO_KHZ(freq) ((freq) * 1000) |
382 | #define KHZ_TO_MHZ(freq) ((freq) / 1000) | 382 | #define KHZ_TO_MHZ(freq) ((freq) / 1000) |
383 | #define DBI_TO_MBI(gain) ((gain) * 100) | 383 | #define DBI_TO_MBI(gain) ((gain) * 100) |
384 | #define MBI_TO_DBI(gain) ((gain) / 100) | 384 | #define MBI_TO_DBI(gain) ((gain) / 100) |
385 | #define DBM_TO_MBM(gain) ((gain) * 100) | 385 | #define DBM_TO_MBM(gain) ((gain) * 100) |
386 | #define MBM_TO_DBM(gain) ((gain) / 100) | 386 | #define MBM_TO_DBM(gain) ((gain) / 100) |
387 | 387 | ||
388 | #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \ | 388 | #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \ |
389 | .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ | 389 | .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ |
390 | .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ | 390 | .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ |
391 | .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ | 391 | .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ |
392 | .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ | 392 | .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ |
393 | .power_rule.max_eirp = DBM_TO_MBM(eirp), \ | 393 | .power_rule.max_eirp = DBM_TO_MBM(eirp), \ |
394 | .flags = reg_flags, \ | 394 | .flags = reg_flags, \ |
395 | } | 395 | } |
396 | 396 | ||
397 | struct mesh_config { | 397 | struct mesh_config { |
398 | /* Timeouts in ms */ | 398 | /* Timeouts in ms */ |
399 | /* Mesh plink management parameters */ | 399 | /* Mesh plink management parameters */ |
400 | u16 dot11MeshRetryTimeout; | 400 | u16 dot11MeshRetryTimeout; |
401 | u16 dot11MeshConfirmTimeout; | 401 | u16 dot11MeshConfirmTimeout; |
402 | u16 dot11MeshHoldingTimeout; | 402 | u16 dot11MeshHoldingTimeout; |
403 | u16 dot11MeshMaxPeerLinks; | 403 | u16 dot11MeshMaxPeerLinks; |
404 | u8 dot11MeshMaxRetries; | 404 | u8 dot11MeshMaxRetries; |
405 | u8 dot11MeshTTL; | 405 | u8 dot11MeshTTL; |
406 | bool auto_open_plinks; | 406 | bool auto_open_plinks; |
407 | /* HWMP parameters */ | 407 | /* HWMP parameters */ |
408 | u8 dot11MeshHWMPmaxPREQretries; | 408 | u8 dot11MeshHWMPmaxPREQretries; |
409 | u32 path_refresh_time; | 409 | u32 path_refresh_time; |
410 | u16 min_discovery_timeout; | 410 | u16 min_discovery_timeout; |
411 | u32 dot11MeshHWMPactivePathTimeout; | 411 | u32 dot11MeshHWMPactivePathTimeout; |
412 | u16 dot11MeshHWMPpreqMinInterval; | 412 | u16 dot11MeshHWMPpreqMinInterval; |
413 | u16 dot11MeshHWMPnetDiameterTraversalTime; | 413 | u16 dot11MeshHWMPnetDiameterTraversalTime; |
414 | }; | 414 | }; |
415 | 415 | ||
416 | /** | 416 | /** |
417 | * struct ieee80211_txq_params - TX queue parameters | 417 | * struct ieee80211_txq_params - TX queue parameters |
418 | * @queue: TX queue identifier (NL80211_TXQ_Q_*) | 418 | * @queue: TX queue identifier (NL80211_TXQ_Q_*) |
419 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled | 419 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled |
420 | * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range | 420 | * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range |
421 | * 1..32767] | 421 | * 1..32767] |
422 | * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range | 422 | * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range |
423 | * 1..32767] | 423 | * 1..32767] |
424 | * @aifs: Arbitration interframe space [0..255] | 424 | * @aifs: Arbitration interframe space [0..255] |
425 | */ | 425 | */ |
426 | struct ieee80211_txq_params { | 426 | struct ieee80211_txq_params { |
427 | enum nl80211_txq_q queue; | 427 | enum nl80211_txq_q queue; |
428 | u16 txop; | 428 | u16 txop; |
429 | u16 cwmin; | 429 | u16 cwmin; |
430 | u16 cwmax; | 430 | u16 cwmax; |
431 | u8 aifs; | 431 | u8 aifs; |
432 | }; | 432 | }; |
433 | 433 | ||
434 | /* from net/wireless.h */ | 434 | /* from net/wireless.h */ |
435 | struct wiphy; | 435 | struct wiphy; |
436 | 436 | ||
437 | /* from net/ieee80211.h */ | 437 | /* from net/ieee80211.h */ |
438 | struct ieee80211_channel; | 438 | struct ieee80211_channel; |
439 | 439 | ||
440 | /** | 440 | /** |
441 | * struct cfg80211_ops - backend description for wireless configuration | 441 | * struct cfg80211_ops - backend description for wireless configuration |
442 | * | 442 | * |
443 | * This struct is registered by fullmac card drivers and/or wireless stacks | 443 | * This struct is registered by fullmac card drivers and/or wireless stacks |
444 | * in order to handle configuration requests on their interfaces. | 444 | * in order to handle configuration requests on their interfaces. |
445 | * | 445 | * |
446 | * All callbacks except where otherwise noted should return 0 | 446 | * All callbacks except where otherwise noted should return 0 |
447 | * on success or a negative error code. | 447 | * on success or a negative error code. |
448 | * | 448 | * |
449 | * All operations are currently invoked under rtnl for consistency with the | 449 | * All operations are currently invoked under rtnl for consistency with the |
450 | * wireless extensions but this is subject to reevaluation as soon as this | 450 | * wireless extensions but this is subject to reevaluation as soon as this |
451 | * code is used more widely and we have a first user without wext. | 451 | * code is used more widely and we have a first user without wext. |
452 | * | 452 | * |
453 | * @add_virtual_intf: create a new virtual interface with the given name, | 453 | * @add_virtual_intf: create a new virtual interface with the given name, |
454 | * must set the struct wireless_dev's iftype. | 454 | * must set the struct wireless_dev's iftype. |
455 | * | 455 | * |
456 | * @del_virtual_intf: remove the virtual interface determined by ifindex. | 456 | * @del_virtual_intf: remove the virtual interface determined by ifindex. |
457 | * | 457 | * |
458 | * @change_virtual_intf: change type/configuration of virtual interface, | 458 | * @change_virtual_intf: change type/configuration of virtual interface, |
459 | * keep the struct wireless_dev's iftype updated. | 459 | * keep the struct wireless_dev's iftype updated. |
460 | * | 460 | * |
461 | * @add_key: add a key with the given parameters. @mac_addr will be %NULL | 461 | * @add_key: add a key with the given parameters. @mac_addr will be %NULL |
462 | * when adding a group key. | 462 | * when adding a group key. |
463 | * | 463 | * |
464 | * @get_key: get information about the key with the given parameters. | 464 | * @get_key: get information about the key with the given parameters. |
465 | * @mac_addr will be %NULL when requesting information for a group | 465 | * @mac_addr will be %NULL when requesting information for a group |
466 | * key. All pointers given to the @callback function need not be valid | 466 | * key. All pointers given to the @callback function need not be valid |
467 | * after it returns. | 467 | * after it returns. |
468 | * | 468 | * |
469 | * @del_key: remove a key given the @mac_addr (%NULL for a group key) | 469 | * @del_key: remove a key given the @mac_addr (%NULL for a group key) |
470 | * and @key_index | 470 | * and @key_index |
471 | * | 471 | * |
472 | * @set_default_key: set the default key on an interface | 472 | * @set_default_key: set the default key on an interface |
473 | * | 473 | * |
474 | * @add_beacon: Add a beacon with given parameters, @head, @interval | 474 | * @add_beacon: Add a beacon with given parameters, @head, @interval |
475 | * and @dtim_period will be valid, @tail is optional. | 475 | * and @dtim_period will be valid, @tail is optional. |
476 | * @set_beacon: Change the beacon parameters for an access point mode | 476 | * @set_beacon: Change the beacon parameters for an access point mode |
477 | * interface. This should reject the call when no beacon has been | 477 | * interface. This should reject the call when no beacon has been |
478 | * configured. | 478 | * configured. |
479 | * @del_beacon: Remove beacon configuration and stop sending the beacon. | 479 | * @del_beacon: Remove beacon configuration and stop sending the beacon. |
480 | * | 480 | * |
481 | * @add_station: Add a new station. | 481 | * @add_station: Add a new station. |
482 | * | 482 | * |
483 | * @del_station: Remove a station; @mac may be NULL to remove all stations. | 483 | * @del_station: Remove a station; @mac may be NULL to remove all stations. |
484 | * | 484 | * |
485 | * @change_station: Modify a given station. | 485 | * @change_station: Modify a given station. |
486 | * | 486 | * |
487 | * @get_mesh_params: Put the current mesh parameters into *params | 487 | * @get_mesh_params: Put the current mesh parameters into *params |
488 | * | 488 | * |
489 | * @set_mesh_params: Set mesh parameters. | 489 | * @set_mesh_params: Set mesh parameters. |
490 | * The mask is a bitfield which tells us which parameters to | 490 | * The mask is a bitfield which tells us which parameters to |
491 | * set, and which to leave alone. | 491 | * set, and which to leave alone. |
492 | * | 492 | * |
493 | * @set_mesh_cfg: set mesh parameters (by now, just mesh id) | 493 | * @set_mesh_cfg: set mesh parameters (by now, just mesh id) |
494 | * | 494 | * |
495 | * @change_bss: Modify parameters for a given BSS. | 495 | * @change_bss: Modify parameters for a given BSS. |
496 | * | 496 | * |
497 | * @set_txq_params: Set TX queue parameters | 497 | * @set_txq_params: Set TX queue parameters |
498 | * | 498 | * |
499 | * @set_channel: Set channel | 499 | * @set_channel: Set channel |
500 | */ | 500 | */ |
501 | struct cfg80211_ops { | 501 | struct cfg80211_ops { |
502 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 502 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
503 | enum nl80211_iftype type, u32 *flags, | 503 | enum nl80211_iftype type, u32 *flags, |
504 | struct vif_params *params); | 504 | struct vif_params *params); |
505 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); | 505 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); |
506 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, | 506 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, |
507 | enum nl80211_iftype type, u32 *flags, | 507 | enum nl80211_iftype type, u32 *flags, |
508 | struct vif_params *params); | 508 | struct vif_params *params); |
509 | 509 | ||
510 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, | 510 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, |
511 | u8 key_index, u8 *mac_addr, | 511 | u8 key_index, u8 *mac_addr, |
512 | struct key_params *params); | 512 | struct key_params *params); |
513 | int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, | 513 | int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, |
514 | u8 key_index, u8 *mac_addr, void *cookie, | 514 | u8 key_index, u8 *mac_addr, void *cookie, |
515 | void (*callback)(void *cookie, struct key_params*)); | 515 | void (*callback)(void *cookie, struct key_params*)); |
516 | int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, | 516 | int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, |
517 | u8 key_index, u8 *mac_addr); | 517 | u8 key_index, u8 *mac_addr); |
518 | int (*set_default_key)(struct wiphy *wiphy, | 518 | int (*set_default_key)(struct wiphy *wiphy, |
519 | struct net_device *netdev, | 519 | struct net_device *netdev, |
520 | u8 key_index); | 520 | u8 key_index); |
521 | 521 | ||
522 | int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, | 522 | int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, |
523 | struct beacon_parameters *info); | 523 | struct beacon_parameters *info); |
524 | int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, | 524 | int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, |
525 | struct beacon_parameters *info); | 525 | struct beacon_parameters *info); |
526 | int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); | 526 | int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); |
527 | 527 | ||
528 | 528 | ||
529 | int (*add_station)(struct wiphy *wiphy, struct net_device *dev, | 529 | int (*add_station)(struct wiphy *wiphy, struct net_device *dev, |
530 | u8 *mac, struct station_parameters *params); | 530 | u8 *mac, struct station_parameters *params); |
531 | int (*del_station)(struct wiphy *wiphy, struct net_device *dev, | 531 | int (*del_station)(struct wiphy *wiphy, struct net_device *dev, |
532 | u8 *mac); | 532 | u8 *mac); |
533 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, | 533 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, |
534 | u8 *mac, struct station_parameters *params); | 534 | u8 *mac, struct station_parameters *params); |
535 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, | 535 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, |
536 | u8 *mac, struct station_info *sinfo); | 536 | u8 *mac, struct station_info *sinfo); |
537 | int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, | 537 | int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, |
538 | int idx, u8 *mac, struct station_info *sinfo); | 538 | int idx, u8 *mac, struct station_info *sinfo); |
539 | 539 | ||
540 | int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, | 540 | int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, |
541 | u8 *dst, u8 *next_hop); | 541 | u8 *dst, u8 *next_hop); |
542 | int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, | 542 | int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, |
543 | u8 *dst); | 543 | u8 *dst); |
544 | int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, | 544 | int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, |
545 | u8 *dst, u8 *next_hop); | 545 | u8 *dst, u8 *next_hop); |
546 | int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, | 546 | int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, |
547 | u8 *dst, u8 *next_hop, | 547 | u8 *dst, u8 *next_hop, |
548 | struct mpath_info *pinfo); | 548 | struct mpath_info *pinfo); |
549 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, | 549 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, |
550 | int idx, u8 *dst, u8 *next_hop, | 550 | int idx, u8 *dst, u8 *next_hop, |
551 | struct mpath_info *pinfo); | 551 | struct mpath_info *pinfo); |
552 | int (*get_mesh_params)(struct wiphy *wiphy, | 552 | int (*get_mesh_params)(struct wiphy *wiphy, |
553 | struct net_device *dev, | 553 | struct net_device *dev, |
554 | struct mesh_config *conf); | 554 | struct mesh_config *conf); |
555 | int (*set_mesh_params)(struct wiphy *wiphy, | 555 | int (*set_mesh_params)(struct wiphy *wiphy, |
556 | struct net_device *dev, | 556 | struct net_device *dev, |
557 | const struct mesh_config *nconf, u32 mask); | 557 | const struct mesh_config *nconf, u32 mask); |
558 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, | 558 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, |
559 | struct bss_parameters *params); | 559 | struct bss_parameters *params); |
560 | 560 | ||
561 | int (*set_txq_params)(struct wiphy *wiphy, | 561 | int (*set_txq_params)(struct wiphy *wiphy, |
562 | struct ieee80211_txq_params *params); | 562 | struct ieee80211_txq_params *params); |
563 | 563 | ||
564 | int (*set_channel)(struct wiphy *wiphy, | 564 | int (*set_channel)(struct wiphy *wiphy, |
565 | struct ieee80211_channel *chan, | 565 | struct ieee80211_channel *chan, |
566 | enum nl80211_sec_chan_offset); | 566 | enum nl80211_channel_type channel_type); |
567 | }; | 567 | }; |
568 | 568 | ||
569 | /* temporary wext handlers */ | 569 | /* temporary wext handlers */ |
570 | int cfg80211_wext_giwname(struct net_device *dev, | 570 | int cfg80211_wext_giwname(struct net_device *dev, |
571 | struct iw_request_info *info, | 571 | struct iw_request_info *info, |
572 | char *name, char *extra); | 572 | char *name, char *extra); |
573 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | 573 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, |
574 | u32 *mode, char *extra); | 574 | u32 *mode, char *extra); |
575 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | 575 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, |
576 | u32 *mode, char *extra); | 576 | u32 *mode, char *extra); |
577 | 577 | ||
578 | #endif /* __NET_CFG80211_H */ | 578 | #endif /* __NET_CFG80211_H */ |
579 | 579 |
include/net/mac80211.h
1 | /* | 1 | /* |
2 | * mac80211 <-> driver interface | 2 | * mac80211 <-> driver interface |
3 | * | 3 | * |
4 | * Copyright 2002-2005, Devicescape Software, Inc. | 4 | * Copyright 2002-2005, Devicescape Software, Inc. |
5 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 5 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
6 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef MAC80211_H | 13 | #ifndef MAC80211_H |
14 | #define MAC80211_H | 14 | #define MAC80211_H |
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/if_ether.h> | 17 | #include <linux/if_ether.h> |
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/wireless.h> | 19 | #include <linux/wireless.h> |
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/ieee80211.h> | 21 | #include <linux/ieee80211.h> |
22 | #include <net/wireless.h> | 22 | #include <net/wireless.h> |
23 | #include <net/cfg80211.h> | 23 | #include <net/cfg80211.h> |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * DOC: Introduction | 26 | * DOC: Introduction |
27 | * | 27 | * |
28 | * mac80211 is the Linux stack for 802.11 hardware that implements | 28 | * mac80211 is the Linux stack for 802.11 hardware that implements |
29 | * only partial functionality in hard- or firmware. This document | 29 | * only partial functionality in hard- or firmware. This document |
30 | * defines the interface between mac80211 and low-level hardware | 30 | * defines the interface between mac80211 and low-level hardware |
31 | * drivers. | 31 | * drivers. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | /** | 34 | /** |
35 | * DOC: Calling mac80211 from interrupts | 35 | * DOC: Calling mac80211 from interrupts |
36 | * | 36 | * |
37 | * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be | 37 | * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be |
38 | * called in hardware interrupt context. The low-level driver must not call any | 38 | * called in hardware interrupt context. The low-level driver must not call any |
39 | * other functions in hardware interrupt context. If there is a need for such | 39 | * other functions in hardware interrupt context. If there is a need for such |
40 | * call, the low-level driver should first ACK the interrupt and perform the | 40 | * call, the low-level driver should first ACK the interrupt and perform the |
41 | * IEEE 802.11 code call after this, e.g. from a scheduled workqueue or even | 41 | * IEEE 802.11 code call after this, e.g. from a scheduled workqueue or even |
42 | * tasklet function. | 42 | * tasklet function. |
43 | * | 43 | * |
44 | * NOTE: If the driver opts to use the _irqsafe() functions, it may not also | 44 | * NOTE: If the driver opts to use the _irqsafe() functions, it may not also |
45 | * use the non-IRQ-safe functions! | 45 | * use the non-IRQ-safe functions! |
46 | */ | 46 | */ |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * DOC: Warning | 49 | * DOC: Warning |
50 | * | 50 | * |
51 | * If you're reading this document and not the header file itself, it will | 51 | * If you're reading this document and not the header file itself, it will |
52 | * be incomplete because not all documentation has been converted yet. | 52 | * be incomplete because not all documentation has been converted yet. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * DOC: Frame format | 56 | * DOC: Frame format |
57 | * | 57 | * |
58 | * As a general rule, when frames are passed between mac80211 and the driver, | 58 | * As a general rule, when frames are passed between mac80211 and the driver, |
59 | * they start with the IEEE 802.11 header and include the same octets that are | 59 | * they start with the IEEE 802.11 header and include the same octets that are |
60 | * sent over the air except for the FCS which should be calculated by the | 60 | * sent over the air except for the FCS which should be calculated by the |
61 | * hardware. | 61 | * hardware. |
62 | * | 62 | * |
63 | * There are, however, various exceptions to this rule for advanced features: | 63 | * There are, however, various exceptions to this rule for advanced features: |
64 | * | 64 | * |
65 | * The first exception is for hardware encryption and decryption offload | 65 | * The first exception is for hardware encryption and decryption offload |
66 | * where the IV/ICV may or may not be generated in hardware. | 66 | * where the IV/ICV may or may not be generated in hardware. |
67 | * | 67 | * |
68 | * Secondly, when the hardware handles fragmentation, the frame handed to | 68 | * Secondly, when the hardware handles fragmentation, the frame handed to |
69 | * the driver from mac80211 is the MSDU, not the MPDU. | 69 | * the driver from mac80211 is the MSDU, not the MPDU. |
70 | * | 70 | * |
71 | * Finally, for received frames, the driver is able to indicate that it has | 71 | * Finally, for received frames, the driver is able to indicate that it has |
72 | * filled a radiotap header and put that in front of the frame; if it does | 72 | * filled a radiotap header and put that in front of the frame; if it does |
73 | * not do so then mac80211 may add this under certain circumstances. | 73 | * not do so then mac80211 may add this under certain circumstances. |
74 | */ | 74 | */ |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * struct ieee80211_ht_bss_info - describing BSS's HT characteristics | 77 | * struct ieee80211_ht_bss_info - describing BSS's HT characteristics |
78 | * | 78 | * |
79 | * This structure describes most essential parameters needed | 79 | * This structure describes most essential parameters needed |
80 | * to describe 802.11n HT characteristics in a BSS. | 80 | * to describe 802.11n HT characteristics in a BSS. |
81 | * | 81 | * |
82 | * @primary_channel: channel number of primery channel | 82 | * @primary_channel: channel number of primery channel |
83 | * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width) | 83 | * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width) |
84 | * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection) | 84 | * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection) |
85 | */ | 85 | */ |
86 | struct ieee80211_ht_bss_info { | 86 | struct ieee80211_ht_bss_info { |
87 | u8 primary_channel; | 87 | u8 primary_channel; |
88 | u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */ | 88 | u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */ |
89 | u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ | 89 | u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ |
90 | }; | 90 | }; |
91 | 91 | ||
92 | /** | 92 | /** |
93 | * enum ieee80211_max_queues - maximum number of queues | 93 | * enum ieee80211_max_queues - maximum number of queues |
94 | * | 94 | * |
95 | * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. | 95 | * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. |
96 | * @IEEE80211_MAX_AMPDU_QUEUES: Maximum number of queues usable | 96 | * @IEEE80211_MAX_AMPDU_QUEUES: Maximum number of queues usable |
97 | * for A-MPDU operation. | 97 | * for A-MPDU operation. |
98 | */ | 98 | */ |
99 | enum ieee80211_max_queues { | 99 | enum ieee80211_max_queues { |
100 | IEEE80211_MAX_QUEUES = 16, | 100 | IEEE80211_MAX_QUEUES = 16, |
101 | IEEE80211_MAX_AMPDU_QUEUES = 16, | 101 | IEEE80211_MAX_AMPDU_QUEUES = 16, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /** | 104 | /** |
105 | * struct ieee80211_tx_queue_params - transmit queue configuration | 105 | * struct ieee80211_tx_queue_params - transmit queue configuration |
106 | * | 106 | * |
107 | * The information provided in this structure is required for QoS | 107 | * The information provided in this structure is required for QoS |
108 | * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. | 108 | * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. |
109 | * | 109 | * |
110 | * @aifs: arbitration interframe space [0..255] | 110 | * @aifs: arbitration interframe space [0..255] |
111 | * @cw_min: minimum contention window [a value of the form | 111 | * @cw_min: minimum contention window [a value of the form |
112 | * 2^n-1 in the range 1..32767] | 112 | * 2^n-1 in the range 1..32767] |
113 | * @cw_max: maximum contention window [like @cw_min] | 113 | * @cw_max: maximum contention window [like @cw_min] |
114 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled | 114 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled |
115 | */ | 115 | */ |
116 | struct ieee80211_tx_queue_params { | 116 | struct ieee80211_tx_queue_params { |
117 | u16 txop; | 117 | u16 txop; |
118 | u16 cw_min; | 118 | u16 cw_min; |
119 | u16 cw_max; | 119 | u16 cw_max; |
120 | u8 aifs; | 120 | u8 aifs; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * struct ieee80211_tx_queue_stats - transmit queue statistics | 124 | * struct ieee80211_tx_queue_stats - transmit queue statistics |
125 | * | 125 | * |
126 | * @len: number of packets in queue | 126 | * @len: number of packets in queue |
127 | * @limit: queue length limit | 127 | * @limit: queue length limit |
128 | * @count: number of frames sent | 128 | * @count: number of frames sent |
129 | */ | 129 | */ |
130 | struct ieee80211_tx_queue_stats { | 130 | struct ieee80211_tx_queue_stats { |
131 | unsigned int len; | 131 | unsigned int len; |
132 | unsigned int limit; | 132 | unsigned int limit; |
133 | unsigned int count; | 133 | unsigned int count; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | struct ieee80211_low_level_stats { | 136 | struct ieee80211_low_level_stats { |
137 | unsigned int dot11ACKFailureCount; | 137 | unsigned int dot11ACKFailureCount; |
138 | unsigned int dot11RTSFailureCount; | 138 | unsigned int dot11RTSFailureCount; |
139 | unsigned int dot11FCSErrorCount; | 139 | unsigned int dot11FCSErrorCount; |
140 | unsigned int dot11RTSSuccessCount; | 140 | unsigned int dot11RTSSuccessCount; |
141 | }; | 141 | }; |
142 | 142 | ||
143 | /** | 143 | /** |
144 | * enum ieee80211_bss_change - BSS change notification flags | 144 | * enum ieee80211_bss_change - BSS change notification flags |
145 | * | 145 | * |
146 | * These flags are used with the bss_info_changed() callback | 146 | * These flags are used with the bss_info_changed() callback |
147 | * to indicate which BSS parameter changed. | 147 | * to indicate which BSS parameter changed. |
148 | * | 148 | * |
149 | * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), | 149 | * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), |
150 | * also implies a change in the AID. | 150 | * also implies a change in the AID. |
151 | * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed | 151 | * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed |
152 | * @BSS_CHANGED_ERP_PREAMBLE: preamble changed | 152 | * @BSS_CHANGED_ERP_PREAMBLE: preamble changed |
153 | * @BSS_CHANGED_ERP_SLOT: slot timing changed | 153 | * @BSS_CHANGED_ERP_SLOT: slot timing changed |
154 | * @BSS_CHANGED_HT: 802.11n parameters changed | 154 | * @BSS_CHANGED_HT: 802.11n parameters changed |
155 | * @BSS_CHANGED_BASIC_RATES: Basic rateset changed | 155 | * @BSS_CHANGED_BASIC_RATES: Basic rateset changed |
156 | */ | 156 | */ |
157 | enum ieee80211_bss_change { | 157 | enum ieee80211_bss_change { |
158 | BSS_CHANGED_ASSOC = 1<<0, | 158 | BSS_CHANGED_ASSOC = 1<<0, |
159 | BSS_CHANGED_ERP_CTS_PROT = 1<<1, | 159 | BSS_CHANGED_ERP_CTS_PROT = 1<<1, |
160 | BSS_CHANGED_ERP_PREAMBLE = 1<<2, | 160 | BSS_CHANGED_ERP_PREAMBLE = 1<<2, |
161 | BSS_CHANGED_ERP_SLOT = 1<<3, | 161 | BSS_CHANGED_ERP_SLOT = 1<<3, |
162 | BSS_CHANGED_HT = 1<<4, | 162 | BSS_CHANGED_HT = 1<<4, |
163 | BSS_CHANGED_BASIC_RATES = 1<<5, | 163 | BSS_CHANGED_BASIC_RATES = 1<<5, |
164 | }; | 164 | }; |
165 | 165 | ||
166 | /** | 166 | /** |
167 | * struct ieee80211_bss_ht_conf - BSS's changing HT configuration | 167 | * struct ieee80211_bss_ht_conf - BSS's changing HT configuration |
168 | * @secondary_channel_offset: secondary channel offset, uses | ||
169 | * %IEEE80211_HT_PARAM_CHA_SEC_ values | ||
170 | * @width_40_ok: indicates that 40 MHz bandwidth may be used for TX | ||
171 | * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info) | 168 | * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info) |
172 | */ | 169 | */ |
173 | struct ieee80211_bss_ht_conf { | 170 | struct ieee80211_bss_ht_conf { |
174 | u8 secondary_channel_offset; | ||
175 | bool width_40_ok; | ||
176 | u16 operation_mode; | 171 | u16 operation_mode; |
177 | }; | 172 | }; |
178 | 173 | ||
179 | /** | 174 | /** |
180 | * struct ieee80211_bss_conf - holds the BSS's changing parameters | 175 | * struct ieee80211_bss_conf - holds the BSS's changing parameters |
181 | * | 176 | * |
182 | * This structure keeps information about a BSS (and an association | 177 | * This structure keeps information about a BSS (and an association |
183 | * to that BSS) that can change during the lifetime of the BSS. | 178 | * to that BSS) that can change during the lifetime of the BSS. |
184 | * | 179 | * |
185 | * @assoc: association status | 180 | * @assoc: association status |
186 | * @aid: association ID number, valid only when @assoc is true | 181 | * @aid: association ID number, valid only when @assoc is true |
187 | * @use_cts_prot: use CTS protection | 182 | * @use_cts_prot: use CTS protection |
188 | * @use_short_preamble: use 802.11b short preamble; | 183 | * @use_short_preamble: use 802.11b short preamble; |
189 | * if the hardware cannot handle this it must set the | 184 | * if the hardware cannot handle this it must set the |
190 | * IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag | 185 | * IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag |
191 | * @use_short_slot: use short slot time (only relevant for ERP); | 186 | * @use_short_slot: use short slot time (only relevant for ERP); |
192 | * if the hardware cannot handle this it must set the | 187 | * if the hardware cannot handle this it must set the |
193 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag | 188 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag |
194 | * @dtim_period: num of beacons before the next DTIM, for PSM | 189 | * @dtim_period: num of beacons before the next DTIM, for PSM |
195 | * @timestamp: beacon timestamp | 190 | * @timestamp: beacon timestamp |
196 | * @beacon_int: beacon interval | 191 | * @beacon_int: beacon interval |
197 | * @assoc_capability: capabilities taken from assoc resp | 192 | * @assoc_capability: capabilities taken from assoc resp |
198 | * @ht: BSS's HT configuration | 193 | * @ht: BSS's HT configuration |
199 | * @basic_rates: bitmap of basic rates, each bit stands for an | 194 | * @basic_rates: bitmap of basic rates, each bit stands for an |
200 | * index into the rate table configured by the driver in | 195 | * index into the rate table configured by the driver in |
201 | * the current band. | 196 | * the current band. |
202 | */ | 197 | */ |
203 | struct ieee80211_bss_conf { | 198 | struct ieee80211_bss_conf { |
204 | /* association related data */ | 199 | /* association related data */ |
205 | bool assoc; | 200 | bool assoc; |
206 | u16 aid; | 201 | u16 aid; |
207 | /* erp related data */ | 202 | /* erp related data */ |
208 | bool use_cts_prot; | 203 | bool use_cts_prot; |
209 | bool use_short_preamble; | 204 | bool use_short_preamble; |
210 | bool use_short_slot; | 205 | bool use_short_slot; |
211 | u8 dtim_period; | 206 | u8 dtim_period; |
212 | u16 beacon_int; | 207 | u16 beacon_int; |
213 | u16 assoc_capability; | 208 | u16 assoc_capability; |
214 | u64 timestamp; | 209 | u64 timestamp; |
215 | u64 basic_rates; | 210 | u64 basic_rates; |
216 | struct ieee80211_bss_ht_conf ht; | 211 | struct ieee80211_bss_ht_conf ht; |
217 | }; | 212 | }; |
218 | 213 | ||
219 | /** | 214 | /** |
220 | * enum mac80211_tx_control_flags - flags to describe transmission information/status | 215 | * enum mac80211_tx_control_flags - flags to describe transmission information/status |
221 | * | 216 | * |
222 | * These flags are used with the @flags member of &ieee80211_tx_info. | 217 | * These flags are used with the @flags member of &ieee80211_tx_info. |
223 | * | 218 | * |
224 | * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. | 219 | * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. |
225 | * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence | 220 | * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence |
226 | * number to this frame, taking care of not overwriting the fragment | 221 | * number to this frame, taking care of not overwriting the fragment |
227 | * number and increasing the sequence number only when the | 222 | * number and increasing the sequence number only when the |
228 | * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly | 223 | * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly |
229 | * assign sequence numbers to QoS-data frames but cannot do so correctly | 224 | * assign sequence numbers to QoS-data frames but cannot do so correctly |
230 | * for non-QoS-data and management frames because beacons need them from | 225 | * for non-QoS-data and management frames because beacons need them from |
231 | * that counter as well and mac80211 cannot guarantee proper sequencing. | 226 | * that counter as well and mac80211 cannot guarantee proper sequencing. |
232 | * If this flag is set, the driver should instruct the hardware to | 227 | * If this flag is set, the driver should instruct the hardware to |
233 | * assign a sequence number to the frame or assign one itself. Cf. IEEE | 228 | * assign a sequence number to the frame or assign one itself. Cf. IEEE |
234 | * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for | 229 | * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for |
235 | * beacons and always be clear for frames without a sequence number field. | 230 | * beacons and always be clear for frames without a sequence number field. |
236 | * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack | 231 | * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack |
237 | * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination | 232 | * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination |
238 | * station | 233 | * station |
239 | * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame | 234 | * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame |
240 | * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon | 235 | * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon |
241 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU | 236 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU |
242 | * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. | 237 | * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. |
243 | * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted | 238 | * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted |
244 | * because the destination STA was in powersave mode. | 239 | * because the destination STA was in powersave mode. |
245 | * @IEEE80211_TX_STAT_ACK: Frame was acknowledged | 240 | * @IEEE80211_TX_STAT_ACK: Frame was acknowledged |
246 | * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status | 241 | * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status |
247 | * is for the whole aggregation. | 242 | * is for the whole aggregation. |
248 | * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, | 243 | * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, |
249 | * so consider using block ack request (BAR). | 244 | * so consider using block ack request (BAR). |
250 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be | 245 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be |
251 | * set by rate control algorithms to indicate probe rate, will | 246 | * set by rate control algorithms to indicate probe rate, will |
252 | * be cleared for fragmented frames (except on the last fragment) | 247 | * be cleared for fragmented frames (except on the last fragment) |
253 | */ | 248 | */ |
254 | enum mac80211_tx_control_flags { | 249 | enum mac80211_tx_control_flags { |
255 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), | 250 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), |
256 | IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), | 251 | IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), |
257 | IEEE80211_TX_CTL_NO_ACK = BIT(2), | 252 | IEEE80211_TX_CTL_NO_ACK = BIT(2), |
258 | IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), | 253 | IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), |
259 | IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), | 254 | IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), |
260 | IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), | 255 | IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), |
261 | IEEE80211_TX_CTL_AMPDU = BIT(6), | 256 | IEEE80211_TX_CTL_AMPDU = BIT(6), |
262 | IEEE80211_TX_CTL_INJECTED = BIT(7), | 257 | IEEE80211_TX_CTL_INJECTED = BIT(7), |
263 | IEEE80211_TX_STAT_TX_FILTERED = BIT(8), | 258 | IEEE80211_TX_STAT_TX_FILTERED = BIT(8), |
264 | IEEE80211_TX_STAT_ACK = BIT(9), | 259 | IEEE80211_TX_STAT_ACK = BIT(9), |
265 | IEEE80211_TX_STAT_AMPDU = BIT(10), | 260 | IEEE80211_TX_STAT_AMPDU = BIT(10), |
266 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), | 261 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), |
267 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), | 262 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), |
268 | }; | 263 | }; |
269 | 264 | ||
270 | enum mac80211_rate_control_flags { | 265 | enum mac80211_rate_control_flags { |
271 | IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), | 266 | IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), |
272 | IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), | 267 | IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), |
273 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), | 268 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), |
274 | 269 | ||
275 | /* rate index is an MCS rate number instead of an index */ | 270 | /* rate index is an MCS rate number instead of an index */ |
276 | IEEE80211_TX_RC_MCS = BIT(3), | 271 | IEEE80211_TX_RC_MCS = BIT(3), |
277 | IEEE80211_TX_RC_GREEN_FIELD = BIT(4), | 272 | IEEE80211_TX_RC_GREEN_FIELD = BIT(4), |
278 | IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), | 273 | IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), |
279 | IEEE80211_TX_RC_DUP_DATA = BIT(6), | 274 | IEEE80211_TX_RC_DUP_DATA = BIT(6), |
280 | IEEE80211_TX_RC_SHORT_GI = BIT(7), | 275 | IEEE80211_TX_RC_SHORT_GI = BIT(7), |
281 | }; | 276 | }; |
282 | 277 | ||
283 | 278 | ||
284 | /* there are 40 bytes if you don't need the rateset to be kept */ | 279 | /* there are 40 bytes if you don't need the rateset to be kept */ |
285 | #define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 | 280 | #define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 |
286 | 281 | ||
287 | /* if you do need the rateset, then you have less space */ | 282 | /* if you do need the rateset, then you have less space */ |
288 | #define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 | 283 | #define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 |
289 | 284 | ||
290 | /* maximum number of rate stages */ | 285 | /* maximum number of rate stages */ |
291 | #define IEEE80211_TX_MAX_RATES 5 | 286 | #define IEEE80211_TX_MAX_RATES 5 |
292 | 287 | ||
293 | /** | 288 | /** |
294 | * struct ieee80211_tx_rate - rate selection/status | 289 | * struct ieee80211_tx_rate - rate selection/status |
295 | * | 290 | * |
296 | * @idx: rate index to attempt to send with | 291 | * @idx: rate index to attempt to send with |
297 | * @flags: rate control flags (&enum mac80211_rate_control_flags) | 292 | * @flags: rate control flags (&enum mac80211_rate_control_flags) |
298 | * @count: number of tries in this rate before going to the next rate | 293 | * @count: number of tries in this rate before going to the next rate |
299 | * | 294 | * |
300 | * A value of -1 for @idx indicates an invalid rate and, if used | 295 | * A value of -1 for @idx indicates an invalid rate and, if used |
301 | * in an array of retry rates, that no more rates should be tried. | 296 | * in an array of retry rates, that no more rates should be tried. |
302 | * | 297 | * |
303 | * When used for transmit status reporting, the driver should | 298 | * When used for transmit status reporting, the driver should |
304 | * always report the rate along with the flags it used. | 299 | * always report the rate along with the flags it used. |
305 | */ | 300 | */ |
306 | struct ieee80211_tx_rate { | 301 | struct ieee80211_tx_rate { |
307 | s8 idx; | 302 | s8 idx; |
308 | u8 count; | 303 | u8 count; |
309 | u8 flags; | 304 | u8 flags; |
310 | } __attribute__((packed)); | 305 | } __attribute__((packed)); |
311 | 306 | ||
312 | /** | 307 | /** |
313 | * struct ieee80211_tx_info - skb transmit information | 308 | * struct ieee80211_tx_info - skb transmit information |
314 | * | 309 | * |
315 | * This structure is placed in skb->cb for three uses: | 310 | * This structure is placed in skb->cb for three uses: |
316 | * (1) mac80211 TX control - mac80211 tells the driver what to do | 311 | * (1) mac80211 TX control - mac80211 tells the driver what to do |
317 | * (2) driver internal use (if applicable) | 312 | * (2) driver internal use (if applicable) |
318 | * (3) TX status information - driver tells mac80211 what happened | 313 | * (3) TX status information - driver tells mac80211 what happened |
319 | * | 314 | * |
320 | * The TX control's sta pointer is only valid during the ->tx call, | 315 | * The TX control's sta pointer is only valid during the ->tx call, |
321 | * it may be NULL. | 316 | * it may be NULL. |
322 | * | 317 | * |
323 | * @flags: transmit info flags, defined above | 318 | * @flags: transmit info flags, defined above |
324 | * @band: the band to transmit on (use for checking for races) | 319 | * @band: the band to transmit on (use for checking for races) |
325 | * @antenna_sel_tx: antenna to use, 0 for automatic diversity | 320 | * @antenna_sel_tx: antenna to use, 0 for automatic diversity |
326 | * @pad: padding, ignore | 321 | * @pad: padding, ignore |
327 | * @control: union for control data | 322 | * @control: union for control data |
328 | * @status: union for status data | 323 | * @status: union for status data |
329 | * @driver_data: array of driver_data pointers | 324 | * @driver_data: array of driver_data pointers |
330 | * @retry_count: number of retries | 325 | * @retry_count: number of retries |
331 | * @ampdu_ack_len: number of aggregated frames. | 326 | * @ampdu_ack_len: number of aggregated frames. |
332 | * relevant only if IEEE80211_TX_STATUS_AMPDU was set. | 327 | * relevant only if IEEE80211_TX_STATUS_AMPDU was set. |
333 | * @ampdu_ack_map: block ack bit map for the aggregation. | 328 | * @ampdu_ack_map: block ack bit map for the aggregation. |
334 | * relevant only if IEEE80211_TX_STATUS_AMPDU was set. | 329 | * relevant only if IEEE80211_TX_STATUS_AMPDU was set. |
335 | * @ack_signal: signal strength of the ACK frame | 330 | * @ack_signal: signal strength of the ACK frame |
336 | */ | 331 | */ |
337 | struct ieee80211_tx_info { | 332 | struct ieee80211_tx_info { |
338 | /* common information */ | 333 | /* common information */ |
339 | u32 flags; | 334 | u32 flags; |
340 | u8 band; | 335 | u8 band; |
341 | 336 | ||
342 | u8 antenna_sel_tx; | 337 | u8 antenna_sel_tx; |
343 | 338 | ||
344 | /* 2 byte hole */ | 339 | /* 2 byte hole */ |
345 | u8 pad[2]; | 340 | u8 pad[2]; |
346 | 341 | ||
347 | union { | 342 | union { |
348 | struct { | 343 | struct { |
349 | union { | 344 | union { |
350 | /* rate control */ | 345 | /* rate control */ |
351 | struct { | 346 | struct { |
352 | struct ieee80211_tx_rate rates[ | 347 | struct ieee80211_tx_rate rates[ |
353 | IEEE80211_TX_MAX_RATES]; | 348 | IEEE80211_TX_MAX_RATES]; |
354 | s8 rts_cts_rate_idx; | 349 | s8 rts_cts_rate_idx; |
355 | }; | 350 | }; |
356 | /* only needed before rate control */ | 351 | /* only needed before rate control */ |
357 | unsigned long jiffies; | 352 | unsigned long jiffies; |
358 | }; | 353 | }; |
359 | /* NB: vif can be NULL for injected frames */ | 354 | /* NB: vif can be NULL for injected frames */ |
360 | struct ieee80211_vif *vif; | 355 | struct ieee80211_vif *vif; |
361 | struct ieee80211_key_conf *hw_key; | 356 | struct ieee80211_key_conf *hw_key; |
362 | struct ieee80211_sta *sta; | 357 | struct ieee80211_sta *sta; |
363 | } control; | 358 | } control; |
364 | struct { | 359 | struct { |
365 | struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; | 360 | struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; |
366 | u8 ampdu_ack_len; | 361 | u8 ampdu_ack_len; |
367 | u64 ampdu_ack_map; | 362 | u64 ampdu_ack_map; |
368 | int ack_signal; | 363 | int ack_signal; |
369 | /* 8 bytes free */ | 364 | /* 8 bytes free */ |
370 | } status; | 365 | } status; |
371 | struct { | 366 | struct { |
372 | struct ieee80211_tx_rate driver_rates[ | 367 | struct ieee80211_tx_rate driver_rates[ |
373 | IEEE80211_TX_MAX_RATES]; | 368 | IEEE80211_TX_MAX_RATES]; |
374 | void *rate_driver_data[ | 369 | void *rate_driver_data[ |
375 | IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; | 370 | IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; |
376 | }; | 371 | }; |
377 | void *driver_data[ | 372 | void *driver_data[ |
378 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; | 373 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; |
379 | }; | 374 | }; |
380 | }; | 375 | }; |
381 | 376 | ||
382 | static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) | 377 | static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) |
383 | { | 378 | { |
384 | return (struct ieee80211_tx_info *)skb->cb; | 379 | return (struct ieee80211_tx_info *)skb->cb; |
385 | } | 380 | } |
386 | 381 | ||
387 | /** | 382 | /** |
388 | * ieee80211_tx_info_clear_status - clear TX status | 383 | * ieee80211_tx_info_clear_status - clear TX status |
389 | * | 384 | * |
390 | * @info: The &struct ieee80211_tx_info to be cleared. | 385 | * @info: The &struct ieee80211_tx_info to be cleared. |
391 | * | 386 | * |
392 | * When the driver passes an skb back to mac80211, it must report | 387 | * When the driver passes an skb back to mac80211, it must report |
393 | * a number of things in TX status. This function clears everything | 388 | * a number of things in TX status. This function clears everything |
394 | * in the TX status but the rate control information (it does clear | 389 | * in the TX status but the rate control information (it does clear |
395 | * the count since you need to fill that in anyway). | 390 | * the count since you need to fill that in anyway). |
396 | * | 391 | * |
397 | * NOTE: You can only use this function if you do NOT use | 392 | * NOTE: You can only use this function if you do NOT use |
398 | * info->driver_data! Use info->rate_driver_data | 393 | * info->driver_data! Use info->rate_driver_data |
399 | * instead if you need only the less space that allows. | 394 | * instead if you need only the less space that allows. |
400 | */ | 395 | */ |
401 | static inline void | 396 | static inline void |
402 | ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | 397 | ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) |
403 | { | 398 | { |
404 | int i; | 399 | int i; |
405 | 400 | ||
406 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != | 401 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != |
407 | offsetof(struct ieee80211_tx_info, control.rates)); | 402 | offsetof(struct ieee80211_tx_info, control.rates)); |
408 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != | 403 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != |
409 | offsetof(struct ieee80211_tx_info, driver_rates)); | 404 | offsetof(struct ieee80211_tx_info, driver_rates)); |
410 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); | 405 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); |
411 | /* clear the rate counts */ | 406 | /* clear the rate counts */ |
412 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) | 407 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) |
413 | info->status.rates[i].count = 0; | 408 | info->status.rates[i].count = 0; |
414 | 409 | ||
415 | BUILD_BUG_ON( | 410 | BUILD_BUG_ON( |
416 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); | 411 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); |
417 | memset(&info->status.ampdu_ack_len, 0, | 412 | memset(&info->status.ampdu_ack_len, 0, |
418 | sizeof(struct ieee80211_tx_info) - | 413 | sizeof(struct ieee80211_tx_info) - |
419 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); | 414 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); |
420 | } | 415 | } |
421 | 416 | ||
422 | 417 | ||
423 | /** | 418 | /** |
424 | * enum mac80211_rx_flags - receive flags | 419 | * enum mac80211_rx_flags - receive flags |
425 | * | 420 | * |
426 | * These flags are used with the @flag member of &struct ieee80211_rx_status. | 421 | * These flags are used with the @flag member of &struct ieee80211_rx_status. |
427 | * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. | 422 | * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. |
428 | * Use together with %RX_FLAG_MMIC_STRIPPED. | 423 | * Use together with %RX_FLAG_MMIC_STRIPPED. |
429 | * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. | 424 | * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. |
430 | * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header. | 425 | * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header. |
431 | * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, | 426 | * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, |
432 | * verification has been done by the hardware. | 427 | * verification has been done by the hardware. |
433 | * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. | 428 | * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. |
434 | * If this flag is set, the stack cannot do any replay detection | 429 | * If this flag is set, the stack cannot do any replay detection |
435 | * hence the driver or hardware will have to do that. | 430 | * hence the driver or hardware will have to do that. |
436 | * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on | 431 | * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on |
437 | * the frame. | 432 | * the frame. |
438 | * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on | 433 | * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on |
439 | * the frame. | 434 | * the frame. |
440 | * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field) | 435 | * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field) |
441 | * is valid. This is useful in monitor mode and necessary for beacon frames | 436 | * is valid. This is useful in monitor mode and necessary for beacon frames |
442 | * to enable IBSS merging. | 437 | * to enable IBSS merging. |
443 | * @RX_FLAG_SHORTPRE: Short preamble was used for this frame | 438 | * @RX_FLAG_SHORTPRE: Short preamble was used for this frame |
444 | */ | 439 | */ |
445 | enum mac80211_rx_flags { | 440 | enum mac80211_rx_flags { |
446 | RX_FLAG_MMIC_ERROR = 1<<0, | 441 | RX_FLAG_MMIC_ERROR = 1<<0, |
447 | RX_FLAG_DECRYPTED = 1<<1, | 442 | RX_FLAG_DECRYPTED = 1<<1, |
448 | RX_FLAG_RADIOTAP = 1<<2, | 443 | RX_FLAG_RADIOTAP = 1<<2, |
449 | RX_FLAG_MMIC_STRIPPED = 1<<3, | 444 | RX_FLAG_MMIC_STRIPPED = 1<<3, |
450 | RX_FLAG_IV_STRIPPED = 1<<4, | 445 | RX_FLAG_IV_STRIPPED = 1<<4, |
451 | RX_FLAG_FAILED_FCS_CRC = 1<<5, | 446 | RX_FLAG_FAILED_FCS_CRC = 1<<5, |
452 | RX_FLAG_FAILED_PLCP_CRC = 1<<6, | 447 | RX_FLAG_FAILED_PLCP_CRC = 1<<6, |
453 | RX_FLAG_TSFT = 1<<7, | 448 | RX_FLAG_TSFT = 1<<7, |
454 | RX_FLAG_SHORTPRE = 1<<8 | 449 | RX_FLAG_SHORTPRE = 1<<8 |
455 | }; | 450 | }; |
456 | 451 | ||
457 | /** | 452 | /** |
458 | * struct ieee80211_rx_status - receive status | 453 | * struct ieee80211_rx_status - receive status |
459 | * | 454 | * |
460 | * The low-level driver should provide this information (the subset | 455 | * The low-level driver should provide this information (the subset |
461 | * supported by hardware) to the 802.11 code with each received | 456 | * supported by hardware) to the 802.11 code with each received |
462 | * frame. | 457 | * frame. |
463 | * | 458 | * |
464 | * @mactime: value in microseconds of the 64-bit Time Synchronization Function | 459 | * @mactime: value in microseconds of the 64-bit Time Synchronization Function |
465 | * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. | 460 | * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. |
466 | * @band: the active band when this frame was received | 461 | * @band: the active band when this frame was received |
467 | * @freq: frequency the radio was tuned to when receiving this frame, in MHz | 462 | * @freq: frequency the radio was tuned to when receiving this frame, in MHz |
468 | * @signal: signal strength when receiving this frame, either in dBm, in dB or | 463 | * @signal: signal strength when receiving this frame, either in dBm, in dB or |
469 | * unspecified depending on the hardware capabilities flags | 464 | * unspecified depending on the hardware capabilities flags |
470 | * @IEEE80211_HW_SIGNAL_* | 465 | * @IEEE80211_HW_SIGNAL_* |
471 | * @noise: noise when receiving this frame, in dBm. | 466 | * @noise: noise when receiving this frame, in dBm. |
472 | * @qual: overall signal quality indication, in percent (0-100). | 467 | * @qual: overall signal quality indication, in percent (0-100). |
473 | * @antenna: antenna used | 468 | * @antenna: antenna used |
474 | * @rate_idx: index of data rate into band's supported rates | 469 | * @rate_idx: index of data rate into band's supported rates |
475 | * @flag: %RX_FLAG_* | 470 | * @flag: %RX_FLAG_* |
476 | */ | 471 | */ |
477 | struct ieee80211_rx_status { | 472 | struct ieee80211_rx_status { |
478 | u64 mactime; | 473 | u64 mactime; |
479 | enum ieee80211_band band; | 474 | enum ieee80211_band band; |
480 | int freq; | 475 | int freq; |
481 | int signal; | 476 | int signal; |
482 | int noise; | 477 | int noise; |
483 | int qual; | 478 | int qual; |
484 | int antenna; | 479 | int antenna; |
485 | int rate_idx; | 480 | int rate_idx; |
486 | int flag; | 481 | int flag; |
487 | }; | 482 | }; |
488 | 483 | ||
489 | /** | 484 | /** |
490 | * enum ieee80211_conf_flags - configuration flags | 485 | * enum ieee80211_conf_flags - configuration flags |
491 | * | 486 | * |
492 | * Flags to define PHY configuration options | 487 | * Flags to define PHY configuration options |
493 | * | 488 | * |
494 | * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) | 489 | * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) |
495 | * @IEEE80211_CONF_PS: Enable 802.11 power save mode | 490 | * @IEEE80211_CONF_PS: Enable 802.11 power save mode |
496 | */ | 491 | */ |
497 | enum ieee80211_conf_flags { | 492 | enum ieee80211_conf_flags { |
498 | IEEE80211_CONF_RADIOTAP = (1<<0), | 493 | IEEE80211_CONF_RADIOTAP = (1<<0), |
499 | IEEE80211_CONF_PS = (1<<1), | 494 | IEEE80211_CONF_PS = (1<<1), |
500 | }; | 495 | }; |
501 | 496 | ||
502 | /* XXX: remove all this once drivers stop trying to use it */ | 497 | /* XXX: remove all this once drivers stop trying to use it */ |
503 | static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) | 498 | static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) |
504 | { | 499 | { |
505 | return 0; | 500 | return 0; |
506 | } | 501 | } |
507 | #define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME()) | 502 | #define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME()) |
508 | 503 | ||
509 | struct ieee80211_ht_conf { | 504 | struct ieee80211_ht_conf { |
510 | bool enabled; | 505 | bool enabled; |
511 | int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary | 506 | enum nl80211_channel_type channel_type; |
512 | * channel below primary; 1 = HT40 enabled, | ||
513 | * secondary channel above primary */ | ||
514 | }; | 507 | }; |
515 | 508 | ||
516 | /** | 509 | /** |
517 | * enum ieee80211_conf_changed - denotes which configuration changed | 510 | * enum ieee80211_conf_changed - denotes which configuration changed |
518 | * | 511 | * |
519 | * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed | 512 | * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed |
520 | * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed | 513 | * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed |
521 | * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed | 514 | * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed |
522 | * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed | 515 | * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed |
523 | * @IEEE80211_CONF_CHANGE_PS: the PS flag changed | 516 | * @IEEE80211_CONF_CHANGE_PS: the PS flag changed |
524 | * @IEEE80211_CONF_CHANGE_POWER: the TX power changed | 517 | * @IEEE80211_CONF_CHANGE_POWER: the TX power changed |
525 | * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed | 518 | * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed |
526 | * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed | 519 | * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed |
527 | * @IEEE80211_CONF_CHANGE_HT: HT configuration changed | 520 | * @IEEE80211_CONF_CHANGE_HT: HT configuration changed |
528 | */ | 521 | */ |
529 | enum ieee80211_conf_changed { | 522 | enum ieee80211_conf_changed { |
530 | IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), | 523 | IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), |
531 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), | 524 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), |
532 | IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), | 525 | IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), |
533 | IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), | 526 | IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), |
534 | IEEE80211_CONF_CHANGE_PS = BIT(4), | 527 | IEEE80211_CONF_CHANGE_PS = BIT(4), |
535 | IEEE80211_CONF_CHANGE_POWER = BIT(5), | 528 | IEEE80211_CONF_CHANGE_POWER = BIT(5), |
536 | IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), | 529 | IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), |
537 | IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), | 530 | IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), |
538 | IEEE80211_CONF_CHANGE_HT = BIT(8), | 531 | IEEE80211_CONF_CHANGE_HT = BIT(8), |
539 | }; | 532 | }; |
540 | 533 | ||
541 | /** | 534 | /** |
542 | * struct ieee80211_conf - configuration of the device | 535 | * struct ieee80211_conf - configuration of the device |
543 | * | 536 | * |
544 | * This struct indicates how the driver shall configure the hardware. | 537 | * This struct indicates how the driver shall configure the hardware. |
545 | * | 538 | * |
546 | * @radio_enabled: when zero, driver is required to switch off the radio. | 539 | * @radio_enabled: when zero, driver is required to switch off the radio. |
547 | * @beacon_int: beacon interval (TODO make interface config) | 540 | * @beacon_int: beacon interval (TODO make interface config) |
548 | * @listen_interval: listen interval in units of beacon interval | 541 | * @listen_interval: listen interval in units of beacon interval |
549 | * @flags: configuration flags defined above | 542 | * @flags: configuration flags defined above |
550 | * @power_level: requested transmit power (in dBm) | 543 | * @power_level: requested transmit power (in dBm) |
551 | * @channel: the channel to tune to | 544 | * @channel: the channel to tune to |
552 | * @ht: the HT configuration for the device | 545 | * @ht: the HT configuration for the device |
553 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame | 546 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame |
554 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, | 547 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, |
555 | * but actually means the number of transmissions not the number of retries | 548 | * but actually means the number of transmissions not the number of retries |
556 | * @short_frame_max_tx_count: Maximum number of transmissions for a "short" | 549 | * @short_frame_max_tx_count: Maximum number of transmissions for a "short" |
557 | * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the | 550 | * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the |
558 | * number of transmissions not the number of retries | 551 | * number of transmissions not the number of retries |
559 | */ | 552 | */ |
560 | struct ieee80211_conf { | 553 | struct ieee80211_conf { |
561 | int beacon_int; | 554 | int beacon_int; |
562 | u32 flags; | 555 | u32 flags; |
563 | int power_level; | 556 | int power_level; |
564 | 557 | ||
565 | u16 listen_interval; | 558 | u16 listen_interval; |
566 | bool radio_enabled; | 559 | bool radio_enabled; |
567 | 560 | ||
568 | u8 long_frame_max_tx_count, short_frame_max_tx_count; | 561 | u8 long_frame_max_tx_count, short_frame_max_tx_count; |
569 | 562 | ||
570 | struct ieee80211_channel *channel; | 563 | struct ieee80211_channel *channel; |
571 | struct ieee80211_ht_conf ht; | 564 | struct ieee80211_ht_conf ht; |
572 | }; | 565 | }; |
573 | 566 | ||
574 | /** | 567 | /** |
575 | * struct ieee80211_vif - per-interface data | 568 | * struct ieee80211_vif - per-interface data |
576 | * | 569 | * |
577 | * Data in this structure is continually present for driver | 570 | * Data in this structure is continually present for driver |
578 | * use during the life of a virtual interface. | 571 | * use during the life of a virtual interface. |
579 | * | 572 | * |
580 | * @type: type of this virtual interface | 573 | * @type: type of this virtual interface |
581 | * @bss_conf: BSS configuration for this interface, either our own | 574 | * @bss_conf: BSS configuration for this interface, either our own |
582 | * or the BSS we're associated to | 575 | * or the BSS we're associated to |
583 | * @drv_priv: data area for driver use, will always be aligned to | 576 | * @drv_priv: data area for driver use, will always be aligned to |
584 | * sizeof(void *). | 577 | * sizeof(void *). |
585 | */ | 578 | */ |
586 | struct ieee80211_vif { | 579 | struct ieee80211_vif { |
587 | enum nl80211_iftype type; | 580 | enum nl80211_iftype type; |
588 | struct ieee80211_bss_conf bss_conf; | 581 | struct ieee80211_bss_conf bss_conf; |
589 | /* must be last */ | 582 | /* must be last */ |
590 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); | 583 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); |
591 | }; | 584 | }; |
592 | 585 | ||
593 | static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | 586 | static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) |
594 | { | 587 | { |
595 | #ifdef CONFIG_MAC80211_MESH | 588 | #ifdef CONFIG_MAC80211_MESH |
596 | return vif->type == NL80211_IFTYPE_MESH_POINT; | 589 | return vif->type == NL80211_IFTYPE_MESH_POINT; |
597 | #endif | 590 | #endif |
598 | return false; | 591 | return false; |
599 | } | 592 | } |
600 | 593 | ||
601 | /** | 594 | /** |
602 | * struct ieee80211_if_init_conf - initial configuration of an interface | 595 | * struct ieee80211_if_init_conf - initial configuration of an interface |
603 | * | 596 | * |
604 | * @vif: pointer to a driver-use per-interface structure. The pointer | 597 | * @vif: pointer to a driver-use per-interface structure. The pointer |
605 | * itself is also used for various functions including | 598 | * itself is also used for various functions including |
606 | * ieee80211_beacon_get() and ieee80211_get_buffered_bc(). | 599 | * ieee80211_beacon_get() and ieee80211_get_buffered_bc(). |
607 | * @type: one of &enum nl80211_iftype constants. Determines the type of | 600 | * @type: one of &enum nl80211_iftype constants. Determines the type of |
608 | * added/removed interface. | 601 | * added/removed interface. |
609 | * @mac_addr: pointer to MAC address of the interface. This pointer is valid | 602 | * @mac_addr: pointer to MAC address of the interface. This pointer is valid |
610 | * until the interface is removed (i.e. it cannot be used after | 603 | * until the interface is removed (i.e. it cannot be used after |
611 | * remove_interface() callback was called for this interface). | 604 | * remove_interface() callback was called for this interface). |
612 | * | 605 | * |
613 | * This structure is used in add_interface() and remove_interface() | 606 | * This structure is used in add_interface() and remove_interface() |
614 | * callbacks of &struct ieee80211_hw. | 607 | * callbacks of &struct ieee80211_hw. |
615 | * | 608 | * |
616 | * When you allow multiple interfaces to be added to your PHY, take care | 609 | * When you allow multiple interfaces to be added to your PHY, take care |
617 | * that the hardware can actually handle multiple MAC addresses. However, | 610 | * that the hardware can actually handle multiple MAC addresses. However, |
618 | * also take care that when there's no interface left with mac_addr != %NULL | 611 | * also take care that when there's no interface left with mac_addr != %NULL |
619 | * you remove the MAC address from the device to avoid acknowledging packets | 612 | * you remove the MAC address from the device to avoid acknowledging packets |
620 | * in pure monitor mode. | 613 | * in pure monitor mode. |
621 | */ | 614 | */ |
622 | struct ieee80211_if_init_conf { | 615 | struct ieee80211_if_init_conf { |
623 | enum nl80211_iftype type; | 616 | enum nl80211_iftype type; |
624 | struct ieee80211_vif *vif; | 617 | struct ieee80211_vif *vif; |
625 | void *mac_addr; | 618 | void *mac_addr; |
626 | }; | 619 | }; |
627 | 620 | ||
628 | /** | 621 | /** |
629 | * enum ieee80211_if_conf_change - interface config change flags | 622 | * enum ieee80211_if_conf_change - interface config change flags |
630 | * | 623 | * |
631 | * @IEEE80211_IFCC_BSSID: The BSSID changed. | 624 | * @IEEE80211_IFCC_BSSID: The BSSID changed. |
632 | * @IEEE80211_IFCC_BEACON: The beacon for this interface changed | 625 | * @IEEE80211_IFCC_BEACON: The beacon for this interface changed |
633 | * (currently AP and MESH only), use ieee80211_beacon_get(). | 626 | * (currently AP and MESH only), use ieee80211_beacon_get(). |
634 | */ | 627 | */ |
635 | enum ieee80211_if_conf_change { | 628 | enum ieee80211_if_conf_change { |
636 | IEEE80211_IFCC_BSSID = BIT(0), | 629 | IEEE80211_IFCC_BSSID = BIT(0), |
637 | IEEE80211_IFCC_BEACON = BIT(1), | 630 | IEEE80211_IFCC_BEACON = BIT(1), |
638 | }; | 631 | }; |
639 | 632 | ||
640 | /** | 633 | /** |
641 | * struct ieee80211_if_conf - configuration of an interface | 634 | * struct ieee80211_if_conf - configuration of an interface |
642 | * | 635 | * |
643 | * @changed: parameters that have changed, see &enum ieee80211_if_conf_change. | 636 | * @changed: parameters that have changed, see &enum ieee80211_if_conf_change. |
644 | * @bssid: BSSID of the network we are associated to/creating. | 637 | * @bssid: BSSID of the network we are associated to/creating. |
645 | * | 638 | * |
646 | * This structure is passed to the config_interface() callback of | 639 | * This structure is passed to the config_interface() callback of |
647 | * &struct ieee80211_hw. | 640 | * &struct ieee80211_hw. |
648 | */ | 641 | */ |
649 | struct ieee80211_if_conf { | 642 | struct ieee80211_if_conf { |
650 | u32 changed; | 643 | u32 changed; |
651 | u8 *bssid; | 644 | u8 *bssid; |
652 | }; | 645 | }; |
653 | 646 | ||
654 | /** | 647 | /** |
655 | * enum ieee80211_key_alg - key algorithm | 648 | * enum ieee80211_key_alg - key algorithm |
656 | * @ALG_WEP: WEP40 or WEP104 | 649 | * @ALG_WEP: WEP40 or WEP104 |
657 | * @ALG_TKIP: TKIP | 650 | * @ALG_TKIP: TKIP |
658 | * @ALG_CCMP: CCMP (AES) | 651 | * @ALG_CCMP: CCMP (AES) |
659 | */ | 652 | */ |
660 | enum ieee80211_key_alg { | 653 | enum ieee80211_key_alg { |
661 | ALG_WEP, | 654 | ALG_WEP, |
662 | ALG_TKIP, | 655 | ALG_TKIP, |
663 | ALG_CCMP, | 656 | ALG_CCMP, |
664 | }; | 657 | }; |
665 | 658 | ||
666 | /** | 659 | /** |
667 | * enum ieee80211_key_len - key length | 660 | * enum ieee80211_key_len - key length |
668 | * @LEN_WEP40: WEP 5-byte long key | 661 | * @LEN_WEP40: WEP 5-byte long key |
669 | * @LEN_WEP104: WEP 13-byte long key | 662 | * @LEN_WEP104: WEP 13-byte long key |
670 | */ | 663 | */ |
671 | enum ieee80211_key_len { | 664 | enum ieee80211_key_len { |
672 | LEN_WEP40 = 5, | 665 | LEN_WEP40 = 5, |
673 | LEN_WEP104 = 13, | 666 | LEN_WEP104 = 13, |
674 | }; | 667 | }; |
675 | 668 | ||
676 | /** | 669 | /** |
677 | * enum ieee80211_key_flags - key flags | 670 | * enum ieee80211_key_flags - key flags |
678 | * | 671 | * |
679 | * These flags are used for communication about keys between the driver | 672 | * These flags are used for communication about keys between the driver |
680 | * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. | 673 | * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. |
681 | * | 674 | * |
682 | * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates | 675 | * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates |
683 | * that the STA this key will be used with could be using QoS. | 676 | * that the STA this key will be used with could be using QoS. |
684 | * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the | 677 | * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the |
685 | * driver to indicate that it requires IV generation for this | 678 | * driver to indicate that it requires IV generation for this |
686 | * particular key. | 679 | * particular key. |
687 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by | 680 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by |
688 | * the driver for a TKIP key if it requires Michael MIC | 681 | * the driver for a TKIP key if it requires Michael MIC |
689 | * generation in software. | 682 | * generation in software. |
690 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates | 683 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates |
691 | * that the key is pairwise rather then a shared key. | 684 | * that the key is pairwise rather then a shared key. |
692 | */ | 685 | */ |
693 | enum ieee80211_key_flags { | 686 | enum ieee80211_key_flags { |
694 | IEEE80211_KEY_FLAG_WMM_STA = 1<<0, | 687 | IEEE80211_KEY_FLAG_WMM_STA = 1<<0, |
695 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, | 688 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, |
696 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, | 689 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, |
697 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, | 690 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, |
698 | }; | 691 | }; |
699 | 692 | ||
700 | /** | 693 | /** |
701 | * struct ieee80211_key_conf - key information | 694 | * struct ieee80211_key_conf - key information |
702 | * | 695 | * |
703 | * This key information is given by mac80211 to the driver by | 696 | * This key information is given by mac80211 to the driver by |
704 | * the set_key() callback in &struct ieee80211_ops. | 697 | * the set_key() callback in &struct ieee80211_ops. |
705 | * | 698 | * |
706 | * @hw_key_idx: To be set by the driver, this is the key index the driver | 699 | * @hw_key_idx: To be set by the driver, this is the key index the driver |
707 | * wants to be given when a frame is transmitted and needs to be | 700 | * wants to be given when a frame is transmitted and needs to be |
708 | * encrypted in hardware. | 701 | * encrypted in hardware. |
709 | * @alg: The key algorithm. | 702 | * @alg: The key algorithm. |
710 | * @flags: key flags, see &enum ieee80211_key_flags. | 703 | * @flags: key flags, see &enum ieee80211_key_flags. |
711 | * @keyidx: the key index (0-3) | 704 | * @keyidx: the key index (0-3) |
712 | * @keylen: key material length | 705 | * @keylen: key material length |
713 | * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) | 706 | * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) |
714 | * data block: | 707 | * data block: |
715 | * - Temporal Encryption Key (128 bits) | 708 | * - Temporal Encryption Key (128 bits) |
716 | * - Temporal Authenticator Tx MIC Key (64 bits) | 709 | * - Temporal Authenticator Tx MIC Key (64 bits) |
717 | * - Temporal Authenticator Rx MIC Key (64 bits) | 710 | * - Temporal Authenticator Rx MIC Key (64 bits) |
718 | * @icv_len: FIXME | 711 | * @icv_len: FIXME |
719 | * @iv_len: FIXME | 712 | * @iv_len: FIXME |
720 | */ | 713 | */ |
721 | struct ieee80211_key_conf { | 714 | struct ieee80211_key_conf { |
722 | enum ieee80211_key_alg alg; | 715 | enum ieee80211_key_alg alg; |
723 | u8 icv_len; | 716 | u8 icv_len; |
724 | u8 iv_len; | 717 | u8 iv_len; |
725 | u8 hw_key_idx; | 718 | u8 hw_key_idx; |
726 | u8 flags; | 719 | u8 flags; |
727 | s8 keyidx; | 720 | s8 keyidx; |
728 | u8 keylen; | 721 | u8 keylen; |
729 | u8 key[0]; | 722 | u8 key[0]; |
730 | }; | 723 | }; |
731 | 724 | ||
732 | /** | 725 | /** |
733 | * enum set_key_cmd - key command | 726 | * enum set_key_cmd - key command |
734 | * | 727 | * |
735 | * Used with the set_key() callback in &struct ieee80211_ops, this | 728 | * Used with the set_key() callback in &struct ieee80211_ops, this |
736 | * indicates whether a key is being removed or added. | 729 | * indicates whether a key is being removed or added. |
737 | * | 730 | * |
738 | * @SET_KEY: a key is set | 731 | * @SET_KEY: a key is set |
739 | * @DISABLE_KEY: a key must be disabled | 732 | * @DISABLE_KEY: a key must be disabled |
740 | */ | 733 | */ |
741 | enum set_key_cmd { | 734 | enum set_key_cmd { |
742 | SET_KEY, DISABLE_KEY, | 735 | SET_KEY, DISABLE_KEY, |
743 | }; | 736 | }; |
744 | 737 | ||
745 | /** | 738 | /** |
746 | * struct ieee80211_sta - station table entry | 739 | * struct ieee80211_sta - station table entry |
747 | * | 740 | * |
748 | * A station table entry represents a station we are possibly | 741 | * A station table entry represents a station we are possibly |
749 | * communicating with. Since stations are RCU-managed in | 742 | * communicating with. Since stations are RCU-managed in |
750 | * mac80211, any ieee80211_sta pointer you get access to must | 743 | * mac80211, any ieee80211_sta pointer you get access to must |
751 | * either be protected by rcu_read_lock() explicitly or implicitly, | 744 | * either be protected by rcu_read_lock() explicitly or implicitly, |
752 | * or you must take good care to not use such a pointer after a | 745 | * or you must take good care to not use such a pointer after a |
753 | * call to your sta_notify callback that removed it. | 746 | * call to your sta_notify callback that removed it. |
754 | * | 747 | * |
755 | * @addr: MAC address | 748 | * @addr: MAC address |
756 | * @aid: AID we assigned to the station if we're an AP | 749 | * @aid: AID we assigned to the station if we're an AP |
757 | * @supp_rates: Bitmap of supported rates (per band) | 750 | * @supp_rates: Bitmap of supported rates (per band) |
758 | * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities | 751 | * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities |
759 | * @drv_priv: data area for driver use, will always be aligned to | 752 | * @drv_priv: data area for driver use, will always be aligned to |
760 | * sizeof(void *), size is determined in hw information. | 753 | * sizeof(void *), size is determined in hw information. |
761 | */ | 754 | */ |
762 | struct ieee80211_sta { | 755 | struct ieee80211_sta { |
763 | u64 supp_rates[IEEE80211_NUM_BANDS]; | 756 | u64 supp_rates[IEEE80211_NUM_BANDS]; |
764 | u8 addr[ETH_ALEN]; | 757 | u8 addr[ETH_ALEN]; |
765 | u16 aid; | 758 | u16 aid; |
766 | struct ieee80211_sta_ht_cap ht_cap; | 759 | struct ieee80211_sta_ht_cap ht_cap; |
767 | 760 | ||
768 | /* must be last */ | 761 | /* must be last */ |
769 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); | 762 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); |
770 | }; | 763 | }; |
771 | 764 | ||
772 | /** | 765 | /** |
773 | * enum sta_notify_cmd - sta notify command | 766 | * enum sta_notify_cmd - sta notify command |
774 | * | 767 | * |
775 | * Used with the sta_notify() callback in &struct ieee80211_ops, this | 768 | * Used with the sta_notify() callback in &struct ieee80211_ops, this |
776 | * indicates addition and removal of a station to station table, | 769 | * indicates addition and removal of a station to station table, |
777 | * or if a associated station made a power state transition. | 770 | * or if a associated station made a power state transition. |
778 | * | 771 | * |
779 | * @STA_NOTIFY_ADD: a station was added to the station table | 772 | * @STA_NOTIFY_ADD: a station was added to the station table |
780 | * @STA_NOTIFY_REMOVE: a station being removed from the station table | 773 | * @STA_NOTIFY_REMOVE: a station being removed from the station table |
781 | * @STA_NOTIFY_SLEEP: a station is now sleeping | 774 | * @STA_NOTIFY_SLEEP: a station is now sleeping |
782 | * @STA_NOTIFY_AWAKE: a sleeping station woke up | 775 | * @STA_NOTIFY_AWAKE: a sleeping station woke up |
783 | */ | 776 | */ |
784 | enum sta_notify_cmd { | 777 | enum sta_notify_cmd { |
785 | STA_NOTIFY_ADD, STA_NOTIFY_REMOVE, | 778 | STA_NOTIFY_ADD, STA_NOTIFY_REMOVE, |
786 | STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, | 779 | STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, |
787 | }; | 780 | }; |
788 | 781 | ||
789 | /** | 782 | /** |
790 | * enum ieee80211_tkip_key_type - get tkip key | 783 | * enum ieee80211_tkip_key_type - get tkip key |
791 | * | 784 | * |
792 | * Used by drivers which need to get a tkip key for skb. Some drivers need a | 785 | * Used by drivers which need to get a tkip key for skb. Some drivers need a |
793 | * phase 1 key, others need a phase 2 key. A single function allows the driver | 786 | * phase 1 key, others need a phase 2 key. A single function allows the driver |
794 | * to get the key, this enum indicates what type of key is required. | 787 | * to get the key, this enum indicates what type of key is required. |
795 | * | 788 | * |
796 | * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key | 789 | * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key |
797 | * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key | 790 | * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key |
798 | */ | 791 | */ |
799 | enum ieee80211_tkip_key_type { | 792 | enum ieee80211_tkip_key_type { |
800 | IEEE80211_TKIP_P1_KEY, | 793 | IEEE80211_TKIP_P1_KEY, |
801 | IEEE80211_TKIP_P2_KEY, | 794 | IEEE80211_TKIP_P2_KEY, |
802 | }; | 795 | }; |
803 | 796 | ||
804 | /** | 797 | /** |
805 | * enum ieee80211_hw_flags - hardware flags | 798 | * enum ieee80211_hw_flags - hardware flags |
806 | * | 799 | * |
807 | * These flags are used to indicate hardware capabilities to | 800 | * These flags are used to indicate hardware capabilities to |
808 | * the stack. Generally, flags here should have their meaning | 801 | * the stack. Generally, flags here should have their meaning |
809 | * done in a way that the simplest hardware doesn't need setting | 802 | * done in a way that the simplest hardware doesn't need setting |
810 | * any particular flags. There are some exceptions to this rule, | 803 | * any particular flags. There are some exceptions to this rule, |
811 | * however, so you are advised to review these flags carefully. | 804 | * however, so you are advised to review these flags carefully. |
812 | * | 805 | * |
813 | * @IEEE80211_HW_RX_INCLUDES_FCS: | 806 | * @IEEE80211_HW_RX_INCLUDES_FCS: |
814 | * Indicates that received frames passed to the stack include | 807 | * Indicates that received frames passed to the stack include |
815 | * the FCS at the end. | 808 | * the FCS at the end. |
816 | * | 809 | * |
817 | * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING: | 810 | * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING: |
818 | * Some wireless LAN chipsets buffer broadcast/multicast frames | 811 | * Some wireless LAN chipsets buffer broadcast/multicast frames |
819 | * for power saving stations in the hardware/firmware and others | 812 | * for power saving stations in the hardware/firmware and others |
820 | * rely on the host system for such buffering. This option is used | 813 | * rely on the host system for such buffering. This option is used |
821 | * to configure the IEEE 802.11 upper layer to buffer broadcast and | 814 | * to configure the IEEE 802.11 upper layer to buffer broadcast and |
822 | * multicast frames when there are power saving stations so that | 815 | * multicast frames when there are power saving stations so that |
823 | * the driver can fetch them with ieee80211_get_buffered_bc(). | 816 | * the driver can fetch them with ieee80211_get_buffered_bc(). |
824 | * | 817 | * |
825 | * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: | 818 | * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: |
826 | * Hardware is not capable of short slot operation on the 2.4 GHz band. | 819 | * Hardware is not capable of short slot operation on the 2.4 GHz band. |
827 | * | 820 | * |
828 | * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: | 821 | * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: |
829 | * Hardware is not capable of receiving frames with short preamble on | 822 | * Hardware is not capable of receiving frames with short preamble on |
830 | * the 2.4 GHz band. | 823 | * the 2.4 GHz band. |
831 | * | 824 | * |
832 | * @IEEE80211_HW_SIGNAL_UNSPEC: | 825 | * @IEEE80211_HW_SIGNAL_UNSPEC: |
833 | * Hardware can provide signal values but we don't know its units. We | 826 | * Hardware can provide signal values but we don't know its units. We |
834 | * expect values between 0 and @max_signal. | 827 | * expect values between 0 and @max_signal. |
835 | * If possible please provide dB or dBm instead. | 828 | * If possible please provide dB or dBm instead. |
836 | * | 829 | * |
837 | * @IEEE80211_HW_SIGNAL_DB: | 830 | * @IEEE80211_HW_SIGNAL_DB: |
838 | * Hardware gives signal values in dB, decibel difference from an | 831 | * Hardware gives signal values in dB, decibel difference from an |
839 | * arbitrary, fixed reference. We expect values between 0 and @max_signal. | 832 | * arbitrary, fixed reference. We expect values between 0 and @max_signal. |
840 | * If possible please provide dBm instead. | 833 | * If possible please provide dBm instead. |
841 | * | 834 | * |
842 | * @IEEE80211_HW_SIGNAL_DBM: | 835 | * @IEEE80211_HW_SIGNAL_DBM: |
843 | * Hardware gives signal values in dBm, decibel difference from | 836 | * Hardware gives signal values in dBm, decibel difference from |
844 | * one milliwatt. This is the preferred method since it is standardized | 837 | * one milliwatt. This is the preferred method since it is standardized |
845 | * between different devices. @max_signal does not need to be set. | 838 | * between different devices. @max_signal does not need to be set. |
846 | * | 839 | * |
847 | * @IEEE80211_HW_NOISE_DBM: | 840 | * @IEEE80211_HW_NOISE_DBM: |
848 | * Hardware can provide noise (radio interference) values in units dBm, | 841 | * Hardware can provide noise (radio interference) values in units dBm, |
849 | * decibel difference from one milliwatt. | 842 | * decibel difference from one milliwatt. |
850 | * | 843 | * |
851 | * @IEEE80211_HW_SPECTRUM_MGMT: | 844 | * @IEEE80211_HW_SPECTRUM_MGMT: |
852 | * Hardware supports spectrum management defined in 802.11h | 845 | * Hardware supports spectrum management defined in 802.11h |
853 | * Measurement, Channel Switch, Quieting, TPC | 846 | * Measurement, Channel Switch, Quieting, TPC |
854 | * | 847 | * |
855 | * @IEEE80211_HW_AMPDU_AGGREGATION: | 848 | * @IEEE80211_HW_AMPDU_AGGREGATION: |
856 | * Hardware supports 11n A-MPDU aggregation. | 849 | * Hardware supports 11n A-MPDU aggregation. |
857 | */ | 850 | */ |
858 | enum ieee80211_hw_flags { | 851 | enum ieee80211_hw_flags { |
859 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, | 852 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, |
860 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, | 853 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, |
861 | IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, | 854 | IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, |
862 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, | 855 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, |
863 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, | 856 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, |
864 | IEEE80211_HW_SIGNAL_DB = 1<<6, | 857 | IEEE80211_HW_SIGNAL_DB = 1<<6, |
865 | IEEE80211_HW_SIGNAL_DBM = 1<<7, | 858 | IEEE80211_HW_SIGNAL_DBM = 1<<7, |
866 | IEEE80211_HW_NOISE_DBM = 1<<8, | 859 | IEEE80211_HW_NOISE_DBM = 1<<8, |
867 | IEEE80211_HW_SPECTRUM_MGMT = 1<<9, | 860 | IEEE80211_HW_SPECTRUM_MGMT = 1<<9, |
868 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, | 861 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, |
869 | }; | 862 | }; |
870 | 863 | ||
871 | /** | 864 | /** |
872 | * struct ieee80211_hw - hardware information and state | 865 | * struct ieee80211_hw - hardware information and state |
873 | * | 866 | * |
874 | * This structure contains the configuration and hardware | 867 | * This structure contains the configuration and hardware |
875 | * information for an 802.11 PHY. | 868 | * information for an 802.11 PHY. |
876 | * | 869 | * |
877 | * @wiphy: This points to the &struct wiphy allocated for this | 870 | * @wiphy: This points to the &struct wiphy allocated for this |
878 | * 802.11 PHY. You must fill in the @perm_addr and @dev | 871 | * 802.11 PHY. You must fill in the @perm_addr and @dev |
879 | * members of this structure using SET_IEEE80211_DEV() | 872 | * members of this structure using SET_IEEE80211_DEV() |
880 | * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported | 873 | * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported |
881 | * bands (with channels, bitrates) are registered here. | 874 | * bands (with channels, bitrates) are registered here. |
882 | * | 875 | * |
883 | * @conf: &struct ieee80211_conf, device configuration, don't use. | 876 | * @conf: &struct ieee80211_conf, device configuration, don't use. |
884 | * | 877 | * |
885 | * @workqueue: single threaded workqueue available for driver use, | 878 | * @workqueue: single threaded workqueue available for driver use, |
886 | * allocated by mac80211 on registration and flushed when an | 879 | * allocated by mac80211 on registration and flushed when an |
887 | * interface is removed. | 880 | * interface is removed. |
888 | * NOTICE: All work performed on this workqueue should NEVER | 881 | * NOTICE: All work performed on this workqueue should NEVER |
889 | * acquire the RTNL lock (i.e. Don't use the function | 882 | * acquire the RTNL lock (i.e. Don't use the function |
890 | * ieee80211_iterate_active_interfaces()) | 883 | * ieee80211_iterate_active_interfaces()) |
891 | * | 884 | * |
892 | * @priv: pointer to private area that was allocated for driver use | 885 | * @priv: pointer to private area that was allocated for driver use |
893 | * along with this structure. | 886 | * along with this structure. |
894 | * | 887 | * |
895 | * @flags: hardware flags, see &enum ieee80211_hw_flags. | 888 | * @flags: hardware flags, see &enum ieee80211_hw_flags. |
896 | * | 889 | * |
897 | * @extra_tx_headroom: headroom to reserve in each transmit skb | 890 | * @extra_tx_headroom: headroom to reserve in each transmit skb |
898 | * for use by the driver (e.g. for transmit headers.) | 891 | * for use by the driver (e.g. for transmit headers.) |
899 | * | 892 | * |
900 | * @channel_change_time: time (in microseconds) it takes to change channels. | 893 | * @channel_change_time: time (in microseconds) it takes to change channels. |
901 | * | 894 | * |
902 | * @max_signal: Maximum value for signal (rssi) in RX information, used | 895 | * @max_signal: Maximum value for signal (rssi) in RX information, used |
903 | * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB | 896 | * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB |
904 | * | 897 | * |
905 | * @max_listen_interval: max listen interval in units of beacon interval | 898 | * @max_listen_interval: max listen interval in units of beacon interval |
906 | * that HW supports | 899 | * that HW supports |
907 | * | 900 | * |
908 | * @queues: number of available hardware transmit queues for | 901 | * @queues: number of available hardware transmit queues for |
909 | * data packets. WMM/QoS requires at least four, these | 902 | * data packets. WMM/QoS requires at least four, these |
910 | * queues need to have configurable access parameters. | 903 | * queues need to have configurable access parameters. |
911 | * | 904 | * |
912 | * @ampdu_queues: number of available hardware transmit queues | 905 | * @ampdu_queues: number of available hardware transmit queues |
913 | * for A-MPDU packets, these have no access parameters | 906 | * for A-MPDU packets, these have no access parameters |
914 | * because they're used only for A-MPDU frames. Note that | 907 | * because they're used only for A-MPDU frames. Note that |
915 | * mac80211 will not currently use any of the regular queues | 908 | * mac80211 will not currently use any of the regular queues |
916 | * for aggregation. | 909 | * for aggregation. |
917 | * | 910 | * |
918 | * @rate_control_algorithm: rate control algorithm for this hardware. | 911 | * @rate_control_algorithm: rate control algorithm for this hardware. |
919 | * If unset (NULL), the default algorithm will be used. Must be | 912 | * If unset (NULL), the default algorithm will be used. Must be |
920 | * set before calling ieee80211_register_hw(). | 913 | * set before calling ieee80211_register_hw(). |
921 | * | 914 | * |
922 | * @vif_data_size: size (in bytes) of the drv_priv data area | 915 | * @vif_data_size: size (in bytes) of the drv_priv data area |
923 | * within &struct ieee80211_vif. | 916 | * within &struct ieee80211_vif. |
924 | * @sta_data_size: size (in bytes) of the drv_priv data area | 917 | * @sta_data_size: size (in bytes) of the drv_priv data area |
925 | * within &struct ieee80211_sta. | 918 | * within &struct ieee80211_sta. |
926 | * | 919 | * |
927 | * @max_rates: maximum number of alternate rate retry stages | 920 | * @max_rates: maximum number of alternate rate retry stages |
928 | * @max_rate_tries: maximum number of tries for each stage | 921 | * @max_rate_tries: maximum number of tries for each stage |
929 | */ | 922 | */ |
930 | struct ieee80211_hw { | 923 | struct ieee80211_hw { |
931 | struct ieee80211_conf conf; | 924 | struct ieee80211_conf conf; |
932 | struct wiphy *wiphy; | 925 | struct wiphy *wiphy; |
933 | struct workqueue_struct *workqueue; | 926 | struct workqueue_struct *workqueue; |
934 | const char *rate_control_algorithm; | 927 | const char *rate_control_algorithm; |
935 | void *priv; | 928 | void *priv; |
936 | u32 flags; | 929 | u32 flags; |
937 | unsigned int extra_tx_headroom; | 930 | unsigned int extra_tx_headroom; |
938 | int channel_change_time; | 931 | int channel_change_time; |
939 | int vif_data_size; | 932 | int vif_data_size; |
940 | int sta_data_size; | 933 | int sta_data_size; |
941 | u16 queues; | 934 | u16 queues; |
942 | u16 ampdu_queues; | 935 | u16 ampdu_queues; |
943 | u16 max_listen_interval; | 936 | u16 max_listen_interval; |
944 | s8 max_signal; | 937 | s8 max_signal; |
945 | u8 max_rates; | 938 | u8 max_rates; |
946 | u8 max_rate_tries; | 939 | u8 max_rate_tries; |
947 | }; | 940 | }; |
948 | 941 | ||
949 | /** | 942 | /** |
950 | * SET_IEEE80211_DEV - set device for 802.11 hardware | 943 | * SET_IEEE80211_DEV - set device for 802.11 hardware |
951 | * | 944 | * |
952 | * @hw: the &struct ieee80211_hw to set the device for | 945 | * @hw: the &struct ieee80211_hw to set the device for |
953 | * @dev: the &struct device of this 802.11 device | 946 | * @dev: the &struct device of this 802.11 device |
954 | */ | 947 | */ |
955 | static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev) | 948 | static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev) |
956 | { | 949 | { |
957 | set_wiphy_dev(hw->wiphy, dev); | 950 | set_wiphy_dev(hw->wiphy, dev); |
958 | } | 951 | } |
959 | 952 | ||
960 | /** | 953 | /** |
961 | * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware | 954 | * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware |
962 | * | 955 | * |
963 | * @hw: the &struct ieee80211_hw to set the MAC address for | 956 | * @hw: the &struct ieee80211_hw to set the MAC address for |
964 | * @addr: the address to set | 957 | * @addr: the address to set |
965 | */ | 958 | */ |
966 | static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) | 959 | static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) |
967 | { | 960 | { |
968 | memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); | 961 | memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); |
969 | } | 962 | } |
970 | 963 | ||
971 | static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) | 964 | static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) |
972 | { | 965 | { |
973 | return hw->queues; | 966 | return hw->queues; |
974 | } | 967 | } |
975 | 968 | ||
976 | static inline int ieee80211_num_queues(struct ieee80211_hw *hw) | 969 | static inline int ieee80211_num_queues(struct ieee80211_hw *hw) |
977 | { | 970 | { |
978 | return hw->queues + hw->ampdu_queues; | 971 | return hw->queues + hw->ampdu_queues; |
979 | } | 972 | } |
980 | 973 | ||
981 | static inline struct ieee80211_rate * | 974 | static inline struct ieee80211_rate * |
982 | ieee80211_get_tx_rate(const struct ieee80211_hw *hw, | 975 | ieee80211_get_tx_rate(const struct ieee80211_hw *hw, |
983 | const struct ieee80211_tx_info *c) | 976 | const struct ieee80211_tx_info *c) |
984 | { | 977 | { |
985 | if (WARN_ON(c->control.rates[0].idx < 0)) | 978 | if (WARN_ON(c->control.rates[0].idx < 0)) |
986 | return NULL; | 979 | return NULL; |
987 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; | 980 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; |
988 | } | 981 | } |
989 | 982 | ||
990 | static inline struct ieee80211_rate * | 983 | static inline struct ieee80211_rate * |
991 | ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, | 984 | ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, |
992 | const struct ieee80211_tx_info *c) | 985 | const struct ieee80211_tx_info *c) |
993 | { | 986 | { |
994 | if (c->control.rts_cts_rate_idx < 0) | 987 | if (c->control.rts_cts_rate_idx < 0) |
995 | return NULL; | 988 | return NULL; |
996 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; | 989 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; |
997 | } | 990 | } |
998 | 991 | ||
999 | static inline struct ieee80211_rate * | 992 | static inline struct ieee80211_rate * |
1000 | ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | 993 | ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, |
1001 | const struct ieee80211_tx_info *c, int idx) | 994 | const struct ieee80211_tx_info *c, int idx) |
1002 | { | 995 | { |
1003 | if (c->control.rates[idx + 1].idx < 0) | 996 | if (c->control.rates[idx + 1].idx < 0) |
1004 | return NULL; | 997 | return NULL; |
1005 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; | 998 | return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; |
1006 | } | 999 | } |
1007 | 1000 | ||
1008 | /** | 1001 | /** |
1009 | * DOC: Hardware crypto acceleration | 1002 | * DOC: Hardware crypto acceleration |
1010 | * | 1003 | * |
1011 | * mac80211 is capable of taking advantage of many hardware | 1004 | * mac80211 is capable of taking advantage of many hardware |
1012 | * acceleration designs for encryption and decryption operations. | 1005 | * acceleration designs for encryption and decryption operations. |
1013 | * | 1006 | * |
1014 | * The set_key() callback in the &struct ieee80211_ops for a given | 1007 | * The set_key() callback in the &struct ieee80211_ops for a given |
1015 | * device is called to enable hardware acceleration of encryption and | 1008 | * device is called to enable hardware acceleration of encryption and |
1016 | * decryption. The callback takes an @address parameter that will be | 1009 | * decryption. The callback takes an @address parameter that will be |
1017 | * the broadcast address for default keys, the other station's hardware | 1010 | * the broadcast address for default keys, the other station's hardware |
1018 | * address for individual keys or the zero address for keys that will | 1011 | * address for individual keys or the zero address for keys that will |
1019 | * be used only for transmission. | 1012 | * be used only for transmission. |
1020 | * Multiple transmission keys with the same key index may be used when | 1013 | * Multiple transmission keys with the same key index may be used when |
1021 | * VLANs are configured for an access point. | 1014 | * VLANs are configured for an access point. |
1022 | * | 1015 | * |
1023 | * The @local_address parameter will always be set to our own address, | 1016 | * The @local_address parameter will always be set to our own address, |
1024 | * this is only relevant if you support multiple local addresses. | 1017 | * this is only relevant if you support multiple local addresses. |
1025 | * | 1018 | * |
1026 | * When transmitting, the TX control data will use the @hw_key_idx | 1019 | * When transmitting, the TX control data will use the @hw_key_idx |
1027 | * selected by the driver by modifying the &struct ieee80211_key_conf | 1020 | * selected by the driver by modifying the &struct ieee80211_key_conf |
1028 | * pointed to by the @key parameter to the set_key() function. | 1021 | * pointed to by the @key parameter to the set_key() function. |
1029 | * | 1022 | * |
1030 | * The set_key() call for the %SET_KEY command should return 0 if | 1023 | * The set_key() call for the %SET_KEY command should return 0 if |
1031 | * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be | 1024 | * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be |
1032 | * added; if you return 0 then hw_key_idx must be assigned to the | 1025 | * added; if you return 0 then hw_key_idx must be assigned to the |
1033 | * hardware key index, you are free to use the full u8 range. | 1026 | * hardware key index, you are free to use the full u8 range. |
1034 | * | 1027 | * |
1035 | * When the cmd is %DISABLE_KEY then it must succeed. | 1028 | * When the cmd is %DISABLE_KEY then it must succeed. |
1036 | * | 1029 | * |
1037 | * Note that it is permissible to not decrypt a frame even if a key | 1030 | * Note that it is permissible to not decrypt a frame even if a key |
1038 | * for it has been uploaded to hardware, the stack will not make any | 1031 | * for it has been uploaded to hardware, the stack will not make any |
1039 | * decision based on whether a key has been uploaded or not but rather | 1032 | * decision based on whether a key has been uploaded or not but rather |
1040 | * based on the receive flags. | 1033 | * based on the receive flags. |
1041 | * | 1034 | * |
1042 | * The &struct ieee80211_key_conf structure pointed to by the @key | 1035 | * The &struct ieee80211_key_conf structure pointed to by the @key |
1043 | * parameter is guaranteed to be valid until another call to set_key() | 1036 | * parameter is guaranteed to be valid until another call to set_key() |
1044 | * removes it, but it can only be used as a cookie to differentiate | 1037 | * removes it, but it can only be used as a cookie to differentiate |
1045 | * keys. | 1038 | * keys. |
1046 | * | 1039 | * |
1047 | * In TKIP some HW need to be provided a phase 1 key, for RX decryption | 1040 | * In TKIP some HW need to be provided a phase 1 key, for RX decryption |
1048 | * acceleration (i.e. iwlwifi). Those drivers should provide update_tkip_key | 1041 | * acceleration (i.e. iwlwifi). Those drivers should provide update_tkip_key |
1049 | * handler. | 1042 | * handler. |
1050 | * The update_tkip_key() call updates the driver with the new phase 1 key. | 1043 | * The update_tkip_key() call updates the driver with the new phase 1 key. |
1051 | * This happens everytime the iv16 wraps around (every 65536 packets). The | 1044 | * This happens everytime the iv16 wraps around (every 65536 packets). The |
1052 | * set_key() call will happen only once for each key (unless the AP did | 1045 | * set_key() call will happen only once for each key (unless the AP did |
1053 | * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is | 1046 | * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is |
1054 | * provided by update_tkip_key only. The trigger that makes mac80211 call this | 1047 | * provided by update_tkip_key only. The trigger that makes mac80211 call this |
1055 | * handler is software decryption with wrap around of iv16. | 1048 | * handler is software decryption with wrap around of iv16. |
1056 | */ | 1049 | */ |
1057 | 1050 | ||
1058 | /** | 1051 | /** |
1059 | * DOC: Frame filtering | 1052 | * DOC: Frame filtering |
1060 | * | 1053 | * |
1061 | * mac80211 requires to see many management frames for proper | 1054 | * mac80211 requires to see many management frames for proper |
1062 | * operation, and users may want to see many more frames when | 1055 | * operation, and users may want to see many more frames when |
1063 | * in monitor mode. However, for best CPU usage and power consumption, | 1056 | * in monitor mode. However, for best CPU usage and power consumption, |
1064 | * having as few frames as possible percolate through the stack is | 1057 | * having as few frames as possible percolate through the stack is |
1065 | * desirable. Hence, the hardware should filter as much as possible. | 1058 | * desirable. Hence, the hardware should filter as much as possible. |
1066 | * | 1059 | * |
1067 | * To achieve this, mac80211 uses filter flags (see below) to tell | 1060 | * To achieve this, mac80211 uses filter flags (see below) to tell |
1068 | * the driver's configure_filter() function which frames should be | 1061 | * the driver's configure_filter() function which frames should be |
1069 | * passed to mac80211 and which should be filtered out. | 1062 | * passed to mac80211 and which should be filtered out. |
1070 | * | 1063 | * |
1071 | * The configure_filter() callback is invoked with the parameters | 1064 | * The configure_filter() callback is invoked with the parameters |
1072 | * @mc_count and @mc_list for the combined multicast address list | 1065 | * @mc_count and @mc_list for the combined multicast address list |
1073 | * of all virtual interfaces, @changed_flags telling which flags | 1066 | * of all virtual interfaces, @changed_flags telling which flags |
1074 | * were changed and @total_flags with the new flag states. | 1067 | * were changed and @total_flags with the new flag states. |
1075 | * | 1068 | * |
1076 | * If your device has no multicast address filters your driver will | 1069 | * If your device has no multicast address filters your driver will |
1077 | * need to check both the %FIF_ALLMULTI flag and the @mc_count | 1070 | * need to check both the %FIF_ALLMULTI flag and the @mc_count |
1078 | * parameter to see whether multicast frames should be accepted | 1071 | * parameter to see whether multicast frames should be accepted |
1079 | * or dropped. | 1072 | * or dropped. |
1080 | * | 1073 | * |
1081 | * All unsupported flags in @total_flags must be cleared. | 1074 | * All unsupported flags in @total_flags must be cleared. |
1082 | * Hardware does not support a flag if it is incapable of _passing_ | 1075 | * Hardware does not support a flag if it is incapable of _passing_ |
1083 | * the frame to the stack. Otherwise the driver must ignore | 1076 | * the frame to the stack. Otherwise the driver must ignore |
1084 | * the flag, but not clear it. | 1077 | * the flag, but not clear it. |
1085 | * You must _only_ clear the flag (announce no support for the | 1078 | * You must _only_ clear the flag (announce no support for the |
1086 | * flag to mac80211) if you are not able to pass the packet type | 1079 | * flag to mac80211) if you are not able to pass the packet type |
1087 | * to the stack (so the hardware always filters it). | 1080 | * to the stack (so the hardware always filters it). |
1088 | * So for example, you should clear @FIF_CONTROL, if your hardware | 1081 | * So for example, you should clear @FIF_CONTROL, if your hardware |
1089 | * always filters control frames. If your hardware always passes | 1082 | * always filters control frames. If your hardware always passes |
1090 | * control frames to the kernel and is incapable of filtering them, | 1083 | * control frames to the kernel and is incapable of filtering them, |
1091 | * you do _not_ clear the @FIF_CONTROL flag. | 1084 | * you do _not_ clear the @FIF_CONTROL flag. |
1092 | * This rule applies to all other FIF flags as well. | 1085 | * This rule applies to all other FIF flags as well. |
1093 | */ | 1086 | */ |
1094 | 1087 | ||
1095 | /** | 1088 | /** |
1096 | * enum ieee80211_filter_flags - hardware filter flags | 1089 | * enum ieee80211_filter_flags - hardware filter flags |
1097 | * | 1090 | * |
1098 | * These flags determine what the filter in hardware should be | 1091 | * These flags determine what the filter in hardware should be |
1099 | * programmed to let through and what should not be passed to the | 1092 | * programmed to let through and what should not be passed to the |
1100 | * stack. It is always safe to pass more frames than requested, | 1093 | * stack. It is always safe to pass more frames than requested, |
1101 | * but this has negative impact on power consumption. | 1094 | * but this has negative impact on power consumption. |
1102 | * | 1095 | * |
1103 | * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, | 1096 | * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, |
1104 | * think of the BSS as your network segment and then this corresponds | 1097 | * think of the BSS as your network segment and then this corresponds |
1105 | * to the regular ethernet device promiscuous mode. | 1098 | * to the regular ethernet device promiscuous mode. |
1106 | * | 1099 | * |
1107 | * @FIF_ALLMULTI: pass all multicast frames, this is used if requested | 1100 | * @FIF_ALLMULTI: pass all multicast frames, this is used if requested |
1108 | * by the user or if the hardware is not capable of filtering by | 1101 | * by the user or if the hardware is not capable of filtering by |
1109 | * multicast address. | 1102 | * multicast address. |
1110 | * | 1103 | * |
1111 | * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the | 1104 | * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the |
1112 | * %RX_FLAG_FAILED_FCS_CRC for them) | 1105 | * %RX_FLAG_FAILED_FCS_CRC for them) |
1113 | * | 1106 | * |
1114 | * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set | 1107 | * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set |
1115 | * the %RX_FLAG_FAILED_PLCP_CRC for them | 1108 | * the %RX_FLAG_FAILED_PLCP_CRC for them |
1116 | * | 1109 | * |
1117 | * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate | 1110 | * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate |
1118 | * to the hardware that it should not filter beacons or probe responses | 1111 | * to the hardware that it should not filter beacons or probe responses |
1119 | * by BSSID. Filtering them can greatly reduce the amount of processing | 1112 | * by BSSID. Filtering them can greatly reduce the amount of processing |
1120 | * mac80211 needs to do and the amount of CPU wakeups, so you should | 1113 | * mac80211 needs to do and the amount of CPU wakeups, so you should |
1121 | * honour this flag if possible. | 1114 | * honour this flag if possible. |
1122 | * | 1115 | * |
1123 | * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then | 1116 | * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then |
1124 | * only those addressed to this station | 1117 | * only those addressed to this station |
1125 | * | 1118 | * |
1126 | * @FIF_OTHER_BSS: pass frames destined to other BSSes | 1119 | * @FIF_OTHER_BSS: pass frames destined to other BSSes |
1127 | */ | 1120 | */ |
1128 | enum ieee80211_filter_flags { | 1121 | enum ieee80211_filter_flags { |
1129 | FIF_PROMISC_IN_BSS = 1<<0, | 1122 | FIF_PROMISC_IN_BSS = 1<<0, |
1130 | FIF_ALLMULTI = 1<<1, | 1123 | FIF_ALLMULTI = 1<<1, |
1131 | FIF_FCSFAIL = 1<<2, | 1124 | FIF_FCSFAIL = 1<<2, |
1132 | FIF_PLCPFAIL = 1<<3, | 1125 | FIF_PLCPFAIL = 1<<3, |
1133 | FIF_BCN_PRBRESP_PROMISC = 1<<4, | 1126 | FIF_BCN_PRBRESP_PROMISC = 1<<4, |
1134 | FIF_CONTROL = 1<<5, | 1127 | FIF_CONTROL = 1<<5, |
1135 | FIF_OTHER_BSS = 1<<6, | 1128 | FIF_OTHER_BSS = 1<<6, |
1136 | }; | 1129 | }; |
1137 | 1130 | ||
1138 | /** | 1131 | /** |
1139 | * enum ieee80211_ampdu_mlme_action - A-MPDU actions | 1132 | * enum ieee80211_ampdu_mlme_action - A-MPDU actions |
1140 | * | 1133 | * |
1141 | * These flags are used with the ampdu_action() callback in | 1134 | * These flags are used with the ampdu_action() callback in |
1142 | * &struct ieee80211_ops to indicate which action is needed. | 1135 | * &struct ieee80211_ops to indicate which action is needed. |
1143 | * @IEEE80211_AMPDU_RX_START: start Rx aggregation | 1136 | * @IEEE80211_AMPDU_RX_START: start Rx aggregation |
1144 | * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation | 1137 | * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation |
1145 | * @IEEE80211_AMPDU_TX_START: start Tx aggregation | 1138 | * @IEEE80211_AMPDU_TX_START: start Tx aggregation |
1146 | * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation | 1139 | * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation |
1147 | * @IEEE80211_AMPDU_TX_RESUME: resume TX aggregation | 1140 | * @IEEE80211_AMPDU_TX_RESUME: resume TX aggregation |
1148 | */ | 1141 | */ |
1149 | enum ieee80211_ampdu_mlme_action { | 1142 | enum ieee80211_ampdu_mlme_action { |
1150 | IEEE80211_AMPDU_RX_START, | 1143 | IEEE80211_AMPDU_RX_START, |
1151 | IEEE80211_AMPDU_RX_STOP, | 1144 | IEEE80211_AMPDU_RX_STOP, |
1152 | IEEE80211_AMPDU_TX_START, | 1145 | IEEE80211_AMPDU_TX_START, |
1153 | IEEE80211_AMPDU_TX_STOP, | 1146 | IEEE80211_AMPDU_TX_STOP, |
1154 | IEEE80211_AMPDU_TX_RESUME, | 1147 | IEEE80211_AMPDU_TX_RESUME, |
1155 | }; | 1148 | }; |
1156 | 1149 | ||
1157 | /** | 1150 | /** |
1158 | * struct ieee80211_ops - callbacks from mac80211 to the driver | 1151 | * struct ieee80211_ops - callbacks from mac80211 to the driver |
1159 | * | 1152 | * |
1160 | * This structure contains various callbacks that the driver may | 1153 | * This structure contains various callbacks that the driver may |
1161 | * handle or, in some cases, must handle, for example to configure | 1154 | * handle or, in some cases, must handle, for example to configure |
1162 | * the hardware to a new channel or to transmit a frame. | 1155 | * the hardware to a new channel or to transmit a frame. |
1163 | * | 1156 | * |
1164 | * @tx: Handler that 802.11 module calls for each transmitted frame. | 1157 | * @tx: Handler that 802.11 module calls for each transmitted frame. |
1165 | * skb contains the buffer starting from the IEEE 802.11 header. | 1158 | * skb contains the buffer starting from the IEEE 802.11 header. |
1166 | * The low-level driver should send the frame out based on | 1159 | * The low-level driver should send the frame out based on |
1167 | * configuration in the TX control data. This handler should, | 1160 | * configuration in the TX control data. This handler should, |
1168 | * preferably, never fail and stop queues appropriately, more | 1161 | * preferably, never fail and stop queues appropriately, more |
1169 | * importantly, however, it must never fail for A-MPDU-queues. | 1162 | * importantly, however, it must never fail for A-MPDU-queues. |
1170 | * Must be implemented and atomic. | 1163 | * Must be implemented and atomic. |
1171 | * | 1164 | * |
1172 | * @start: Called before the first netdevice attached to the hardware | 1165 | * @start: Called before the first netdevice attached to the hardware |
1173 | * is enabled. This should turn on the hardware and must turn on | 1166 | * is enabled. This should turn on the hardware and must turn on |
1174 | * frame reception (for possibly enabled monitor interfaces.) | 1167 | * frame reception (for possibly enabled monitor interfaces.) |
1175 | * Returns negative error codes, these may be seen in userspace, | 1168 | * Returns negative error codes, these may be seen in userspace, |
1176 | * or zero. | 1169 | * or zero. |
1177 | * When the device is started it should not have a MAC address | 1170 | * When the device is started it should not have a MAC address |
1178 | * to avoid acknowledging frames before a non-monitor device | 1171 | * to avoid acknowledging frames before a non-monitor device |
1179 | * is added. | 1172 | * is added. |
1180 | * Must be implemented. | 1173 | * Must be implemented. |
1181 | * | 1174 | * |
1182 | * @stop: Called after last netdevice attached to the hardware | 1175 | * @stop: Called after last netdevice attached to the hardware |
1183 | * is disabled. This should turn off the hardware (at least | 1176 | * is disabled. This should turn off the hardware (at least |
1184 | * it must turn off frame reception.) | 1177 | * it must turn off frame reception.) |
1185 | * May be called right after add_interface if that rejects | 1178 | * May be called right after add_interface if that rejects |
1186 | * an interface. | 1179 | * an interface. |
1187 | * Must be implemented. | 1180 | * Must be implemented. |
1188 | * | 1181 | * |
1189 | * @add_interface: Called when a netdevice attached to the hardware is | 1182 | * @add_interface: Called when a netdevice attached to the hardware is |
1190 | * enabled. Because it is not called for monitor mode devices, @start | 1183 | * enabled. Because it is not called for monitor mode devices, @start |
1191 | * and @stop must be implemented. | 1184 | * and @stop must be implemented. |
1192 | * The driver should perform any initialization it needs before | 1185 | * The driver should perform any initialization it needs before |
1193 | * the device can be enabled. The initial configuration for the | 1186 | * the device can be enabled. The initial configuration for the |
1194 | * interface is given in the conf parameter. | 1187 | * interface is given in the conf parameter. |
1195 | * The callback may refuse to add an interface by returning a | 1188 | * The callback may refuse to add an interface by returning a |
1196 | * negative error code (which will be seen in userspace.) | 1189 | * negative error code (which will be seen in userspace.) |
1197 | * Must be implemented. | 1190 | * Must be implemented. |
1198 | * | 1191 | * |
1199 | * @remove_interface: Notifies a driver that an interface is going down. | 1192 | * @remove_interface: Notifies a driver that an interface is going down. |
1200 | * The @stop callback is called after this if it is the last interface | 1193 | * The @stop callback is called after this if it is the last interface |
1201 | * and no monitor interfaces are present. | 1194 | * and no monitor interfaces are present. |
1202 | * When all interfaces are removed, the MAC address in the hardware | 1195 | * When all interfaces are removed, the MAC address in the hardware |
1203 | * must be cleared so the device no longer acknowledges packets, | 1196 | * must be cleared so the device no longer acknowledges packets, |
1204 | * the mac_addr member of the conf structure is, however, set to the | 1197 | * the mac_addr member of the conf structure is, however, set to the |
1205 | * MAC address of the device going away. | 1198 | * MAC address of the device going away. |
1206 | * Hence, this callback must be implemented. | 1199 | * Hence, this callback must be implemented. |
1207 | * | 1200 | * |
1208 | * @config: Handler for configuration requests. IEEE 802.11 code calls this | 1201 | * @config: Handler for configuration requests. IEEE 802.11 code calls this |
1209 | * function to change hardware configuration, e.g., channel. | 1202 | * function to change hardware configuration, e.g., channel. |
1210 | * | 1203 | * |
1211 | * @config_interface: Handler for configuration requests related to interfaces | 1204 | * @config_interface: Handler for configuration requests related to interfaces |
1212 | * (e.g. BSSID changes.) | 1205 | * (e.g. BSSID changes.) |
1213 | * | 1206 | * |
1214 | * @bss_info_changed: Handler for configuration requests related to BSS | 1207 | * @bss_info_changed: Handler for configuration requests related to BSS |
1215 | * parameters that may vary during BSS's lifespan, and may affect low | 1208 | * parameters that may vary during BSS's lifespan, and may affect low |
1216 | * level driver (e.g. assoc/disassoc status, erp parameters). | 1209 | * level driver (e.g. assoc/disassoc status, erp parameters). |
1217 | * This function should not be used if no BSS has been set, unless | 1210 | * This function should not be used if no BSS has been set, unless |
1218 | * for association indication. The @changed parameter indicates which | 1211 | * for association indication. The @changed parameter indicates which |
1219 | * of the bss parameters has changed when a call is made. | 1212 | * of the bss parameters has changed when a call is made. |
1220 | * | 1213 | * |
1221 | * @configure_filter: Configure the device's RX filter. | 1214 | * @configure_filter: Configure the device's RX filter. |
1222 | * See the section "Frame filtering" for more information. | 1215 | * See the section "Frame filtering" for more information. |
1223 | * This callback must be implemented and atomic. | 1216 | * This callback must be implemented and atomic. |
1224 | * | 1217 | * |
1225 | * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit | 1218 | * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit |
1226 | * must be set or cleared for a given STA. Must be atomic. | 1219 | * must be set or cleared for a given STA. Must be atomic. |
1227 | * | 1220 | * |
1228 | * @set_key: See the section "Hardware crypto acceleration" | 1221 | * @set_key: See the section "Hardware crypto acceleration" |
1229 | * This callback can sleep, and is only called between add_interface | 1222 | * This callback can sleep, and is only called between add_interface |
1230 | * and remove_interface calls, i.e. while the interface with the | 1223 | * and remove_interface calls, i.e. while the interface with the |
1231 | * given local_address is enabled. | 1224 | * given local_address is enabled. |
1232 | * | 1225 | * |
1233 | * @update_tkip_key: See the section "Hardware crypto acceleration" | 1226 | * @update_tkip_key: See the section "Hardware crypto acceleration" |
1234 | * This callback will be called in the context of Rx. Called for drivers | 1227 | * This callback will be called in the context of Rx. Called for drivers |
1235 | * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. | 1228 | * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. |
1236 | * | 1229 | * |
1237 | * @hw_scan: Ask the hardware to service the scan request, no need to start | 1230 | * @hw_scan: Ask the hardware to service the scan request, no need to start |
1238 | * the scan state machine in stack. The scan must honour the channel | 1231 | * the scan state machine in stack. The scan must honour the channel |
1239 | * configuration done by the regulatory agent in the wiphy's registered | 1232 | * configuration done by the regulatory agent in the wiphy's registered |
1240 | * bands. When the scan finishes, ieee80211_scan_completed() must be | 1233 | * bands. When the scan finishes, ieee80211_scan_completed() must be |
1241 | * called; note that it also must be called when the scan cannot finish | 1234 | * called; note that it also must be called when the scan cannot finish |
1242 | * because the hardware is turned off! Anything else is a bug! | 1235 | * because the hardware is turned off! Anything else is a bug! |
1243 | * | 1236 | * |
1244 | * @get_stats: return low-level statistics | 1237 | * @get_stats: return low-level statistics |
1245 | * | 1238 | * |
1246 | * @get_tkip_seq: If your device implements TKIP encryption in hardware this | 1239 | * @get_tkip_seq: If your device implements TKIP encryption in hardware this |
1247 | * callback should be provided to read the TKIP transmit IVs (both IV32 | 1240 | * callback should be provided to read the TKIP transmit IVs (both IV32 |
1248 | * and IV16) for the given key from hardware. | 1241 | * and IV16) for the given key from hardware. |
1249 | * | 1242 | * |
1250 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) | 1243 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) |
1251 | * | 1244 | * |
1252 | * @sta_notify: Notifies low level driver about addition, removal or power | 1245 | * @sta_notify: Notifies low level driver about addition, removal or power |
1253 | * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. | 1246 | * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. |
1254 | * Must be atomic. | 1247 | * Must be atomic. |
1255 | * | 1248 | * |
1256 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 1249 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
1257 | * bursting) for a hardware TX queue. | 1250 | * bursting) for a hardware TX queue. |
1258 | * | 1251 | * |
1259 | * @get_tx_stats: Get statistics of the current TX queue status. This is used | 1252 | * @get_tx_stats: Get statistics of the current TX queue status. This is used |
1260 | * to get number of currently queued packets (queue length), maximum queue | 1253 | * to get number of currently queued packets (queue length), maximum queue |
1261 | * size (limit), and total number of packets sent using each TX queue | 1254 | * size (limit), and total number of packets sent using each TX queue |
1262 | * (count). The 'stats' pointer points to an array that has hw->queues + | 1255 | * (count). The 'stats' pointer points to an array that has hw->queues + |
1263 | * hw->ampdu_queues items. | 1256 | * hw->ampdu_queues items. |
1264 | * | 1257 | * |
1265 | * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, | 1258 | * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, |
1266 | * this is only used for IBSS mode debugging and, as such, is not a | 1259 | * this is only used for IBSS mode debugging and, as such, is not a |
1267 | * required function. Must be atomic. | 1260 | * required function. Must be atomic. |
1268 | * | 1261 | * |
1269 | * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize | 1262 | * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize |
1270 | * with other STAs in the IBSS. This is only used in IBSS mode. This | 1263 | * with other STAs in the IBSS. This is only used in IBSS mode. This |
1271 | * function is optional if the firmware/hardware takes full care of | 1264 | * function is optional if the firmware/hardware takes full care of |
1272 | * TSF synchronization. | 1265 | * TSF synchronization. |
1273 | * | 1266 | * |
1274 | * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. | 1267 | * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. |
1275 | * This is needed only for IBSS mode and the result of this function is | 1268 | * This is needed only for IBSS mode and the result of this function is |
1276 | * used to determine whether to reply to Probe Requests. | 1269 | * used to determine whether to reply to Probe Requests. |
1277 | * | 1270 | * |
1278 | * @ampdu_action: Perform a certain A-MPDU action | 1271 | * @ampdu_action: Perform a certain A-MPDU action |
1279 | * The RA/TID combination determines the destination and TID we want | 1272 | * The RA/TID combination determines the destination and TID we want |
1280 | * the ampdu action to be performed for. The action is defined through | 1273 | * the ampdu action to be performed for. The action is defined through |
1281 | * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) | 1274 | * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) |
1282 | * is the first frame we expect to perform the action on. notice | 1275 | * is the first frame we expect to perform the action on. notice |
1283 | * that TX/RX_STOP can pass NULL for this parameter. | 1276 | * that TX/RX_STOP can pass NULL for this parameter. |
1284 | */ | 1277 | */ |
1285 | struct ieee80211_ops { | 1278 | struct ieee80211_ops { |
1286 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 1279 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
1287 | int (*start)(struct ieee80211_hw *hw); | 1280 | int (*start)(struct ieee80211_hw *hw); |
1288 | void (*stop)(struct ieee80211_hw *hw); | 1281 | void (*stop)(struct ieee80211_hw *hw); |
1289 | int (*add_interface)(struct ieee80211_hw *hw, | 1282 | int (*add_interface)(struct ieee80211_hw *hw, |
1290 | struct ieee80211_if_init_conf *conf); | 1283 | struct ieee80211_if_init_conf *conf); |
1291 | void (*remove_interface)(struct ieee80211_hw *hw, | 1284 | void (*remove_interface)(struct ieee80211_hw *hw, |
1292 | struct ieee80211_if_init_conf *conf); | 1285 | struct ieee80211_if_init_conf *conf); |
1293 | int (*config)(struct ieee80211_hw *hw, u32 changed); | 1286 | int (*config)(struct ieee80211_hw *hw, u32 changed); |
1294 | int (*config_interface)(struct ieee80211_hw *hw, | 1287 | int (*config_interface)(struct ieee80211_hw *hw, |
1295 | struct ieee80211_vif *vif, | 1288 | struct ieee80211_vif *vif, |
1296 | struct ieee80211_if_conf *conf); | 1289 | struct ieee80211_if_conf *conf); |
1297 | void (*bss_info_changed)(struct ieee80211_hw *hw, | 1290 | void (*bss_info_changed)(struct ieee80211_hw *hw, |
1298 | struct ieee80211_vif *vif, | 1291 | struct ieee80211_vif *vif, |
1299 | struct ieee80211_bss_conf *info, | 1292 | struct ieee80211_bss_conf *info, |
1300 | u32 changed); | 1293 | u32 changed); |
1301 | void (*configure_filter)(struct ieee80211_hw *hw, | 1294 | void (*configure_filter)(struct ieee80211_hw *hw, |
1302 | unsigned int changed_flags, | 1295 | unsigned int changed_flags, |
1303 | unsigned int *total_flags, | 1296 | unsigned int *total_flags, |
1304 | int mc_count, struct dev_addr_list *mc_list); | 1297 | int mc_count, struct dev_addr_list *mc_list); |
1305 | int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, | 1298 | int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, |
1306 | bool set); | 1299 | bool set); |
1307 | int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 1300 | int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
1308 | const u8 *local_address, const u8 *address, | 1301 | const u8 *local_address, const u8 *address, |
1309 | struct ieee80211_key_conf *key); | 1302 | struct ieee80211_key_conf *key); |
1310 | void (*update_tkip_key)(struct ieee80211_hw *hw, | 1303 | void (*update_tkip_key)(struct ieee80211_hw *hw, |
1311 | struct ieee80211_key_conf *conf, const u8 *address, | 1304 | struct ieee80211_key_conf *conf, const u8 *address, |
1312 | u32 iv32, u16 *phase1key); | 1305 | u32 iv32, u16 *phase1key); |
1313 | int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); | 1306 | int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); |
1314 | int (*get_stats)(struct ieee80211_hw *hw, | 1307 | int (*get_stats)(struct ieee80211_hw *hw, |
1315 | struct ieee80211_low_level_stats *stats); | 1308 | struct ieee80211_low_level_stats *stats); |
1316 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, | 1309 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
1317 | u32 *iv32, u16 *iv16); | 1310 | u32 *iv32, u16 *iv16); |
1318 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); | 1311 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); |
1319 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1312 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1320 | enum sta_notify_cmd, struct ieee80211_sta *sta); | 1313 | enum sta_notify_cmd, struct ieee80211_sta *sta); |
1321 | int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, | 1314 | int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, |
1322 | const struct ieee80211_tx_queue_params *params); | 1315 | const struct ieee80211_tx_queue_params *params); |
1323 | int (*get_tx_stats)(struct ieee80211_hw *hw, | 1316 | int (*get_tx_stats)(struct ieee80211_hw *hw, |
1324 | struct ieee80211_tx_queue_stats *stats); | 1317 | struct ieee80211_tx_queue_stats *stats); |
1325 | u64 (*get_tsf)(struct ieee80211_hw *hw); | 1318 | u64 (*get_tsf)(struct ieee80211_hw *hw); |
1326 | void (*reset_tsf)(struct ieee80211_hw *hw); | 1319 | void (*reset_tsf)(struct ieee80211_hw *hw); |
1327 | int (*tx_last_beacon)(struct ieee80211_hw *hw); | 1320 | int (*tx_last_beacon)(struct ieee80211_hw *hw); |
1328 | int (*ampdu_action)(struct ieee80211_hw *hw, | 1321 | int (*ampdu_action)(struct ieee80211_hw *hw, |
1329 | enum ieee80211_ampdu_mlme_action action, | 1322 | enum ieee80211_ampdu_mlme_action action, |
1330 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 1323 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); |
1331 | }; | 1324 | }; |
1332 | 1325 | ||
1333 | /** | 1326 | /** |
1334 | * ieee80211_alloc_hw - Allocate a new hardware device | 1327 | * ieee80211_alloc_hw - Allocate a new hardware device |
1335 | * | 1328 | * |
1336 | * This must be called once for each hardware device. The returned pointer | 1329 | * This must be called once for each hardware device. The returned pointer |
1337 | * must be used to refer to this device when calling other functions. | 1330 | * must be used to refer to this device when calling other functions. |
1338 | * mac80211 allocates a private data area for the driver pointed to by | 1331 | * mac80211 allocates a private data area for the driver pointed to by |
1339 | * @priv in &struct ieee80211_hw, the size of this area is given as | 1332 | * @priv in &struct ieee80211_hw, the size of this area is given as |
1340 | * @priv_data_len. | 1333 | * @priv_data_len. |
1341 | * | 1334 | * |
1342 | * @priv_data_len: length of private data | 1335 | * @priv_data_len: length of private data |
1343 | * @ops: callbacks for this device | 1336 | * @ops: callbacks for this device |
1344 | */ | 1337 | */ |
1345 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 1338 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
1346 | const struct ieee80211_ops *ops); | 1339 | const struct ieee80211_ops *ops); |
1347 | 1340 | ||
1348 | /** | 1341 | /** |
1349 | * ieee80211_register_hw - Register hardware device | 1342 | * ieee80211_register_hw - Register hardware device |
1350 | * | 1343 | * |
1351 | * You must call this function before any other functions in | 1344 | * You must call this function before any other functions in |
1352 | * mac80211. Note that before a hardware can be registered, you | 1345 | * mac80211. Note that before a hardware can be registered, you |
1353 | * need to fill the contained wiphy's information. | 1346 | * need to fill the contained wiphy's information. |
1354 | * | 1347 | * |
1355 | * @hw: the device to register as returned by ieee80211_alloc_hw() | 1348 | * @hw: the device to register as returned by ieee80211_alloc_hw() |
1356 | */ | 1349 | */ |
1357 | int ieee80211_register_hw(struct ieee80211_hw *hw); | 1350 | int ieee80211_register_hw(struct ieee80211_hw *hw); |
1358 | 1351 | ||
1359 | #ifdef CONFIG_MAC80211_LEDS | 1352 | #ifdef CONFIG_MAC80211_LEDS |
1360 | extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); | 1353 | extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); |
1361 | extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); | 1354 | extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); |
1362 | extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); | 1355 | extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); |
1363 | extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); | 1356 | extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); |
1364 | #endif | 1357 | #endif |
1365 | /** | 1358 | /** |
1366 | * ieee80211_get_tx_led_name - get name of TX LED | 1359 | * ieee80211_get_tx_led_name - get name of TX LED |
1367 | * | 1360 | * |
1368 | * mac80211 creates a transmit LED trigger for each wireless hardware | 1361 | * mac80211 creates a transmit LED trigger for each wireless hardware |
1369 | * that can be used to drive LEDs if your driver registers a LED device. | 1362 | * that can be used to drive LEDs if your driver registers a LED device. |
1370 | * This function returns the name (or %NULL if not configured for LEDs) | 1363 | * This function returns the name (or %NULL if not configured for LEDs) |
1371 | * of the trigger so you can automatically link the LED device. | 1364 | * of the trigger so you can automatically link the LED device. |
1372 | * | 1365 | * |
1373 | * @hw: the hardware to get the LED trigger name for | 1366 | * @hw: the hardware to get the LED trigger name for |
1374 | */ | 1367 | */ |
1375 | static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) | 1368 | static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) |
1376 | { | 1369 | { |
1377 | #ifdef CONFIG_MAC80211_LEDS | 1370 | #ifdef CONFIG_MAC80211_LEDS |
1378 | return __ieee80211_get_tx_led_name(hw); | 1371 | return __ieee80211_get_tx_led_name(hw); |
1379 | #else | 1372 | #else |
1380 | return NULL; | 1373 | return NULL; |
1381 | #endif | 1374 | #endif |
1382 | } | 1375 | } |
1383 | 1376 | ||
1384 | /** | 1377 | /** |
1385 | * ieee80211_get_rx_led_name - get name of RX LED | 1378 | * ieee80211_get_rx_led_name - get name of RX LED |
1386 | * | 1379 | * |
1387 | * mac80211 creates a receive LED trigger for each wireless hardware | 1380 | * mac80211 creates a receive LED trigger for each wireless hardware |
1388 | * that can be used to drive LEDs if your driver registers a LED device. | 1381 | * that can be used to drive LEDs if your driver registers a LED device. |
1389 | * This function returns the name (or %NULL if not configured for LEDs) | 1382 | * This function returns the name (or %NULL if not configured for LEDs) |
1390 | * of the trigger so you can automatically link the LED device. | 1383 | * of the trigger so you can automatically link the LED device. |
1391 | * | 1384 | * |
1392 | * @hw: the hardware to get the LED trigger name for | 1385 | * @hw: the hardware to get the LED trigger name for |
1393 | */ | 1386 | */ |
1394 | static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) | 1387 | static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) |
1395 | { | 1388 | { |
1396 | #ifdef CONFIG_MAC80211_LEDS | 1389 | #ifdef CONFIG_MAC80211_LEDS |
1397 | return __ieee80211_get_rx_led_name(hw); | 1390 | return __ieee80211_get_rx_led_name(hw); |
1398 | #else | 1391 | #else |
1399 | return NULL; | 1392 | return NULL; |
1400 | #endif | 1393 | #endif |
1401 | } | 1394 | } |
1402 | 1395 | ||
1403 | /** | 1396 | /** |
1404 | * ieee80211_get_assoc_led_name - get name of association LED | 1397 | * ieee80211_get_assoc_led_name - get name of association LED |
1405 | * | 1398 | * |
1406 | * mac80211 creates a association LED trigger for each wireless hardware | 1399 | * mac80211 creates a association LED trigger for each wireless hardware |
1407 | * that can be used to drive LEDs if your driver registers a LED device. | 1400 | * that can be used to drive LEDs if your driver registers a LED device. |
1408 | * This function returns the name (or %NULL if not configured for LEDs) | 1401 | * This function returns the name (or %NULL if not configured for LEDs) |
1409 | * of the trigger so you can automatically link the LED device. | 1402 | * of the trigger so you can automatically link the LED device. |
1410 | * | 1403 | * |
1411 | * @hw: the hardware to get the LED trigger name for | 1404 | * @hw: the hardware to get the LED trigger name for |
1412 | */ | 1405 | */ |
1413 | static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) | 1406 | static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) |
1414 | { | 1407 | { |
1415 | #ifdef CONFIG_MAC80211_LEDS | 1408 | #ifdef CONFIG_MAC80211_LEDS |
1416 | return __ieee80211_get_assoc_led_name(hw); | 1409 | return __ieee80211_get_assoc_led_name(hw); |
1417 | #else | 1410 | #else |
1418 | return NULL; | 1411 | return NULL; |
1419 | #endif | 1412 | #endif |
1420 | } | 1413 | } |
1421 | 1414 | ||
1422 | /** | 1415 | /** |
1423 | * ieee80211_get_radio_led_name - get name of radio LED | 1416 | * ieee80211_get_radio_led_name - get name of radio LED |
1424 | * | 1417 | * |
1425 | * mac80211 creates a radio change LED trigger for each wireless hardware | 1418 | * mac80211 creates a radio change LED trigger for each wireless hardware |
1426 | * that can be used to drive LEDs if your driver registers a LED device. | 1419 | * that can be used to drive LEDs if your driver registers a LED device. |
1427 | * This function returns the name (or %NULL if not configured for LEDs) | 1420 | * This function returns the name (or %NULL if not configured for LEDs) |
1428 | * of the trigger so you can automatically link the LED device. | 1421 | * of the trigger so you can automatically link the LED device. |
1429 | * | 1422 | * |
1430 | * @hw: the hardware to get the LED trigger name for | 1423 | * @hw: the hardware to get the LED trigger name for |
1431 | */ | 1424 | */ |
1432 | static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) | 1425 | static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) |
1433 | { | 1426 | { |
1434 | #ifdef CONFIG_MAC80211_LEDS | 1427 | #ifdef CONFIG_MAC80211_LEDS |
1435 | return __ieee80211_get_radio_led_name(hw); | 1428 | return __ieee80211_get_radio_led_name(hw); |
1436 | #else | 1429 | #else |
1437 | return NULL; | 1430 | return NULL; |
1438 | #endif | 1431 | #endif |
1439 | } | 1432 | } |
1440 | 1433 | ||
1441 | /** | 1434 | /** |
1442 | * ieee80211_unregister_hw - Unregister a hardware device | 1435 | * ieee80211_unregister_hw - Unregister a hardware device |
1443 | * | 1436 | * |
1444 | * This function instructs mac80211 to free allocated resources | 1437 | * This function instructs mac80211 to free allocated resources |
1445 | * and unregister netdevices from the networking subsystem. | 1438 | * and unregister netdevices from the networking subsystem. |
1446 | * | 1439 | * |
1447 | * @hw: the hardware to unregister | 1440 | * @hw: the hardware to unregister |
1448 | */ | 1441 | */ |
1449 | void ieee80211_unregister_hw(struct ieee80211_hw *hw); | 1442 | void ieee80211_unregister_hw(struct ieee80211_hw *hw); |
1450 | 1443 | ||
1451 | /** | 1444 | /** |
1452 | * ieee80211_free_hw - free hardware descriptor | 1445 | * ieee80211_free_hw - free hardware descriptor |
1453 | * | 1446 | * |
1454 | * This function frees everything that was allocated, including the | 1447 | * This function frees everything that was allocated, including the |
1455 | * private data for the driver. You must call ieee80211_unregister_hw() | 1448 | * private data for the driver. You must call ieee80211_unregister_hw() |
1456 | * before calling this function. | 1449 | * before calling this function. |
1457 | * | 1450 | * |
1458 | * @hw: the hardware to free | 1451 | * @hw: the hardware to free |
1459 | */ | 1452 | */ |
1460 | void ieee80211_free_hw(struct ieee80211_hw *hw); | 1453 | void ieee80211_free_hw(struct ieee80211_hw *hw); |
1461 | 1454 | ||
1462 | /* trick to avoid symbol clashes with the ieee80211 subsystem */ | 1455 | /* trick to avoid symbol clashes with the ieee80211 subsystem */ |
1463 | void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | 1456 | void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, |
1464 | struct ieee80211_rx_status *status); | 1457 | struct ieee80211_rx_status *status); |
1465 | 1458 | ||
1466 | /** | 1459 | /** |
1467 | * ieee80211_rx - receive frame | 1460 | * ieee80211_rx - receive frame |
1468 | * | 1461 | * |
1469 | * Use this function to hand received frames to mac80211. The receive | 1462 | * Use this function to hand received frames to mac80211. The receive |
1470 | * buffer in @skb must start with an IEEE 802.11 header or a radiotap | 1463 | * buffer in @skb must start with an IEEE 802.11 header or a radiotap |
1471 | * header if %RX_FLAG_RADIOTAP is set in the @status flags. | 1464 | * header if %RX_FLAG_RADIOTAP is set in the @status flags. |
1472 | * | 1465 | * |
1473 | * This function may not be called in IRQ context. Calls to this function | 1466 | * This function may not be called in IRQ context. Calls to this function |
1474 | * for a single hardware must be synchronized against each other. Calls | 1467 | * for a single hardware must be synchronized against each other. Calls |
1475 | * to this function and ieee80211_rx_irqsafe() may not be mixed for a | 1468 | * to this function and ieee80211_rx_irqsafe() may not be mixed for a |
1476 | * single hardware. | 1469 | * single hardware. |
1477 | * | 1470 | * |
1478 | * @hw: the hardware this frame came in on | 1471 | * @hw: the hardware this frame came in on |
1479 | * @skb: the buffer to receive, owned by mac80211 after this call | 1472 | * @skb: the buffer to receive, owned by mac80211 after this call |
1480 | * @status: status of this frame; the status pointer need not be valid | 1473 | * @status: status of this frame; the status pointer need not be valid |
1481 | * after this function returns | 1474 | * after this function returns |
1482 | */ | 1475 | */ |
1483 | static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | 1476 | static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, |
1484 | struct ieee80211_rx_status *status) | 1477 | struct ieee80211_rx_status *status) |
1485 | { | 1478 | { |
1486 | __ieee80211_rx(hw, skb, status); | 1479 | __ieee80211_rx(hw, skb, status); |
1487 | } | 1480 | } |
1488 | 1481 | ||
1489 | /** | 1482 | /** |
1490 | * ieee80211_rx_irqsafe - receive frame | 1483 | * ieee80211_rx_irqsafe - receive frame |
1491 | * | 1484 | * |
1492 | * Like ieee80211_rx() but can be called in IRQ context | 1485 | * Like ieee80211_rx() but can be called in IRQ context |
1493 | * (internally defers to a tasklet.) | 1486 | * (internally defers to a tasklet.) |
1494 | * | 1487 | * |
1495 | * Calls to this function and ieee80211_rx() may not be mixed for a | 1488 | * Calls to this function and ieee80211_rx() may not be mixed for a |
1496 | * single hardware. | 1489 | * single hardware. |
1497 | * | 1490 | * |
1498 | * @hw: the hardware this frame came in on | 1491 | * @hw: the hardware this frame came in on |
1499 | * @skb: the buffer to receive, owned by mac80211 after this call | 1492 | * @skb: the buffer to receive, owned by mac80211 after this call |
1500 | * @status: status of this frame; the status pointer need not be valid | 1493 | * @status: status of this frame; the status pointer need not be valid |
1501 | * after this function returns and is not freed by mac80211, | 1494 | * after this function returns and is not freed by mac80211, |
1502 | * it is recommended that it points to a stack area | 1495 | * it is recommended that it points to a stack area |
1503 | */ | 1496 | */ |
1504 | void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, | 1497 | void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, |
1505 | struct sk_buff *skb, | 1498 | struct sk_buff *skb, |
1506 | struct ieee80211_rx_status *status); | 1499 | struct ieee80211_rx_status *status); |
1507 | 1500 | ||
1508 | /** | 1501 | /** |
1509 | * ieee80211_tx_status - transmit status callback | 1502 | * ieee80211_tx_status - transmit status callback |
1510 | * | 1503 | * |
1511 | * Call this function for all transmitted frames after they have been | 1504 | * Call this function for all transmitted frames after they have been |
1512 | * transmitted. It is permissible to not call this function for | 1505 | * transmitted. It is permissible to not call this function for |
1513 | * multicast frames but this can affect statistics. | 1506 | * multicast frames but this can affect statistics. |
1514 | * | 1507 | * |
1515 | * This function may not be called in IRQ context. Calls to this function | 1508 | * This function may not be called in IRQ context. Calls to this function |
1516 | * for a single hardware must be synchronized against each other. Calls | 1509 | * for a single hardware must be synchronized against each other. Calls |
1517 | * to this function and ieee80211_tx_status_irqsafe() may not be mixed | 1510 | * to this function and ieee80211_tx_status_irqsafe() may not be mixed |
1518 | * for a single hardware. | 1511 | * for a single hardware. |
1519 | * | 1512 | * |
1520 | * @hw: the hardware the frame was transmitted by | 1513 | * @hw: the hardware the frame was transmitted by |
1521 | * @skb: the frame that was transmitted, owned by mac80211 after this call | 1514 | * @skb: the frame that was transmitted, owned by mac80211 after this call |
1522 | */ | 1515 | */ |
1523 | void ieee80211_tx_status(struct ieee80211_hw *hw, | 1516 | void ieee80211_tx_status(struct ieee80211_hw *hw, |
1524 | struct sk_buff *skb); | 1517 | struct sk_buff *skb); |
1525 | 1518 | ||
1526 | /** | 1519 | /** |
1527 | * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback | 1520 | * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback |
1528 | * | 1521 | * |
1529 | * Like ieee80211_tx_status() but can be called in IRQ context | 1522 | * Like ieee80211_tx_status() but can be called in IRQ context |
1530 | * (internally defers to a tasklet.) | 1523 | * (internally defers to a tasklet.) |
1531 | * | 1524 | * |
1532 | * Calls to this function and ieee80211_tx_status() may not be mixed for a | 1525 | * Calls to this function and ieee80211_tx_status() may not be mixed for a |
1533 | * single hardware. | 1526 | * single hardware. |
1534 | * | 1527 | * |
1535 | * @hw: the hardware the frame was transmitted by | 1528 | * @hw: the hardware the frame was transmitted by |
1536 | * @skb: the frame that was transmitted, owned by mac80211 after this call | 1529 | * @skb: the frame that was transmitted, owned by mac80211 after this call |
1537 | */ | 1530 | */ |
1538 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | 1531 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, |
1539 | struct sk_buff *skb); | 1532 | struct sk_buff *skb); |
1540 | 1533 | ||
1541 | /** | 1534 | /** |
1542 | * ieee80211_beacon_get - beacon generation function | 1535 | * ieee80211_beacon_get - beacon generation function |
1543 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1536 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1544 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1537 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1545 | * | 1538 | * |
1546 | * If the beacon frames are generated by the host system (i.e., not in | 1539 | * If the beacon frames are generated by the host system (i.e., not in |
1547 | * hardware/firmware), the low-level driver uses this function to receive | 1540 | * hardware/firmware), the low-level driver uses this function to receive |
1548 | * the next beacon frame from the 802.11 code. The low-level is responsible | 1541 | * the next beacon frame from the 802.11 code. The low-level is responsible |
1549 | * for calling this function before beacon data is needed (e.g., based on | 1542 | * for calling this function before beacon data is needed (e.g., based on |
1550 | * hardware interrupt). Returned skb is used only once and low-level driver | 1543 | * hardware interrupt). Returned skb is used only once and low-level driver |
1551 | * is responsible for freeing it. | 1544 | * is responsible for freeing it. |
1552 | */ | 1545 | */ |
1553 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1546 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
1554 | struct ieee80211_vif *vif); | 1547 | struct ieee80211_vif *vif); |
1555 | 1548 | ||
1556 | /** | 1549 | /** |
1557 | * ieee80211_rts_get - RTS frame generation function | 1550 | * ieee80211_rts_get - RTS frame generation function |
1558 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1551 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1559 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1552 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1560 | * @frame: pointer to the frame that is going to be protected by the RTS. | 1553 | * @frame: pointer to the frame that is going to be protected by the RTS. |
1561 | * @frame_len: the frame length (in octets). | 1554 | * @frame_len: the frame length (in octets). |
1562 | * @frame_txctl: &struct ieee80211_tx_info of the frame. | 1555 | * @frame_txctl: &struct ieee80211_tx_info of the frame. |
1563 | * @rts: The buffer where to store the RTS frame. | 1556 | * @rts: The buffer where to store the RTS frame. |
1564 | * | 1557 | * |
1565 | * If the RTS frames are generated by the host system (i.e., not in | 1558 | * If the RTS frames are generated by the host system (i.e., not in |
1566 | * hardware/firmware), the low-level driver uses this function to receive | 1559 | * hardware/firmware), the low-level driver uses this function to receive |
1567 | * the next RTS frame from the 802.11 code. The low-level is responsible | 1560 | * the next RTS frame from the 802.11 code. The low-level is responsible |
1568 | * for calling this function before and RTS frame is needed. | 1561 | * for calling this function before and RTS frame is needed. |
1569 | */ | 1562 | */ |
1570 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1563 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1571 | const void *frame, size_t frame_len, | 1564 | const void *frame, size_t frame_len, |
1572 | const struct ieee80211_tx_info *frame_txctl, | 1565 | const struct ieee80211_tx_info *frame_txctl, |
1573 | struct ieee80211_rts *rts); | 1566 | struct ieee80211_rts *rts); |
1574 | 1567 | ||
1575 | /** | 1568 | /** |
1576 | * ieee80211_rts_duration - Get the duration field for an RTS frame | 1569 | * ieee80211_rts_duration - Get the duration field for an RTS frame |
1577 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1570 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1578 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1571 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1579 | * @frame_len: the length of the frame that is going to be protected by the RTS. | 1572 | * @frame_len: the length of the frame that is going to be protected by the RTS. |
1580 | * @frame_txctl: &struct ieee80211_tx_info of the frame. | 1573 | * @frame_txctl: &struct ieee80211_tx_info of the frame. |
1581 | * | 1574 | * |
1582 | * If the RTS is generated in firmware, but the host system must provide | 1575 | * If the RTS is generated in firmware, but the host system must provide |
1583 | * the duration field, the low-level driver uses this function to receive | 1576 | * the duration field, the low-level driver uses this function to receive |
1584 | * the duration field value in little-endian byteorder. | 1577 | * the duration field value in little-endian byteorder. |
1585 | */ | 1578 | */ |
1586 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | 1579 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, |
1587 | struct ieee80211_vif *vif, size_t frame_len, | 1580 | struct ieee80211_vif *vif, size_t frame_len, |
1588 | const struct ieee80211_tx_info *frame_txctl); | 1581 | const struct ieee80211_tx_info *frame_txctl); |
1589 | 1582 | ||
1590 | /** | 1583 | /** |
1591 | * ieee80211_ctstoself_get - CTS-to-self frame generation function | 1584 | * ieee80211_ctstoself_get - CTS-to-self frame generation function |
1592 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1585 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1593 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1586 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1594 | * @frame: pointer to the frame that is going to be protected by the CTS-to-self. | 1587 | * @frame: pointer to the frame that is going to be protected by the CTS-to-self. |
1595 | * @frame_len: the frame length (in octets). | 1588 | * @frame_len: the frame length (in octets). |
1596 | * @frame_txctl: &struct ieee80211_tx_info of the frame. | 1589 | * @frame_txctl: &struct ieee80211_tx_info of the frame. |
1597 | * @cts: The buffer where to store the CTS-to-self frame. | 1590 | * @cts: The buffer where to store the CTS-to-self frame. |
1598 | * | 1591 | * |
1599 | * If the CTS-to-self frames are generated by the host system (i.e., not in | 1592 | * If the CTS-to-self frames are generated by the host system (i.e., not in |
1600 | * hardware/firmware), the low-level driver uses this function to receive | 1593 | * hardware/firmware), the low-level driver uses this function to receive |
1601 | * the next CTS-to-self frame from the 802.11 code. The low-level is responsible | 1594 | * the next CTS-to-self frame from the 802.11 code. The low-level is responsible |
1602 | * for calling this function before and CTS-to-self frame is needed. | 1595 | * for calling this function before and CTS-to-self frame is needed. |
1603 | */ | 1596 | */ |
1604 | void ieee80211_ctstoself_get(struct ieee80211_hw *hw, | 1597 | void ieee80211_ctstoself_get(struct ieee80211_hw *hw, |
1605 | struct ieee80211_vif *vif, | 1598 | struct ieee80211_vif *vif, |
1606 | const void *frame, size_t frame_len, | 1599 | const void *frame, size_t frame_len, |
1607 | const struct ieee80211_tx_info *frame_txctl, | 1600 | const struct ieee80211_tx_info *frame_txctl, |
1608 | struct ieee80211_cts *cts); | 1601 | struct ieee80211_cts *cts); |
1609 | 1602 | ||
1610 | /** | 1603 | /** |
1611 | * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame | 1604 | * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame |
1612 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1605 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1613 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1606 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1614 | * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. | 1607 | * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. |
1615 | * @frame_txctl: &struct ieee80211_tx_info of the frame. | 1608 | * @frame_txctl: &struct ieee80211_tx_info of the frame. |
1616 | * | 1609 | * |
1617 | * If the CTS-to-self is generated in firmware, but the host system must provide | 1610 | * If the CTS-to-self is generated in firmware, but the host system must provide |
1618 | * the duration field, the low-level driver uses this function to receive | 1611 | * the duration field, the low-level driver uses this function to receive |
1619 | * the duration field value in little-endian byteorder. | 1612 | * the duration field value in little-endian byteorder. |
1620 | */ | 1613 | */ |
1621 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | 1614 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, |
1622 | struct ieee80211_vif *vif, | 1615 | struct ieee80211_vif *vif, |
1623 | size_t frame_len, | 1616 | size_t frame_len, |
1624 | const struct ieee80211_tx_info *frame_txctl); | 1617 | const struct ieee80211_tx_info *frame_txctl); |
1625 | 1618 | ||
1626 | /** | 1619 | /** |
1627 | * ieee80211_generic_frame_duration - Calculate the duration field for a frame | 1620 | * ieee80211_generic_frame_duration - Calculate the duration field for a frame |
1628 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1621 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1629 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1622 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1630 | * @frame_len: the length of the frame. | 1623 | * @frame_len: the length of the frame. |
1631 | * @rate: the rate at which the frame is going to be transmitted. | 1624 | * @rate: the rate at which the frame is going to be transmitted. |
1632 | * | 1625 | * |
1633 | * Calculate the duration field of some generic frame, given its | 1626 | * Calculate the duration field of some generic frame, given its |
1634 | * length and transmission rate (in 100kbps). | 1627 | * length and transmission rate (in 100kbps). |
1635 | */ | 1628 | */ |
1636 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | 1629 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, |
1637 | struct ieee80211_vif *vif, | 1630 | struct ieee80211_vif *vif, |
1638 | size_t frame_len, | 1631 | size_t frame_len, |
1639 | struct ieee80211_rate *rate); | 1632 | struct ieee80211_rate *rate); |
1640 | 1633 | ||
1641 | /** | 1634 | /** |
1642 | * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames | 1635 | * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames |
1643 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1636 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1644 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 1637 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
1645 | * | 1638 | * |
1646 | * Function for accessing buffered broadcast and multicast frames. If | 1639 | * Function for accessing buffered broadcast and multicast frames. If |
1647 | * hardware/firmware does not implement buffering of broadcast/multicast | 1640 | * hardware/firmware does not implement buffering of broadcast/multicast |
1648 | * frames when power saving is used, 802.11 code buffers them in the host | 1641 | * frames when power saving is used, 802.11 code buffers them in the host |
1649 | * memory. The low-level driver uses this function to fetch next buffered | 1642 | * memory. The low-level driver uses this function to fetch next buffered |
1650 | * frame. In most cases, this is used when generating beacon frame. This | 1643 | * frame. In most cases, this is used when generating beacon frame. This |
1651 | * function returns a pointer to the next buffered skb or NULL if no more | 1644 | * function returns a pointer to the next buffered skb or NULL if no more |
1652 | * buffered frames are available. | 1645 | * buffered frames are available. |
1653 | * | 1646 | * |
1654 | * Note: buffered frames are returned only after DTIM beacon frame was | 1647 | * Note: buffered frames are returned only after DTIM beacon frame was |
1655 | * generated with ieee80211_beacon_get() and the low-level driver must thus | 1648 | * generated with ieee80211_beacon_get() and the low-level driver must thus |
1656 | * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns | 1649 | * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns |
1657 | * NULL if the previous generated beacon was not DTIM, so the low-level driver | 1650 | * NULL if the previous generated beacon was not DTIM, so the low-level driver |
1658 | * does not need to check for DTIM beacons separately and should be able to | 1651 | * does not need to check for DTIM beacons separately and should be able to |
1659 | * use common code for all beacons. | 1652 | * use common code for all beacons. |
1660 | */ | 1653 | */ |
1661 | struct sk_buff * | 1654 | struct sk_buff * |
1662 | ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 1655 | ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
1663 | 1656 | ||
1664 | /** | 1657 | /** |
1665 | * ieee80211_get_hdrlen_from_skb - get header length from data | 1658 | * ieee80211_get_hdrlen_from_skb - get header length from data |
1666 | * | 1659 | * |
1667 | * Given an skb with a raw 802.11 header at the data pointer this function | 1660 | * Given an skb with a raw 802.11 header at the data pointer this function |
1668 | * returns the 802.11 header length in bytes (not including encryption | 1661 | * returns the 802.11 header length in bytes (not including encryption |
1669 | * headers). If the data in the sk_buff is too short to contain a valid 802.11 | 1662 | * headers). If the data in the sk_buff is too short to contain a valid 802.11 |
1670 | * header the function returns 0. | 1663 | * header the function returns 0. |
1671 | * | 1664 | * |
1672 | * @skb: the frame | 1665 | * @skb: the frame |
1673 | */ | 1666 | */ |
1674 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); | 1667 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); |
1675 | 1668 | ||
1676 | /** | 1669 | /** |
1677 | * ieee80211_hdrlen - get header length in bytes from frame control | 1670 | * ieee80211_hdrlen - get header length in bytes from frame control |
1678 | * @fc: frame control field in little-endian format | 1671 | * @fc: frame control field in little-endian format |
1679 | */ | 1672 | */ |
1680 | unsigned int ieee80211_hdrlen(__le16 fc); | 1673 | unsigned int ieee80211_hdrlen(__le16 fc); |
1681 | 1674 | ||
1682 | /** | 1675 | /** |
1683 | * ieee80211_get_tkip_key - get a TKIP rc4 for skb | 1676 | * ieee80211_get_tkip_key - get a TKIP rc4 for skb |
1684 | * | 1677 | * |
1685 | * This function computes a TKIP rc4 key for an skb. It computes | 1678 | * This function computes a TKIP rc4 key for an skb. It computes |
1686 | * a phase 1 key if needed (iv16 wraps around). This function is to | 1679 | * a phase 1 key if needed (iv16 wraps around). This function is to |
1687 | * be used by drivers which can do HW encryption but need to compute | 1680 | * be used by drivers which can do HW encryption but need to compute |
1688 | * to phase 1/2 key in SW. | 1681 | * to phase 1/2 key in SW. |
1689 | * | 1682 | * |
1690 | * @keyconf: the parameter passed with the set key | 1683 | * @keyconf: the parameter passed with the set key |
1691 | * @skb: the skb for which the key is needed | 1684 | * @skb: the skb for which the key is needed |
1692 | * @type: TBD | 1685 | * @type: TBD |
1693 | * @key: a buffer to which the key will be written | 1686 | * @key: a buffer to which the key will be written |
1694 | */ | 1687 | */ |
1695 | void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | 1688 | void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, |
1696 | struct sk_buff *skb, | 1689 | struct sk_buff *skb, |
1697 | enum ieee80211_tkip_key_type type, u8 *key); | 1690 | enum ieee80211_tkip_key_type type, u8 *key); |
1698 | /** | 1691 | /** |
1699 | * ieee80211_wake_queue - wake specific queue | 1692 | * ieee80211_wake_queue - wake specific queue |
1700 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1693 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1701 | * @queue: queue number (counted from zero). | 1694 | * @queue: queue number (counted from zero). |
1702 | * | 1695 | * |
1703 | * Drivers should use this function instead of netif_wake_queue. | 1696 | * Drivers should use this function instead of netif_wake_queue. |
1704 | */ | 1697 | */ |
1705 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); | 1698 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); |
1706 | 1699 | ||
1707 | /** | 1700 | /** |
1708 | * ieee80211_stop_queue - stop specific queue | 1701 | * ieee80211_stop_queue - stop specific queue |
1709 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1702 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1710 | * @queue: queue number (counted from zero). | 1703 | * @queue: queue number (counted from zero). |
1711 | * | 1704 | * |
1712 | * Drivers should use this function instead of netif_stop_queue. | 1705 | * Drivers should use this function instead of netif_stop_queue. |
1713 | */ | 1706 | */ |
1714 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); | 1707 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); |
1715 | 1708 | ||
1716 | /** | 1709 | /** |
1717 | * ieee80211_queue_stopped - test status of the queue | 1710 | * ieee80211_queue_stopped - test status of the queue |
1718 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1711 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1719 | * @queue: queue number (counted from zero). | 1712 | * @queue: queue number (counted from zero). |
1720 | * | 1713 | * |
1721 | * Drivers should use this function instead of netif_stop_queue. | 1714 | * Drivers should use this function instead of netif_stop_queue. |
1722 | */ | 1715 | */ |
1723 | 1716 | ||
1724 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue); | 1717 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue); |
1725 | 1718 | ||
1726 | /** | 1719 | /** |
1727 | * ieee80211_stop_queues - stop all queues | 1720 | * ieee80211_stop_queues - stop all queues |
1728 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1721 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1729 | * | 1722 | * |
1730 | * Drivers should use this function instead of netif_stop_queue. | 1723 | * Drivers should use this function instead of netif_stop_queue. |
1731 | */ | 1724 | */ |
1732 | void ieee80211_stop_queues(struct ieee80211_hw *hw); | 1725 | void ieee80211_stop_queues(struct ieee80211_hw *hw); |
1733 | 1726 | ||
1734 | /** | 1727 | /** |
1735 | * ieee80211_wake_queues - wake all queues | 1728 | * ieee80211_wake_queues - wake all queues |
1736 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1729 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1737 | * | 1730 | * |
1738 | * Drivers should use this function instead of netif_wake_queue. | 1731 | * Drivers should use this function instead of netif_wake_queue. |
1739 | */ | 1732 | */ |
1740 | void ieee80211_wake_queues(struct ieee80211_hw *hw); | 1733 | void ieee80211_wake_queues(struct ieee80211_hw *hw); |
1741 | 1734 | ||
1742 | /** | 1735 | /** |
1743 | * ieee80211_scan_completed - completed hardware scan | 1736 | * ieee80211_scan_completed - completed hardware scan |
1744 | * | 1737 | * |
1745 | * When hardware scan offload is used (i.e. the hw_scan() callback is | 1738 | * When hardware scan offload is used (i.e. the hw_scan() callback is |
1746 | * assigned) this function needs to be called by the driver to notify | 1739 | * assigned) this function needs to be called by the driver to notify |
1747 | * mac80211 that the scan finished. | 1740 | * mac80211 that the scan finished. |
1748 | * | 1741 | * |
1749 | * @hw: the hardware that finished the scan | 1742 | * @hw: the hardware that finished the scan |
1750 | */ | 1743 | */ |
1751 | void ieee80211_scan_completed(struct ieee80211_hw *hw); | 1744 | void ieee80211_scan_completed(struct ieee80211_hw *hw); |
1752 | 1745 | ||
1753 | /** | 1746 | /** |
1754 | * ieee80211_iterate_active_interfaces - iterate active interfaces | 1747 | * ieee80211_iterate_active_interfaces - iterate active interfaces |
1755 | * | 1748 | * |
1756 | * This function iterates over the interfaces associated with a given | 1749 | * This function iterates over the interfaces associated with a given |
1757 | * hardware that are currently active and calls the callback for them. | 1750 | * hardware that are currently active and calls the callback for them. |
1758 | * This function allows the iterator function to sleep, when the iterator | 1751 | * This function allows the iterator function to sleep, when the iterator |
1759 | * function is atomic @ieee80211_iterate_active_interfaces_atomic can | 1752 | * function is atomic @ieee80211_iterate_active_interfaces_atomic can |
1760 | * be used. | 1753 | * be used. |
1761 | * | 1754 | * |
1762 | * @hw: the hardware struct of which the interfaces should be iterated over | 1755 | * @hw: the hardware struct of which the interfaces should be iterated over |
1763 | * @iterator: the iterator function to call | 1756 | * @iterator: the iterator function to call |
1764 | * @data: first argument of the iterator function | 1757 | * @data: first argument of the iterator function |
1765 | */ | 1758 | */ |
1766 | void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, | 1759 | void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, |
1767 | void (*iterator)(void *data, u8 *mac, | 1760 | void (*iterator)(void *data, u8 *mac, |
1768 | struct ieee80211_vif *vif), | 1761 | struct ieee80211_vif *vif), |
1769 | void *data); | 1762 | void *data); |
1770 | 1763 | ||
1771 | /** | 1764 | /** |
1772 | * ieee80211_iterate_active_interfaces_atomic - iterate active interfaces | 1765 | * ieee80211_iterate_active_interfaces_atomic - iterate active interfaces |
1773 | * | 1766 | * |
1774 | * This function iterates over the interfaces associated with a given | 1767 | * This function iterates over the interfaces associated with a given |
1775 | * hardware that are currently active and calls the callback for them. | 1768 | * hardware that are currently active and calls the callback for them. |
1776 | * This function requires the iterator callback function to be atomic, | 1769 | * This function requires the iterator callback function to be atomic, |
1777 | * if that is not desired, use @ieee80211_iterate_active_interfaces instead. | 1770 | * if that is not desired, use @ieee80211_iterate_active_interfaces instead. |
1778 | * | 1771 | * |
1779 | * @hw: the hardware struct of which the interfaces should be iterated over | 1772 | * @hw: the hardware struct of which the interfaces should be iterated over |
1780 | * @iterator: the iterator function to call, cannot sleep | 1773 | * @iterator: the iterator function to call, cannot sleep |
1781 | * @data: first argument of the iterator function | 1774 | * @data: first argument of the iterator function |
1782 | */ | 1775 | */ |
1783 | void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, | 1776 | void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, |
1784 | void (*iterator)(void *data, | 1777 | void (*iterator)(void *data, |
1785 | u8 *mac, | 1778 | u8 *mac, |
1786 | struct ieee80211_vif *vif), | 1779 | struct ieee80211_vif *vif), |
1787 | void *data); | 1780 | void *data); |
1788 | 1781 | ||
1789 | /** | 1782 | /** |
1790 | * ieee80211_start_tx_ba_session - Start a tx Block Ack session. | 1783 | * ieee80211_start_tx_ba_session - Start a tx Block Ack session. |
1791 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1784 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1792 | * @ra: receiver address of the BA session recipient | 1785 | * @ra: receiver address of the BA session recipient |
1793 | * @tid: the TID to BA on. | 1786 | * @tid: the TID to BA on. |
1794 | * | 1787 | * |
1795 | * Return: success if addBA request was sent, failure otherwise | 1788 | * Return: success if addBA request was sent, failure otherwise |
1796 | * | 1789 | * |
1797 | * Although mac80211/low level driver/user space application can estimate | 1790 | * Although mac80211/low level driver/user space application can estimate |
1798 | * the need to start aggregation on a certain RA/TID, the session level | 1791 | * the need to start aggregation on a certain RA/TID, the session level |
1799 | * will be managed by the mac80211. | 1792 | * will be managed by the mac80211. |
1800 | */ | 1793 | */ |
1801 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); | 1794 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); |
1802 | 1795 | ||
1803 | /** | 1796 | /** |
1804 | * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. | 1797 | * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. |
1805 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1798 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1806 | * @ra: receiver address of the BA session recipient. | 1799 | * @ra: receiver address of the BA session recipient. |
1807 | * @tid: the TID to BA on. | 1800 | * @tid: the TID to BA on. |
1808 | * | 1801 | * |
1809 | * This function must be called by low level driver once it has | 1802 | * This function must be called by low level driver once it has |
1810 | * finished with preparations for the BA session. | 1803 | * finished with preparations for the BA session. |
1811 | */ | 1804 | */ |
1812 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); | 1805 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); |
1813 | 1806 | ||
1814 | /** | 1807 | /** |
1815 | * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. | 1808 | * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. |
1816 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1809 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1817 | * @ra: receiver address of the BA session recipient. | 1810 | * @ra: receiver address of the BA session recipient. |
1818 | * @tid: the TID to BA on. | 1811 | * @tid: the TID to BA on. |
1819 | * | 1812 | * |
1820 | * This function must be called by low level driver once it has | 1813 | * This function must be called by low level driver once it has |
1821 | * finished with preparations for the BA session. | 1814 | * finished with preparations for the BA session. |
1822 | * This version of the function is IRQ-safe. | 1815 | * This version of the function is IRQ-safe. |
1823 | */ | 1816 | */ |
1824 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, | 1817 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, |
1825 | u16 tid); | 1818 | u16 tid); |
1826 | 1819 | ||
1827 | /** | 1820 | /** |
1828 | * ieee80211_stop_tx_ba_session - Stop a Block Ack session. | 1821 | * ieee80211_stop_tx_ba_session - Stop a Block Ack session. |
1829 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1822 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1830 | * @ra: receiver address of the BA session recipient | 1823 | * @ra: receiver address of the BA session recipient |
1831 | * @tid: the TID to stop BA. | 1824 | * @tid: the TID to stop BA. |
1832 | * @initiator: if indicates initiator DELBA frame will be sent. | 1825 | * @initiator: if indicates initiator DELBA frame will be sent. |
1833 | * | 1826 | * |
1834 | * Return: error if no sta with matching da found, success otherwise | 1827 | * Return: error if no sta with matching da found, success otherwise |
1835 | * | 1828 | * |
1836 | * Although mac80211/low level driver/user space application can estimate | 1829 | * Although mac80211/low level driver/user space application can estimate |
1837 | * the need to stop aggregation on a certain RA/TID, the session level | 1830 | * the need to stop aggregation on a certain RA/TID, the session level |
1838 | * will be managed by the mac80211. | 1831 | * will be managed by the mac80211. |
1839 | */ | 1832 | */ |
1840 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | 1833 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, |
1841 | u8 *ra, u16 tid, | 1834 | u8 *ra, u16 tid, |
1842 | enum ieee80211_back_parties initiator); | 1835 | enum ieee80211_back_parties initiator); |
1843 | 1836 | ||
1844 | /** | 1837 | /** |
1845 | * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. | 1838 | * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. |
1846 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1839 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1847 | * @ra: receiver address of the BA session recipient. | 1840 | * @ra: receiver address of the BA session recipient. |
1848 | * @tid: the desired TID to BA on. | 1841 | * @tid: the desired TID to BA on. |
1849 | * | 1842 | * |
1850 | * This function must be called by low level driver once it has | 1843 | * This function must be called by low level driver once it has |
1851 | * finished with preparations for the BA session tear down. | 1844 | * finished with preparations for the BA session tear down. |
1852 | */ | 1845 | */ |
1853 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); | 1846 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); |
1854 | 1847 | ||
1855 | /** | 1848 | /** |
1856 | * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. | 1849 | * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. |
1857 | * @hw: pointer as obtained from ieee80211_alloc_hw(). | 1850 | * @hw: pointer as obtained from ieee80211_alloc_hw(). |
1858 | * @ra: receiver address of the BA session recipient. | 1851 | * @ra: receiver address of the BA session recipient. |
1859 | * @tid: the desired TID to BA on. | 1852 | * @tid: the desired TID to BA on. |
1860 | * | 1853 | * |
1861 | * This function must be called by low level driver once it has | 1854 | * This function must be called by low level driver once it has |
1862 | * finished with preparations for the BA session tear down. | 1855 | * finished with preparations for the BA session tear down. |
1863 | * This version of the function is IRQ-safe. | 1856 | * This version of the function is IRQ-safe. |
1864 | */ | 1857 | */ |
1865 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, | 1858 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, |
1866 | u16 tid); | 1859 | u16 tid); |
1867 | 1860 | ||
1868 | /** | 1861 | /** |
1869 | * ieee80211_find_sta - find a station | 1862 | * ieee80211_find_sta - find a station |
1870 | * | 1863 | * |
1871 | * @hw: pointer as obtained from ieee80211_alloc_hw() | 1864 | * @hw: pointer as obtained from ieee80211_alloc_hw() |
1872 | * @addr: station's address | 1865 | * @addr: station's address |
1873 | * | 1866 | * |
1874 | * This function must be called under RCU lock and the | 1867 | * This function must be called under RCU lock and the |
1875 | * resulting pointer is only valid under RCU lock as well. | 1868 | * resulting pointer is only valid under RCU lock as well. |
1876 | */ | 1869 | */ |
1877 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, | 1870 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, |
1878 | const u8 *addr); | 1871 | const u8 *addr); |
1879 | 1872 | ||
1880 | 1873 | ||
1881 | /* Rate control API */ | 1874 | /* Rate control API */ |
1882 | 1875 | ||
1883 | /** | 1876 | /** |
1884 | * struct ieee80211_tx_rate_control - rate control information for/from RC algo | 1877 | * struct ieee80211_tx_rate_control - rate control information for/from RC algo |
1885 | * | 1878 | * |
1886 | * @hw: The hardware the algorithm is invoked for. | 1879 | * @hw: The hardware the algorithm is invoked for. |
1887 | * @sband: The band this frame is being transmitted on. | 1880 | * @sband: The band this frame is being transmitted on. |
1888 | * @bss_conf: the current BSS configuration | 1881 | * @bss_conf: the current BSS configuration |
1889 | * @reported_rate: The rate control algorithm can fill this in to indicate | 1882 | * @reported_rate: The rate control algorithm can fill this in to indicate |
1890 | * which rate should be reported to userspace as the current rate and | 1883 | * which rate should be reported to userspace as the current rate and |
1891 | * used for rate calculations in the mesh network. | 1884 | * used for rate calculations in the mesh network. |
1892 | * @rts: whether RTS will be used for this frame because it is longer than the | 1885 | * @rts: whether RTS will be used for this frame because it is longer than the |
1893 | * RTS threshold | 1886 | * RTS threshold |
1894 | * @short_preamble: whether mac80211 will request short-preamble transmission | 1887 | * @short_preamble: whether mac80211 will request short-preamble transmission |
1895 | * if the selected rate supports it | 1888 | * if the selected rate supports it |
1896 | * @max_rate_idx: user-requested maximum rate (not MCS for now) | 1889 | * @max_rate_idx: user-requested maximum rate (not MCS for now) |
1897 | * @skb: the skb that will be transmitted, the control information in it needs | 1890 | * @skb: the skb that will be transmitted, the control information in it needs |
1898 | * to be filled in | 1891 | * to be filled in |
1899 | */ | 1892 | */ |
1900 | struct ieee80211_tx_rate_control { | 1893 | struct ieee80211_tx_rate_control { |
1901 | struct ieee80211_hw *hw; | 1894 | struct ieee80211_hw *hw; |
1902 | struct ieee80211_supported_band *sband; | 1895 | struct ieee80211_supported_band *sband; |
1903 | struct ieee80211_bss_conf *bss_conf; | 1896 | struct ieee80211_bss_conf *bss_conf; |
1904 | struct sk_buff *skb; | 1897 | struct sk_buff *skb; |
1905 | struct ieee80211_tx_rate reported_rate; | 1898 | struct ieee80211_tx_rate reported_rate; |
1906 | bool rts, short_preamble; | 1899 | bool rts, short_preamble; |
1907 | u8 max_rate_idx; | 1900 | u8 max_rate_idx; |
1908 | }; | 1901 | }; |
1909 | 1902 | ||
1910 | struct rate_control_ops { | 1903 | struct rate_control_ops { |
1911 | struct module *module; | 1904 | struct module *module; |
1912 | const char *name; | 1905 | const char *name; |
1913 | void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); | 1906 | void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); |
1914 | void (*free)(void *priv); | 1907 | void (*free)(void *priv); |
1915 | 1908 | ||
1916 | void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); | 1909 | void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); |
1917 | void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, | 1910 | void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, |
1918 | struct ieee80211_sta *sta, void *priv_sta); | 1911 | struct ieee80211_sta *sta, void *priv_sta); |
1919 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, | 1912 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, |
1920 | void *priv_sta); | 1913 | void *priv_sta); |
1921 | 1914 | ||
1922 | void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, | 1915 | void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, |
1923 | struct ieee80211_sta *sta, void *priv_sta, | 1916 | struct ieee80211_sta *sta, void *priv_sta, |
1924 | struct sk_buff *skb); | 1917 | struct sk_buff *skb); |
1925 | void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 1918 | void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, |
1926 | struct ieee80211_tx_rate_control *txrc); | 1919 | struct ieee80211_tx_rate_control *txrc); |
1927 | 1920 | ||
1928 | void (*add_sta_debugfs)(void *priv, void *priv_sta, | 1921 | void (*add_sta_debugfs)(void *priv, void *priv_sta, |
1929 | struct dentry *dir); | 1922 | struct dentry *dir); |
1930 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); | 1923 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); |
1931 | }; | 1924 | }; |
1932 | 1925 | ||
1933 | static inline int rate_supported(struct ieee80211_sta *sta, | 1926 | static inline int rate_supported(struct ieee80211_sta *sta, |
1934 | enum ieee80211_band band, | 1927 | enum ieee80211_band band, |
1935 | int index) | 1928 | int index) |
1936 | { | 1929 | { |
1937 | return (sta == NULL || sta->supp_rates[band] & BIT(index)); | 1930 | return (sta == NULL || sta->supp_rates[band] & BIT(index)); |
1938 | } | 1931 | } |
1939 | 1932 | ||
1940 | static inline s8 | 1933 | static inline s8 |
1941 | rate_lowest_index(struct ieee80211_supported_band *sband, | 1934 | rate_lowest_index(struct ieee80211_supported_band *sband, |
1942 | struct ieee80211_sta *sta) | 1935 | struct ieee80211_sta *sta) |
1943 | { | 1936 | { |
1944 | int i; | 1937 | int i; |
1945 | 1938 | ||
1946 | for (i = 0; i < sband->n_bitrates; i++) | 1939 | for (i = 0; i < sband->n_bitrates; i++) |
1947 | if (rate_supported(sta, sband->band, i)) | 1940 | if (rate_supported(sta, sband->band, i)) |
1948 | return i; | 1941 | return i; |
1949 | 1942 | ||
1950 | /* warn when we cannot find a rate. */ | 1943 | /* warn when we cannot find a rate. */ |
1951 | WARN_ON(1); | 1944 | WARN_ON(1); |
1952 | 1945 | ||
1953 | return 0; | 1946 | return 0; |
1954 | } | 1947 | } |
1955 | 1948 | ||
1956 | 1949 | ||
1957 | int ieee80211_rate_control_register(struct rate_control_ops *ops); | 1950 | int ieee80211_rate_control_register(struct rate_control_ops *ops); |
1958 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops); | 1951 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops); |
1959 | 1952 | ||
1960 | #endif /* MAC80211_H */ | 1953 | #endif /* MAC80211_H */ |
1961 | 1954 |
net/mac80211/cfg.c
1 | /* | 1 | /* |
2 | * mac80211 configuration hooks for cfg80211 | 2 | * mac80211 configuration hooks for cfg80211 |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
5 | * | 5 | * |
6 | * This file is GPLv2 as found in COPYING. | 6 | * This file is GPLv2 as found in COPYING. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/ieee80211.h> | 9 | #include <linux/ieee80211.h> |
10 | #include <linux/nl80211.h> | 10 | #include <linux/nl80211.h> |
11 | #include <linux/rtnetlink.h> | 11 | #include <linux/rtnetlink.h> |
12 | #include <net/net_namespace.h> | 12 | #include <net/net_namespace.h> |
13 | #include <linux/rcupdate.h> | 13 | #include <linux/rcupdate.h> |
14 | #include <net/cfg80211.h> | 14 | #include <net/cfg80211.h> |
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "cfg.h" | 16 | #include "cfg.h" |
17 | #include "rate.h" | 17 | #include "rate.h" |
18 | #include "mesh.h" | 18 | #include "mesh.h" |
19 | 19 | ||
20 | static bool nl80211_type_check(enum nl80211_iftype type) | 20 | static bool nl80211_type_check(enum nl80211_iftype type) |
21 | { | 21 | { |
22 | switch (type) { | 22 | switch (type) { |
23 | case NL80211_IFTYPE_ADHOC: | 23 | case NL80211_IFTYPE_ADHOC: |
24 | case NL80211_IFTYPE_STATION: | 24 | case NL80211_IFTYPE_STATION: |
25 | case NL80211_IFTYPE_MONITOR: | 25 | case NL80211_IFTYPE_MONITOR: |
26 | #ifdef CONFIG_MAC80211_MESH | 26 | #ifdef CONFIG_MAC80211_MESH |
27 | case NL80211_IFTYPE_MESH_POINT: | 27 | case NL80211_IFTYPE_MESH_POINT: |
28 | #endif | 28 | #endif |
29 | case NL80211_IFTYPE_AP: | 29 | case NL80211_IFTYPE_AP: |
30 | case NL80211_IFTYPE_AP_VLAN: | 30 | case NL80211_IFTYPE_AP_VLAN: |
31 | case NL80211_IFTYPE_WDS: | 31 | case NL80211_IFTYPE_WDS: |
32 | return true; | 32 | return true; |
33 | default: | 33 | default: |
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 38 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
39 | enum nl80211_iftype type, u32 *flags, | 39 | enum nl80211_iftype type, u32 *flags, |
40 | struct vif_params *params) | 40 | struct vif_params *params) |
41 | { | 41 | { |
42 | struct ieee80211_local *local = wiphy_priv(wiphy); | 42 | struct ieee80211_local *local = wiphy_priv(wiphy); |
43 | struct net_device *dev; | 43 | struct net_device *dev; |
44 | struct ieee80211_sub_if_data *sdata; | 44 | struct ieee80211_sub_if_data *sdata; |
45 | int err; | 45 | int err; |
46 | 46 | ||
47 | if (!nl80211_type_check(type)) | 47 | if (!nl80211_type_check(type)) |
48 | return -EINVAL; | 48 | return -EINVAL; |
49 | 49 | ||
50 | err = ieee80211_if_add(local, name, &dev, type, params); | 50 | err = ieee80211_if_add(local, name, &dev, type, params); |
51 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 51 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) |
52 | return err; | 52 | return err; |
53 | 53 | ||
54 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 54 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
55 | sdata->u.mntr_flags = *flags; | 55 | sdata->u.mntr_flags = *flags; |
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
58 | 58 | ||
59 | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | 59 | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) |
60 | { | 60 | { |
61 | struct net_device *dev; | 61 | struct net_device *dev; |
62 | struct ieee80211_sub_if_data *sdata; | 62 | struct ieee80211_sub_if_data *sdata; |
63 | 63 | ||
64 | /* we're under RTNL */ | 64 | /* we're under RTNL */ |
65 | dev = __dev_get_by_index(&init_net, ifindex); | 65 | dev = __dev_get_by_index(&init_net, ifindex); |
66 | if (!dev) | 66 | if (!dev) |
67 | return -ENODEV; | 67 | return -ENODEV; |
68 | 68 | ||
69 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 69 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
70 | 70 | ||
71 | ieee80211_if_remove(sdata); | 71 | ieee80211_if_remove(sdata); |
72 | 72 | ||
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 76 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, |
77 | enum nl80211_iftype type, u32 *flags, | 77 | enum nl80211_iftype type, u32 *flags, |
78 | struct vif_params *params) | 78 | struct vif_params *params) |
79 | { | 79 | { |
80 | struct net_device *dev; | 80 | struct net_device *dev; |
81 | struct ieee80211_sub_if_data *sdata; | 81 | struct ieee80211_sub_if_data *sdata; |
82 | int ret; | 82 | int ret; |
83 | 83 | ||
84 | /* we're under RTNL */ | 84 | /* we're under RTNL */ |
85 | dev = __dev_get_by_index(&init_net, ifindex); | 85 | dev = __dev_get_by_index(&init_net, ifindex); |
86 | if (!dev) | 86 | if (!dev) |
87 | return -ENODEV; | 87 | return -ENODEV; |
88 | 88 | ||
89 | if (!nl80211_type_check(type)) | 89 | if (!nl80211_type_check(type)) |
90 | return -EINVAL; | 90 | return -EINVAL; |
91 | 91 | ||
92 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 92 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
93 | 93 | ||
94 | ret = ieee80211_if_change_type(sdata, type); | 94 | ret = ieee80211_if_change_type(sdata, type); |
95 | if (ret) | 95 | if (ret) |
96 | return ret; | 96 | return ret; |
97 | 97 | ||
98 | if (netif_running(sdata->dev)) | 98 | if (netif_running(sdata->dev)) |
99 | return -EBUSY; | 99 | return -EBUSY; |
100 | 100 | ||
101 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | 101 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) |
102 | ieee80211_sdata_set_mesh_id(sdata, | 102 | ieee80211_sdata_set_mesh_id(sdata, |
103 | params->mesh_id_len, | 103 | params->mesh_id_len, |
104 | params->mesh_id); | 104 | params->mesh_id); |
105 | 105 | ||
106 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) | 106 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) |
107 | return 0; | 107 | return 0; |
108 | 108 | ||
109 | sdata->u.mntr_flags = *flags; | 109 | sdata->u.mntr_flags = *flags; |
110 | return 0; | 110 | return 0; |
111 | } | 111 | } |
112 | 112 | ||
113 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 113 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
114 | u8 key_idx, u8 *mac_addr, | 114 | u8 key_idx, u8 *mac_addr, |
115 | struct key_params *params) | 115 | struct key_params *params) |
116 | { | 116 | { |
117 | struct ieee80211_sub_if_data *sdata; | 117 | struct ieee80211_sub_if_data *sdata; |
118 | struct sta_info *sta = NULL; | 118 | struct sta_info *sta = NULL; |
119 | enum ieee80211_key_alg alg; | 119 | enum ieee80211_key_alg alg; |
120 | struct ieee80211_key *key; | 120 | struct ieee80211_key *key; |
121 | int err; | 121 | int err; |
122 | 122 | ||
123 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 123 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
124 | 124 | ||
125 | switch (params->cipher) { | 125 | switch (params->cipher) { |
126 | case WLAN_CIPHER_SUITE_WEP40: | 126 | case WLAN_CIPHER_SUITE_WEP40: |
127 | case WLAN_CIPHER_SUITE_WEP104: | 127 | case WLAN_CIPHER_SUITE_WEP104: |
128 | alg = ALG_WEP; | 128 | alg = ALG_WEP; |
129 | break; | 129 | break; |
130 | case WLAN_CIPHER_SUITE_TKIP: | 130 | case WLAN_CIPHER_SUITE_TKIP: |
131 | alg = ALG_TKIP; | 131 | alg = ALG_TKIP; |
132 | break; | 132 | break; |
133 | case WLAN_CIPHER_SUITE_CCMP: | 133 | case WLAN_CIPHER_SUITE_CCMP: |
134 | alg = ALG_CCMP; | 134 | alg = ALG_CCMP; |
135 | break; | 135 | break; |
136 | default: | 136 | default: |
137 | return -EINVAL; | 137 | return -EINVAL; |
138 | } | 138 | } |
139 | 139 | ||
140 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | 140 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); |
141 | if (!key) | 141 | if (!key) |
142 | return -ENOMEM; | 142 | return -ENOMEM; |
143 | 143 | ||
144 | rcu_read_lock(); | 144 | rcu_read_lock(); |
145 | 145 | ||
146 | if (mac_addr) { | 146 | if (mac_addr) { |
147 | sta = sta_info_get(sdata->local, mac_addr); | 147 | sta = sta_info_get(sdata->local, mac_addr); |
148 | if (!sta) { | 148 | if (!sta) { |
149 | ieee80211_key_free(key); | 149 | ieee80211_key_free(key); |
150 | err = -ENOENT; | 150 | err = -ENOENT; |
151 | goto out_unlock; | 151 | goto out_unlock; |
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | ieee80211_key_link(key, sdata, sta); | 155 | ieee80211_key_link(key, sdata, sta); |
156 | 156 | ||
157 | err = 0; | 157 | err = 0; |
158 | out_unlock: | 158 | out_unlock: |
159 | rcu_read_unlock(); | 159 | rcu_read_unlock(); |
160 | 160 | ||
161 | return err; | 161 | return err; |
162 | } | 162 | } |
163 | 163 | ||
164 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 164 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
165 | u8 key_idx, u8 *mac_addr) | 165 | u8 key_idx, u8 *mac_addr) |
166 | { | 166 | { |
167 | struct ieee80211_sub_if_data *sdata; | 167 | struct ieee80211_sub_if_data *sdata; |
168 | struct sta_info *sta; | 168 | struct sta_info *sta; |
169 | int ret; | 169 | int ret; |
170 | 170 | ||
171 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 171 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
172 | 172 | ||
173 | rcu_read_lock(); | 173 | rcu_read_lock(); |
174 | 174 | ||
175 | if (mac_addr) { | 175 | if (mac_addr) { |
176 | ret = -ENOENT; | 176 | ret = -ENOENT; |
177 | 177 | ||
178 | sta = sta_info_get(sdata->local, mac_addr); | 178 | sta = sta_info_get(sdata->local, mac_addr); |
179 | if (!sta) | 179 | if (!sta) |
180 | goto out_unlock; | 180 | goto out_unlock; |
181 | 181 | ||
182 | if (sta->key) { | 182 | if (sta->key) { |
183 | ieee80211_key_free(sta->key); | 183 | ieee80211_key_free(sta->key); |
184 | WARN_ON(sta->key); | 184 | WARN_ON(sta->key); |
185 | ret = 0; | 185 | ret = 0; |
186 | } | 186 | } |
187 | 187 | ||
188 | goto out_unlock; | 188 | goto out_unlock; |
189 | } | 189 | } |
190 | 190 | ||
191 | if (!sdata->keys[key_idx]) { | 191 | if (!sdata->keys[key_idx]) { |
192 | ret = -ENOENT; | 192 | ret = -ENOENT; |
193 | goto out_unlock; | 193 | goto out_unlock; |
194 | } | 194 | } |
195 | 195 | ||
196 | ieee80211_key_free(sdata->keys[key_idx]); | 196 | ieee80211_key_free(sdata->keys[key_idx]); |
197 | WARN_ON(sdata->keys[key_idx]); | 197 | WARN_ON(sdata->keys[key_idx]); |
198 | 198 | ||
199 | ret = 0; | 199 | ret = 0; |
200 | out_unlock: | 200 | out_unlock: |
201 | rcu_read_unlock(); | 201 | rcu_read_unlock(); |
202 | 202 | ||
203 | return ret; | 203 | return ret; |
204 | } | 204 | } |
205 | 205 | ||
206 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 206 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
207 | u8 key_idx, u8 *mac_addr, void *cookie, | 207 | u8 key_idx, u8 *mac_addr, void *cookie, |
208 | void (*callback)(void *cookie, | 208 | void (*callback)(void *cookie, |
209 | struct key_params *params)) | 209 | struct key_params *params)) |
210 | { | 210 | { |
211 | struct ieee80211_sub_if_data *sdata; | 211 | struct ieee80211_sub_if_data *sdata; |
212 | struct sta_info *sta = NULL; | 212 | struct sta_info *sta = NULL; |
213 | u8 seq[6] = {0}; | 213 | u8 seq[6] = {0}; |
214 | struct key_params params; | 214 | struct key_params params; |
215 | struct ieee80211_key *key; | 215 | struct ieee80211_key *key; |
216 | u32 iv32; | 216 | u32 iv32; |
217 | u16 iv16; | 217 | u16 iv16; |
218 | int err = -ENOENT; | 218 | int err = -ENOENT; |
219 | 219 | ||
220 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 220 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
221 | 221 | ||
222 | rcu_read_lock(); | 222 | rcu_read_lock(); |
223 | 223 | ||
224 | if (mac_addr) { | 224 | if (mac_addr) { |
225 | sta = sta_info_get(sdata->local, mac_addr); | 225 | sta = sta_info_get(sdata->local, mac_addr); |
226 | if (!sta) | 226 | if (!sta) |
227 | goto out; | 227 | goto out; |
228 | 228 | ||
229 | key = sta->key; | 229 | key = sta->key; |
230 | } else | 230 | } else |
231 | key = sdata->keys[key_idx]; | 231 | key = sdata->keys[key_idx]; |
232 | 232 | ||
233 | if (!key) | 233 | if (!key) |
234 | goto out; | 234 | goto out; |
235 | 235 | ||
236 | memset(¶ms, 0, sizeof(params)); | 236 | memset(¶ms, 0, sizeof(params)); |
237 | 237 | ||
238 | switch (key->conf.alg) { | 238 | switch (key->conf.alg) { |
239 | case ALG_TKIP: | 239 | case ALG_TKIP: |
240 | params.cipher = WLAN_CIPHER_SUITE_TKIP; | 240 | params.cipher = WLAN_CIPHER_SUITE_TKIP; |
241 | 241 | ||
242 | iv32 = key->u.tkip.tx.iv32; | 242 | iv32 = key->u.tkip.tx.iv32; |
243 | iv16 = key->u.tkip.tx.iv16; | 243 | iv16 = key->u.tkip.tx.iv16; |
244 | 244 | ||
245 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 245 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
246 | sdata->local->ops->get_tkip_seq) | 246 | sdata->local->ops->get_tkip_seq) |
247 | sdata->local->ops->get_tkip_seq( | 247 | sdata->local->ops->get_tkip_seq( |
248 | local_to_hw(sdata->local), | 248 | local_to_hw(sdata->local), |
249 | key->conf.hw_key_idx, | 249 | key->conf.hw_key_idx, |
250 | &iv32, &iv16); | 250 | &iv32, &iv16); |
251 | 251 | ||
252 | seq[0] = iv16 & 0xff; | 252 | seq[0] = iv16 & 0xff; |
253 | seq[1] = (iv16 >> 8) & 0xff; | 253 | seq[1] = (iv16 >> 8) & 0xff; |
254 | seq[2] = iv32 & 0xff; | 254 | seq[2] = iv32 & 0xff; |
255 | seq[3] = (iv32 >> 8) & 0xff; | 255 | seq[3] = (iv32 >> 8) & 0xff; |
256 | seq[4] = (iv32 >> 16) & 0xff; | 256 | seq[4] = (iv32 >> 16) & 0xff; |
257 | seq[5] = (iv32 >> 24) & 0xff; | 257 | seq[5] = (iv32 >> 24) & 0xff; |
258 | params.seq = seq; | 258 | params.seq = seq; |
259 | params.seq_len = 6; | 259 | params.seq_len = 6; |
260 | break; | 260 | break; |
261 | case ALG_CCMP: | 261 | case ALG_CCMP: |
262 | params.cipher = WLAN_CIPHER_SUITE_CCMP; | 262 | params.cipher = WLAN_CIPHER_SUITE_CCMP; |
263 | seq[0] = key->u.ccmp.tx_pn[5]; | 263 | seq[0] = key->u.ccmp.tx_pn[5]; |
264 | seq[1] = key->u.ccmp.tx_pn[4]; | 264 | seq[1] = key->u.ccmp.tx_pn[4]; |
265 | seq[2] = key->u.ccmp.tx_pn[3]; | 265 | seq[2] = key->u.ccmp.tx_pn[3]; |
266 | seq[3] = key->u.ccmp.tx_pn[2]; | 266 | seq[3] = key->u.ccmp.tx_pn[2]; |
267 | seq[4] = key->u.ccmp.tx_pn[1]; | 267 | seq[4] = key->u.ccmp.tx_pn[1]; |
268 | seq[5] = key->u.ccmp.tx_pn[0]; | 268 | seq[5] = key->u.ccmp.tx_pn[0]; |
269 | params.seq = seq; | 269 | params.seq = seq; |
270 | params.seq_len = 6; | 270 | params.seq_len = 6; |
271 | break; | 271 | break; |
272 | case ALG_WEP: | 272 | case ALG_WEP: |
273 | if (key->conf.keylen == 5) | 273 | if (key->conf.keylen == 5) |
274 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | 274 | params.cipher = WLAN_CIPHER_SUITE_WEP40; |
275 | else | 275 | else |
276 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | 276 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
277 | break; | 277 | break; |
278 | } | 278 | } |
279 | 279 | ||
280 | params.key = key->conf.key; | 280 | params.key = key->conf.key; |
281 | params.key_len = key->conf.keylen; | 281 | params.key_len = key->conf.keylen; |
282 | 282 | ||
283 | callback(cookie, ¶ms); | 283 | callback(cookie, ¶ms); |
284 | err = 0; | 284 | err = 0; |
285 | 285 | ||
286 | out: | 286 | out: |
287 | rcu_read_unlock(); | 287 | rcu_read_unlock(); |
288 | return err; | 288 | return err; |
289 | } | 289 | } |
290 | 290 | ||
291 | static int ieee80211_config_default_key(struct wiphy *wiphy, | 291 | static int ieee80211_config_default_key(struct wiphy *wiphy, |
292 | struct net_device *dev, | 292 | struct net_device *dev, |
293 | u8 key_idx) | 293 | u8 key_idx) |
294 | { | 294 | { |
295 | struct ieee80211_sub_if_data *sdata; | 295 | struct ieee80211_sub_if_data *sdata; |
296 | 296 | ||
297 | rcu_read_lock(); | 297 | rcu_read_lock(); |
298 | 298 | ||
299 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 299 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
300 | ieee80211_set_default_key(sdata, key_idx); | 300 | ieee80211_set_default_key(sdata, key_idx); |
301 | 301 | ||
302 | rcu_read_unlock(); | 302 | rcu_read_unlock(); |
303 | 303 | ||
304 | return 0; | 304 | return 0; |
305 | } | 305 | } |
306 | 306 | ||
307 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 307 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
308 | { | 308 | { |
309 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 309 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
310 | 310 | ||
311 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 311 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
312 | STATION_INFO_RX_BYTES | | 312 | STATION_INFO_RX_BYTES | |
313 | STATION_INFO_TX_BYTES | | 313 | STATION_INFO_TX_BYTES | |
314 | STATION_INFO_TX_BITRATE; | 314 | STATION_INFO_TX_BITRATE; |
315 | 315 | ||
316 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 316 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
317 | sinfo->rx_bytes = sta->rx_bytes; | 317 | sinfo->rx_bytes = sta->rx_bytes; |
318 | sinfo->tx_bytes = sta->tx_bytes; | 318 | sinfo->tx_bytes = sta->tx_bytes; |
319 | 319 | ||
320 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 320 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { |
321 | sinfo->filled |= STATION_INFO_SIGNAL; | 321 | sinfo->filled |= STATION_INFO_SIGNAL; |
322 | sinfo->signal = (s8)sta->last_signal; | 322 | sinfo->signal = (s8)sta->last_signal; |
323 | } | 323 | } |
324 | 324 | ||
325 | sinfo->txrate.flags = 0; | 325 | sinfo->txrate.flags = 0; |
326 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) | 326 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) |
327 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | 327 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; |
328 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 328 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
329 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 329 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
330 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | 330 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) |
331 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 331 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
332 | 332 | ||
333 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | 333 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { |
334 | struct ieee80211_supported_band *sband; | 334 | struct ieee80211_supported_band *sband; |
335 | sband = sta->local->hw.wiphy->bands[ | 335 | sband = sta->local->hw.wiphy->bands[ |
336 | sta->local->hw.conf.channel->band]; | 336 | sta->local->hw.conf.channel->band]; |
337 | sinfo->txrate.legacy = | 337 | sinfo->txrate.legacy = |
338 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | 338 | sband->bitrates[sta->last_tx_rate.idx].bitrate; |
339 | } else | 339 | } else |
340 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | 340 | sinfo->txrate.mcs = sta->last_tx_rate.idx; |
341 | 341 | ||
342 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 342 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
343 | #ifdef CONFIG_MAC80211_MESH | 343 | #ifdef CONFIG_MAC80211_MESH |
344 | sinfo->filled |= STATION_INFO_LLID | | 344 | sinfo->filled |= STATION_INFO_LLID | |
345 | STATION_INFO_PLID | | 345 | STATION_INFO_PLID | |
346 | STATION_INFO_PLINK_STATE; | 346 | STATION_INFO_PLINK_STATE; |
347 | 347 | ||
348 | sinfo->llid = le16_to_cpu(sta->llid); | 348 | sinfo->llid = le16_to_cpu(sta->llid); |
349 | sinfo->plid = le16_to_cpu(sta->plid); | 349 | sinfo->plid = le16_to_cpu(sta->plid); |
350 | sinfo->plink_state = sta->plink_state; | 350 | sinfo->plink_state = sta->plink_state; |
351 | #endif | 351 | #endif |
352 | } | 352 | } |
353 | } | 353 | } |
354 | 354 | ||
355 | 355 | ||
356 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 356 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
357 | int idx, u8 *mac, struct station_info *sinfo) | 357 | int idx, u8 *mac, struct station_info *sinfo) |
358 | { | 358 | { |
359 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 359 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
360 | struct sta_info *sta; | 360 | struct sta_info *sta; |
361 | int ret = -ENOENT; | 361 | int ret = -ENOENT; |
362 | 362 | ||
363 | rcu_read_lock(); | 363 | rcu_read_lock(); |
364 | 364 | ||
365 | sta = sta_info_get_by_idx(local, idx, dev); | 365 | sta = sta_info_get_by_idx(local, idx, dev); |
366 | if (sta) { | 366 | if (sta) { |
367 | ret = 0; | 367 | ret = 0; |
368 | memcpy(mac, sta->sta.addr, ETH_ALEN); | 368 | memcpy(mac, sta->sta.addr, ETH_ALEN); |
369 | sta_set_sinfo(sta, sinfo); | 369 | sta_set_sinfo(sta, sinfo); |
370 | } | 370 | } |
371 | 371 | ||
372 | rcu_read_unlock(); | 372 | rcu_read_unlock(); |
373 | 373 | ||
374 | return ret; | 374 | return ret; |
375 | } | 375 | } |
376 | 376 | ||
377 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 377 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
378 | u8 *mac, struct station_info *sinfo) | 378 | u8 *mac, struct station_info *sinfo) |
379 | { | 379 | { |
380 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 380 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
381 | struct sta_info *sta; | 381 | struct sta_info *sta; |
382 | int ret = -ENOENT; | 382 | int ret = -ENOENT; |
383 | 383 | ||
384 | rcu_read_lock(); | 384 | rcu_read_lock(); |
385 | 385 | ||
386 | /* XXX: verify sta->dev == dev */ | 386 | /* XXX: verify sta->dev == dev */ |
387 | 387 | ||
388 | sta = sta_info_get(local, mac); | 388 | sta = sta_info_get(local, mac); |
389 | if (sta) { | 389 | if (sta) { |
390 | ret = 0; | 390 | ret = 0; |
391 | sta_set_sinfo(sta, sinfo); | 391 | sta_set_sinfo(sta, sinfo); |
392 | } | 392 | } |
393 | 393 | ||
394 | rcu_read_unlock(); | 394 | rcu_read_unlock(); |
395 | 395 | ||
396 | return ret; | 396 | return ret; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* | 399 | /* |
400 | * This handles both adding a beacon and setting new beacon info | 400 | * This handles both adding a beacon and setting new beacon info |
401 | */ | 401 | */ |
402 | static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | 402 | static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, |
403 | struct beacon_parameters *params) | 403 | struct beacon_parameters *params) |
404 | { | 404 | { |
405 | struct beacon_data *new, *old; | 405 | struct beacon_data *new, *old; |
406 | int new_head_len, new_tail_len; | 406 | int new_head_len, new_tail_len; |
407 | int size; | 407 | int size; |
408 | int err = -EINVAL; | 408 | int err = -EINVAL; |
409 | 409 | ||
410 | old = sdata->u.ap.beacon; | 410 | old = sdata->u.ap.beacon; |
411 | 411 | ||
412 | /* head must not be zero-length */ | 412 | /* head must not be zero-length */ |
413 | if (params->head && !params->head_len) | 413 | if (params->head && !params->head_len) |
414 | return -EINVAL; | 414 | return -EINVAL; |
415 | 415 | ||
416 | /* | 416 | /* |
417 | * This is a kludge. beacon interval should really be part | 417 | * This is a kludge. beacon interval should really be part |
418 | * of the beacon information. | 418 | * of the beacon information. |
419 | */ | 419 | */ |
420 | if (params->interval) { | 420 | if (params->interval) { |
421 | sdata->local->hw.conf.beacon_int = params->interval; | 421 | sdata->local->hw.conf.beacon_int = params->interval; |
422 | err = ieee80211_hw_config(sdata->local, | 422 | err = ieee80211_hw_config(sdata->local, |
423 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL); | 423 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL); |
424 | if (err < 0) | 424 | if (err < 0) |
425 | return err; | 425 | return err; |
426 | /* | 426 | /* |
427 | * We updated some parameter so if below bails out | 427 | * We updated some parameter so if below bails out |
428 | * it's not an error. | 428 | * it's not an error. |
429 | */ | 429 | */ |
430 | err = 0; | 430 | err = 0; |
431 | } | 431 | } |
432 | 432 | ||
433 | /* Need to have a beacon head if we don't have one yet */ | 433 | /* Need to have a beacon head if we don't have one yet */ |
434 | if (!params->head && !old) | 434 | if (!params->head && !old) |
435 | return err; | 435 | return err; |
436 | 436 | ||
437 | /* sorry, no way to start beaconing without dtim period */ | 437 | /* sorry, no way to start beaconing without dtim period */ |
438 | if (!params->dtim_period && !old) | 438 | if (!params->dtim_period && !old) |
439 | return err; | 439 | return err; |
440 | 440 | ||
441 | /* new or old head? */ | 441 | /* new or old head? */ |
442 | if (params->head) | 442 | if (params->head) |
443 | new_head_len = params->head_len; | 443 | new_head_len = params->head_len; |
444 | else | 444 | else |
445 | new_head_len = old->head_len; | 445 | new_head_len = old->head_len; |
446 | 446 | ||
447 | /* new or old tail? */ | 447 | /* new or old tail? */ |
448 | if (params->tail || !old) | 448 | if (params->tail || !old) |
449 | /* params->tail_len will be zero for !params->tail */ | 449 | /* params->tail_len will be zero for !params->tail */ |
450 | new_tail_len = params->tail_len; | 450 | new_tail_len = params->tail_len; |
451 | else | 451 | else |
452 | new_tail_len = old->tail_len; | 452 | new_tail_len = old->tail_len; |
453 | 453 | ||
454 | size = sizeof(*new) + new_head_len + new_tail_len; | 454 | size = sizeof(*new) + new_head_len + new_tail_len; |
455 | 455 | ||
456 | new = kzalloc(size, GFP_KERNEL); | 456 | new = kzalloc(size, GFP_KERNEL); |
457 | if (!new) | 457 | if (!new) |
458 | return -ENOMEM; | 458 | return -ENOMEM; |
459 | 459 | ||
460 | /* start filling the new info now */ | 460 | /* start filling the new info now */ |
461 | 461 | ||
462 | /* new or old dtim period? */ | 462 | /* new or old dtim period? */ |
463 | if (params->dtim_period) | 463 | if (params->dtim_period) |
464 | new->dtim_period = params->dtim_period; | 464 | new->dtim_period = params->dtim_period; |
465 | else | 465 | else |
466 | new->dtim_period = old->dtim_period; | 466 | new->dtim_period = old->dtim_period; |
467 | 467 | ||
468 | /* | 468 | /* |
469 | * pointers go into the block we allocated, | 469 | * pointers go into the block we allocated, |
470 | * memory is | beacon_data | head | tail | | 470 | * memory is | beacon_data | head | tail | |
471 | */ | 471 | */ |
472 | new->head = ((u8 *) new) + sizeof(*new); | 472 | new->head = ((u8 *) new) + sizeof(*new); |
473 | new->tail = new->head + new_head_len; | 473 | new->tail = new->head + new_head_len; |
474 | new->head_len = new_head_len; | 474 | new->head_len = new_head_len; |
475 | new->tail_len = new_tail_len; | 475 | new->tail_len = new_tail_len; |
476 | 476 | ||
477 | /* copy in head */ | 477 | /* copy in head */ |
478 | if (params->head) | 478 | if (params->head) |
479 | memcpy(new->head, params->head, new_head_len); | 479 | memcpy(new->head, params->head, new_head_len); |
480 | else | 480 | else |
481 | memcpy(new->head, old->head, new_head_len); | 481 | memcpy(new->head, old->head, new_head_len); |
482 | 482 | ||
483 | /* copy in optional tail */ | 483 | /* copy in optional tail */ |
484 | if (params->tail) | 484 | if (params->tail) |
485 | memcpy(new->tail, params->tail, new_tail_len); | 485 | memcpy(new->tail, params->tail, new_tail_len); |
486 | else | 486 | else |
487 | if (old) | 487 | if (old) |
488 | memcpy(new->tail, old->tail, new_tail_len); | 488 | memcpy(new->tail, old->tail, new_tail_len); |
489 | 489 | ||
490 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 490 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
491 | 491 | ||
492 | synchronize_rcu(); | 492 | synchronize_rcu(); |
493 | 493 | ||
494 | kfree(old); | 494 | kfree(old); |
495 | 495 | ||
496 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 496 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); |
497 | } | 497 | } |
498 | 498 | ||
499 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 499 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, |
500 | struct beacon_parameters *params) | 500 | struct beacon_parameters *params) |
501 | { | 501 | { |
502 | struct ieee80211_sub_if_data *sdata; | 502 | struct ieee80211_sub_if_data *sdata; |
503 | struct beacon_data *old; | 503 | struct beacon_data *old; |
504 | 504 | ||
505 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 505 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
506 | 506 | ||
507 | if (sdata->vif.type != NL80211_IFTYPE_AP) | 507 | if (sdata->vif.type != NL80211_IFTYPE_AP) |
508 | return -EINVAL; | 508 | return -EINVAL; |
509 | 509 | ||
510 | old = sdata->u.ap.beacon; | 510 | old = sdata->u.ap.beacon; |
511 | 511 | ||
512 | if (old) | 512 | if (old) |
513 | return -EALREADY; | 513 | return -EALREADY; |
514 | 514 | ||
515 | return ieee80211_config_beacon(sdata, params); | 515 | return ieee80211_config_beacon(sdata, params); |
516 | } | 516 | } |
517 | 517 | ||
518 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | 518 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, |
519 | struct beacon_parameters *params) | 519 | struct beacon_parameters *params) |
520 | { | 520 | { |
521 | struct ieee80211_sub_if_data *sdata; | 521 | struct ieee80211_sub_if_data *sdata; |
522 | struct beacon_data *old; | 522 | struct beacon_data *old; |
523 | 523 | ||
524 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 524 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
525 | 525 | ||
526 | if (sdata->vif.type != NL80211_IFTYPE_AP) | 526 | if (sdata->vif.type != NL80211_IFTYPE_AP) |
527 | return -EINVAL; | 527 | return -EINVAL; |
528 | 528 | ||
529 | old = sdata->u.ap.beacon; | 529 | old = sdata->u.ap.beacon; |
530 | 530 | ||
531 | if (!old) | 531 | if (!old) |
532 | return -ENOENT; | 532 | return -ENOENT; |
533 | 533 | ||
534 | return ieee80211_config_beacon(sdata, params); | 534 | return ieee80211_config_beacon(sdata, params); |
535 | } | 535 | } |
536 | 536 | ||
537 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | 537 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) |
538 | { | 538 | { |
539 | struct ieee80211_sub_if_data *sdata; | 539 | struct ieee80211_sub_if_data *sdata; |
540 | struct beacon_data *old; | 540 | struct beacon_data *old; |
541 | 541 | ||
542 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 542 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
543 | 543 | ||
544 | if (sdata->vif.type != NL80211_IFTYPE_AP) | 544 | if (sdata->vif.type != NL80211_IFTYPE_AP) |
545 | return -EINVAL; | 545 | return -EINVAL; |
546 | 546 | ||
547 | old = sdata->u.ap.beacon; | 547 | old = sdata->u.ap.beacon; |
548 | 548 | ||
549 | if (!old) | 549 | if (!old) |
550 | return -ENOENT; | 550 | return -ENOENT; |
551 | 551 | ||
552 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 552 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); |
553 | synchronize_rcu(); | 553 | synchronize_rcu(); |
554 | kfree(old); | 554 | kfree(old); |
555 | 555 | ||
556 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 556 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); |
557 | } | 557 | } |
558 | 558 | ||
559 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ | 559 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ |
560 | struct iapp_layer2_update { | 560 | struct iapp_layer2_update { |
561 | u8 da[ETH_ALEN]; /* broadcast */ | 561 | u8 da[ETH_ALEN]; /* broadcast */ |
562 | u8 sa[ETH_ALEN]; /* STA addr */ | 562 | u8 sa[ETH_ALEN]; /* STA addr */ |
563 | __be16 len; /* 6 */ | 563 | __be16 len; /* 6 */ |
564 | u8 dsap; /* 0 */ | 564 | u8 dsap; /* 0 */ |
565 | u8 ssap; /* 0 */ | 565 | u8 ssap; /* 0 */ |
566 | u8 control; | 566 | u8 control; |
567 | u8 xid_info[3]; | 567 | u8 xid_info[3]; |
568 | } __attribute__ ((packed)); | 568 | } __attribute__ ((packed)); |
569 | 569 | ||
570 | static void ieee80211_send_layer2_update(struct sta_info *sta) | 570 | static void ieee80211_send_layer2_update(struct sta_info *sta) |
571 | { | 571 | { |
572 | struct iapp_layer2_update *msg; | 572 | struct iapp_layer2_update *msg; |
573 | struct sk_buff *skb; | 573 | struct sk_buff *skb; |
574 | 574 | ||
575 | /* Send Level 2 Update Frame to update forwarding tables in layer 2 | 575 | /* Send Level 2 Update Frame to update forwarding tables in layer 2 |
576 | * bridge devices */ | 576 | * bridge devices */ |
577 | 577 | ||
578 | skb = dev_alloc_skb(sizeof(*msg)); | 578 | skb = dev_alloc_skb(sizeof(*msg)); |
579 | if (!skb) | 579 | if (!skb) |
580 | return; | 580 | return; |
581 | msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); | 581 | msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); |
582 | 582 | ||
583 | /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) | 583 | /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) |
584 | * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ | 584 | * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ |
585 | 585 | ||
586 | memset(msg->da, 0xff, ETH_ALEN); | 586 | memset(msg->da, 0xff, ETH_ALEN); |
587 | memcpy(msg->sa, sta->sta.addr, ETH_ALEN); | 587 | memcpy(msg->sa, sta->sta.addr, ETH_ALEN); |
588 | msg->len = htons(6); | 588 | msg->len = htons(6); |
589 | msg->dsap = 0; | 589 | msg->dsap = 0; |
590 | msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ | 590 | msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ |
591 | msg->control = 0xaf; /* XID response lsb.1111F101. | 591 | msg->control = 0xaf; /* XID response lsb.1111F101. |
592 | * F=0 (no poll command; unsolicited frame) */ | 592 | * F=0 (no poll command; unsolicited frame) */ |
593 | msg->xid_info[0] = 0x81; /* XID format identifier */ | 593 | msg->xid_info[0] = 0x81; /* XID format identifier */ |
594 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ | 594 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ |
595 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ | 595 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ |
596 | 596 | ||
597 | skb->dev = sta->sdata->dev; | 597 | skb->dev = sta->sdata->dev; |
598 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); | 598 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
599 | memset(skb->cb, 0, sizeof(skb->cb)); | 599 | memset(skb->cb, 0, sizeof(skb->cb)); |
600 | netif_rx(skb); | 600 | netif_rx(skb); |
601 | } | 601 | } |
602 | 602 | ||
603 | static void sta_apply_parameters(struct ieee80211_local *local, | 603 | static void sta_apply_parameters(struct ieee80211_local *local, |
604 | struct sta_info *sta, | 604 | struct sta_info *sta, |
605 | struct station_parameters *params) | 605 | struct station_parameters *params) |
606 | { | 606 | { |
607 | u32 rates; | 607 | u32 rates; |
608 | int i, j; | 608 | int i, j; |
609 | struct ieee80211_supported_band *sband; | 609 | struct ieee80211_supported_band *sband; |
610 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 610 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
611 | 611 | ||
612 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 612 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
613 | 613 | ||
614 | /* | 614 | /* |
615 | * FIXME: updating the flags is racy when this function is | 615 | * FIXME: updating the flags is racy when this function is |
616 | * called from ieee80211_change_station(), this will | 616 | * called from ieee80211_change_station(), this will |
617 | * be resolved in a future patch. | 617 | * be resolved in a future patch. |
618 | */ | 618 | */ |
619 | 619 | ||
620 | if (params->station_flags & STATION_FLAG_CHANGED) { | 620 | if (params->station_flags & STATION_FLAG_CHANGED) { |
621 | spin_lock_bh(&sta->lock); | 621 | spin_lock_bh(&sta->lock); |
622 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 622 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
623 | if (params->station_flags & STATION_FLAG_AUTHORIZED) | 623 | if (params->station_flags & STATION_FLAG_AUTHORIZED) |
624 | sta->flags |= WLAN_STA_AUTHORIZED; | 624 | sta->flags |= WLAN_STA_AUTHORIZED; |
625 | 625 | ||
626 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; | 626 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; |
627 | if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) | 627 | if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) |
628 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; | 628 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; |
629 | 629 | ||
630 | sta->flags &= ~WLAN_STA_WME; | 630 | sta->flags &= ~WLAN_STA_WME; |
631 | if (params->station_flags & STATION_FLAG_WME) | 631 | if (params->station_flags & STATION_FLAG_WME) |
632 | sta->flags |= WLAN_STA_WME; | 632 | sta->flags |= WLAN_STA_WME; |
633 | spin_unlock_bh(&sta->lock); | 633 | spin_unlock_bh(&sta->lock); |
634 | } | 634 | } |
635 | 635 | ||
636 | /* | 636 | /* |
637 | * FIXME: updating the following information is racy when this | 637 | * FIXME: updating the following information is racy when this |
638 | * function is called from ieee80211_change_station(). | 638 | * function is called from ieee80211_change_station(). |
639 | * However, all this information should be static so | 639 | * However, all this information should be static so |
640 | * maybe we should just reject attemps to change it. | 640 | * maybe we should just reject attemps to change it. |
641 | */ | 641 | */ |
642 | 642 | ||
643 | if (params->aid) { | 643 | if (params->aid) { |
644 | sta->sta.aid = params->aid; | 644 | sta->sta.aid = params->aid; |
645 | if (sta->sta.aid > IEEE80211_MAX_AID) | 645 | if (sta->sta.aid > IEEE80211_MAX_AID) |
646 | sta->sta.aid = 0; /* XXX: should this be an error? */ | 646 | sta->sta.aid = 0; /* XXX: should this be an error? */ |
647 | } | 647 | } |
648 | 648 | ||
649 | if (params->listen_interval >= 0) | 649 | if (params->listen_interval >= 0) |
650 | sta->listen_interval = params->listen_interval; | 650 | sta->listen_interval = params->listen_interval; |
651 | 651 | ||
652 | if (params->supported_rates) { | 652 | if (params->supported_rates) { |
653 | rates = 0; | 653 | rates = 0; |
654 | 654 | ||
655 | for (i = 0; i < params->supported_rates_len; i++) { | 655 | for (i = 0; i < params->supported_rates_len; i++) { |
656 | int rate = (params->supported_rates[i] & 0x7f) * 5; | 656 | int rate = (params->supported_rates[i] & 0x7f) * 5; |
657 | for (j = 0; j < sband->n_bitrates; j++) { | 657 | for (j = 0; j < sband->n_bitrates; j++) { |
658 | if (sband->bitrates[j].bitrate == rate) | 658 | if (sband->bitrates[j].bitrate == rate) |
659 | rates |= BIT(j); | 659 | rates |= BIT(j); |
660 | } | 660 | } |
661 | } | 661 | } |
662 | sta->sta.supp_rates[local->oper_channel->band] = rates; | 662 | sta->sta.supp_rates[local->oper_channel->band] = rates; |
663 | } | 663 | } |
664 | 664 | ||
665 | if (params->ht_capa) | 665 | if (params->ht_capa) |
666 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 666 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, |
667 | params->ht_capa, | 667 | params->ht_capa, |
668 | &sta->sta.ht_cap); | 668 | &sta->sta.ht_cap); |
669 | 669 | ||
670 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 670 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { |
671 | switch (params->plink_action) { | 671 | switch (params->plink_action) { |
672 | case PLINK_ACTION_OPEN: | 672 | case PLINK_ACTION_OPEN: |
673 | mesh_plink_open(sta); | 673 | mesh_plink_open(sta); |
674 | break; | 674 | break; |
675 | case PLINK_ACTION_BLOCK: | 675 | case PLINK_ACTION_BLOCK: |
676 | mesh_plink_block(sta); | 676 | mesh_plink_block(sta); |
677 | break; | 677 | break; |
678 | } | 678 | } |
679 | } | 679 | } |
680 | } | 680 | } |
681 | 681 | ||
682 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | 682 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, |
683 | u8 *mac, struct station_parameters *params) | 683 | u8 *mac, struct station_parameters *params) |
684 | { | 684 | { |
685 | struct ieee80211_local *local = wiphy_priv(wiphy); | 685 | struct ieee80211_local *local = wiphy_priv(wiphy); |
686 | struct sta_info *sta; | 686 | struct sta_info *sta; |
687 | struct ieee80211_sub_if_data *sdata; | 687 | struct ieee80211_sub_if_data *sdata; |
688 | int err; | 688 | int err; |
689 | 689 | ||
690 | /* Prevent a race with changing the rate control algorithm */ | 690 | /* Prevent a race with changing the rate control algorithm */ |
691 | if (!netif_running(dev)) | 691 | if (!netif_running(dev)) |
692 | return -ENETDOWN; | 692 | return -ENETDOWN; |
693 | 693 | ||
694 | if (params->vlan) { | 694 | if (params->vlan) { |
695 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 695 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
696 | 696 | ||
697 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 697 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
698 | sdata->vif.type != NL80211_IFTYPE_AP) | 698 | sdata->vif.type != NL80211_IFTYPE_AP) |
699 | return -EINVAL; | 699 | return -EINVAL; |
700 | } else | 700 | } else |
701 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 701 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
702 | 702 | ||
703 | if (compare_ether_addr(mac, dev->dev_addr) == 0) | 703 | if (compare_ether_addr(mac, dev->dev_addr) == 0) |
704 | return -EINVAL; | 704 | return -EINVAL; |
705 | 705 | ||
706 | if (is_multicast_ether_addr(mac)) | 706 | if (is_multicast_ether_addr(mac)) |
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | 708 | ||
709 | sta = sta_info_alloc(sdata, mac, GFP_KERNEL); | 709 | sta = sta_info_alloc(sdata, mac, GFP_KERNEL); |
710 | if (!sta) | 710 | if (!sta) |
711 | return -ENOMEM; | 711 | return -ENOMEM; |
712 | 712 | ||
713 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 713 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; |
714 | 714 | ||
715 | sta_apply_parameters(local, sta, params); | 715 | sta_apply_parameters(local, sta, params); |
716 | 716 | ||
717 | rate_control_rate_init(sta); | 717 | rate_control_rate_init(sta); |
718 | 718 | ||
719 | rcu_read_lock(); | 719 | rcu_read_lock(); |
720 | 720 | ||
721 | err = sta_info_insert(sta); | 721 | err = sta_info_insert(sta); |
722 | if (err) { | 722 | if (err) { |
723 | /* STA has been freed */ | 723 | /* STA has been freed */ |
724 | rcu_read_unlock(); | 724 | rcu_read_unlock(); |
725 | return err; | 725 | return err; |
726 | } | 726 | } |
727 | 727 | ||
728 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 728 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
729 | sdata->vif.type == NL80211_IFTYPE_AP) | 729 | sdata->vif.type == NL80211_IFTYPE_AP) |
730 | ieee80211_send_layer2_update(sta); | 730 | ieee80211_send_layer2_update(sta); |
731 | 731 | ||
732 | rcu_read_unlock(); | 732 | rcu_read_unlock(); |
733 | 733 | ||
734 | return 0; | 734 | return 0; |
735 | } | 735 | } |
736 | 736 | ||
737 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 737 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
738 | u8 *mac) | 738 | u8 *mac) |
739 | { | 739 | { |
740 | struct ieee80211_local *local = wiphy_priv(wiphy); | 740 | struct ieee80211_local *local = wiphy_priv(wiphy); |
741 | struct ieee80211_sub_if_data *sdata; | 741 | struct ieee80211_sub_if_data *sdata; |
742 | struct sta_info *sta; | 742 | struct sta_info *sta; |
743 | 743 | ||
744 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 744 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
745 | 745 | ||
746 | if (mac) { | 746 | if (mac) { |
747 | rcu_read_lock(); | 747 | rcu_read_lock(); |
748 | 748 | ||
749 | /* XXX: get sta belonging to dev */ | 749 | /* XXX: get sta belonging to dev */ |
750 | sta = sta_info_get(local, mac); | 750 | sta = sta_info_get(local, mac); |
751 | if (!sta) { | 751 | if (!sta) { |
752 | rcu_read_unlock(); | 752 | rcu_read_unlock(); |
753 | return -ENOENT; | 753 | return -ENOENT; |
754 | } | 754 | } |
755 | 755 | ||
756 | sta_info_unlink(&sta); | 756 | sta_info_unlink(&sta); |
757 | rcu_read_unlock(); | 757 | rcu_read_unlock(); |
758 | 758 | ||
759 | sta_info_destroy(sta); | 759 | sta_info_destroy(sta); |
760 | } else | 760 | } else |
761 | sta_info_flush(local, sdata); | 761 | sta_info_flush(local, sdata); |
762 | 762 | ||
763 | return 0; | 763 | return 0; |
764 | } | 764 | } |
765 | 765 | ||
766 | static int ieee80211_change_station(struct wiphy *wiphy, | 766 | static int ieee80211_change_station(struct wiphy *wiphy, |
767 | struct net_device *dev, | 767 | struct net_device *dev, |
768 | u8 *mac, | 768 | u8 *mac, |
769 | struct station_parameters *params) | 769 | struct station_parameters *params) |
770 | { | 770 | { |
771 | struct ieee80211_local *local = wiphy_priv(wiphy); | 771 | struct ieee80211_local *local = wiphy_priv(wiphy); |
772 | struct sta_info *sta; | 772 | struct sta_info *sta; |
773 | struct ieee80211_sub_if_data *vlansdata; | 773 | struct ieee80211_sub_if_data *vlansdata; |
774 | 774 | ||
775 | rcu_read_lock(); | 775 | rcu_read_lock(); |
776 | 776 | ||
777 | /* XXX: get sta belonging to dev */ | 777 | /* XXX: get sta belonging to dev */ |
778 | sta = sta_info_get(local, mac); | 778 | sta = sta_info_get(local, mac); |
779 | if (!sta) { | 779 | if (!sta) { |
780 | rcu_read_unlock(); | 780 | rcu_read_unlock(); |
781 | return -ENOENT; | 781 | return -ENOENT; |
782 | } | 782 | } |
783 | 783 | ||
784 | if (params->vlan && params->vlan != sta->sdata->dev) { | 784 | if (params->vlan && params->vlan != sta->sdata->dev) { |
785 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 785 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
786 | 786 | ||
787 | if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 787 | if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
788 | vlansdata->vif.type != NL80211_IFTYPE_AP) { | 788 | vlansdata->vif.type != NL80211_IFTYPE_AP) { |
789 | rcu_read_unlock(); | 789 | rcu_read_unlock(); |
790 | return -EINVAL; | 790 | return -EINVAL; |
791 | } | 791 | } |
792 | 792 | ||
793 | sta->sdata = vlansdata; | 793 | sta->sdata = vlansdata; |
794 | ieee80211_send_layer2_update(sta); | 794 | ieee80211_send_layer2_update(sta); |
795 | } | 795 | } |
796 | 796 | ||
797 | sta_apply_parameters(local, sta, params); | 797 | sta_apply_parameters(local, sta, params); |
798 | 798 | ||
799 | rcu_read_unlock(); | 799 | rcu_read_unlock(); |
800 | 800 | ||
801 | return 0; | 801 | return 0; |
802 | } | 802 | } |
803 | 803 | ||
804 | #ifdef CONFIG_MAC80211_MESH | 804 | #ifdef CONFIG_MAC80211_MESH |
805 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 805 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
806 | u8 *dst, u8 *next_hop) | 806 | u8 *dst, u8 *next_hop) |
807 | { | 807 | { |
808 | struct ieee80211_local *local = wiphy_priv(wiphy); | 808 | struct ieee80211_local *local = wiphy_priv(wiphy); |
809 | struct ieee80211_sub_if_data *sdata; | 809 | struct ieee80211_sub_if_data *sdata; |
810 | struct mesh_path *mpath; | 810 | struct mesh_path *mpath; |
811 | struct sta_info *sta; | 811 | struct sta_info *sta; |
812 | int err; | 812 | int err; |
813 | 813 | ||
814 | if (!netif_running(dev)) | 814 | if (!netif_running(dev)) |
815 | return -ENETDOWN; | 815 | return -ENETDOWN; |
816 | 816 | ||
817 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 817 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
818 | 818 | ||
819 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 819 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
820 | return -ENOTSUPP; | 820 | return -ENOTSUPP; |
821 | 821 | ||
822 | rcu_read_lock(); | 822 | rcu_read_lock(); |
823 | sta = sta_info_get(local, next_hop); | 823 | sta = sta_info_get(local, next_hop); |
824 | if (!sta) { | 824 | if (!sta) { |
825 | rcu_read_unlock(); | 825 | rcu_read_unlock(); |
826 | return -ENOENT; | 826 | return -ENOENT; |
827 | } | 827 | } |
828 | 828 | ||
829 | err = mesh_path_add(dst, sdata); | 829 | err = mesh_path_add(dst, sdata); |
830 | if (err) { | 830 | if (err) { |
831 | rcu_read_unlock(); | 831 | rcu_read_unlock(); |
832 | return err; | 832 | return err; |
833 | } | 833 | } |
834 | 834 | ||
835 | mpath = mesh_path_lookup(dst, sdata); | 835 | mpath = mesh_path_lookup(dst, sdata); |
836 | if (!mpath) { | 836 | if (!mpath) { |
837 | rcu_read_unlock(); | 837 | rcu_read_unlock(); |
838 | return -ENXIO; | 838 | return -ENXIO; |
839 | } | 839 | } |
840 | mesh_path_fix_nexthop(mpath, sta); | 840 | mesh_path_fix_nexthop(mpath, sta); |
841 | 841 | ||
842 | rcu_read_unlock(); | 842 | rcu_read_unlock(); |
843 | return 0; | 843 | return 0; |
844 | } | 844 | } |
845 | 845 | ||
846 | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | 846 | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, |
847 | u8 *dst) | 847 | u8 *dst) |
848 | { | 848 | { |
849 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 849 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
850 | 850 | ||
851 | if (dst) | 851 | if (dst) |
852 | return mesh_path_del(dst, sdata); | 852 | return mesh_path_del(dst, sdata); |
853 | 853 | ||
854 | mesh_path_flush(sdata); | 854 | mesh_path_flush(sdata); |
855 | return 0; | 855 | return 0; |
856 | } | 856 | } |
857 | 857 | ||
858 | static int ieee80211_change_mpath(struct wiphy *wiphy, | 858 | static int ieee80211_change_mpath(struct wiphy *wiphy, |
859 | struct net_device *dev, | 859 | struct net_device *dev, |
860 | u8 *dst, u8 *next_hop) | 860 | u8 *dst, u8 *next_hop) |
861 | { | 861 | { |
862 | struct ieee80211_local *local = wiphy_priv(wiphy); | 862 | struct ieee80211_local *local = wiphy_priv(wiphy); |
863 | struct ieee80211_sub_if_data *sdata; | 863 | struct ieee80211_sub_if_data *sdata; |
864 | struct mesh_path *mpath; | 864 | struct mesh_path *mpath; |
865 | struct sta_info *sta; | 865 | struct sta_info *sta; |
866 | 866 | ||
867 | if (!netif_running(dev)) | 867 | if (!netif_running(dev)) |
868 | return -ENETDOWN; | 868 | return -ENETDOWN; |
869 | 869 | ||
870 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 870 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
871 | 871 | ||
872 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 872 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
873 | return -ENOTSUPP; | 873 | return -ENOTSUPP; |
874 | 874 | ||
875 | rcu_read_lock(); | 875 | rcu_read_lock(); |
876 | 876 | ||
877 | sta = sta_info_get(local, next_hop); | 877 | sta = sta_info_get(local, next_hop); |
878 | if (!sta) { | 878 | if (!sta) { |
879 | rcu_read_unlock(); | 879 | rcu_read_unlock(); |
880 | return -ENOENT; | 880 | return -ENOENT; |
881 | } | 881 | } |
882 | 882 | ||
883 | mpath = mesh_path_lookup(dst, sdata); | 883 | mpath = mesh_path_lookup(dst, sdata); |
884 | if (!mpath) { | 884 | if (!mpath) { |
885 | rcu_read_unlock(); | 885 | rcu_read_unlock(); |
886 | return -ENOENT; | 886 | return -ENOENT; |
887 | } | 887 | } |
888 | 888 | ||
889 | mesh_path_fix_nexthop(mpath, sta); | 889 | mesh_path_fix_nexthop(mpath, sta); |
890 | 890 | ||
891 | rcu_read_unlock(); | 891 | rcu_read_unlock(); |
892 | return 0; | 892 | return 0; |
893 | } | 893 | } |
894 | 894 | ||
895 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | 895 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, |
896 | struct mpath_info *pinfo) | 896 | struct mpath_info *pinfo) |
897 | { | 897 | { |
898 | if (mpath->next_hop) | 898 | if (mpath->next_hop) |
899 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 899 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); |
900 | else | 900 | else |
901 | memset(next_hop, 0, ETH_ALEN); | 901 | memset(next_hop, 0, ETH_ALEN); |
902 | 902 | ||
903 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 903 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
904 | MPATH_INFO_DSN | | 904 | MPATH_INFO_DSN | |
905 | MPATH_INFO_METRIC | | 905 | MPATH_INFO_METRIC | |
906 | MPATH_INFO_EXPTIME | | 906 | MPATH_INFO_EXPTIME | |
907 | MPATH_INFO_DISCOVERY_TIMEOUT | | 907 | MPATH_INFO_DISCOVERY_TIMEOUT | |
908 | MPATH_INFO_DISCOVERY_RETRIES | | 908 | MPATH_INFO_DISCOVERY_RETRIES | |
909 | MPATH_INFO_FLAGS; | 909 | MPATH_INFO_FLAGS; |
910 | 910 | ||
911 | pinfo->frame_qlen = mpath->frame_queue.qlen; | 911 | pinfo->frame_qlen = mpath->frame_queue.qlen; |
912 | pinfo->dsn = mpath->dsn; | 912 | pinfo->dsn = mpath->dsn; |
913 | pinfo->metric = mpath->metric; | 913 | pinfo->metric = mpath->metric; |
914 | if (time_before(jiffies, mpath->exp_time)) | 914 | if (time_before(jiffies, mpath->exp_time)) |
915 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | 915 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); |
916 | pinfo->discovery_timeout = | 916 | pinfo->discovery_timeout = |
917 | jiffies_to_msecs(mpath->discovery_timeout); | 917 | jiffies_to_msecs(mpath->discovery_timeout); |
918 | pinfo->discovery_retries = mpath->discovery_retries; | 918 | pinfo->discovery_retries = mpath->discovery_retries; |
919 | pinfo->flags = 0; | 919 | pinfo->flags = 0; |
920 | if (mpath->flags & MESH_PATH_ACTIVE) | 920 | if (mpath->flags & MESH_PATH_ACTIVE) |
921 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | 921 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; |
922 | if (mpath->flags & MESH_PATH_RESOLVING) | 922 | if (mpath->flags & MESH_PATH_RESOLVING) |
923 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 923 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; |
924 | if (mpath->flags & MESH_PATH_DSN_VALID) | 924 | if (mpath->flags & MESH_PATH_DSN_VALID) |
925 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | 925 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; |
926 | if (mpath->flags & MESH_PATH_FIXED) | 926 | if (mpath->flags & MESH_PATH_FIXED) |
927 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | 927 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; |
928 | if (mpath->flags & MESH_PATH_RESOLVING) | 928 | if (mpath->flags & MESH_PATH_RESOLVING) |
929 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 929 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; |
930 | 930 | ||
931 | pinfo->flags = mpath->flags; | 931 | pinfo->flags = mpath->flags; |
932 | } | 932 | } |
933 | 933 | ||
934 | static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | 934 | static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, |
935 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) | 935 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) |
936 | 936 | ||
937 | { | 937 | { |
938 | struct ieee80211_sub_if_data *sdata; | 938 | struct ieee80211_sub_if_data *sdata; |
939 | struct mesh_path *mpath; | 939 | struct mesh_path *mpath; |
940 | 940 | ||
941 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 941 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
942 | 942 | ||
943 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 943 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
944 | return -ENOTSUPP; | 944 | return -ENOTSUPP; |
945 | 945 | ||
946 | rcu_read_lock(); | 946 | rcu_read_lock(); |
947 | mpath = mesh_path_lookup(dst, sdata); | 947 | mpath = mesh_path_lookup(dst, sdata); |
948 | if (!mpath) { | 948 | if (!mpath) { |
949 | rcu_read_unlock(); | 949 | rcu_read_unlock(); |
950 | return -ENOENT; | 950 | return -ENOENT; |
951 | } | 951 | } |
952 | memcpy(dst, mpath->dst, ETH_ALEN); | 952 | memcpy(dst, mpath->dst, ETH_ALEN); |
953 | mpath_set_pinfo(mpath, next_hop, pinfo); | 953 | mpath_set_pinfo(mpath, next_hop, pinfo); |
954 | rcu_read_unlock(); | 954 | rcu_read_unlock(); |
955 | return 0; | 955 | return 0; |
956 | } | 956 | } |
957 | 957 | ||
958 | static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | 958 | static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, |
959 | int idx, u8 *dst, u8 *next_hop, | 959 | int idx, u8 *dst, u8 *next_hop, |
960 | struct mpath_info *pinfo) | 960 | struct mpath_info *pinfo) |
961 | { | 961 | { |
962 | struct ieee80211_sub_if_data *sdata; | 962 | struct ieee80211_sub_if_data *sdata; |
963 | struct mesh_path *mpath; | 963 | struct mesh_path *mpath; |
964 | 964 | ||
965 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 965 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
966 | 966 | ||
967 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 967 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
968 | return -ENOTSUPP; | 968 | return -ENOTSUPP; |
969 | 969 | ||
970 | rcu_read_lock(); | 970 | rcu_read_lock(); |
971 | mpath = mesh_path_lookup_by_idx(idx, sdata); | 971 | mpath = mesh_path_lookup_by_idx(idx, sdata); |
972 | if (!mpath) { | 972 | if (!mpath) { |
973 | rcu_read_unlock(); | 973 | rcu_read_unlock(); |
974 | return -ENOENT; | 974 | return -ENOENT; |
975 | } | 975 | } |
976 | memcpy(dst, mpath->dst, ETH_ALEN); | 976 | memcpy(dst, mpath->dst, ETH_ALEN); |
977 | mpath_set_pinfo(mpath, next_hop, pinfo); | 977 | mpath_set_pinfo(mpath, next_hop, pinfo); |
978 | rcu_read_unlock(); | 978 | rcu_read_unlock(); |
979 | return 0; | 979 | return 0; |
980 | } | 980 | } |
981 | 981 | ||
982 | static int ieee80211_get_mesh_params(struct wiphy *wiphy, | 982 | static int ieee80211_get_mesh_params(struct wiphy *wiphy, |
983 | struct net_device *dev, | 983 | struct net_device *dev, |
984 | struct mesh_config *conf) | 984 | struct mesh_config *conf) |
985 | { | 985 | { |
986 | struct ieee80211_sub_if_data *sdata; | 986 | struct ieee80211_sub_if_data *sdata; |
987 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 987 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
988 | 988 | ||
989 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 989 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
990 | return -ENOTSUPP; | 990 | return -ENOTSUPP; |
991 | memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); | 991 | memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); |
992 | return 0; | 992 | return 0; |
993 | } | 993 | } |
994 | 994 | ||
995 | static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | 995 | static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) |
996 | { | 996 | { |
997 | return (mask >> (parm-1)) & 0x1; | 997 | return (mask >> (parm-1)) & 0x1; |
998 | } | 998 | } |
999 | 999 | ||
1000 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | 1000 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, |
1001 | struct net_device *dev, | 1001 | struct net_device *dev, |
1002 | const struct mesh_config *nconf, u32 mask) | 1002 | const struct mesh_config *nconf, u32 mask) |
1003 | { | 1003 | { |
1004 | struct mesh_config *conf; | 1004 | struct mesh_config *conf; |
1005 | struct ieee80211_sub_if_data *sdata; | 1005 | struct ieee80211_sub_if_data *sdata; |
1006 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1006 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1007 | 1007 | ||
1008 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 1008 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) |
1009 | return -ENOTSUPP; | 1009 | return -ENOTSUPP; |
1010 | 1010 | ||
1011 | /* Set the config options which we are interested in setting */ | 1011 | /* Set the config options which we are interested in setting */ |
1012 | conf = &(sdata->u.mesh.mshcfg); | 1012 | conf = &(sdata->u.mesh.mshcfg); |
1013 | if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) | 1013 | if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) |
1014 | conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout; | 1014 | conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout; |
1015 | if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask)) | 1015 | if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask)) |
1016 | conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout; | 1016 | conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout; |
1017 | if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask)) | 1017 | if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask)) |
1018 | conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout; | 1018 | conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout; |
1019 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask)) | 1019 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask)) |
1020 | conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks; | 1020 | conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks; |
1021 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask)) | 1021 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask)) |
1022 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; | 1022 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; |
1023 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | 1023 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) |
1024 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1024 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1025 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1025 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1026 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1026 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1027 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | 1027 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) |
1028 | conf->dot11MeshHWMPmaxPREQretries = | 1028 | conf->dot11MeshHWMPmaxPREQretries = |
1029 | nconf->dot11MeshHWMPmaxPREQretries; | 1029 | nconf->dot11MeshHWMPmaxPREQretries; |
1030 | if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask)) | 1030 | if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask)) |
1031 | conf->path_refresh_time = nconf->path_refresh_time; | 1031 | conf->path_refresh_time = nconf->path_refresh_time; |
1032 | if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask)) | 1032 | if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask)) |
1033 | conf->min_discovery_timeout = nconf->min_discovery_timeout; | 1033 | conf->min_discovery_timeout = nconf->min_discovery_timeout; |
1034 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask)) | 1034 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask)) |
1035 | conf->dot11MeshHWMPactivePathTimeout = | 1035 | conf->dot11MeshHWMPactivePathTimeout = |
1036 | nconf->dot11MeshHWMPactivePathTimeout; | 1036 | nconf->dot11MeshHWMPactivePathTimeout; |
1037 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask)) | 1037 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask)) |
1038 | conf->dot11MeshHWMPpreqMinInterval = | 1038 | conf->dot11MeshHWMPpreqMinInterval = |
1039 | nconf->dot11MeshHWMPpreqMinInterval; | 1039 | nconf->dot11MeshHWMPpreqMinInterval; |
1040 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 1040 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
1041 | mask)) | 1041 | mask)) |
1042 | conf->dot11MeshHWMPnetDiameterTraversalTime = | 1042 | conf->dot11MeshHWMPnetDiameterTraversalTime = |
1043 | nconf->dot11MeshHWMPnetDiameterTraversalTime; | 1043 | nconf->dot11MeshHWMPnetDiameterTraversalTime; |
1044 | return 0; | 1044 | return 0; |
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | #endif | 1047 | #endif |
1048 | 1048 | ||
1049 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1049 | static int ieee80211_change_bss(struct wiphy *wiphy, |
1050 | struct net_device *dev, | 1050 | struct net_device *dev, |
1051 | struct bss_parameters *params) | 1051 | struct bss_parameters *params) |
1052 | { | 1052 | { |
1053 | struct ieee80211_sub_if_data *sdata; | 1053 | struct ieee80211_sub_if_data *sdata; |
1054 | u32 changed = 0; | 1054 | u32 changed = 0; |
1055 | 1055 | ||
1056 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1056 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1057 | 1057 | ||
1058 | if (sdata->vif.type != NL80211_IFTYPE_AP) | 1058 | if (sdata->vif.type != NL80211_IFTYPE_AP) |
1059 | return -EINVAL; | 1059 | return -EINVAL; |
1060 | 1060 | ||
1061 | if (params->use_cts_prot >= 0) { | 1061 | if (params->use_cts_prot >= 0) { |
1062 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; | 1062 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; |
1063 | changed |= BSS_CHANGED_ERP_CTS_PROT; | 1063 | changed |= BSS_CHANGED_ERP_CTS_PROT; |
1064 | } | 1064 | } |
1065 | if (params->use_short_preamble >= 0) { | 1065 | if (params->use_short_preamble >= 0) { |
1066 | sdata->vif.bss_conf.use_short_preamble = | 1066 | sdata->vif.bss_conf.use_short_preamble = |
1067 | params->use_short_preamble; | 1067 | params->use_short_preamble; |
1068 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1068 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
1069 | } | 1069 | } |
1070 | if (params->use_short_slot_time >= 0) { | 1070 | if (params->use_short_slot_time >= 0) { |
1071 | sdata->vif.bss_conf.use_short_slot = | 1071 | sdata->vif.bss_conf.use_short_slot = |
1072 | params->use_short_slot_time; | 1072 | params->use_short_slot_time; |
1073 | changed |= BSS_CHANGED_ERP_SLOT; | 1073 | changed |= BSS_CHANGED_ERP_SLOT; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | if (params->basic_rates) { | 1076 | if (params->basic_rates) { |
1077 | int i, j; | 1077 | int i, j; |
1078 | u32 rates = 0; | 1078 | u32 rates = 0; |
1079 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1079 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1080 | struct ieee80211_supported_band *sband = | 1080 | struct ieee80211_supported_band *sband = |
1081 | wiphy->bands[local->oper_channel->band]; | 1081 | wiphy->bands[local->oper_channel->band]; |
1082 | 1082 | ||
1083 | for (i = 0; i < params->basic_rates_len; i++) { | 1083 | for (i = 0; i < params->basic_rates_len; i++) { |
1084 | int rate = (params->basic_rates[i] & 0x7f) * 5; | 1084 | int rate = (params->basic_rates[i] & 0x7f) * 5; |
1085 | for (j = 0; j < sband->n_bitrates; j++) { | 1085 | for (j = 0; j < sband->n_bitrates; j++) { |
1086 | if (sband->bitrates[j].bitrate == rate) | 1086 | if (sband->bitrates[j].bitrate == rate) |
1087 | rates |= BIT(j); | 1087 | rates |= BIT(j); |
1088 | } | 1088 | } |
1089 | } | 1089 | } |
1090 | sdata->vif.bss_conf.basic_rates = rates; | 1090 | sdata->vif.bss_conf.basic_rates = rates; |
1091 | changed |= BSS_CHANGED_BASIC_RATES; | 1091 | changed |= BSS_CHANGED_BASIC_RATES; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | ieee80211_bss_info_change_notify(sdata, changed); | 1094 | ieee80211_bss_info_change_notify(sdata, changed); |
1095 | 1095 | ||
1096 | return 0; | 1096 | return 0; |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | static int ieee80211_set_txq_params(struct wiphy *wiphy, | 1099 | static int ieee80211_set_txq_params(struct wiphy *wiphy, |
1100 | struct ieee80211_txq_params *params) | 1100 | struct ieee80211_txq_params *params) |
1101 | { | 1101 | { |
1102 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1102 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1103 | struct ieee80211_tx_queue_params p; | 1103 | struct ieee80211_tx_queue_params p; |
1104 | 1104 | ||
1105 | if (!local->ops->conf_tx) | 1105 | if (!local->ops->conf_tx) |
1106 | return -EOPNOTSUPP; | 1106 | return -EOPNOTSUPP; |
1107 | 1107 | ||
1108 | memset(&p, 0, sizeof(p)); | 1108 | memset(&p, 0, sizeof(p)); |
1109 | p.aifs = params->aifs; | 1109 | p.aifs = params->aifs; |
1110 | p.cw_max = params->cwmax; | 1110 | p.cw_max = params->cwmax; |
1111 | p.cw_min = params->cwmin; | 1111 | p.cw_min = params->cwmin; |
1112 | p.txop = params->txop; | 1112 | p.txop = params->txop; |
1113 | if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { | 1113 | if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { |
1114 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1114 | printk(KERN_DEBUG "%s: failed to set TX queue " |
1115 | "parameters for queue %d\n", local->mdev->name, | 1115 | "parameters for queue %d\n", local->mdev->name, |
1116 | params->queue); | 1116 | params->queue); |
1117 | return -EINVAL; | 1117 | return -EINVAL; |
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | return 0; | 1120 | return 0; |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | static int ieee80211_set_channel(struct wiphy *wiphy, | 1123 | static int ieee80211_set_channel(struct wiphy *wiphy, |
1124 | struct ieee80211_channel *chan, | 1124 | struct ieee80211_channel *chan, |
1125 | enum nl80211_sec_chan_offset sec_chan_offset) | 1125 | enum nl80211_channel_type channel_type) |
1126 | { | 1126 | { |
1127 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1127 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1128 | 1128 | ||
1129 | local->oper_channel = chan; | 1129 | local->oper_channel = chan; |
1130 | local->oper_sec_chan_offset = sec_chan_offset; | 1130 | local->oper_channel_type = channel_type; |
1131 | 1131 | ||
1132 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1132 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1133 | } | 1133 | } |
1134 | 1134 | ||
1135 | struct cfg80211_ops mac80211_config_ops = { | 1135 | struct cfg80211_ops mac80211_config_ops = { |
1136 | .add_virtual_intf = ieee80211_add_iface, | 1136 | .add_virtual_intf = ieee80211_add_iface, |
1137 | .del_virtual_intf = ieee80211_del_iface, | 1137 | .del_virtual_intf = ieee80211_del_iface, |
1138 | .change_virtual_intf = ieee80211_change_iface, | 1138 | .change_virtual_intf = ieee80211_change_iface, |
1139 | .add_key = ieee80211_add_key, | 1139 | .add_key = ieee80211_add_key, |
1140 | .del_key = ieee80211_del_key, | 1140 | .del_key = ieee80211_del_key, |
1141 | .get_key = ieee80211_get_key, | 1141 | .get_key = ieee80211_get_key, |
1142 | .set_default_key = ieee80211_config_default_key, | 1142 | .set_default_key = ieee80211_config_default_key, |
1143 | .add_beacon = ieee80211_add_beacon, | 1143 | .add_beacon = ieee80211_add_beacon, |
1144 | .set_beacon = ieee80211_set_beacon, | 1144 | .set_beacon = ieee80211_set_beacon, |
1145 | .del_beacon = ieee80211_del_beacon, | 1145 | .del_beacon = ieee80211_del_beacon, |
1146 | .add_station = ieee80211_add_station, | 1146 | .add_station = ieee80211_add_station, |
1147 | .del_station = ieee80211_del_station, | 1147 | .del_station = ieee80211_del_station, |
1148 | .change_station = ieee80211_change_station, | 1148 | .change_station = ieee80211_change_station, |
1149 | .get_station = ieee80211_get_station, | 1149 | .get_station = ieee80211_get_station, |
1150 | .dump_station = ieee80211_dump_station, | 1150 | .dump_station = ieee80211_dump_station, |
1151 | #ifdef CONFIG_MAC80211_MESH | 1151 | #ifdef CONFIG_MAC80211_MESH |
1152 | .add_mpath = ieee80211_add_mpath, | 1152 | .add_mpath = ieee80211_add_mpath, |
1153 | .del_mpath = ieee80211_del_mpath, | 1153 | .del_mpath = ieee80211_del_mpath, |
1154 | .change_mpath = ieee80211_change_mpath, | 1154 | .change_mpath = ieee80211_change_mpath, |
1155 | .get_mpath = ieee80211_get_mpath, | 1155 | .get_mpath = ieee80211_get_mpath, |
1156 | .dump_mpath = ieee80211_dump_mpath, | 1156 | .dump_mpath = ieee80211_dump_mpath, |
1157 | .set_mesh_params = ieee80211_set_mesh_params, | 1157 | .set_mesh_params = ieee80211_set_mesh_params, |
1158 | .get_mesh_params = ieee80211_get_mesh_params, | 1158 | .get_mesh_params = ieee80211_get_mesh_params, |
1159 | #endif | 1159 | #endif |
1160 | .change_bss = ieee80211_change_bss, | 1160 | .change_bss = ieee80211_change_bss, |
1161 | .set_txq_params = ieee80211_set_txq_params, | 1161 | .set_txq_params = ieee80211_set_txq_params, |
1162 | .set_channel = ieee80211_set_channel, | 1162 | .set_channel = ieee80211_set_channel, |
1163 | }; | 1163 | }; |
1164 | 1164 |
net/mac80211/ht.c
1 | /* | 1 | /* |
2 | * HT handling | 2 | * HT handling |
3 | * | 3 | * |
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | 4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> |
5 | * Copyright 2002-2005, Instant802 Networks, Inc. | 5 | * Copyright 2002-2005, Instant802 Networks, Inc. |
6 | * Copyright 2005-2006, Devicescape Software, Inc. | 6 | * Copyright 2005-2006, Devicescape Software, Inc. |
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
9 | * Copyright 2007-2008, Intel Corporation | 9 | * Copyright 2007-2008, Intel Corporation |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 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 | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/ieee80211.h> | 16 | #include <linux/ieee80211.h> |
17 | #include <net/wireless.h> | 17 | #include <net/wireless.h> |
18 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "sta_info.h" | 20 | #include "sta_info.h" |
21 | #include "wme.h" | 21 | #include "wme.h" |
22 | 22 | ||
23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, |
24 | struct ieee80211_ht_cap *ht_cap_ie, | 24 | struct ieee80211_ht_cap *ht_cap_ie, |
25 | struct ieee80211_sta_ht_cap *ht_cap) | 25 | struct ieee80211_sta_ht_cap *ht_cap) |
26 | { | 26 | { |
27 | u8 ampdu_info, tx_mcs_set_cap; | 27 | u8 ampdu_info, tx_mcs_set_cap; |
28 | int i, max_tx_streams; | 28 | int i, max_tx_streams; |
29 | 29 | ||
30 | BUG_ON(!ht_cap); | 30 | BUG_ON(!ht_cap); |
31 | 31 | ||
32 | memset(ht_cap, 0, sizeof(*ht_cap)); | 32 | memset(ht_cap, 0, sizeof(*ht_cap)); |
33 | 33 | ||
34 | if (!ht_cap_ie) | 34 | if (!ht_cap_ie) |
35 | return; | 35 | return; |
36 | 36 | ||
37 | ht_cap->ht_supported = true; | 37 | ht_cap->ht_supported = true; |
38 | 38 | ||
39 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap; | 39 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap; |
40 | ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS; | 40 | ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS; |
41 | ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; | 41 | ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; |
42 | 42 | ||
43 | ampdu_info = ht_cap_ie->ampdu_params_info; | 43 | ampdu_info = ht_cap_ie->ampdu_params_info; |
44 | ht_cap->ampdu_factor = | 44 | ht_cap->ampdu_factor = |
45 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; | 45 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; |
46 | ht_cap->ampdu_density = | 46 | ht_cap->ampdu_density = |
47 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 47 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
48 | 48 | ||
49 | /* own MCS TX capabilities */ | 49 | /* own MCS TX capabilities */ |
50 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 50 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; |
51 | 51 | ||
52 | /* can we TX with MCS rates? */ | 52 | /* can we TX with MCS rates? */ |
53 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | 53 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) |
54 | return; | 54 | return; |
55 | 55 | ||
56 | /* Counting from 0, therefore +1 */ | 56 | /* Counting from 0, therefore +1 */ |
57 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | 57 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) |
58 | max_tx_streams = | 58 | max_tx_streams = |
59 | ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | 59 | ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) |
60 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | 60 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; |
61 | else | 61 | else |
62 | max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; | 62 | max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * 802.11n D5.0 20.3.5 / 20.6 says: | 65 | * 802.11n D5.0 20.3.5 / 20.6 says: |
66 | * - indices 0 to 7 and 32 are single spatial stream | 66 | * - indices 0 to 7 and 32 are single spatial stream |
67 | * - 8 to 31 are multiple spatial streams using equal modulation | 67 | * - 8 to 31 are multiple spatial streams using equal modulation |
68 | * [8..15 for two streams, 16..23 for three and 24..31 for four] | 68 | * [8..15 for two streams, 16..23 for three and 24..31 for four] |
69 | * - remainder are multiple spatial streams using unequal modulation | 69 | * - remainder are multiple spatial streams using unequal modulation |
70 | */ | 70 | */ |
71 | for (i = 0; i < max_tx_streams; i++) | 71 | for (i = 0; i < max_tx_streams; i++) |
72 | ht_cap->mcs.rx_mask[i] = | 72 | ht_cap->mcs.rx_mask[i] = |
73 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 73 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
74 | 74 | ||
75 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 75 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
76 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 76 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
77 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 77 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
78 | ht_cap->mcs.rx_mask[i] = | 78 | ht_cap->mcs.rx_mask[i] = |
79 | sband->ht_cap.mcs.rx_mask[i] & | 79 | sband->ht_cap.mcs.rx_mask[i] & |
80 | ht_cap_ie->mcs.rx_mask[i]; | 80 | ht_cap_ie->mcs.rx_mask[i]; |
81 | 81 | ||
82 | /* handle MCS rate 32 too */ | 82 | /* handle MCS rate 32 too */ |
83 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 83 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
84 | ht_cap->mcs.rx_mask[32/8] |= 1; | 84 | ht_cap->mcs.rx_mask[32/8] |= 1; |
85 | } | 85 | } |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * ieee80211_enable_ht should be called only after the operating band | 88 | * ieee80211_enable_ht should be called only after the operating band |
89 | * has been determined as ht configuration depends on the hw's | 89 | * has been determined as ht configuration depends on the hw's |
90 | * HT abilities for a specific band. | 90 | * HT abilities for a specific band. |
91 | */ | 91 | */ |
92 | u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | 92 | u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, |
93 | struct ieee80211_ht_info *hti, | 93 | struct ieee80211_ht_info *hti, |
94 | u16 ap_ht_cap_flags) | 94 | u16 ap_ht_cap_flags) |
95 | { | 95 | { |
96 | struct ieee80211_local *local = sdata->local; | 96 | struct ieee80211_local *local = sdata->local; |
97 | struct ieee80211_supported_band *sband; | 97 | struct ieee80211_supported_band *sband; |
98 | struct ieee80211_bss_ht_conf ht; | 98 | struct ieee80211_bss_ht_conf ht; |
99 | u32 changed = 0; | 99 | u32 changed = 0; |
100 | bool enable_ht = true, ht_changed; | 100 | bool enable_ht = true, ht_changed; |
101 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
101 | 102 | ||
102 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 103 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
103 | 104 | ||
104 | memset(&ht, 0, sizeof(ht)); | 105 | memset(&ht, 0, sizeof(ht)); |
105 | 106 | ||
106 | /* HT is not supported */ | 107 | /* HT is not supported */ |
107 | if (!sband->ht_cap.ht_supported) | 108 | if (!sband->ht_cap.ht_supported) |
108 | enable_ht = false; | 109 | enable_ht = false; |
109 | 110 | ||
110 | /* check that channel matches the right operating channel */ | 111 | /* check that channel matches the right operating channel */ |
111 | if (local->hw.conf.channel->center_freq != | 112 | if (local->hw.conf.channel->center_freq != |
112 | ieee80211_channel_to_frequency(hti->control_chan)) | 113 | ieee80211_channel_to_frequency(hti->control_chan)) |
113 | enable_ht = false; | 114 | enable_ht = false; |
114 | 115 | ||
115 | /* | 116 | if (enable_ht) { |
116 | * XXX: This is totally incorrect when there are multiple virtual | 117 | channel_type = NL80211_CHAN_HT20; |
117 | * interfaces, needs to be fixed later. | 118 | |
118 | */ | 119 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && |
119 | ht_changed = local->hw.conf.ht.enabled != enable_ht; | 120 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && |
121 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | ||
122 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
123 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
124 | channel_type = NL80211_CHAN_HT40PLUS; | ||
125 | break; | ||
126 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
127 | channel_type = NL80211_CHAN_HT40MINUS; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | ht_changed = local->hw.conf.ht.enabled != enable_ht || | ||
134 | channel_type != local->hw.conf.ht.channel_type; | ||
135 | |||
136 | local->oper_channel_type = channel_type; | ||
120 | local->hw.conf.ht.enabled = enable_ht; | 137 | local->hw.conf.ht.enabled = enable_ht; |
138 | |||
121 | if (ht_changed) | 139 | if (ht_changed) |
122 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 140 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); |
123 | 141 | ||
124 | /* disable HT */ | 142 | /* disable HT */ |
125 | if (!enable_ht) | 143 | if (!enable_ht) |
126 | return 0; | 144 | return 0; |
127 | ht.secondary_channel_offset = | 145 | |
128 | hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
129 | ht.width_40_ok = | ||
130 | !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
131 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | ||
132 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY); | ||
133 | ht.operation_mode = le16_to_cpu(hti->operation_mode); | 146 | ht.operation_mode = le16_to_cpu(hti->operation_mode); |
134 | 147 | ||
135 | /* if bss configuration changed store the new one */ | 148 | /* if bss configuration changed store the new one */ |
136 | if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { | 149 | if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { |
137 | changed |= BSS_CHANGED_HT; | 150 | changed |= BSS_CHANGED_HT; |
138 | sdata->vif.bss_conf.ht = ht; | 151 | sdata->vif.bss_conf.ht = ht; |
139 | } | 152 | } |
140 | 153 | ||
141 | return changed; | 154 | return changed; |
142 | } | 155 | } |
143 | 156 | ||
144 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | 157 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, |
145 | const u8 *da, u16 tid, | 158 | const u8 *da, u16 tid, |
146 | u8 dialog_token, u16 start_seq_num, | 159 | u8 dialog_token, u16 start_seq_num, |
147 | u16 agg_size, u16 timeout) | 160 | u16 agg_size, u16 timeout) |
148 | { | 161 | { |
149 | struct ieee80211_local *local = sdata->local; | 162 | struct ieee80211_local *local = sdata->local; |
150 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 163 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
151 | struct sk_buff *skb; | 164 | struct sk_buff *skb; |
152 | struct ieee80211_mgmt *mgmt; | 165 | struct ieee80211_mgmt *mgmt; |
153 | u16 capab; | 166 | u16 capab; |
154 | 167 | ||
155 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | 168 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); |
156 | 169 | ||
157 | if (!skb) { | 170 | if (!skb) { |
158 | printk(KERN_ERR "%s: failed to allocate buffer " | 171 | printk(KERN_ERR "%s: failed to allocate buffer " |
159 | "for addba request frame\n", sdata->dev->name); | 172 | "for addba request frame\n", sdata->dev->name); |
160 | return; | 173 | return; |
161 | } | 174 | } |
162 | skb_reserve(skb, local->hw.extra_tx_headroom); | 175 | skb_reserve(skb, local->hw.extra_tx_headroom); |
163 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 176 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
164 | memset(mgmt, 0, 24); | 177 | memset(mgmt, 0, 24); |
165 | memcpy(mgmt->da, da, ETH_ALEN); | 178 | memcpy(mgmt->da, da, ETH_ALEN); |
166 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 179 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
167 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 180 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
168 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 181 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
169 | else | 182 | else |
170 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 183 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
171 | 184 | ||
172 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 185 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
173 | IEEE80211_STYPE_ACTION); | 186 | IEEE80211_STYPE_ACTION); |
174 | 187 | ||
175 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); | 188 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); |
176 | 189 | ||
177 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | 190 | mgmt->u.action.category = WLAN_CATEGORY_BACK; |
178 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; | 191 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; |
179 | 192 | ||
180 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; | 193 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; |
181 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ | 194 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ |
182 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | 195 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ |
183 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ | 196 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ |
184 | 197 | ||
185 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); | 198 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); |
186 | 199 | ||
187 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); | 200 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); |
188 | mgmt->u.action.u.addba_req.start_seq_num = | 201 | mgmt->u.action.u.addba_req.start_seq_num = |
189 | cpu_to_le16(start_seq_num << 4); | 202 | cpu_to_le16(start_seq_num << 4); |
190 | 203 | ||
191 | ieee80211_tx_skb(sdata, skb, 0); | 204 | ieee80211_tx_skb(sdata, skb, 0); |
192 | } | 205 | } |
193 | 206 | ||
194 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | 207 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, |
195 | u8 dialog_token, u16 status, u16 policy, | 208 | u8 dialog_token, u16 status, u16 policy, |
196 | u16 buf_size, u16 timeout) | 209 | u16 buf_size, u16 timeout) |
197 | { | 210 | { |
198 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 211 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
199 | struct ieee80211_local *local = sdata->local; | 212 | struct ieee80211_local *local = sdata->local; |
200 | struct sk_buff *skb; | 213 | struct sk_buff *skb; |
201 | struct ieee80211_mgmt *mgmt; | 214 | struct ieee80211_mgmt *mgmt; |
202 | u16 capab; | 215 | u16 capab; |
203 | 216 | ||
204 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | 217 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); |
205 | 218 | ||
206 | if (!skb) { | 219 | if (!skb) { |
207 | printk(KERN_DEBUG "%s: failed to allocate buffer " | 220 | printk(KERN_DEBUG "%s: failed to allocate buffer " |
208 | "for addba resp frame\n", sdata->dev->name); | 221 | "for addba resp frame\n", sdata->dev->name); |
209 | return; | 222 | return; |
210 | } | 223 | } |
211 | 224 | ||
212 | skb_reserve(skb, local->hw.extra_tx_headroom); | 225 | skb_reserve(skb, local->hw.extra_tx_headroom); |
213 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 226 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
214 | memset(mgmt, 0, 24); | 227 | memset(mgmt, 0, 24); |
215 | memcpy(mgmt->da, da, ETH_ALEN); | 228 | memcpy(mgmt->da, da, ETH_ALEN); |
216 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 229 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
217 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 230 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
218 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 231 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
219 | else | 232 | else |
220 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 233 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
221 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 234 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
222 | IEEE80211_STYPE_ACTION); | 235 | IEEE80211_STYPE_ACTION); |
223 | 236 | ||
224 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | 237 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); |
225 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | 238 | mgmt->u.action.category = WLAN_CATEGORY_BACK; |
226 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | 239 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; |
227 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | 240 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; |
228 | 241 | ||
229 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | 242 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ |
230 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | 243 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ |
231 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | 244 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ |
232 | 245 | ||
233 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | 246 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); |
234 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | 247 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); |
235 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | 248 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); |
236 | 249 | ||
237 | ieee80211_tx_skb(sdata, skb, 0); | 250 | ieee80211_tx_skb(sdata, skb, 0); |
238 | } | 251 | } |
239 | 252 | ||
240 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 253 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
241 | const u8 *da, u16 tid, | 254 | const u8 *da, u16 tid, |
242 | u16 initiator, u16 reason_code) | 255 | u16 initiator, u16 reason_code) |
243 | { | 256 | { |
244 | struct ieee80211_local *local = sdata->local; | 257 | struct ieee80211_local *local = sdata->local; |
245 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 258 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
246 | struct sk_buff *skb; | 259 | struct sk_buff *skb; |
247 | struct ieee80211_mgmt *mgmt; | 260 | struct ieee80211_mgmt *mgmt; |
248 | u16 params; | 261 | u16 params; |
249 | 262 | ||
250 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | 263 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); |
251 | 264 | ||
252 | if (!skb) { | 265 | if (!skb) { |
253 | printk(KERN_ERR "%s: failed to allocate buffer " | 266 | printk(KERN_ERR "%s: failed to allocate buffer " |
254 | "for delba frame\n", sdata->dev->name); | 267 | "for delba frame\n", sdata->dev->name); |
255 | return; | 268 | return; |
256 | } | 269 | } |
257 | 270 | ||
258 | skb_reserve(skb, local->hw.extra_tx_headroom); | 271 | skb_reserve(skb, local->hw.extra_tx_headroom); |
259 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 272 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
260 | memset(mgmt, 0, 24); | 273 | memset(mgmt, 0, 24); |
261 | memcpy(mgmt->da, da, ETH_ALEN); | 274 | memcpy(mgmt->da, da, ETH_ALEN); |
262 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 275 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
263 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 276 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
264 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 277 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
265 | else | 278 | else |
266 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 279 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
267 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 280 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
268 | IEEE80211_STYPE_ACTION); | 281 | IEEE80211_STYPE_ACTION); |
269 | 282 | ||
270 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); | 283 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); |
271 | 284 | ||
272 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | 285 | mgmt->u.action.category = WLAN_CATEGORY_BACK; |
273 | mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; | 286 | mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; |
274 | params = (u16)(initiator << 11); /* bit 11 initiator */ | 287 | params = (u16)(initiator << 11); /* bit 11 initiator */ |
275 | params |= (u16)(tid << 12); /* bit 15:12 TID number */ | 288 | params |= (u16)(tid << 12); /* bit 15:12 TID number */ |
276 | 289 | ||
277 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | 290 | mgmt->u.action.u.delba.params = cpu_to_le16(params); |
278 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | 291 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); |
279 | 292 | ||
280 | ieee80211_tx_skb(sdata, skb, 0); | 293 | ieee80211_tx_skb(sdata, skb, 0); |
281 | } | 294 | } |
282 | 295 | ||
283 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | 296 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) |
284 | { | 297 | { |
285 | struct ieee80211_local *local = sdata->local; | 298 | struct ieee80211_local *local = sdata->local; |
286 | struct sk_buff *skb; | 299 | struct sk_buff *skb; |
287 | struct ieee80211_bar *bar; | 300 | struct ieee80211_bar *bar; |
288 | u16 bar_control = 0; | 301 | u16 bar_control = 0; |
289 | 302 | ||
290 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | 303 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); |
291 | if (!skb) { | 304 | if (!skb) { |
292 | printk(KERN_ERR "%s: failed to allocate buffer for " | 305 | printk(KERN_ERR "%s: failed to allocate buffer for " |
293 | "bar frame\n", sdata->dev->name); | 306 | "bar frame\n", sdata->dev->name); |
294 | return; | 307 | return; |
295 | } | 308 | } |
296 | skb_reserve(skb, local->hw.extra_tx_headroom); | 309 | skb_reserve(skb, local->hw.extra_tx_headroom); |
297 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); | 310 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); |
298 | memset(bar, 0, sizeof(*bar)); | 311 | memset(bar, 0, sizeof(*bar)); |
299 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | 312 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | |
300 | IEEE80211_STYPE_BACK_REQ); | 313 | IEEE80211_STYPE_BACK_REQ); |
301 | memcpy(bar->ra, ra, ETH_ALEN); | 314 | memcpy(bar->ra, ra, ETH_ALEN); |
302 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | 315 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); |
303 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | 316 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; |
304 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | 317 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; |
305 | bar_control |= (u16)(tid << 12); | 318 | bar_control |= (u16)(tid << 12); |
306 | bar->control = cpu_to_le16(bar_control); | 319 | bar->control = cpu_to_le16(bar_control); |
307 | bar->start_seq_num = cpu_to_le16(ssn); | 320 | bar->start_seq_num = cpu_to_le16(ssn); |
308 | 321 | ||
309 | ieee80211_tx_skb(sdata, skb, 0); | 322 | ieee80211_tx_skb(sdata, skb, 0); |
310 | } | 323 | } |
311 | 324 | ||
312 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | 325 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, |
313 | u16 initiator, u16 reason) | 326 | u16 initiator, u16 reason) |
314 | { | 327 | { |
315 | struct ieee80211_local *local = sdata->local; | 328 | struct ieee80211_local *local = sdata->local; |
316 | struct ieee80211_hw *hw = &local->hw; | 329 | struct ieee80211_hw *hw = &local->hw; |
317 | struct sta_info *sta; | 330 | struct sta_info *sta; |
318 | int ret, i; | 331 | int ret, i; |
319 | 332 | ||
320 | rcu_read_lock(); | 333 | rcu_read_lock(); |
321 | 334 | ||
322 | sta = sta_info_get(local, ra); | 335 | sta = sta_info_get(local, ra); |
323 | if (!sta) { | 336 | if (!sta) { |
324 | rcu_read_unlock(); | 337 | rcu_read_unlock(); |
325 | return; | 338 | return; |
326 | } | 339 | } |
327 | 340 | ||
328 | /* check if TID is in operational state */ | 341 | /* check if TID is in operational state */ |
329 | spin_lock_bh(&sta->lock); | 342 | spin_lock_bh(&sta->lock); |
330 | if (sta->ampdu_mlme.tid_state_rx[tid] | 343 | if (sta->ampdu_mlme.tid_state_rx[tid] |
331 | != HT_AGG_STATE_OPERATIONAL) { | 344 | != HT_AGG_STATE_OPERATIONAL) { |
332 | spin_unlock_bh(&sta->lock); | 345 | spin_unlock_bh(&sta->lock); |
333 | rcu_read_unlock(); | 346 | rcu_read_unlock(); |
334 | return; | 347 | return; |
335 | } | 348 | } |
336 | sta->ampdu_mlme.tid_state_rx[tid] = | 349 | sta->ampdu_mlme.tid_state_rx[tid] = |
337 | HT_AGG_STATE_REQ_STOP_BA_MSK | | 350 | HT_AGG_STATE_REQ_STOP_BA_MSK | |
338 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 351 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
339 | spin_unlock_bh(&sta->lock); | 352 | spin_unlock_bh(&sta->lock); |
340 | 353 | ||
341 | /* stop HW Rx aggregation. ampdu_action existence | 354 | /* stop HW Rx aggregation. ampdu_action existence |
342 | * already verified in session init so we add the BUG_ON */ | 355 | * already verified in session init so we add the BUG_ON */ |
343 | BUG_ON(!local->ops->ampdu_action); | 356 | BUG_ON(!local->ops->ampdu_action); |
344 | 357 | ||
345 | #ifdef CONFIG_MAC80211_HT_DEBUG | 358 | #ifdef CONFIG_MAC80211_HT_DEBUG |
346 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", | 359 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", |
347 | ra, tid); | 360 | ra, tid); |
348 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 361 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
349 | 362 | ||
350 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, | 363 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, |
351 | &sta->sta, tid, NULL); | 364 | &sta->sta, tid, NULL); |
352 | if (ret) | 365 | if (ret) |
353 | printk(KERN_DEBUG "HW problem - can not stop rx " | 366 | printk(KERN_DEBUG "HW problem - can not stop rx " |
354 | "aggregation for tid %d\n", tid); | 367 | "aggregation for tid %d\n", tid); |
355 | 368 | ||
356 | /* shutdown timer has not expired */ | 369 | /* shutdown timer has not expired */ |
357 | if (initiator != WLAN_BACK_TIMER) | 370 | if (initiator != WLAN_BACK_TIMER) |
358 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | 371 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); |
359 | 372 | ||
360 | /* check if this is a self generated aggregation halt */ | 373 | /* check if this is a self generated aggregation halt */ |
361 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | 374 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) |
362 | ieee80211_send_delba(sdata, ra, tid, 0, reason); | 375 | ieee80211_send_delba(sdata, ra, tid, 0, reason); |
363 | 376 | ||
364 | /* free the reordering buffer */ | 377 | /* free the reordering buffer */ |
365 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | 378 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { |
366 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | 379 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { |
367 | /* release the reordered frames */ | 380 | /* release the reordered frames */ |
368 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | 381 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); |
369 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | 382 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; |
370 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | 383 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; |
371 | } | 384 | } |
372 | } | 385 | } |
373 | /* free resources */ | 386 | /* free resources */ |
374 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | 387 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); |
375 | kfree(sta->ampdu_mlme.tid_rx[tid]); | 388 | kfree(sta->ampdu_mlme.tid_rx[tid]); |
376 | sta->ampdu_mlme.tid_rx[tid] = NULL; | 389 | sta->ampdu_mlme.tid_rx[tid] = NULL; |
377 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | 390 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; |
378 | 391 | ||
379 | rcu_read_unlock(); | 392 | rcu_read_unlock(); |
380 | } | 393 | } |
381 | 394 | ||
382 | 395 | ||
383 | /* | 396 | /* |
384 | * After sending add Block Ack request we activated a timer until | 397 | * After sending add Block Ack request we activated a timer until |
385 | * add Block Ack response will arrive from the recipient. | 398 | * add Block Ack response will arrive from the recipient. |
386 | * If this timer expires sta_addba_resp_timer_expired will be executed. | 399 | * If this timer expires sta_addba_resp_timer_expired will be executed. |
387 | */ | 400 | */ |
388 | static void sta_addba_resp_timer_expired(unsigned long data) | 401 | static void sta_addba_resp_timer_expired(unsigned long data) |
389 | { | 402 | { |
390 | /* not an elegant detour, but there is no choice as the timer passes | 403 | /* not an elegant detour, but there is no choice as the timer passes |
391 | * only one argument, and both sta_info and TID are needed, so init | 404 | * only one argument, and both sta_info and TID are needed, so init |
392 | * flow in sta_info_create gives the TID as data, while the timer_to_id | 405 | * flow in sta_info_create gives the TID as data, while the timer_to_id |
393 | * array gives the sta through container_of */ | 406 | * array gives the sta through container_of */ |
394 | u16 tid = *(u8 *)data; | 407 | u16 tid = *(u8 *)data; |
395 | struct sta_info *temp_sta = container_of((void *)data, | 408 | struct sta_info *temp_sta = container_of((void *)data, |
396 | struct sta_info, timer_to_tid[tid]); | 409 | struct sta_info, timer_to_tid[tid]); |
397 | 410 | ||
398 | struct ieee80211_local *local = temp_sta->local; | 411 | struct ieee80211_local *local = temp_sta->local; |
399 | struct ieee80211_hw *hw = &local->hw; | 412 | struct ieee80211_hw *hw = &local->hw; |
400 | struct sta_info *sta; | 413 | struct sta_info *sta; |
401 | u8 *state; | 414 | u8 *state; |
402 | 415 | ||
403 | rcu_read_lock(); | 416 | rcu_read_lock(); |
404 | 417 | ||
405 | sta = sta_info_get(local, temp_sta->sta.addr); | 418 | sta = sta_info_get(local, temp_sta->sta.addr); |
406 | if (!sta) { | 419 | if (!sta) { |
407 | rcu_read_unlock(); | 420 | rcu_read_unlock(); |
408 | return; | 421 | return; |
409 | } | 422 | } |
410 | 423 | ||
411 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 424 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
412 | /* check if the TID waits for addBA response */ | 425 | /* check if the TID waits for addBA response */ |
413 | spin_lock_bh(&sta->lock); | 426 | spin_lock_bh(&sta->lock); |
414 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | 427 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { |
415 | spin_unlock_bh(&sta->lock); | 428 | spin_unlock_bh(&sta->lock); |
416 | *state = HT_AGG_STATE_IDLE; | 429 | *state = HT_AGG_STATE_IDLE; |
417 | #ifdef CONFIG_MAC80211_HT_DEBUG | 430 | #ifdef CONFIG_MAC80211_HT_DEBUG |
418 | printk(KERN_DEBUG "timer expired on tid %d but we are not " | 431 | printk(KERN_DEBUG "timer expired on tid %d but we are not " |
419 | "expecting addBA response there", tid); | 432 | "expecting addBA response there", tid); |
420 | #endif | 433 | #endif |
421 | goto timer_expired_exit; | 434 | goto timer_expired_exit; |
422 | } | 435 | } |
423 | 436 | ||
424 | #ifdef CONFIG_MAC80211_HT_DEBUG | 437 | #ifdef CONFIG_MAC80211_HT_DEBUG |
425 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); | 438 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); |
426 | #endif | 439 | #endif |
427 | 440 | ||
428 | /* go through the state check in stop_BA_session */ | 441 | /* go through the state check in stop_BA_session */ |
429 | *state = HT_AGG_STATE_OPERATIONAL; | 442 | *state = HT_AGG_STATE_OPERATIONAL; |
430 | spin_unlock_bh(&sta->lock); | 443 | spin_unlock_bh(&sta->lock); |
431 | ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid, | 444 | ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid, |
432 | WLAN_BACK_INITIATOR); | 445 | WLAN_BACK_INITIATOR); |
433 | 446 | ||
434 | timer_expired_exit: | 447 | timer_expired_exit: |
435 | rcu_read_unlock(); | 448 | rcu_read_unlock(); |
436 | } | 449 | } |
437 | 450 | ||
438 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) | 451 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) |
439 | { | 452 | { |
440 | struct ieee80211_local *local = sdata->local; | 453 | struct ieee80211_local *local = sdata->local; |
441 | int i; | 454 | int i; |
442 | 455 | ||
443 | for (i = 0; i < STA_TID_NUM; i++) { | 456 | for (i = 0; i < STA_TID_NUM; i++) { |
444 | ieee80211_stop_tx_ba_session(&local->hw, addr, i, | 457 | ieee80211_stop_tx_ba_session(&local->hw, addr, i, |
445 | WLAN_BACK_INITIATOR); | 458 | WLAN_BACK_INITIATOR); |
446 | ieee80211_sta_stop_rx_ba_session(sdata, addr, i, | 459 | ieee80211_sta_stop_rx_ba_session(sdata, addr, i, |
447 | WLAN_BACK_RECIPIENT, | 460 | WLAN_BACK_RECIPIENT, |
448 | WLAN_REASON_QSTA_LEAVE_QBSS); | 461 | WLAN_REASON_QSTA_LEAVE_QBSS); |
449 | } | 462 | } |
450 | } | 463 | } |
451 | 464 | ||
452 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | 465 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) |
453 | { | 466 | { |
454 | struct ieee80211_local *local = hw_to_local(hw); | 467 | struct ieee80211_local *local = hw_to_local(hw); |
455 | struct sta_info *sta; | 468 | struct sta_info *sta; |
456 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
457 | u16 start_seq_num; | 470 | u16 start_seq_num; |
458 | u8 *state; | 471 | u8 *state; |
459 | int ret; | 472 | int ret; |
460 | 473 | ||
461 | if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | 474 | if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) |
462 | return -EINVAL; | 475 | return -EINVAL; |
463 | 476 | ||
464 | #ifdef CONFIG_MAC80211_HT_DEBUG | 477 | #ifdef CONFIG_MAC80211_HT_DEBUG |
465 | printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", | 478 | printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", |
466 | ra, tid); | 479 | ra, tid); |
467 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 480 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
468 | 481 | ||
469 | rcu_read_lock(); | 482 | rcu_read_lock(); |
470 | 483 | ||
471 | sta = sta_info_get(local, ra); | 484 | sta = sta_info_get(local, ra); |
472 | if (!sta) { | 485 | if (!sta) { |
473 | #ifdef CONFIG_MAC80211_HT_DEBUG | 486 | #ifdef CONFIG_MAC80211_HT_DEBUG |
474 | printk(KERN_DEBUG "Could not find the station\n"); | 487 | printk(KERN_DEBUG "Could not find the station\n"); |
475 | #endif | 488 | #endif |
476 | ret = -ENOENT; | 489 | ret = -ENOENT; |
477 | goto exit; | 490 | goto exit; |
478 | } | 491 | } |
479 | 492 | ||
480 | spin_lock_bh(&sta->lock); | 493 | spin_lock_bh(&sta->lock); |
481 | 494 | ||
482 | /* we have tried too many times, receiver does not want A-MPDU */ | 495 | /* we have tried too many times, receiver does not want A-MPDU */ |
483 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | 496 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { |
484 | ret = -EBUSY; | 497 | ret = -EBUSY; |
485 | goto err_unlock_sta; | 498 | goto err_unlock_sta; |
486 | } | 499 | } |
487 | 500 | ||
488 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 501 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
489 | /* check if the TID is not in aggregation flow already */ | 502 | /* check if the TID is not in aggregation flow already */ |
490 | if (*state != HT_AGG_STATE_IDLE) { | 503 | if (*state != HT_AGG_STATE_IDLE) { |
491 | #ifdef CONFIG_MAC80211_HT_DEBUG | 504 | #ifdef CONFIG_MAC80211_HT_DEBUG |
492 | printk(KERN_DEBUG "BA request denied - session is not " | 505 | printk(KERN_DEBUG "BA request denied - session is not " |
493 | "idle on tid %u\n", tid); | 506 | "idle on tid %u\n", tid); |
494 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 507 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
495 | ret = -EAGAIN; | 508 | ret = -EAGAIN; |
496 | goto err_unlock_sta; | 509 | goto err_unlock_sta; |
497 | } | 510 | } |
498 | 511 | ||
499 | /* prepare A-MPDU MLME for Tx aggregation */ | 512 | /* prepare A-MPDU MLME for Tx aggregation */ |
500 | sta->ampdu_mlme.tid_tx[tid] = | 513 | sta->ampdu_mlme.tid_tx[tid] = |
501 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | 514 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); |
502 | if (!sta->ampdu_mlme.tid_tx[tid]) { | 515 | if (!sta->ampdu_mlme.tid_tx[tid]) { |
503 | #ifdef CONFIG_MAC80211_HT_DEBUG | 516 | #ifdef CONFIG_MAC80211_HT_DEBUG |
504 | if (net_ratelimit()) | 517 | if (net_ratelimit()) |
505 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | 518 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", |
506 | tid); | 519 | tid); |
507 | #endif | 520 | #endif |
508 | ret = -ENOMEM; | 521 | ret = -ENOMEM; |
509 | goto err_unlock_sta; | 522 | goto err_unlock_sta; |
510 | } | 523 | } |
511 | /* Tx timer */ | 524 | /* Tx timer */ |
512 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 525 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
513 | sta_addba_resp_timer_expired; | 526 | sta_addba_resp_timer_expired; |
514 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | 527 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = |
515 | (unsigned long)&sta->timer_to_tid[tid]; | 528 | (unsigned long)&sta->timer_to_tid[tid]; |
516 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 529 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
517 | 530 | ||
518 | if (hw->ampdu_queues) { | 531 | if (hw->ampdu_queues) { |
519 | /* create a new queue for this aggregation */ | 532 | /* create a new queue for this aggregation */ |
520 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | 533 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); |
521 | 534 | ||
522 | /* case no queue is available to aggregation | 535 | /* case no queue is available to aggregation |
523 | * don't switch to aggregation */ | 536 | * don't switch to aggregation */ |
524 | if (ret) { | 537 | if (ret) { |
525 | #ifdef CONFIG_MAC80211_HT_DEBUG | 538 | #ifdef CONFIG_MAC80211_HT_DEBUG |
526 | printk(KERN_DEBUG "BA request denied - " | 539 | printk(KERN_DEBUG "BA request denied - " |
527 | "queue unavailable for tid %d\n", tid); | 540 | "queue unavailable for tid %d\n", tid); |
528 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 541 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
529 | goto err_unlock_queue; | 542 | goto err_unlock_queue; |
530 | } | 543 | } |
531 | } | 544 | } |
532 | sdata = sta->sdata; | 545 | sdata = sta->sdata; |
533 | 546 | ||
534 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | 547 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the |
535 | * call back right away, it must see that the flow has begun */ | 548 | * call back right away, it must see that the flow has begun */ |
536 | *state |= HT_ADDBA_REQUESTED_MSK; | 549 | *state |= HT_ADDBA_REQUESTED_MSK; |
537 | 550 | ||
538 | /* This is slightly racy because the queue isn't stopped */ | 551 | /* This is slightly racy because the queue isn't stopped */ |
539 | start_seq_num = sta->tid_seq[tid]; | 552 | start_seq_num = sta->tid_seq[tid]; |
540 | 553 | ||
541 | if (local->ops->ampdu_action) | 554 | if (local->ops->ampdu_action) |
542 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | 555 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, |
543 | &sta->sta, tid, &start_seq_num); | 556 | &sta->sta, tid, &start_seq_num); |
544 | 557 | ||
545 | if (ret) { | 558 | if (ret) { |
546 | /* No need to requeue the packets in the agg queue, since we | 559 | /* No need to requeue the packets in the agg queue, since we |
547 | * held the tx lock: no packet could be enqueued to the newly | 560 | * held the tx lock: no packet could be enqueued to the newly |
548 | * allocated queue */ | 561 | * allocated queue */ |
549 | if (hw->ampdu_queues) | 562 | if (hw->ampdu_queues) |
550 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | 563 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); |
551 | #ifdef CONFIG_MAC80211_HT_DEBUG | 564 | #ifdef CONFIG_MAC80211_HT_DEBUG |
552 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | 565 | printk(KERN_DEBUG "BA request denied - HW unavailable for" |
553 | " tid %d\n", tid); | 566 | " tid %d\n", tid); |
554 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 567 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
555 | *state = HT_AGG_STATE_IDLE; | 568 | *state = HT_AGG_STATE_IDLE; |
556 | goto err_unlock_queue; | 569 | goto err_unlock_queue; |
557 | } | 570 | } |
558 | 571 | ||
559 | /* Will put all the packets in the new SW queue */ | 572 | /* Will put all the packets in the new SW queue */ |
560 | if (hw->ampdu_queues) | 573 | if (hw->ampdu_queues) |
561 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | 574 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); |
562 | spin_unlock_bh(&sta->lock); | 575 | spin_unlock_bh(&sta->lock); |
563 | 576 | ||
564 | /* send an addBA request */ | 577 | /* send an addBA request */ |
565 | sta->ampdu_mlme.dialog_token_allocator++; | 578 | sta->ampdu_mlme.dialog_token_allocator++; |
566 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | 579 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = |
567 | sta->ampdu_mlme.dialog_token_allocator; | 580 | sta->ampdu_mlme.dialog_token_allocator; |
568 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | 581 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; |
569 | 582 | ||
570 | 583 | ||
571 | ieee80211_send_addba_request(sta->sdata, ra, tid, | 584 | ieee80211_send_addba_request(sta->sdata, ra, tid, |
572 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | 585 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, |
573 | sta->ampdu_mlme.tid_tx[tid]->ssn, | 586 | sta->ampdu_mlme.tid_tx[tid]->ssn, |
574 | 0x40, 5000); | 587 | 0x40, 5000); |
575 | /* activate the timer for the recipient's addBA response */ | 588 | /* activate the timer for the recipient's addBA response */ |
576 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | 589 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = |
577 | jiffies + ADDBA_RESP_INTERVAL; | 590 | jiffies + ADDBA_RESP_INTERVAL; |
578 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 591 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
579 | #ifdef CONFIG_MAC80211_HT_DEBUG | 592 | #ifdef CONFIG_MAC80211_HT_DEBUG |
580 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | 593 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); |
581 | #endif | 594 | #endif |
582 | goto exit; | 595 | goto exit; |
583 | 596 | ||
584 | err_unlock_queue: | 597 | err_unlock_queue: |
585 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 598 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
586 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 599 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
587 | ret = -EBUSY; | 600 | ret = -EBUSY; |
588 | err_unlock_sta: | 601 | err_unlock_sta: |
589 | spin_unlock_bh(&sta->lock); | 602 | spin_unlock_bh(&sta->lock); |
590 | exit: | 603 | exit: |
591 | rcu_read_unlock(); | 604 | rcu_read_unlock(); |
592 | return ret; | 605 | return ret; |
593 | } | 606 | } |
594 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 607 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
595 | 608 | ||
596 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | 609 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, |
597 | u8 *ra, u16 tid, | 610 | u8 *ra, u16 tid, |
598 | enum ieee80211_back_parties initiator) | 611 | enum ieee80211_back_parties initiator) |
599 | { | 612 | { |
600 | struct ieee80211_local *local = hw_to_local(hw); | 613 | struct ieee80211_local *local = hw_to_local(hw); |
601 | struct sta_info *sta; | 614 | struct sta_info *sta; |
602 | u8 *state; | 615 | u8 *state; |
603 | int ret = 0; | 616 | int ret = 0; |
604 | 617 | ||
605 | if (tid >= STA_TID_NUM) | 618 | if (tid >= STA_TID_NUM) |
606 | return -EINVAL; | 619 | return -EINVAL; |
607 | 620 | ||
608 | rcu_read_lock(); | 621 | rcu_read_lock(); |
609 | sta = sta_info_get(local, ra); | 622 | sta = sta_info_get(local, ra); |
610 | if (!sta) { | 623 | if (!sta) { |
611 | rcu_read_unlock(); | 624 | rcu_read_unlock(); |
612 | return -ENOENT; | 625 | return -ENOENT; |
613 | } | 626 | } |
614 | 627 | ||
615 | /* check if the TID is in aggregation */ | 628 | /* check if the TID is in aggregation */ |
616 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 629 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
617 | spin_lock_bh(&sta->lock); | 630 | spin_lock_bh(&sta->lock); |
618 | 631 | ||
619 | if (*state != HT_AGG_STATE_OPERATIONAL) { | 632 | if (*state != HT_AGG_STATE_OPERATIONAL) { |
620 | ret = -ENOENT; | 633 | ret = -ENOENT; |
621 | goto stop_BA_exit; | 634 | goto stop_BA_exit; |
622 | } | 635 | } |
623 | 636 | ||
624 | #ifdef CONFIG_MAC80211_HT_DEBUG | 637 | #ifdef CONFIG_MAC80211_HT_DEBUG |
625 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", | 638 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", |
626 | ra, tid); | 639 | ra, tid); |
627 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 640 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
628 | 641 | ||
629 | if (hw->ampdu_queues) | 642 | if (hw->ampdu_queues) |
630 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); | 643 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); |
631 | 644 | ||
632 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | 645 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | |
633 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 646 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
634 | 647 | ||
635 | if (local->ops->ampdu_action) | 648 | if (local->ops->ampdu_action) |
636 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, | 649 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, |
637 | &sta->sta, tid, NULL); | 650 | &sta->sta, tid, NULL); |
638 | 651 | ||
639 | /* case HW denied going back to legacy */ | 652 | /* case HW denied going back to legacy */ |
640 | if (ret) { | 653 | if (ret) { |
641 | WARN_ON(ret != -EBUSY); | 654 | WARN_ON(ret != -EBUSY); |
642 | *state = HT_AGG_STATE_OPERATIONAL; | 655 | *state = HT_AGG_STATE_OPERATIONAL; |
643 | if (hw->ampdu_queues) | 656 | if (hw->ampdu_queues) |
644 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 657 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
645 | goto stop_BA_exit; | 658 | goto stop_BA_exit; |
646 | } | 659 | } |
647 | 660 | ||
648 | stop_BA_exit: | 661 | stop_BA_exit: |
649 | spin_unlock_bh(&sta->lock); | 662 | spin_unlock_bh(&sta->lock); |
650 | rcu_read_unlock(); | 663 | rcu_read_unlock(); |
651 | return ret; | 664 | return ret; |
652 | } | 665 | } |
653 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | 666 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); |
654 | 667 | ||
655 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | 668 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) |
656 | { | 669 | { |
657 | struct ieee80211_local *local = hw_to_local(hw); | 670 | struct ieee80211_local *local = hw_to_local(hw); |
658 | struct sta_info *sta; | 671 | struct sta_info *sta; |
659 | u8 *state; | 672 | u8 *state; |
660 | 673 | ||
661 | if (tid >= STA_TID_NUM) { | 674 | if (tid >= STA_TID_NUM) { |
662 | #ifdef CONFIG_MAC80211_HT_DEBUG | 675 | #ifdef CONFIG_MAC80211_HT_DEBUG |
663 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | 676 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", |
664 | tid, STA_TID_NUM); | 677 | tid, STA_TID_NUM); |
665 | #endif | 678 | #endif |
666 | return; | 679 | return; |
667 | } | 680 | } |
668 | 681 | ||
669 | rcu_read_lock(); | 682 | rcu_read_lock(); |
670 | sta = sta_info_get(local, ra); | 683 | sta = sta_info_get(local, ra); |
671 | if (!sta) { | 684 | if (!sta) { |
672 | rcu_read_unlock(); | 685 | rcu_read_unlock(); |
673 | #ifdef CONFIG_MAC80211_HT_DEBUG | 686 | #ifdef CONFIG_MAC80211_HT_DEBUG |
674 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | 687 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); |
675 | #endif | 688 | #endif |
676 | return; | 689 | return; |
677 | } | 690 | } |
678 | 691 | ||
679 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 692 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
680 | spin_lock_bh(&sta->lock); | 693 | spin_lock_bh(&sta->lock); |
681 | 694 | ||
682 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | 695 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { |
683 | #ifdef CONFIG_MAC80211_HT_DEBUG | 696 | #ifdef CONFIG_MAC80211_HT_DEBUG |
684 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | 697 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", |
685 | *state); | 698 | *state); |
686 | #endif | 699 | #endif |
687 | spin_unlock_bh(&sta->lock); | 700 | spin_unlock_bh(&sta->lock); |
688 | rcu_read_unlock(); | 701 | rcu_read_unlock(); |
689 | return; | 702 | return; |
690 | } | 703 | } |
691 | 704 | ||
692 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | 705 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); |
693 | 706 | ||
694 | *state |= HT_ADDBA_DRV_READY_MSK; | 707 | *state |= HT_ADDBA_DRV_READY_MSK; |
695 | 708 | ||
696 | if (*state == HT_AGG_STATE_OPERATIONAL) { | 709 | if (*state == HT_AGG_STATE_OPERATIONAL) { |
697 | #ifdef CONFIG_MAC80211_HT_DEBUG | 710 | #ifdef CONFIG_MAC80211_HT_DEBUG |
698 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | 711 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); |
699 | #endif | 712 | #endif |
700 | if (hw->ampdu_queues) | 713 | if (hw->ampdu_queues) |
701 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 714 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
702 | } | 715 | } |
703 | spin_unlock_bh(&sta->lock); | 716 | spin_unlock_bh(&sta->lock); |
704 | rcu_read_unlock(); | 717 | rcu_read_unlock(); |
705 | } | 718 | } |
706 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | 719 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); |
707 | 720 | ||
708 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | 721 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) |
709 | { | 722 | { |
710 | struct ieee80211_local *local = hw_to_local(hw); | 723 | struct ieee80211_local *local = hw_to_local(hw); |
711 | struct sta_info *sta; | 724 | struct sta_info *sta; |
712 | u8 *state; | 725 | u8 *state; |
713 | int agg_queue; | 726 | int agg_queue; |
714 | 727 | ||
715 | if (tid >= STA_TID_NUM) { | 728 | if (tid >= STA_TID_NUM) { |
716 | #ifdef CONFIG_MAC80211_HT_DEBUG | 729 | #ifdef CONFIG_MAC80211_HT_DEBUG |
717 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | 730 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", |
718 | tid, STA_TID_NUM); | 731 | tid, STA_TID_NUM); |
719 | #endif | 732 | #endif |
720 | return; | 733 | return; |
721 | } | 734 | } |
722 | 735 | ||
723 | #ifdef CONFIG_MAC80211_HT_DEBUG | 736 | #ifdef CONFIG_MAC80211_HT_DEBUG |
724 | printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", | 737 | printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", |
725 | ra, tid); | 738 | ra, tid); |
726 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 739 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
727 | 740 | ||
728 | rcu_read_lock(); | 741 | rcu_read_lock(); |
729 | sta = sta_info_get(local, ra); | 742 | sta = sta_info_get(local, ra); |
730 | if (!sta) { | 743 | if (!sta) { |
731 | #ifdef CONFIG_MAC80211_HT_DEBUG | 744 | #ifdef CONFIG_MAC80211_HT_DEBUG |
732 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | 745 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); |
733 | #endif | 746 | #endif |
734 | rcu_read_unlock(); | 747 | rcu_read_unlock(); |
735 | return; | 748 | return; |
736 | } | 749 | } |
737 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 750 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
738 | 751 | ||
739 | /* NOTE: no need to use sta->lock in this state check, as | 752 | /* NOTE: no need to use sta->lock in this state check, as |
740 | * ieee80211_stop_tx_ba_session will let only one stop call to | 753 | * ieee80211_stop_tx_ba_session will let only one stop call to |
741 | * pass through per sta/tid | 754 | * pass through per sta/tid |
742 | */ | 755 | */ |
743 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | 756 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { |
744 | #ifdef CONFIG_MAC80211_HT_DEBUG | 757 | #ifdef CONFIG_MAC80211_HT_DEBUG |
745 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | 758 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); |
746 | #endif | 759 | #endif |
747 | rcu_read_unlock(); | 760 | rcu_read_unlock(); |
748 | return; | 761 | return; |
749 | } | 762 | } |
750 | 763 | ||
751 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | 764 | if (*state & HT_AGG_STATE_INITIATOR_MSK) |
752 | ieee80211_send_delba(sta->sdata, ra, tid, | 765 | ieee80211_send_delba(sta->sdata, ra, tid, |
753 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 766 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
754 | 767 | ||
755 | if (hw->ampdu_queues) { | 768 | if (hw->ampdu_queues) { |
756 | agg_queue = sta->tid_to_tx_q[tid]; | 769 | agg_queue = sta->tid_to_tx_q[tid]; |
757 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | 770 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); |
758 | 771 | ||
759 | /* We just requeued the all the frames that were in the | 772 | /* We just requeued the all the frames that were in the |
760 | * removed queue, and since we might miss a softirq we do | 773 | * removed queue, and since we might miss a softirq we do |
761 | * netif_schedule_queue. ieee80211_wake_queue is not used | 774 | * netif_schedule_queue. ieee80211_wake_queue is not used |
762 | * here as this queue is not necessarily stopped | 775 | * here as this queue is not necessarily stopped |
763 | */ | 776 | */ |
764 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, | 777 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, |
765 | agg_queue)); | 778 | agg_queue)); |
766 | } | 779 | } |
767 | spin_lock_bh(&sta->lock); | 780 | spin_lock_bh(&sta->lock); |
768 | *state = HT_AGG_STATE_IDLE; | 781 | *state = HT_AGG_STATE_IDLE; |
769 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 782 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
770 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 783 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
771 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 784 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
772 | spin_unlock_bh(&sta->lock); | 785 | spin_unlock_bh(&sta->lock); |
773 | 786 | ||
774 | rcu_read_unlock(); | 787 | rcu_read_unlock(); |
775 | } | 788 | } |
776 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | 789 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); |
777 | 790 | ||
778 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | 791 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, |
779 | const u8 *ra, u16 tid) | 792 | const u8 *ra, u16 tid) |
780 | { | 793 | { |
781 | struct ieee80211_local *local = hw_to_local(hw); | 794 | struct ieee80211_local *local = hw_to_local(hw); |
782 | struct ieee80211_ra_tid *ra_tid; | 795 | struct ieee80211_ra_tid *ra_tid; |
783 | struct sk_buff *skb = dev_alloc_skb(0); | 796 | struct sk_buff *skb = dev_alloc_skb(0); |
784 | 797 | ||
785 | if (unlikely(!skb)) { | 798 | if (unlikely(!skb)) { |
786 | #ifdef CONFIG_MAC80211_HT_DEBUG | 799 | #ifdef CONFIG_MAC80211_HT_DEBUG |
787 | if (net_ratelimit()) | 800 | if (net_ratelimit()) |
788 | printk(KERN_WARNING "%s: Not enough memory, " | 801 | printk(KERN_WARNING "%s: Not enough memory, " |
789 | "dropping start BA session", skb->dev->name); | 802 | "dropping start BA session", skb->dev->name); |
790 | #endif | 803 | #endif |
791 | return; | 804 | return; |
792 | } | 805 | } |
793 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | 806 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; |
794 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | 807 | memcpy(&ra_tid->ra, ra, ETH_ALEN); |
795 | ra_tid->tid = tid; | 808 | ra_tid->tid = tid; |
796 | 809 | ||
797 | skb->pkt_type = IEEE80211_ADDBA_MSG; | 810 | skb->pkt_type = IEEE80211_ADDBA_MSG; |
798 | skb_queue_tail(&local->skb_queue, skb); | 811 | skb_queue_tail(&local->skb_queue, skb); |
799 | tasklet_schedule(&local->tasklet); | 812 | tasklet_schedule(&local->tasklet); |
800 | } | 813 | } |
801 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | 814 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); |
802 | 815 | ||
803 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | 816 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, |
804 | const u8 *ra, u16 tid) | 817 | const u8 *ra, u16 tid) |
805 | { | 818 | { |
806 | struct ieee80211_local *local = hw_to_local(hw); | 819 | struct ieee80211_local *local = hw_to_local(hw); |
807 | struct ieee80211_ra_tid *ra_tid; | 820 | struct ieee80211_ra_tid *ra_tid; |
808 | struct sk_buff *skb = dev_alloc_skb(0); | 821 | struct sk_buff *skb = dev_alloc_skb(0); |
809 | 822 | ||
810 | if (unlikely(!skb)) { | 823 | if (unlikely(!skb)) { |
811 | #ifdef CONFIG_MAC80211_HT_DEBUG | 824 | #ifdef CONFIG_MAC80211_HT_DEBUG |
812 | if (net_ratelimit()) | 825 | if (net_ratelimit()) |
813 | printk(KERN_WARNING "%s: Not enough memory, " | 826 | printk(KERN_WARNING "%s: Not enough memory, " |
814 | "dropping stop BA session", skb->dev->name); | 827 | "dropping stop BA session", skb->dev->name); |
815 | #endif | 828 | #endif |
816 | return; | 829 | return; |
817 | } | 830 | } |
818 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | 831 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; |
819 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | 832 | memcpy(&ra_tid->ra, ra, ETH_ALEN); |
820 | ra_tid->tid = tid; | 833 | ra_tid->tid = tid; |
821 | 834 | ||
822 | skb->pkt_type = IEEE80211_DELBA_MSG; | 835 | skb->pkt_type = IEEE80211_DELBA_MSG; |
823 | skb_queue_tail(&local->skb_queue, skb); | 836 | skb_queue_tail(&local->skb_queue, skb); |
824 | tasklet_schedule(&local->tasklet); | 837 | tasklet_schedule(&local->tasklet); |
825 | } | 838 | } |
826 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | 839 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); |
827 | 840 | ||
828 | /* | 841 | /* |
829 | * After accepting the AddBA Request we activated a timer, | 842 | * After accepting the AddBA Request we activated a timer, |
830 | * resetting it after each frame that arrives from the originator. | 843 | * resetting it after each frame that arrives from the originator. |
831 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | 844 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. |
832 | */ | 845 | */ |
833 | static void sta_rx_agg_session_timer_expired(unsigned long data) | 846 | static void sta_rx_agg_session_timer_expired(unsigned long data) |
834 | { | 847 | { |
835 | /* not an elegant detour, but there is no choice as the timer passes | 848 | /* not an elegant detour, but there is no choice as the timer passes |
836 | * only one argument, and various sta_info are needed here, so init | 849 | * only one argument, and various sta_info are needed here, so init |
837 | * flow in sta_info_create gives the TID as data, while the timer_to_id | 850 | * flow in sta_info_create gives the TID as data, while the timer_to_id |
838 | * array gives the sta through container_of */ | 851 | * array gives the sta through container_of */ |
839 | u8 *ptid = (u8 *)data; | 852 | u8 *ptid = (u8 *)data; |
840 | u8 *timer_to_id = ptid - *ptid; | 853 | u8 *timer_to_id = ptid - *ptid; |
841 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | 854 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, |
842 | timer_to_tid[0]); | 855 | timer_to_tid[0]); |
843 | 856 | ||
844 | #ifdef CONFIG_MAC80211_HT_DEBUG | 857 | #ifdef CONFIG_MAC80211_HT_DEBUG |
845 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | 858 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); |
846 | #endif | 859 | #endif |
847 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | 860 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, |
848 | (u16)*ptid, WLAN_BACK_TIMER, | 861 | (u16)*ptid, WLAN_BACK_TIMER, |
849 | WLAN_REASON_QSTA_TIMEOUT); | 862 | WLAN_REASON_QSTA_TIMEOUT); |
850 | } | 863 | } |
851 | 864 | ||
852 | void ieee80211_process_addba_request(struct ieee80211_local *local, | 865 | void ieee80211_process_addba_request(struct ieee80211_local *local, |
853 | struct sta_info *sta, | 866 | struct sta_info *sta, |
854 | struct ieee80211_mgmt *mgmt, | 867 | struct ieee80211_mgmt *mgmt, |
855 | size_t len) | 868 | size_t len) |
856 | { | 869 | { |
857 | struct ieee80211_hw *hw = &local->hw; | 870 | struct ieee80211_hw *hw = &local->hw; |
858 | struct ieee80211_conf *conf = &hw->conf; | 871 | struct ieee80211_conf *conf = &hw->conf; |
859 | struct tid_ampdu_rx *tid_agg_rx; | 872 | struct tid_ampdu_rx *tid_agg_rx; |
860 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | 873 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; |
861 | u8 dialog_token; | 874 | u8 dialog_token; |
862 | int ret = -EOPNOTSUPP; | 875 | int ret = -EOPNOTSUPP; |
863 | 876 | ||
864 | /* extract session parameters from addba request frame */ | 877 | /* extract session parameters from addba request frame */ |
865 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | 878 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; |
866 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | 879 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); |
867 | start_seq_num = | 880 | start_seq_num = |
868 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | 881 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; |
869 | 882 | ||
870 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | 883 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); |
871 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | 884 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; |
872 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 885 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
873 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | 886 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; |
874 | 887 | ||
875 | status = WLAN_STATUS_REQUEST_DECLINED; | 888 | status = WLAN_STATUS_REQUEST_DECLINED; |
876 | 889 | ||
877 | /* sanity check for incoming parameters: | 890 | /* sanity check for incoming parameters: |
878 | * check if configuration can support the BA policy | 891 | * check if configuration can support the BA policy |
879 | * and if buffer size does not exceeds max value */ | 892 | * and if buffer size does not exceeds max value */ |
880 | /* XXX: check own ht delayed BA capability?? */ | 893 | /* XXX: check own ht delayed BA capability?? */ |
881 | if (((ba_policy != 1) | 894 | if (((ba_policy != 1) |
882 | && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) | 895 | && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) |
883 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | 896 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { |
884 | status = WLAN_STATUS_INVALID_QOS_PARAM; | 897 | status = WLAN_STATUS_INVALID_QOS_PARAM; |
885 | #ifdef CONFIG_MAC80211_HT_DEBUG | 898 | #ifdef CONFIG_MAC80211_HT_DEBUG |
886 | if (net_ratelimit()) | 899 | if (net_ratelimit()) |
887 | printk(KERN_DEBUG "AddBA Req with bad params from " | 900 | printk(KERN_DEBUG "AddBA Req with bad params from " |
888 | "%pM on tid %u. policy %d, buffer size %d\n", | 901 | "%pM on tid %u. policy %d, buffer size %d\n", |
889 | mgmt->sa, tid, ba_policy, | 902 | mgmt->sa, tid, ba_policy, |
890 | buf_size); | 903 | buf_size); |
891 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 904 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
892 | goto end_no_lock; | 905 | goto end_no_lock; |
893 | } | 906 | } |
894 | /* determine default buffer size */ | 907 | /* determine default buffer size */ |
895 | if (buf_size == 0) { | 908 | if (buf_size == 0) { |
896 | struct ieee80211_supported_band *sband; | 909 | struct ieee80211_supported_band *sband; |
897 | 910 | ||
898 | sband = local->hw.wiphy->bands[conf->channel->band]; | 911 | sband = local->hw.wiphy->bands[conf->channel->band]; |
899 | buf_size = IEEE80211_MIN_AMPDU_BUF; | 912 | buf_size = IEEE80211_MIN_AMPDU_BUF; |
900 | buf_size = buf_size << sband->ht_cap.ampdu_factor; | 913 | buf_size = buf_size << sband->ht_cap.ampdu_factor; |
901 | } | 914 | } |
902 | 915 | ||
903 | 916 | ||
904 | /* examine state machine */ | 917 | /* examine state machine */ |
905 | spin_lock_bh(&sta->lock); | 918 | spin_lock_bh(&sta->lock); |
906 | 919 | ||
907 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | 920 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { |
908 | #ifdef CONFIG_MAC80211_HT_DEBUG | 921 | #ifdef CONFIG_MAC80211_HT_DEBUG |
909 | if (net_ratelimit()) | 922 | if (net_ratelimit()) |
910 | printk(KERN_DEBUG "unexpected AddBA Req from " | 923 | printk(KERN_DEBUG "unexpected AddBA Req from " |
911 | "%pM on tid %u\n", | 924 | "%pM on tid %u\n", |
912 | mgmt->sa, tid); | 925 | mgmt->sa, tid); |
913 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 926 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
914 | goto end; | 927 | goto end; |
915 | } | 928 | } |
916 | 929 | ||
917 | /* prepare A-MPDU MLME for Rx aggregation */ | 930 | /* prepare A-MPDU MLME for Rx aggregation */ |
918 | sta->ampdu_mlme.tid_rx[tid] = | 931 | sta->ampdu_mlme.tid_rx[tid] = |
919 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | 932 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); |
920 | if (!sta->ampdu_mlme.tid_rx[tid]) { | 933 | if (!sta->ampdu_mlme.tid_rx[tid]) { |
921 | #ifdef CONFIG_MAC80211_HT_DEBUG | 934 | #ifdef CONFIG_MAC80211_HT_DEBUG |
922 | if (net_ratelimit()) | 935 | if (net_ratelimit()) |
923 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", | 936 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", |
924 | tid); | 937 | tid); |
925 | #endif | 938 | #endif |
926 | goto end; | 939 | goto end; |
927 | } | 940 | } |
928 | /* rx timer */ | 941 | /* rx timer */ |
929 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = | 942 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = |
930 | sta_rx_agg_session_timer_expired; | 943 | sta_rx_agg_session_timer_expired; |
931 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = | 944 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = |
932 | (unsigned long)&sta->timer_to_tid[tid]; | 945 | (unsigned long)&sta->timer_to_tid[tid]; |
933 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | 946 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); |
934 | 947 | ||
935 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | 948 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; |
936 | 949 | ||
937 | /* prepare reordering buffer */ | 950 | /* prepare reordering buffer */ |
938 | tid_agg_rx->reorder_buf = | 951 | tid_agg_rx->reorder_buf = |
939 | kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); | 952 | kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); |
940 | if (!tid_agg_rx->reorder_buf) { | 953 | if (!tid_agg_rx->reorder_buf) { |
941 | #ifdef CONFIG_MAC80211_HT_DEBUG | 954 | #ifdef CONFIG_MAC80211_HT_DEBUG |
942 | if (net_ratelimit()) | 955 | if (net_ratelimit()) |
943 | printk(KERN_ERR "can not allocate reordering buffer " | 956 | printk(KERN_ERR "can not allocate reordering buffer " |
944 | "to tid %d\n", tid); | 957 | "to tid %d\n", tid); |
945 | #endif | 958 | #endif |
946 | kfree(sta->ampdu_mlme.tid_rx[tid]); | 959 | kfree(sta->ampdu_mlme.tid_rx[tid]); |
947 | goto end; | 960 | goto end; |
948 | } | 961 | } |
949 | memset(tid_agg_rx->reorder_buf, 0, | 962 | memset(tid_agg_rx->reorder_buf, 0, |
950 | buf_size * sizeof(struct sk_buff *)); | 963 | buf_size * sizeof(struct sk_buff *)); |
951 | 964 | ||
952 | if (local->ops->ampdu_action) | 965 | if (local->ops->ampdu_action) |
953 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | 966 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, |
954 | &sta->sta, tid, &start_seq_num); | 967 | &sta->sta, tid, &start_seq_num); |
955 | #ifdef CONFIG_MAC80211_HT_DEBUG | 968 | #ifdef CONFIG_MAC80211_HT_DEBUG |
956 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | 969 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); |
957 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 970 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
958 | 971 | ||
959 | if (ret) { | 972 | if (ret) { |
960 | kfree(tid_agg_rx->reorder_buf); | 973 | kfree(tid_agg_rx->reorder_buf); |
961 | kfree(tid_agg_rx); | 974 | kfree(tid_agg_rx); |
962 | sta->ampdu_mlme.tid_rx[tid] = NULL; | 975 | sta->ampdu_mlme.tid_rx[tid] = NULL; |
963 | goto end; | 976 | goto end; |
964 | } | 977 | } |
965 | 978 | ||
966 | /* change state and send addba resp */ | 979 | /* change state and send addba resp */ |
967 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | 980 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; |
968 | tid_agg_rx->dialog_token = dialog_token; | 981 | tid_agg_rx->dialog_token = dialog_token; |
969 | tid_agg_rx->ssn = start_seq_num; | 982 | tid_agg_rx->ssn = start_seq_num; |
970 | tid_agg_rx->head_seq_num = start_seq_num; | 983 | tid_agg_rx->head_seq_num = start_seq_num; |
971 | tid_agg_rx->buf_size = buf_size; | 984 | tid_agg_rx->buf_size = buf_size; |
972 | tid_agg_rx->timeout = timeout; | 985 | tid_agg_rx->timeout = timeout; |
973 | tid_agg_rx->stored_mpdu_num = 0; | 986 | tid_agg_rx->stored_mpdu_num = 0; |
974 | status = WLAN_STATUS_SUCCESS; | 987 | status = WLAN_STATUS_SUCCESS; |
975 | end: | 988 | end: |
976 | spin_unlock_bh(&sta->lock); | 989 | spin_unlock_bh(&sta->lock); |
977 | 990 | ||
978 | end_no_lock: | 991 | end_no_lock: |
979 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, | 992 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, |
980 | dialog_token, status, 1, buf_size, timeout); | 993 | dialog_token, status, 1, buf_size, timeout); |
981 | } | 994 | } |
982 | 995 | ||
983 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | 996 | void ieee80211_process_addba_resp(struct ieee80211_local *local, |
984 | struct sta_info *sta, | 997 | struct sta_info *sta, |
985 | struct ieee80211_mgmt *mgmt, | 998 | struct ieee80211_mgmt *mgmt, |
986 | size_t len) | 999 | size_t len) |
987 | { | 1000 | { |
988 | struct ieee80211_hw *hw = &local->hw; | 1001 | struct ieee80211_hw *hw = &local->hw; |
989 | u16 capab; | 1002 | u16 capab; |
990 | u16 tid, start_seq_num; | 1003 | u16 tid, start_seq_num; |
991 | u8 *state; | 1004 | u8 *state; |
992 | 1005 | ||
993 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 1006 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
994 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 1007 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
995 | 1008 | ||
996 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 1009 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
997 | 1010 | ||
998 | spin_lock_bh(&sta->lock); | 1011 | spin_lock_bh(&sta->lock); |
999 | 1012 | ||
1000 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | 1013 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { |
1001 | spin_unlock_bh(&sta->lock); | 1014 | spin_unlock_bh(&sta->lock); |
1002 | return; | 1015 | return; |
1003 | } | 1016 | } |
1004 | 1017 | ||
1005 | if (mgmt->u.action.u.addba_resp.dialog_token != | 1018 | if (mgmt->u.action.u.addba_resp.dialog_token != |
1006 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { | 1019 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { |
1007 | spin_unlock_bh(&sta->lock); | 1020 | spin_unlock_bh(&sta->lock); |
1008 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1021 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1009 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | 1022 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); |
1010 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1023 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1011 | return; | 1024 | return; |
1012 | } | 1025 | } |
1013 | 1026 | ||
1014 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 1027 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
1015 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1028 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1016 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); | 1029 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); |
1017 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1030 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1018 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | 1031 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) |
1019 | == WLAN_STATUS_SUCCESS) { | 1032 | == WLAN_STATUS_SUCCESS) { |
1020 | *state |= HT_ADDBA_RECEIVED_MSK; | 1033 | *state |= HT_ADDBA_RECEIVED_MSK; |
1021 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 1034 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
1022 | 1035 | ||
1023 | if (*state == HT_AGG_STATE_OPERATIONAL && | 1036 | if (*state == HT_AGG_STATE_OPERATIONAL && |
1024 | local->hw.ampdu_queues) | 1037 | local->hw.ampdu_queues) |
1025 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 1038 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
1026 | 1039 | ||
1027 | if (local->ops->ampdu_action) { | 1040 | if (local->ops->ampdu_action) { |
1028 | (void)local->ops->ampdu_action(hw, | 1041 | (void)local->ops->ampdu_action(hw, |
1029 | IEEE80211_AMPDU_TX_RESUME, | 1042 | IEEE80211_AMPDU_TX_RESUME, |
1030 | &sta->sta, tid, &start_seq_num); | 1043 | &sta->sta, tid, &start_seq_num); |
1031 | } | 1044 | } |
1032 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1045 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1033 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); | 1046 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); |
1034 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1047 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1035 | spin_unlock_bh(&sta->lock); | 1048 | spin_unlock_bh(&sta->lock); |
1036 | } else { | 1049 | } else { |
1037 | sta->ampdu_mlme.addba_req_num[tid]++; | 1050 | sta->ampdu_mlme.addba_req_num[tid]++; |
1038 | /* this will allow the state check in stop_BA_session */ | 1051 | /* this will allow the state check in stop_BA_session */ |
1039 | *state = HT_AGG_STATE_OPERATIONAL; | 1052 | *state = HT_AGG_STATE_OPERATIONAL; |
1040 | spin_unlock_bh(&sta->lock); | 1053 | spin_unlock_bh(&sta->lock); |
1041 | ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid, | 1054 | ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid, |
1042 | WLAN_BACK_INITIATOR); | 1055 | WLAN_BACK_INITIATOR); |
1043 | } | 1056 | } |
1044 | } | 1057 | } |
1045 | 1058 | ||
1046 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 1059 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
1047 | struct sta_info *sta, | 1060 | struct sta_info *sta, |
1048 | struct ieee80211_mgmt *mgmt, size_t len) | 1061 | struct ieee80211_mgmt *mgmt, size_t len) |
1049 | { | 1062 | { |
1050 | struct ieee80211_local *local = sdata->local; | 1063 | struct ieee80211_local *local = sdata->local; |
1051 | u16 tid, params; | 1064 | u16 tid, params; |
1052 | u16 initiator; | 1065 | u16 initiator; |
1053 | 1066 | ||
1054 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | 1067 | params = le16_to_cpu(mgmt->u.action.u.delba.params); |
1055 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | 1068 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; |
1056 | initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; | 1069 | initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; |
1057 | 1070 | ||
1058 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1071 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1059 | if (net_ratelimit()) | 1072 | if (net_ratelimit()) |
1060 | printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n", | 1073 | printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n", |
1061 | mgmt->sa, initiator ? "initiator" : "recipient", tid, | 1074 | mgmt->sa, initiator ? "initiator" : "recipient", tid, |
1062 | mgmt->u.action.u.delba.reason_code); | 1075 | mgmt->u.action.u.delba.reason_code); |
1063 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1076 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1064 | 1077 | ||
1065 | if (initiator == WLAN_BACK_INITIATOR) | 1078 | if (initiator == WLAN_BACK_INITIATOR) |
1066 | ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid, | 1079 | ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid, |
1067 | WLAN_BACK_INITIATOR, 0); | 1080 | WLAN_BACK_INITIATOR, 0); |
1068 | else { /* WLAN_BACK_RECIPIENT */ | 1081 | else { /* WLAN_BACK_RECIPIENT */ |
1069 | spin_lock_bh(&sta->lock); | 1082 | spin_lock_bh(&sta->lock); |
1070 | sta->ampdu_mlme.tid_state_tx[tid] = | 1083 | sta->ampdu_mlme.tid_state_tx[tid] = |
1071 | HT_AGG_STATE_OPERATIONAL; | 1084 | HT_AGG_STATE_OPERATIONAL; |
1072 | spin_unlock_bh(&sta->lock); | 1085 | spin_unlock_bh(&sta->lock); |
net/mac80211/ieee80211_i.h
1 | /* | 1 | /* |
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
3 | * Copyright 2005, Devicescape Software, Inc. | 3 | * Copyright 2005, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef IEEE80211_I_H | 12 | #ifndef IEEE80211_I_H |
13 | #define IEEE80211_I_H | 13 | #define IEEE80211_I_H |
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/if_ether.h> | 17 | #include <linux/if_ether.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
21 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
26 | #include <net/cfg80211.h> | 26 | #include <net/cfg80211.h> |
27 | #include <net/wireless.h> | 27 | #include <net/wireless.h> |
28 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
29 | #include <net/mac80211.h> | 29 | #include <net/mac80211.h> |
30 | #include "key.h" | 30 | #include "key.h" |
31 | #include "sta_info.h" | 31 | #include "sta_info.h" |
32 | 32 | ||
33 | struct ieee80211_local; | 33 | struct ieee80211_local; |
34 | 34 | ||
35 | /* Maximum number of broadcast/multicast frames to buffer when some of the | 35 | /* Maximum number of broadcast/multicast frames to buffer when some of the |
36 | * associated stations are using power saving. */ | 36 | * associated stations are using power saving. */ |
37 | #define AP_MAX_BC_BUFFER 128 | 37 | #define AP_MAX_BC_BUFFER 128 |
38 | 38 | ||
39 | /* Maximum number of frames buffered to all STAs, including multicast frames. | 39 | /* Maximum number of frames buffered to all STAs, including multicast frames. |
40 | * Note: increasing this limit increases the potential memory requirement. Each | 40 | * Note: increasing this limit increases the potential memory requirement. Each |
41 | * frame can be up to about 2 kB long. */ | 41 | * frame can be up to about 2 kB long. */ |
42 | #define TOTAL_MAX_TX_BUFFER 512 | 42 | #define TOTAL_MAX_TX_BUFFER 512 |
43 | 43 | ||
44 | /* Required encryption head and tailroom */ | 44 | /* Required encryption head and tailroom */ |
45 | #define IEEE80211_ENCRYPT_HEADROOM 8 | 45 | #define IEEE80211_ENCRYPT_HEADROOM 8 |
46 | #define IEEE80211_ENCRYPT_TAILROOM 12 | 46 | #define IEEE80211_ENCRYPT_TAILROOM 12 |
47 | 47 | ||
48 | /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent | 48 | /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent |
49 | * reception of at least three fragmented frames. This limit can be increased | 49 | * reception of at least three fragmented frames. This limit can be increased |
50 | * by changing this define, at the cost of slower frame reassembly and | 50 | * by changing this define, at the cost of slower frame reassembly and |
51 | * increased memory use (about 2 kB of RAM per entry). */ | 51 | * increased memory use (about 2 kB of RAM per entry). */ |
52 | #define IEEE80211_FRAGMENT_MAX 4 | 52 | #define IEEE80211_FRAGMENT_MAX 4 |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Time after which we ignore scan results and no longer report/use | 55 | * Time after which we ignore scan results and no longer report/use |
56 | * them in any way. | 56 | * them in any way. |
57 | */ | 57 | */ |
58 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | 58 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) |
59 | 59 | ||
60 | struct ieee80211_fragment_entry { | 60 | struct ieee80211_fragment_entry { |
61 | unsigned long first_frag_time; | 61 | unsigned long first_frag_time; |
62 | unsigned int seq; | 62 | unsigned int seq; |
63 | unsigned int rx_queue; | 63 | unsigned int rx_queue; |
64 | unsigned int last_frag; | 64 | unsigned int last_frag; |
65 | unsigned int extra_len; | 65 | unsigned int extra_len; |
66 | struct sk_buff_head skb_list; | 66 | struct sk_buff_head skb_list; |
67 | int ccmp; /* Whether fragments were encrypted with CCMP */ | 67 | int ccmp; /* Whether fragments were encrypted with CCMP */ |
68 | u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ | 68 | u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ |
69 | }; | 69 | }; |
70 | 70 | ||
71 | 71 | ||
72 | struct ieee80211_bss { | 72 | struct ieee80211_bss { |
73 | struct list_head list; | 73 | struct list_head list; |
74 | struct ieee80211_bss *hnext; | 74 | struct ieee80211_bss *hnext; |
75 | size_t ssid_len; | 75 | size_t ssid_len; |
76 | 76 | ||
77 | atomic_t users; | 77 | atomic_t users; |
78 | 78 | ||
79 | u8 bssid[ETH_ALEN]; | 79 | u8 bssid[ETH_ALEN]; |
80 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 80 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
81 | u8 dtim_period; | 81 | u8 dtim_period; |
82 | u16 capability; /* host byte order */ | 82 | u16 capability; /* host byte order */ |
83 | enum ieee80211_band band; | 83 | enum ieee80211_band band; |
84 | int freq; | 84 | int freq; |
85 | int signal, noise, qual; | 85 | int signal, noise, qual; |
86 | u8 *ies; /* all information elements from the last Beacon or Probe | 86 | u8 *ies; /* all information elements from the last Beacon or Probe |
87 | * Response frames; note Beacon frame is not allowed to | 87 | * Response frames; note Beacon frame is not allowed to |
88 | * override values from Probe Response */ | 88 | * override values from Probe Response */ |
89 | size_t ies_len; | 89 | size_t ies_len; |
90 | bool wmm_used; | 90 | bool wmm_used; |
91 | #ifdef CONFIG_MAC80211_MESH | 91 | #ifdef CONFIG_MAC80211_MESH |
92 | u8 *mesh_id; | 92 | u8 *mesh_id; |
93 | size_t mesh_id_len; | 93 | size_t mesh_id_len; |
94 | u8 *mesh_cfg; | 94 | u8 *mesh_cfg; |
95 | #endif | 95 | #endif |
96 | #define IEEE80211_MAX_SUPP_RATES 32 | 96 | #define IEEE80211_MAX_SUPP_RATES 32 |
97 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 97 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
98 | size_t supp_rates_len; | 98 | size_t supp_rates_len; |
99 | u64 timestamp; | 99 | u64 timestamp; |
100 | int beacon_int; | 100 | int beacon_int; |
101 | 101 | ||
102 | unsigned long last_probe_resp; | 102 | unsigned long last_probe_resp; |
103 | unsigned long last_update; | 103 | unsigned long last_update; |
104 | 104 | ||
105 | /* during assocation, we save an ERP value from a probe response so | 105 | /* during assocation, we save an ERP value from a probe response so |
106 | * that we can feed ERP info to the driver when handling the | 106 | * that we can feed ERP info to the driver when handling the |
107 | * association completes. these fields probably won't be up-to-date | 107 | * association completes. these fields probably won't be up-to-date |
108 | * otherwise, you probably don't want to use them. */ | 108 | * otherwise, you probably don't want to use them. */ |
109 | int has_erp_value; | 109 | int has_erp_value; |
110 | u8 erp_value; | 110 | u8 erp_value; |
111 | }; | 111 | }; |
112 | 112 | ||
113 | static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss) | 113 | static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss) |
114 | { | 114 | { |
115 | #ifdef CONFIG_MAC80211_MESH | 115 | #ifdef CONFIG_MAC80211_MESH |
116 | return bss->mesh_cfg; | 116 | return bss->mesh_cfg; |
117 | #endif | 117 | #endif |
118 | return NULL; | 118 | return NULL; |
119 | } | 119 | } |
120 | 120 | ||
121 | static inline u8 *bss_mesh_id(struct ieee80211_bss *bss) | 121 | static inline u8 *bss_mesh_id(struct ieee80211_bss *bss) |
122 | { | 122 | { |
123 | #ifdef CONFIG_MAC80211_MESH | 123 | #ifdef CONFIG_MAC80211_MESH |
124 | return bss->mesh_id; | 124 | return bss->mesh_id; |
125 | #endif | 125 | #endif |
126 | return NULL; | 126 | return NULL; |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline u8 bss_mesh_id_len(struct ieee80211_bss *bss) | 129 | static inline u8 bss_mesh_id_len(struct ieee80211_bss *bss) |
130 | { | 130 | { |
131 | #ifdef CONFIG_MAC80211_MESH | 131 | #ifdef CONFIG_MAC80211_MESH |
132 | return bss->mesh_id_len; | 132 | return bss->mesh_id_len; |
133 | #endif | 133 | #endif |
134 | return 0; | 134 | return 0; |
135 | } | 135 | } |
136 | 136 | ||
137 | 137 | ||
138 | typedef unsigned __bitwise__ ieee80211_tx_result; | 138 | typedef unsigned __bitwise__ ieee80211_tx_result; |
139 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) | 139 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) |
140 | #define TX_DROP ((__force ieee80211_tx_result) 1u) | 140 | #define TX_DROP ((__force ieee80211_tx_result) 1u) |
141 | #define TX_QUEUED ((__force ieee80211_tx_result) 2u) | 141 | #define TX_QUEUED ((__force ieee80211_tx_result) 2u) |
142 | 142 | ||
143 | #define IEEE80211_TX_FRAGMENTED BIT(0) | 143 | #define IEEE80211_TX_FRAGMENTED BIT(0) |
144 | #define IEEE80211_TX_UNICAST BIT(1) | 144 | #define IEEE80211_TX_UNICAST BIT(1) |
145 | #define IEEE80211_TX_PS_BUFFERED BIT(2) | 145 | #define IEEE80211_TX_PS_BUFFERED BIT(2) |
146 | 146 | ||
147 | struct ieee80211_tx_data { | 147 | struct ieee80211_tx_data { |
148 | struct sk_buff *skb; | 148 | struct sk_buff *skb; |
149 | struct net_device *dev; | 149 | struct net_device *dev; |
150 | struct ieee80211_local *local; | 150 | struct ieee80211_local *local; |
151 | struct ieee80211_sub_if_data *sdata; | 151 | struct ieee80211_sub_if_data *sdata; |
152 | struct sta_info *sta; | 152 | struct sta_info *sta; |
153 | struct ieee80211_key *key; | 153 | struct ieee80211_key *key; |
154 | 154 | ||
155 | struct ieee80211_channel *channel; | 155 | struct ieee80211_channel *channel; |
156 | 156 | ||
157 | /* Extra fragments (in addition to the first fragment | 157 | /* Extra fragments (in addition to the first fragment |
158 | * in skb) */ | 158 | * in skb) */ |
159 | struct sk_buff **extra_frag; | 159 | struct sk_buff **extra_frag; |
160 | int num_extra_frag; | 160 | int num_extra_frag; |
161 | 161 | ||
162 | u16 ethertype; | 162 | u16 ethertype; |
163 | unsigned int flags; | 163 | unsigned int flags; |
164 | }; | 164 | }; |
165 | 165 | ||
166 | 166 | ||
167 | typedef unsigned __bitwise__ ieee80211_rx_result; | 167 | typedef unsigned __bitwise__ ieee80211_rx_result; |
168 | #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) | 168 | #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) |
169 | #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) | 169 | #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) |
170 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) | 170 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) |
171 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) | 171 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) |
172 | 172 | ||
173 | #define IEEE80211_RX_IN_SCAN BIT(0) | 173 | #define IEEE80211_RX_IN_SCAN BIT(0) |
174 | /* frame is destined to interface currently processed (incl. multicast frames) */ | 174 | /* frame is destined to interface currently processed (incl. multicast frames) */ |
175 | #define IEEE80211_RX_RA_MATCH BIT(1) | 175 | #define IEEE80211_RX_RA_MATCH BIT(1) |
176 | #define IEEE80211_RX_AMSDU BIT(2) | 176 | #define IEEE80211_RX_AMSDU BIT(2) |
177 | #define IEEE80211_RX_CMNTR_REPORTED BIT(3) | 177 | #define IEEE80211_RX_CMNTR_REPORTED BIT(3) |
178 | #define IEEE80211_RX_FRAGMENTED BIT(4) | 178 | #define IEEE80211_RX_FRAGMENTED BIT(4) |
179 | 179 | ||
180 | struct ieee80211_rx_data { | 180 | struct ieee80211_rx_data { |
181 | struct sk_buff *skb; | 181 | struct sk_buff *skb; |
182 | struct net_device *dev; | 182 | struct net_device *dev; |
183 | struct ieee80211_local *local; | 183 | struct ieee80211_local *local; |
184 | struct ieee80211_sub_if_data *sdata; | 184 | struct ieee80211_sub_if_data *sdata; |
185 | struct sta_info *sta; | 185 | struct sta_info *sta; |
186 | struct ieee80211_key *key; | 186 | struct ieee80211_key *key; |
187 | struct ieee80211_rx_status *status; | 187 | struct ieee80211_rx_status *status; |
188 | struct ieee80211_rate *rate; | 188 | struct ieee80211_rate *rate; |
189 | 189 | ||
190 | unsigned int flags; | 190 | unsigned int flags; |
191 | int sent_ps_buffered; | 191 | int sent_ps_buffered; |
192 | int queue; | 192 | int queue; |
193 | u32 tkip_iv32; | 193 | u32 tkip_iv32; |
194 | u16 tkip_iv16; | 194 | u16 tkip_iv16; |
195 | }; | 195 | }; |
196 | 196 | ||
197 | struct ieee80211_tx_stored_packet { | 197 | struct ieee80211_tx_stored_packet { |
198 | struct sk_buff *skb; | 198 | struct sk_buff *skb; |
199 | struct sk_buff **extra_frag; | 199 | struct sk_buff **extra_frag; |
200 | int num_extra_frag; | 200 | int num_extra_frag; |
201 | }; | 201 | }; |
202 | 202 | ||
203 | struct beacon_data { | 203 | struct beacon_data { |
204 | u8 *head, *tail; | 204 | u8 *head, *tail; |
205 | int head_len, tail_len; | 205 | int head_len, tail_len; |
206 | int dtim_period; | 206 | int dtim_period; |
207 | }; | 207 | }; |
208 | 208 | ||
209 | struct ieee80211_if_ap { | 209 | struct ieee80211_if_ap { |
210 | struct beacon_data *beacon; | 210 | struct beacon_data *beacon; |
211 | 211 | ||
212 | struct list_head vlans; | 212 | struct list_head vlans; |
213 | 213 | ||
214 | /* yes, this looks ugly, but guarantees that we can later use | 214 | /* yes, this looks ugly, but guarantees that we can later use |
215 | * bitmap_empty :) | 215 | * bitmap_empty :) |
216 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ | 216 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ |
217 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; | 217 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; |
218 | struct sk_buff_head ps_bc_buf; | 218 | struct sk_buff_head ps_bc_buf; |
219 | atomic_t num_sta_ps; /* number of stations in PS mode */ | 219 | atomic_t num_sta_ps; /* number of stations in PS mode */ |
220 | int dtim_count; | 220 | int dtim_count; |
221 | }; | 221 | }; |
222 | 222 | ||
223 | struct ieee80211_if_wds { | 223 | struct ieee80211_if_wds { |
224 | struct sta_info *sta; | 224 | struct sta_info *sta; |
225 | u8 remote_addr[ETH_ALEN]; | 225 | u8 remote_addr[ETH_ALEN]; |
226 | }; | 226 | }; |
227 | 227 | ||
228 | struct ieee80211_if_vlan { | 228 | struct ieee80211_if_vlan { |
229 | struct list_head list; | 229 | struct list_head list; |
230 | }; | 230 | }; |
231 | 231 | ||
232 | struct mesh_stats { | 232 | struct mesh_stats { |
233 | __u32 fwded_frames; /* Mesh forwarded frames */ | 233 | __u32 fwded_frames; /* Mesh forwarded frames */ |
234 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ | 234 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ |
235 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ | 235 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ |
236 | atomic_t estab_plinks; | 236 | atomic_t estab_plinks; |
237 | }; | 237 | }; |
238 | 238 | ||
239 | #define PREQ_Q_F_START 0x1 | 239 | #define PREQ_Q_F_START 0x1 |
240 | #define PREQ_Q_F_REFRESH 0x2 | 240 | #define PREQ_Q_F_REFRESH 0x2 |
241 | struct mesh_preq_queue { | 241 | struct mesh_preq_queue { |
242 | struct list_head list; | 242 | struct list_head list; |
243 | u8 dst[ETH_ALEN]; | 243 | u8 dst[ETH_ALEN]; |
244 | u8 flags; | 244 | u8 flags; |
245 | }; | 245 | }; |
246 | 246 | ||
247 | /* flags used in struct ieee80211_if_sta.flags */ | 247 | /* flags used in struct ieee80211_if_sta.flags */ |
248 | #define IEEE80211_STA_SSID_SET BIT(0) | 248 | #define IEEE80211_STA_SSID_SET BIT(0) |
249 | #define IEEE80211_STA_BSSID_SET BIT(1) | 249 | #define IEEE80211_STA_BSSID_SET BIT(1) |
250 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) | 250 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) |
251 | #define IEEE80211_STA_AUTHENTICATED BIT(3) | 251 | #define IEEE80211_STA_AUTHENTICATED BIT(3) |
252 | #define IEEE80211_STA_ASSOCIATED BIT(4) | 252 | #define IEEE80211_STA_ASSOCIATED BIT(4) |
253 | #define IEEE80211_STA_PROBEREQ_POLL BIT(5) | 253 | #define IEEE80211_STA_PROBEREQ_POLL BIT(5) |
254 | #define IEEE80211_STA_CREATE_IBSS BIT(6) | 254 | #define IEEE80211_STA_CREATE_IBSS BIT(6) |
255 | #define IEEE80211_STA_MIXED_CELL BIT(7) | 255 | #define IEEE80211_STA_MIXED_CELL BIT(7) |
256 | #define IEEE80211_STA_WMM_ENABLED BIT(8) | 256 | #define IEEE80211_STA_WMM_ENABLED BIT(8) |
257 | #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) | 257 | #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) |
258 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) | 258 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) |
259 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) | 259 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) |
260 | #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) | 260 | #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) |
261 | /* flags for MLME request */ | 261 | /* flags for MLME request */ |
262 | #define IEEE80211_STA_REQ_SCAN 0 | 262 | #define IEEE80211_STA_REQ_SCAN 0 |
263 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 | 263 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 |
264 | #define IEEE80211_STA_REQ_AUTH 2 | 264 | #define IEEE80211_STA_REQ_AUTH 2 |
265 | #define IEEE80211_STA_REQ_RUN 3 | 265 | #define IEEE80211_STA_REQ_RUN 3 |
266 | 266 | ||
267 | /* STA/IBSS MLME states */ | 267 | /* STA/IBSS MLME states */ |
268 | enum ieee80211_sta_mlme_state { | 268 | enum ieee80211_sta_mlme_state { |
269 | IEEE80211_STA_MLME_DISABLED, | 269 | IEEE80211_STA_MLME_DISABLED, |
270 | IEEE80211_STA_MLME_DIRECT_PROBE, | 270 | IEEE80211_STA_MLME_DIRECT_PROBE, |
271 | IEEE80211_STA_MLME_AUTHENTICATE, | 271 | IEEE80211_STA_MLME_AUTHENTICATE, |
272 | IEEE80211_STA_MLME_ASSOCIATE, | 272 | IEEE80211_STA_MLME_ASSOCIATE, |
273 | IEEE80211_STA_MLME_ASSOCIATED, | 273 | IEEE80211_STA_MLME_ASSOCIATED, |
274 | IEEE80211_STA_MLME_IBSS_SEARCH, | 274 | IEEE80211_STA_MLME_IBSS_SEARCH, |
275 | IEEE80211_STA_MLME_IBSS_JOINED, | 275 | IEEE80211_STA_MLME_IBSS_JOINED, |
276 | }; | 276 | }; |
277 | 277 | ||
278 | /* bitfield of allowed auth algs */ | 278 | /* bitfield of allowed auth algs */ |
279 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) | 279 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) |
280 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) | 280 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) |
281 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) | 281 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) |
282 | 282 | ||
283 | struct ieee80211_if_sta { | 283 | struct ieee80211_if_sta { |
284 | struct timer_list timer; | 284 | struct timer_list timer; |
285 | struct work_struct work; | 285 | struct work_struct work; |
286 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 286 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
288 | enum ieee80211_sta_mlme_state state; | 288 | enum ieee80211_sta_mlme_state state; |
289 | size_t ssid_len; | 289 | size_t ssid_len; |
290 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 290 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
291 | size_t scan_ssid_len; | 291 | size_t scan_ssid_len; |
292 | u16 aid; | 292 | u16 aid; |
293 | u16 ap_capab, capab; | 293 | u16 ap_capab, capab; |
294 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 294 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
295 | size_t extra_ie_len; | 295 | size_t extra_ie_len; |
296 | 296 | ||
297 | /* The last AssocReq/Resp IEs */ | 297 | /* The last AssocReq/Resp IEs */ |
298 | u8 *assocreq_ies, *assocresp_ies; | 298 | u8 *assocreq_ies, *assocresp_ies; |
299 | size_t assocreq_ies_len, assocresp_ies_len; | 299 | size_t assocreq_ies_len, assocresp_ies_len; |
300 | 300 | ||
301 | struct sk_buff_head skb_queue; | 301 | struct sk_buff_head skb_queue; |
302 | 302 | ||
303 | int assoc_scan_tries; /* number of scans done pre-association */ | 303 | int assoc_scan_tries; /* number of scans done pre-association */ |
304 | int direct_probe_tries; /* retries for direct probes */ | 304 | int direct_probe_tries; /* retries for direct probes */ |
305 | int auth_tries; /* retries for auth req */ | 305 | int auth_tries; /* retries for auth req */ |
306 | int assoc_tries; /* retries for assoc req */ | 306 | int assoc_tries; /* retries for assoc req */ |
307 | 307 | ||
308 | unsigned long request; | 308 | unsigned long request; |
309 | 309 | ||
310 | unsigned long last_probe; | 310 | unsigned long last_probe; |
311 | 311 | ||
312 | unsigned int flags; | 312 | unsigned int flags; |
313 | 313 | ||
314 | unsigned int auth_algs; /* bitfield of allowed auth algs */ | 314 | unsigned int auth_algs; /* bitfield of allowed auth algs */ |
315 | int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ | 315 | int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ |
316 | int auth_transaction; | 316 | int auth_transaction; |
317 | 317 | ||
318 | unsigned long ibss_join_req; | 318 | unsigned long ibss_join_req; |
319 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | 319 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ |
320 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | 320 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; |
321 | 321 | ||
322 | int wmm_last_param_set; | 322 | int wmm_last_param_set; |
323 | }; | 323 | }; |
324 | 324 | ||
325 | struct ieee80211_if_mesh { | 325 | struct ieee80211_if_mesh { |
326 | struct work_struct work; | 326 | struct work_struct work; |
327 | struct timer_list housekeeping_timer; | 327 | struct timer_list housekeeping_timer; |
328 | struct timer_list mesh_path_timer; | 328 | struct timer_list mesh_path_timer; |
329 | struct sk_buff_head skb_queue; | 329 | struct sk_buff_head skb_queue; |
330 | 330 | ||
331 | bool housekeeping; | 331 | bool housekeeping; |
332 | 332 | ||
333 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 333 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
334 | size_t mesh_id_len; | 334 | size_t mesh_id_len; |
335 | /* Active Path Selection Protocol Identifier */ | 335 | /* Active Path Selection Protocol Identifier */ |
336 | u8 mesh_pp_id[4]; | 336 | u8 mesh_pp_id[4]; |
337 | /* Active Path Selection Metric Identifier */ | 337 | /* Active Path Selection Metric Identifier */ |
338 | u8 mesh_pm_id[4]; | 338 | u8 mesh_pm_id[4]; |
339 | /* Congestion Control Mode Identifier */ | 339 | /* Congestion Control Mode Identifier */ |
340 | u8 mesh_cc_id[4]; | 340 | u8 mesh_cc_id[4]; |
341 | /* Local mesh Destination Sequence Number */ | 341 | /* Local mesh Destination Sequence Number */ |
342 | u32 dsn; | 342 | u32 dsn; |
343 | /* Last used PREQ ID */ | 343 | /* Last used PREQ ID */ |
344 | u32 preq_id; | 344 | u32 preq_id; |
345 | atomic_t mpaths; | 345 | atomic_t mpaths; |
346 | /* Timestamp of last DSN update */ | 346 | /* Timestamp of last DSN update */ |
347 | unsigned long last_dsn_update; | 347 | unsigned long last_dsn_update; |
348 | /* Timestamp of last DSN sent */ | 348 | /* Timestamp of last DSN sent */ |
349 | unsigned long last_preq; | 349 | unsigned long last_preq; |
350 | struct mesh_rmc *rmc; | 350 | struct mesh_rmc *rmc; |
351 | spinlock_t mesh_preq_queue_lock; | 351 | spinlock_t mesh_preq_queue_lock; |
352 | struct mesh_preq_queue preq_queue; | 352 | struct mesh_preq_queue preq_queue; |
353 | int preq_queue_len; | 353 | int preq_queue_len; |
354 | struct mesh_stats mshstats; | 354 | struct mesh_stats mshstats; |
355 | struct mesh_config mshcfg; | 355 | struct mesh_config mshcfg; |
356 | u32 mesh_seqnum; | 356 | u32 mesh_seqnum; |
357 | bool accepting_plinks; | 357 | bool accepting_plinks; |
358 | }; | 358 | }; |
359 | 359 | ||
360 | #ifdef CONFIG_MAC80211_MESH | 360 | #ifdef CONFIG_MAC80211_MESH |
361 | #define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \ | 361 | #define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \ |
362 | do { (msh)->mshstats.name++; } while (0) | 362 | do { (msh)->mshstats.name++; } while (0) |
363 | #else | 363 | #else |
364 | #define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \ | 364 | #define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \ |
365 | do { } while (0) | 365 | do { } while (0) |
366 | #endif | 366 | #endif |
367 | 367 | ||
368 | /** | 368 | /** |
369 | * enum ieee80211_sub_if_data_flags - virtual interface flags | 369 | * enum ieee80211_sub_if_data_flags - virtual interface flags |
370 | * | 370 | * |
371 | * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets | 371 | * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets |
372 | * @IEEE80211_SDATA_PROMISC: interface is promisc | 372 | * @IEEE80211_SDATA_PROMISC: interface is promisc |
373 | * @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active | 373 | * @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active |
374 | * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode | 374 | * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode |
375 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between | 375 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between |
376 | * associated stations and deliver multicast frames both | 376 | * associated stations and deliver multicast frames both |
377 | * back to wireless media and to the local net stack. | 377 | * back to wireless media and to the local net stack. |
378 | */ | 378 | */ |
379 | enum ieee80211_sub_if_data_flags { | 379 | enum ieee80211_sub_if_data_flags { |
380 | IEEE80211_SDATA_ALLMULTI = BIT(0), | 380 | IEEE80211_SDATA_ALLMULTI = BIT(0), |
381 | IEEE80211_SDATA_PROMISC = BIT(1), | 381 | IEEE80211_SDATA_PROMISC = BIT(1), |
382 | IEEE80211_SDATA_USERSPACE_MLME = BIT(2), | 382 | IEEE80211_SDATA_USERSPACE_MLME = BIT(2), |
383 | IEEE80211_SDATA_OPERATING_GMODE = BIT(3), | 383 | IEEE80211_SDATA_OPERATING_GMODE = BIT(3), |
384 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(4), | 384 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(4), |
385 | }; | 385 | }; |
386 | 386 | ||
387 | struct ieee80211_sub_if_data { | 387 | struct ieee80211_sub_if_data { |
388 | struct list_head list; | 388 | struct list_head list; |
389 | 389 | ||
390 | struct wireless_dev wdev; | 390 | struct wireless_dev wdev; |
391 | 391 | ||
392 | /* keys */ | 392 | /* keys */ |
393 | struct list_head key_list; | 393 | struct list_head key_list; |
394 | 394 | ||
395 | struct net_device *dev; | 395 | struct net_device *dev; |
396 | struct ieee80211_local *local; | 396 | struct ieee80211_local *local; |
397 | 397 | ||
398 | unsigned int flags; | 398 | unsigned int flags; |
399 | 399 | ||
400 | int drop_unencrypted; | 400 | int drop_unencrypted; |
401 | 401 | ||
402 | /* Fragment table for host-based reassembly */ | 402 | /* Fragment table for host-based reassembly */ |
403 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 403 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
404 | unsigned int fragment_next; | 404 | unsigned int fragment_next; |
405 | 405 | ||
406 | #define NUM_DEFAULT_KEYS 4 | 406 | #define NUM_DEFAULT_KEYS 4 |
407 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; | 407 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; |
408 | struct ieee80211_key *default_key; | 408 | struct ieee80211_key *default_key; |
409 | 409 | ||
410 | u16 sequence_number; | 410 | u16 sequence_number; |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * AP this belongs to: self in AP mode and | 413 | * AP this belongs to: self in AP mode and |
414 | * corresponding AP in VLAN mode, NULL for | 414 | * corresponding AP in VLAN mode, NULL for |
415 | * all others (might be needed later in IBSS) | 415 | * all others (might be needed later in IBSS) |
416 | */ | 416 | */ |
417 | struct ieee80211_if_ap *bss; | 417 | struct ieee80211_if_ap *bss; |
418 | 418 | ||
419 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 419 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ |
420 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 420 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ |
421 | 421 | ||
422 | union { | 422 | union { |
423 | struct ieee80211_if_ap ap; | 423 | struct ieee80211_if_ap ap; |
424 | struct ieee80211_if_wds wds; | 424 | struct ieee80211_if_wds wds; |
425 | struct ieee80211_if_vlan vlan; | 425 | struct ieee80211_if_vlan vlan; |
426 | struct ieee80211_if_sta sta; | 426 | struct ieee80211_if_sta sta; |
427 | #ifdef CONFIG_MAC80211_MESH | 427 | #ifdef CONFIG_MAC80211_MESH |
428 | struct ieee80211_if_mesh mesh; | 428 | struct ieee80211_if_mesh mesh; |
429 | #endif | 429 | #endif |
430 | u32 mntr_flags; | 430 | u32 mntr_flags; |
431 | } u; | 431 | } u; |
432 | 432 | ||
433 | #ifdef CONFIG_MAC80211_DEBUGFS | 433 | #ifdef CONFIG_MAC80211_DEBUGFS |
434 | struct dentry *debugfsdir; | 434 | struct dentry *debugfsdir; |
435 | union { | 435 | union { |
436 | struct { | 436 | struct { |
437 | struct dentry *drop_unencrypted; | 437 | struct dentry *drop_unencrypted; |
438 | struct dentry *state; | 438 | struct dentry *state; |
439 | struct dentry *bssid; | 439 | struct dentry *bssid; |
440 | struct dentry *prev_bssid; | 440 | struct dentry *prev_bssid; |
441 | struct dentry *ssid_len; | 441 | struct dentry *ssid_len; |
442 | struct dentry *aid; | 442 | struct dentry *aid; |
443 | struct dentry *ap_capab; | 443 | struct dentry *ap_capab; |
444 | struct dentry *capab; | 444 | struct dentry *capab; |
445 | struct dentry *extra_ie_len; | 445 | struct dentry *extra_ie_len; |
446 | struct dentry *auth_tries; | 446 | struct dentry *auth_tries; |
447 | struct dentry *assoc_tries; | 447 | struct dentry *assoc_tries; |
448 | struct dentry *auth_algs; | 448 | struct dentry *auth_algs; |
449 | struct dentry *auth_alg; | 449 | struct dentry *auth_alg; |
450 | struct dentry *auth_transaction; | 450 | struct dentry *auth_transaction; |
451 | struct dentry *flags; | 451 | struct dentry *flags; |
452 | struct dentry *force_unicast_rateidx; | 452 | struct dentry *force_unicast_rateidx; |
453 | struct dentry *max_ratectrl_rateidx; | 453 | struct dentry *max_ratectrl_rateidx; |
454 | } sta; | 454 | } sta; |
455 | struct { | 455 | struct { |
456 | struct dentry *drop_unencrypted; | 456 | struct dentry *drop_unencrypted; |
457 | struct dentry *num_sta_ps; | 457 | struct dentry *num_sta_ps; |
458 | struct dentry *dtim_count; | 458 | struct dentry *dtim_count; |
459 | struct dentry *force_unicast_rateidx; | 459 | struct dentry *force_unicast_rateidx; |
460 | struct dentry *max_ratectrl_rateidx; | 460 | struct dentry *max_ratectrl_rateidx; |
461 | struct dentry *num_buffered_multicast; | 461 | struct dentry *num_buffered_multicast; |
462 | } ap; | 462 | } ap; |
463 | struct { | 463 | struct { |
464 | struct dentry *drop_unencrypted; | 464 | struct dentry *drop_unencrypted; |
465 | struct dentry *peer; | 465 | struct dentry *peer; |
466 | struct dentry *force_unicast_rateidx; | 466 | struct dentry *force_unicast_rateidx; |
467 | struct dentry *max_ratectrl_rateidx; | 467 | struct dentry *max_ratectrl_rateidx; |
468 | } wds; | 468 | } wds; |
469 | struct { | 469 | struct { |
470 | struct dentry *drop_unencrypted; | 470 | struct dentry *drop_unencrypted; |
471 | struct dentry *force_unicast_rateidx; | 471 | struct dentry *force_unicast_rateidx; |
472 | struct dentry *max_ratectrl_rateidx; | 472 | struct dentry *max_ratectrl_rateidx; |
473 | } vlan; | 473 | } vlan; |
474 | struct { | 474 | struct { |
475 | struct dentry *mode; | 475 | struct dentry *mode; |
476 | } monitor; | 476 | } monitor; |
477 | } debugfs; | 477 | } debugfs; |
478 | struct { | 478 | struct { |
479 | struct dentry *default_key; | 479 | struct dentry *default_key; |
480 | } common_debugfs; | 480 | } common_debugfs; |
481 | 481 | ||
482 | #ifdef CONFIG_MAC80211_MESH | 482 | #ifdef CONFIG_MAC80211_MESH |
483 | struct dentry *mesh_stats_dir; | 483 | struct dentry *mesh_stats_dir; |
484 | struct { | 484 | struct { |
485 | struct dentry *fwded_frames; | 485 | struct dentry *fwded_frames; |
486 | struct dentry *dropped_frames_ttl; | 486 | struct dentry *dropped_frames_ttl; |
487 | struct dentry *dropped_frames_no_route; | 487 | struct dentry *dropped_frames_no_route; |
488 | struct dentry *estab_plinks; | 488 | struct dentry *estab_plinks; |
489 | struct timer_list mesh_path_timer; | 489 | struct timer_list mesh_path_timer; |
490 | } mesh_stats; | 490 | } mesh_stats; |
491 | 491 | ||
492 | struct dentry *mesh_config_dir; | 492 | struct dentry *mesh_config_dir; |
493 | struct { | 493 | struct { |
494 | struct dentry *dot11MeshRetryTimeout; | 494 | struct dentry *dot11MeshRetryTimeout; |
495 | struct dentry *dot11MeshConfirmTimeout; | 495 | struct dentry *dot11MeshConfirmTimeout; |
496 | struct dentry *dot11MeshHoldingTimeout; | 496 | struct dentry *dot11MeshHoldingTimeout; |
497 | struct dentry *dot11MeshMaxRetries; | 497 | struct dentry *dot11MeshMaxRetries; |
498 | struct dentry *dot11MeshTTL; | 498 | struct dentry *dot11MeshTTL; |
499 | struct dentry *auto_open_plinks; | 499 | struct dentry *auto_open_plinks; |
500 | struct dentry *dot11MeshMaxPeerLinks; | 500 | struct dentry *dot11MeshMaxPeerLinks; |
501 | struct dentry *dot11MeshHWMPactivePathTimeout; | 501 | struct dentry *dot11MeshHWMPactivePathTimeout; |
502 | struct dentry *dot11MeshHWMPpreqMinInterval; | 502 | struct dentry *dot11MeshHWMPpreqMinInterval; |
503 | struct dentry *dot11MeshHWMPnetDiameterTraversalTime; | 503 | struct dentry *dot11MeshHWMPnetDiameterTraversalTime; |
504 | struct dentry *dot11MeshHWMPmaxPREQretries; | 504 | struct dentry *dot11MeshHWMPmaxPREQretries; |
505 | struct dentry *path_refresh_time; | 505 | struct dentry *path_refresh_time; |
506 | struct dentry *min_discovery_timeout; | 506 | struct dentry *min_discovery_timeout; |
507 | } mesh_config; | 507 | } mesh_config; |
508 | #endif | 508 | #endif |
509 | 509 | ||
510 | #endif | 510 | #endif |
511 | /* must be last, dynamically sized area in this! */ | 511 | /* must be last, dynamically sized area in this! */ |
512 | struct ieee80211_vif vif; | 512 | struct ieee80211_vif vif; |
513 | }; | 513 | }; |
514 | 514 | ||
515 | static inline | 515 | static inline |
516 | struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | 516 | struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) |
517 | { | 517 | { |
518 | return container_of(p, struct ieee80211_sub_if_data, vif); | 518 | return container_of(p, struct ieee80211_sub_if_data, vif); |
519 | } | 519 | } |
520 | 520 | ||
521 | static inline void | 521 | static inline void |
522 | ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, | 522 | ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, |
523 | u8 mesh_id_len, u8 *mesh_id) | 523 | u8 mesh_id_len, u8 *mesh_id) |
524 | { | 524 | { |
525 | #ifdef CONFIG_MAC80211_MESH | 525 | #ifdef CONFIG_MAC80211_MESH |
526 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 526 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
527 | ifmsh->mesh_id_len = mesh_id_len; | 527 | ifmsh->mesh_id_len = mesh_id_len; |
528 | memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); | 528 | memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); |
529 | #else | 529 | #else |
530 | WARN_ON(1); | 530 | WARN_ON(1); |
531 | #endif | 531 | #endif |
532 | } | 532 | } |
533 | 533 | ||
534 | enum { | 534 | enum { |
535 | IEEE80211_RX_MSG = 1, | 535 | IEEE80211_RX_MSG = 1, |
536 | IEEE80211_TX_STATUS_MSG = 2, | 536 | IEEE80211_TX_STATUS_MSG = 2, |
537 | IEEE80211_DELBA_MSG = 3, | 537 | IEEE80211_DELBA_MSG = 3, |
538 | IEEE80211_ADDBA_MSG = 4, | 538 | IEEE80211_ADDBA_MSG = 4, |
539 | }; | 539 | }; |
540 | 540 | ||
541 | /* maximum number of hardware queues we support. */ | 541 | /* maximum number of hardware queues we support. */ |
542 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) | 542 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) |
543 | 543 | ||
544 | struct ieee80211_master_priv { | 544 | struct ieee80211_master_priv { |
545 | struct ieee80211_local *local; | 545 | struct ieee80211_local *local; |
546 | }; | 546 | }; |
547 | 547 | ||
548 | struct ieee80211_local { | 548 | struct ieee80211_local { |
549 | /* embed the driver visible part. | 549 | /* embed the driver visible part. |
550 | * don't cast (use the static inlines below), but we keep | 550 | * don't cast (use the static inlines below), but we keep |
551 | * it first anyway so they become a no-op */ | 551 | * it first anyway so they become a no-op */ |
552 | struct ieee80211_hw hw; | 552 | struct ieee80211_hw hw; |
553 | 553 | ||
554 | const struct ieee80211_ops *ops; | 554 | const struct ieee80211_ops *ops; |
555 | 555 | ||
556 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; | 556 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; |
557 | 557 | ||
558 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ | 558 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ |
559 | int open_count; | 559 | int open_count; |
560 | int monitors, cooked_mntrs; | 560 | int monitors, cooked_mntrs; |
561 | /* number of interfaces with corresponding FIF_ flags */ | 561 | /* number of interfaces with corresponding FIF_ flags */ |
562 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; | 562 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; |
563 | unsigned int filter_flags; /* FIF_* */ | 563 | unsigned int filter_flags; /* FIF_* */ |
564 | struct iw_statistics wstats; | 564 | struct iw_statistics wstats; |
565 | u8 wstats_flags; | 565 | u8 wstats_flags; |
566 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | 566 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ |
567 | int tx_headroom; /* required headroom for hardware/radiotap */ | 567 | int tx_headroom; /* required headroom for hardware/radiotap */ |
568 | 568 | ||
569 | /* Tasklet and skb queue to process calls from IRQ mode. All frames | 569 | /* Tasklet and skb queue to process calls from IRQ mode. All frames |
570 | * added to skb_queue will be processed, but frames in | 570 | * added to skb_queue will be processed, but frames in |
571 | * skb_queue_unreliable may be dropped if the total length of these | 571 | * skb_queue_unreliable may be dropped if the total length of these |
572 | * queues increases over the limit. */ | 572 | * queues increases over the limit. */ |
573 | #define IEEE80211_IRQSAFE_QUEUE_LIMIT 128 | 573 | #define IEEE80211_IRQSAFE_QUEUE_LIMIT 128 |
574 | struct tasklet_struct tasklet; | 574 | struct tasklet_struct tasklet; |
575 | struct sk_buff_head skb_queue; | 575 | struct sk_buff_head skb_queue; |
576 | struct sk_buff_head skb_queue_unreliable; | 576 | struct sk_buff_head skb_queue_unreliable; |
577 | 577 | ||
578 | /* Station data */ | 578 | /* Station data */ |
579 | /* | 579 | /* |
580 | * The lock only protects the list, hash, timer and counter | 580 | * The lock only protects the list, hash, timer and counter |
581 | * against manipulation, reads are done in RCU. Additionally, | 581 | * against manipulation, reads are done in RCU. Additionally, |
582 | * the lock protects each BSS's TIM bitmap. | 582 | * the lock protects each BSS's TIM bitmap. |
583 | */ | 583 | */ |
584 | spinlock_t sta_lock; | 584 | spinlock_t sta_lock; |
585 | unsigned long num_sta; | 585 | unsigned long num_sta; |
586 | struct list_head sta_list; | 586 | struct list_head sta_list; |
587 | struct list_head sta_flush_list; | 587 | struct list_head sta_flush_list; |
588 | struct work_struct sta_flush_work; | 588 | struct work_struct sta_flush_work; |
589 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 589 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
590 | struct timer_list sta_cleanup; | 590 | struct timer_list sta_cleanup; |
591 | 591 | ||
592 | unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | 592 | unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; |
593 | unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | 593 | unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; |
594 | struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; | 594 | struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; |
595 | struct tasklet_struct tx_pending_tasklet; | 595 | struct tasklet_struct tx_pending_tasklet; |
596 | 596 | ||
597 | /* number of interfaces with corresponding IFF_ flags */ | 597 | /* number of interfaces with corresponding IFF_ flags */ |
598 | atomic_t iff_allmultis, iff_promiscs; | 598 | atomic_t iff_allmultis, iff_promiscs; |
599 | 599 | ||
600 | struct rate_control_ref *rate_ctrl; | 600 | struct rate_control_ref *rate_ctrl; |
601 | 601 | ||
602 | int rts_threshold; | 602 | int rts_threshold; |
603 | int fragmentation_threshold; | 603 | int fragmentation_threshold; |
604 | 604 | ||
605 | struct crypto_blkcipher *wep_tx_tfm; | 605 | struct crypto_blkcipher *wep_tx_tfm; |
606 | struct crypto_blkcipher *wep_rx_tfm; | 606 | struct crypto_blkcipher *wep_rx_tfm; |
607 | u32 wep_iv; | 607 | u32 wep_iv; |
608 | 608 | ||
609 | struct list_head interfaces; | 609 | struct list_head interfaces; |
610 | 610 | ||
611 | /* | 611 | /* |
612 | * Key lock, protects sdata's key_list and sta_info's | 612 | * Key lock, protects sdata's key_list and sta_info's |
613 | * key pointers (write access, they're RCU.) | 613 | * key pointers (write access, they're RCU.) |
614 | */ | 614 | */ |
615 | spinlock_t key_lock; | 615 | spinlock_t key_lock; |
616 | 616 | ||
617 | 617 | ||
618 | /* Scanning and BSS list */ | 618 | /* Scanning and BSS list */ |
619 | bool sw_scanning, hw_scanning; | 619 | bool sw_scanning, hw_scanning; |
620 | int scan_channel_idx; | 620 | int scan_channel_idx; |
621 | enum ieee80211_band scan_band; | 621 | enum ieee80211_band scan_band; |
622 | 622 | ||
623 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; | 623 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; |
624 | unsigned long last_scan_completed; | 624 | unsigned long last_scan_completed; |
625 | struct delayed_work scan_work; | 625 | struct delayed_work scan_work; |
626 | struct ieee80211_sub_if_data *scan_sdata; | 626 | struct ieee80211_sub_if_data *scan_sdata; |
627 | struct ieee80211_channel *oper_channel, *scan_channel; | 627 | struct ieee80211_channel *oper_channel, *scan_channel; |
628 | enum nl80211_sec_chan_offset oper_sec_chan_offset; | 628 | enum nl80211_channel_type oper_channel_type; |
629 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 629 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
630 | size_t scan_ssid_len; | 630 | size_t scan_ssid_len; |
631 | struct list_head bss_list; | 631 | struct list_head bss_list; |
632 | struct ieee80211_bss *bss_hash[STA_HASH_SIZE]; | 632 | struct ieee80211_bss *bss_hash[STA_HASH_SIZE]; |
633 | spinlock_t bss_lock; | 633 | spinlock_t bss_lock; |
634 | 634 | ||
635 | /* SNMP counters */ | 635 | /* SNMP counters */ |
636 | /* dot11CountersTable */ | 636 | /* dot11CountersTable */ |
637 | u32 dot11TransmittedFragmentCount; | 637 | u32 dot11TransmittedFragmentCount; |
638 | u32 dot11MulticastTransmittedFrameCount; | 638 | u32 dot11MulticastTransmittedFrameCount; |
639 | u32 dot11FailedCount; | 639 | u32 dot11FailedCount; |
640 | u32 dot11RetryCount; | 640 | u32 dot11RetryCount; |
641 | u32 dot11MultipleRetryCount; | 641 | u32 dot11MultipleRetryCount; |
642 | u32 dot11FrameDuplicateCount; | 642 | u32 dot11FrameDuplicateCount; |
643 | u32 dot11ReceivedFragmentCount; | 643 | u32 dot11ReceivedFragmentCount; |
644 | u32 dot11MulticastReceivedFrameCount; | 644 | u32 dot11MulticastReceivedFrameCount; |
645 | u32 dot11TransmittedFrameCount; | 645 | u32 dot11TransmittedFrameCount; |
646 | u32 dot11WEPUndecryptableCount; | 646 | u32 dot11WEPUndecryptableCount; |
647 | 647 | ||
648 | #ifdef CONFIG_MAC80211_LEDS | 648 | #ifdef CONFIG_MAC80211_LEDS |
649 | int tx_led_counter, rx_led_counter; | 649 | int tx_led_counter, rx_led_counter; |
650 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; | 650 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; |
651 | char tx_led_name[32], rx_led_name[32], | 651 | char tx_led_name[32], rx_led_name[32], |
652 | assoc_led_name[32], radio_led_name[32]; | 652 | assoc_led_name[32], radio_led_name[32]; |
653 | #endif | 653 | #endif |
654 | 654 | ||
655 | #ifdef CONFIG_MAC80211_DEBUGFS | 655 | #ifdef CONFIG_MAC80211_DEBUGFS |
656 | struct work_struct sta_debugfs_add; | 656 | struct work_struct sta_debugfs_add; |
657 | #endif | 657 | #endif |
658 | 658 | ||
659 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 659 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
660 | /* TX/RX handler statistics */ | 660 | /* TX/RX handler statistics */ |
661 | unsigned int tx_handlers_drop; | 661 | unsigned int tx_handlers_drop; |
662 | unsigned int tx_handlers_queued; | 662 | unsigned int tx_handlers_queued; |
663 | unsigned int tx_handlers_drop_unencrypted; | 663 | unsigned int tx_handlers_drop_unencrypted; |
664 | unsigned int tx_handlers_drop_fragment; | 664 | unsigned int tx_handlers_drop_fragment; |
665 | unsigned int tx_handlers_drop_wep; | 665 | unsigned int tx_handlers_drop_wep; |
666 | unsigned int tx_handlers_drop_not_assoc; | 666 | unsigned int tx_handlers_drop_not_assoc; |
667 | unsigned int tx_handlers_drop_unauth_port; | 667 | unsigned int tx_handlers_drop_unauth_port; |
668 | unsigned int rx_handlers_drop; | 668 | unsigned int rx_handlers_drop; |
669 | unsigned int rx_handlers_queued; | 669 | unsigned int rx_handlers_queued; |
670 | unsigned int rx_handlers_drop_nullfunc; | 670 | unsigned int rx_handlers_drop_nullfunc; |
671 | unsigned int rx_handlers_drop_defrag; | 671 | unsigned int rx_handlers_drop_defrag; |
672 | unsigned int rx_handlers_drop_short; | 672 | unsigned int rx_handlers_drop_short; |
673 | unsigned int rx_handlers_drop_passive_scan; | 673 | unsigned int rx_handlers_drop_passive_scan; |
674 | unsigned int tx_expand_skb_head; | 674 | unsigned int tx_expand_skb_head; |
675 | unsigned int tx_expand_skb_head_cloned; | 675 | unsigned int tx_expand_skb_head_cloned; |
676 | unsigned int rx_expand_skb_head; | 676 | unsigned int rx_expand_skb_head; |
677 | unsigned int rx_expand_skb_head2; | 677 | unsigned int rx_expand_skb_head2; |
678 | unsigned int rx_handlers_fragments; | 678 | unsigned int rx_handlers_fragments; |
679 | unsigned int tx_status_drop; | 679 | unsigned int tx_status_drop; |
680 | #define I802_DEBUG_INC(c) (c)++ | 680 | #define I802_DEBUG_INC(c) (c)++ |
681 | #else /* CONFIG_MAC80211_DEBUG_COUNTERS */ | 681 | #else /* CONFIG_MAC80211_DEBUG_COUNTERS */ |
682 | #define I802_DEBUG_INC(c) do { } while (0) | 682 | #define I802_DEBUG_INC(c) do { } while (0) |
683 | #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ | 683 | #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ |
684 | 684 | ||
685 | 685 | ||
686 | int total_ps_buffered; /* total number of all buffered unicast and | 686 | int total_ps_buffered; /* total number of all buffered unicast and |
687 | * multicast packets for power saving stations | 687 | * multicast packets for power saving stations |
688 | */ | 688 | */ |
689 | int wifi_wme_noack_test; | 689 | int wifi_wme_noack_test; |
690 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 690 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
691 | 691 | ||
692 | #ifdef CONFIG_MAC80211_DEBUGFS | 692 | #ifdef CONFIG_MAC80211_DEBUGFS |
693 | struct local_debugfsdentries { | 693 | struct local_debugfsdentries { |
694 | struct dentry *rcdir; | 694 | struct dentry *rcdir; |
695 | struct dentry *rcname; | 695 | struct dentry *rcname; |
696 | struct dentry *frequency; | 696 | struct dentry *frequency; |
697 | struct dentry *rts_threshold; | 697 | struct dentry *rts_threshold; |
698 | struct dentry *fragmentation_threshold; | 698 | struct dentry *fragmentation_threshold; |
699 | struct dentry *short_retry_limit; | 699 | struct dentry *short_retry_limit; |
700 | struct dentry *long_retry_limit; | 700 | struct dentry *long_retry_limit; |
701 | struct dentry *total_ps_buffered; | 701 | struct dentry *total_ps_buffered; |
702 | struct dentry *wep_iv; | 702 | struct dentry *wep_iv; |
703 | struct dentry *statistics; | 703 | struct dentry *statistics; |
704 | struct local_debugfsdentries_statsdentries { | 704 | struct local_debugfsdentries_statsdentries { |
705 | struct dentry *transmitted_fragment_count; | 705 | struct dentry *transmitted_fragment_count; |
706 | struct dentry *multicast_transmitted_frame_count; | 706 | struct dentry *multicast_transmitted_frame_count; |
707 | struct dentry *failed_count; | 707 | struct dentry *failed_count; |
708 | struct dentry *retry_count; | 708 | struct dentry *retry_count; |
709 | struct dentry *multiple_retry_count; | 709 | struct dentry *multiple_retry_count; |
710 | struct dentry *frame_duplicate_count; | 710 | struct dentry *frame_duplicate_count; |
711 | struct dentry *received_fragment_count; | 711 | struct dentry *received_fragment_count; |
712 | struct dentry *multicast_received_frame_count; | 712 | struct dentry *multicast_received_frame_count; |
713 | struct dentry *transmitted_frame_count; | 713 | struct dentry *transmitted_frame_count; |
714 | struct dentry *wep_undecryptable_count; | 714 | struct dentry *wep_undecryptable_count; |
715 | struct dentry *num_scans; | 715 | struct dentry *num_scans; |
716 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 716 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
717 | struct dentry *tx_handlers_drop; | 717 | struct dentry *tx_handlers_drop; |
718 | struct dentry *tx_handlers_queued; | 718 | struct dentry *tx_handlers_queued; |
719 | struct dentry *tx_handlers_drop_unencrypted; | 719 | struct dentry *tx_handlers_drop_unencrypted; |
720 | struct dentry *tx_handlers_drop_fragment; | 720 | struct dentry *tx_handlers_drop_fragment; |
721 | struct dentry *tx_handlers_drop_wep; | 721 | struct dentry *tx_handlers_drop_wep; |
722 | struct dentry *tx_handlers_drop_not_assoc; | 722 | struct dentry *tx_handlers_drop_not_assoc; |
723 | struct dentry *tx_handlers_drop_unauth_port; | 723 | struct dentry *tx_handlers_drop_unauth_port; |
724 | struct dentry *rx_handlers_drop; | 724 | struct dentry *rx_handlers_drop; |
725 | struct dentry *rx_handlers_queued; | 725 | struct dentry *rx_handlers_queued; |
726 | struct dentry *rx_handlers_drop_nullfunc; | 726 | struct dentry *rx_handlers_drop_nullfunc; |
727 | struct dentry *rx_handlers_drop_defrag; | 727 | struct dentry *rx_handlers_drop_defrag; |
728 | struct dentry *rx_handlers_drop_short; | 728 | struct dentry *rx_handlers_drop_short; |
729 | struct dentry *rx_handlers_drop_passive_scan; | 729 | struct dentry *rx_handlers_drop_passive_scan; |
730 | struct dentry *tx_expand_skb_head; | 730 | struct dentry *tx_expand_skb_head; |
731 | struct dentry *tx_expand_skb_head_cloned; | 731 | struct dentry *tx_expand_skb_head_cloned; |
732 | struct dentry *rx_expand_skb_head; | 732 | struct dentry *rx_expand_skb_head; |
733 | struct dentry *rx_expand_skb_head2; | 733 | struct dentry *rx_expand_skb_head2; |
734 | struct dentry *rx_handlers_fragments; | 734 | struct dentry *rx_handlers_fragments; |
735 | struct dentry *tx_status_drop; | 735 | struct dentry *tx_status_drop; |
736 | #endif | 736 | #endif |
737 | struct dentry *dot11ACKFailureCount; | 737 | struct dentry *dot11ACKFailureCount; |
738 | struct dentry *dot11RTSFailureCount; | 738 | struct dentry *dot11RTSFailureCount; |
739 | struct dentry *dot11FCSErrorCount; | 739 | struct dentry *dot11FCSErrorCount; |
740 | struct dentry *dot11RTSSuccessCount; | 740 | struct dentry *dot11RTSSuccessCount; |
741 | } stats; | 741 | } stats; |
742 | struct dentry *stations; | 742 | struct dentry *stations; |
743 | struct dentry *keys; | 743 | struct dentry *keys; |
744 | } debugfs; | 744 | } debugfs; |
745 | #endif | 745 | #endif |
746 | }; | 746 | }; |
747 | 747 | ||
748 | static inline struct ieee80211_sub_if_data * | 748 | static inline struct ieee80211_sub_if_data * |
749 | IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) | 749 | IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) |
750 | { | 750 | { |
751 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 751 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
752 | 752 | ||
753 | BUG_ON(!local || local->mdev == dev); | 753 | BUG_ON(!local || local->mdev == dev); |
754 | 754 | ||
755 | return netdev_priv(dev); | 755 | return netdev_priv(dev); |
756 | } | 756 | } |
757 | 757 | ||
758 | /* this struct represents 802.11n's RA/TID combination */ | 758 | /* this struct represents 802.11n's RA/TID combination */ |
759 | struct ieee80211_ra_tid { | 759 | struct ieee80211_ra_tid { |
760 | u8 ra[ETH_ALEN]; | 760 | u8 ra[ETH_ALEN]; |
761 | u16 tid; | 761 | u16 tid; |
762 | }; | 762 | }; |
763 | 763 | ||
764 | /* Parsed Information Elements */ | 764 | /* Parsed Information Elements */ |
765 | struct ieee802_11_elems { | 765 | struct ieee802_11_elems { |
766 | u8 *ie_start; | 766 | u8 *ie_start; |
767 | size_t total_len; | 767 | size_t total_len; |
768 | 768 | ||
769 | /* pointers to IEs */ | 769 | /* pointers to IEs */ |
770 | u8 *ssid; | 770 | u8 *ssid; |
771 | u8 *supp_rates; | 771 | u8 *supp_rates; |
772 | u8 *fh_params; | 772 | u8 *fh_params; |
773 | u8 *ds_params; | 773 | u8 *ds_params; |
774 | u8 *cf_params; | 774 | u8 *cf_params; |
775 | u8 *tim; | 775 | u8 *tim; |
776 | u8 *ibss_params; | 776 | u8 *ibss_params; |
777 | u8 *challenge; | 777 | u8 *challenge; |
778 | u8 *wpa; | 778 | u8 *wpa; |
779 | u8 *rsn; | 779 | u8 *rsn; |
780 | u8 *erp_info; | 780 | u8 *erp_info; |
781 | u8 *ext_supp_rates; | 781 | u8 *ext_supp_rates; |
782 | u8 *wmm_info; | 782 | u8 *wmm_info; |
783 | u8 *wmm_param; | 783 | u8 *wmm_param; |
784 | struct ieee80211_ht_cap *ht_cap_elem; | 784 | struct ieee80211_ht_cap *ht_cap_elem; |
785 | struct ieee80211_ht_info *ht_info_elem; | 785 | struct ieee80211_ht_info *ht_info_elem; |
786 | u8 *mesh_config; | 786 | u8 *mesh_config; |
787 | u8 *mesh_id; | 787 | u8 *mesh_id; |
788 | u8 *peer_link; | 788 | u8 *peer_link; |
789 | u8 *preq; | 789 | u8 *preq; |
790 | u8 *prep; | 790 | u8 *prep; |
791 | u8 *perr; | 791 | u8 *perr; |
792 | u8 *ch_switch_elem; | 792 | u8 *ch_switch_elem; |
793 | u8 *country_elem; | 793 | u8 *country_elem; |
794 | u8 *pwr_constr_elem; | 794 | u8 *pwr_constr_elem; |
795 | u8 *quiet_elem; /* first quite element */ | 795 | u8 *quiet_elem; /* first quite element */ |
796 | 796 | ||
797 | /* length of them, respectively */ | 797 | /* length of them, respectively */ |
798 | u8 ssid_len; | 798 | u8 ssid_len; |
799 | u8 supp_rates_len; | 799 | u8 supp_rates_len; |
800 | u8 fh_params_len; | 800 | u8 fh_params_len; |
801 | u8 ds_params_len; | 801 | u8 ds_params_len; |
802 | u8 cf_params_len; | 802 | u8 cf_params_len; |
803 | u8 tim_len; | 803 | u8 tim_len; |
804 | u8 ibss_params_len; | 804 | u8 ibss_params_len; |
805 | u8 challenge_len; | 805 | u8 challenge_len; |
806 | u8 wpa_len; | 806 | u8 wpa_len; |
807 | u8 rsn_len; | 807 | u8 rsn_len; |
808 | u8 erp_info_len; | 808 | u8 erp_info_len; |
809 | u8 ext_supp_rates_len; | 809 | u8 ext_supp_rates_len; |
810 | u8 wmm_info_len; | 810 | u8 wmm_info_len; |
811 | u8 wmm_param_len; | 811 | u8 wmm_param_len; |
812 | u8 mesh_config_len; | 812 | u8 mesh_config_len; |
813 | u8 mesh_id_len; | 813 | u8 mesh_id_len; |
814 | u8 peer_link_len; | 814 | u8 peer_link_len; |
815 | u8 preq_len; | 815 | u8 preq_len; |
816 | u8 prep_len; | 816 | u8 prep_len; |
817 | u8 perr_len; | 817 | u8 perr_len; |
818 | u8 ch_switch_elem_len; | 818 | u8 ch_switch_elem_len; |
819 | u8 country_elem_len; | 819 | u8 country_elem_len; |
820 | u8 pwr_constr_elem_len; | 820 | u8 pwr_constr_elem_len; |
821 | u8 quiet_elem_len; | 821 | u8 quiet_elem_len; |
822 | u8 num_of_quiet_elem; /* can be more the one */ | 822 | u8 num_of_quiet_elem; /* can be more the one */ |
823 | }; | 823 | }; |
824 | 824 | ||
825 | static inline struct ieee80211_local *hw_to_local( | 825 | static inline struct ieee80211_local *hw_to_local( |
826 | struct ieee80211_hw *hw) | 826 | struct ieee80211_hw *hw) |
827 | { | 827 | { |
828 | return container_of(hw, struct ieee80211_local, hw); | 828 | return container_of(hw, struct ieee80211_local, hw); |
829 | } | 829 | } |
830 | 830 | ||
831 | static inline struct ieee80211_hw *local_to_hw( | 831 | static inline struct ieee80211_hw *local_to_hw( |
832 | struct ieee80211_local *local) | 832 | struct ieee80211_local *local) |
833 | { | 833 | { |
834 | return &local->hw; | 834 | return &local->hw; |
835 | } | 835 | } |
836 | 836 | ||
837 | 837 | ||
838 | static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | 838 | static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) |
839 | { | 839 | { |
840 | return compare_ether_addr(raddr, addr) == 0 || | 840 | return compare_ether_addr(raddr, addr) == 0 || |
841 | is_broadcast_ether_addr(raddr); | 841 | is_broadcast_ether_addr(raddr); |
842 | } | 842 | } |
843 | 843 | ||
844 | 844 | ||
845 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); | 845 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); |
846 | int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); | 846 | int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); |
847 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | 847 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); |
848 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 848 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
849 | u32 changed); | 849 | u32 changed); |
850 | void ieee80211_configure_filter(struct ieee80211_local *local); | 850 | void ieee80211_configure_filter(struct ieee80211_local *local); |
851 | 851 | ||
852 | /* wireless extensions */ | 852 | /* wireless extensions */ |
853 | extern const struct iw_handler_def ieee80211_iw_handler_def; | 853 | extern const struct iw_handler_def ieee80211_iw_handler_def; |
854 | 854 | ||
855 | /* STA/IBSS code */ | 855 | /* STA/IBSS code */ |
856 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); | 856 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); |
857 | void ieee80211_scan_work(struct work_struct *work); | 857 | void ieee80211_scan_work(struct work_struct *work); |
858 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 858 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
859 | struct ieee80211_rx_status *rx_status); | 859 | struct ieee80211_rx_status *rx_status); |
860 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); | 860 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); |
861 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); | 861 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); |
862 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | 862 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); |
863 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 863 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, |
864 | struct ieee80211_if_sta *ifsta); | 864 | struct ieee80211_if_sta *ifsta); |
865 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 865 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
866 | u8 *bssid, u8 *addr, u64 supp_rates); | 866 | u8 *bssid, u8 *addr, u64 supp_rates); |
867 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); | 867 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); |
868 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | 868 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); |
869 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | 869 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); |
870 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | 870 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, |
871 | struct ieee802_11_elems *elems, | 871 | struct ieee802_11_elems *elems, |
872 | enum ieee80211_band band); | 872 | enum ieee80211_band band); |
873 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 873 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
874 | u8 *ssid, size_t ssid_len); | 874 | u8 *ssid, size_t ssid_len); |
875 | 875 | ||
876 | /* scan/BSS handling */ | 876 | /* scan/BSS handling */ |
877 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 877 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
878 | u8 *ssid, size_t ssid_len); | 878 | u8 *ssid, size_t ssid_len); |
879 | int ieee80211_scan_results(struct ieee80211_local *local, | 879 | int ieee80211_scan_results(struct ieee80211_local *local, |
880 | struct iw_request_info *info, | 880 | struct iw_request_info *info, |
881 | char *buf, size_t len); | 881 | char *buf, size_t len); |
882 | ieee80211_rx_result | 882 | ieee80211_rx_result |
883 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, | 883 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, |
884 | struct sk_buff *skb, | 884 | struct sk_buff *skb, |
885 | struct ieee80211_rx_status *rx_status); | 885 | struct ieee80211_rx_status *rx_status); |
886 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local); | 886 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local); |
887 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local); | 887 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local); |
888 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | 888 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
889 | char *ie, size_t len); | 889 | char *ie, size_t len); |
890 | 890 | ||
891 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 891 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
892 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 892 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, |
893 | u8 *ssid, size_t ssid_len); | 893 | u8 *ssid, size_t ssid_len); |
894 | struct ieee80211_bss * | 894 | struct ieee80211_bss * |
895 | ieee80211_bss_info_update(struct ieee80211_local *local, | 895 | ieee80211_bss_info_update(struct ieee80211_local *local, |
896 | struct ieee80211_rx_status *rx_status, | 896 | struct ieee80211_rx_status *rx_status, |
897 | struct ieee80211_mgmt *mgmt, | 897 | struct ieee80211_mgmt *mgmt, |
898 | size_t len, | 898 | size_t len, |
899 | struct ieee802_11_elems *elems, | 899 | struct ieee802_11_elems *elems, |
900 | int freq, bool beacon); | 900 | int freq, bool beacon); |
901 | struct ieee80211_bss * | 901 | struct ieee80211_bss * |
902 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | 902 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, |
903 | u8 *ssid, u8 ssid_len); | 903 | u8 *ssid, u8 ssid_len); |
904 | struct ieee80211_bss * | 904 | struct ieee80211_bss * |
905 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | 905 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, |
906 | u8 *ssid, u8 ssid_len); | 906 | u8 *ssid, u8 ssid_len); |
907 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 907 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
908 | struct ieee80211_bss *bss); | 908 | struct ieee80211_bss *bss); |
909 | 909 | ||
910 | /* interface handling */ | 910 | /* interface handling */ |
911 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 911 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
912 | struct net_device **new_dev, enum nl80211_iftype type, | 912 | struct net_device **new_dev, enum nl80211_iftype type, |
913 | struct vif_params *params); | 913 | struct vif_params *params); |
914 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 914 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
915 | enum nl80211_iftype type); | 915 | enum nl80211_iftype type); |
916 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | 916 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); |
917 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 917 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
918 | 918 | ||
919 | /* tx handling */ | 919 | /* tx handling */ |
920 | void ieee80211_clear_tx_pending(struct ieee80211_local *local); | 920 | void ieee80211_clear_tx_pending(struct ieee80211_local *local); |
921 | void ieee80211_tx_pending(unsigned long data); | 921 | void ieee80211_tx_pending(unsigned long data); |
922 | int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); | 922 | int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); |
923 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); | 923 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); |
924 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); | 924 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); |
925 | 925 | ||
926 | /* HT */ | 926 | /* HT */ |
927 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 927 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, |
928 | struct ieee80211_ht_cap *ht_cap_ie, | 928 | struct ieee80211_ht_cap *ht_cap_ie, |
929 | struct ieee80211_sta_ht_cap *ht_cap); | 929 | struct ieee80211_sta_ht_cap *ht_cap); |
930 | u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | 930 | u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, |
931 | struct ieee80211_ht_info *hti, | 931 | struct ieee80211_ht_info *hti, |
932 | u16 ap_ht_cap_flags); | 932 | u16 ap_ht_cap_flags); |
933 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | 933 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); |
934 | 934 | ||
935 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | 935 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, |
936 | u16 tid, u16 initiator, u16 reason); | 936 | u16 tid, u16 initiator, u16 reason); |
937 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr); | 937 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr); |
938 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 938 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
939 | struct sta_info *sta, | 939 | struct sta_info *sta, |
940 | struct ieee80211_mgmt *mgmt, size_t len); | 940 | struct ieee80211_mgmt *mgmt, size_t len); |
941 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | 941 | void ieee80211_process_addba_resp(struct ieee80211_local *local, |
942 | struct sta_info *sta, | 942 | struct sta_info *sta, |
943 | struct ieee80211_mgmt *mgmt, | 943 | struct ieee80211_mgmt *mgmt, |
944 | size_t len); | 944 | size_t len); |
945 | void ieee80211_process_addba_request(struct ieee80211_local *local, | 945 | void ieee80211_process_addba_request(struct ieee80211_local *local, |
946 | struct sta_info *sta, | 946 | struct sta_info *sta, |
947 | struct ieee80211_mgmt *mgmt, | 947 | struct ieee80211_mgmt *mgmt, |
948 | size_t len); | 948 | size_t len); |
949 | 949 | ||
950 | /* Spectrum management */ | 950 | /* Spectrum management */ |
951 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 951 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
952 | struct ieee80211_mgmt *mgmt, | 952 | struct ieee80211_mgmt *mgmt, |
953 | size_t len); | 953 | size_t len); |
954 | 954 | ||
955 | /* utility functions/constants */ | 955 | /* utility functions/constants */ |
956 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 956 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
957 | extern const unsigned char rfc1042_header[6]; | 957 | extern const unsigned char rfc1042_header[6]; |
958 | extern const unsigned char bridge_tunnel_header[6]; | 958 | extern const unsigned char bridge_tunnel_header[6]; |
959 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 959 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
960 | enum nl80211_iftype type); | 960 | enum nl80211_iftype type); |
961 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 961 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
962 | int rate, int erp, int short_preamble); | 962 | int rate, int erp, int short_preamble); |
963 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, | 963 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, |
964 | struct ieee80211_hdr *hdr); | 964 | struct ieee80211_hdr *hdr); |
965 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); | 965 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); |
966 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 966 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
967 | int encrypt); | 967 | int encrypt); |
968 | void ieee802_11_parse_elems(u8 *start, size_t len, | 968 | void ieee802_11_parse_elems(u8 *start, size_t len, |
969 | struct ieee802_11_elems *elems); | 969 | struct ieee802_11_elems *elems); |
970 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); | 970 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); |
971 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 971 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, |
972 | enum ieee80211_band band); | 972 | enum ieee80211_band band); |
973 | 973 | ||
974 | #ifdef CONFIG_MAC80211_NOINLINE | 974 | #ifdef CONFIG_MAC80211_NOINLINE |
975 | #define debug_noinline noinline | 975 | #define debug_noinline noinline |
976 | #else | 976 | #else |
977 | #define debug_noinline | 977 | #define debug_noinline |
978 | #endif | 978 | #endif |
979 | 979 | ||
980 | #endif /* IEEE80211_I_H */ | 980 | #endif /* IEEE80211_I_H */ |
981 | 981 |
net/mac80211/main.c
1 | /* | 1 | /* |
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <net/mac80211.h> | 11 | #include <net/mac80211.h> |
12 | #include <net/ieee80211_radiotap.h> | 12 | #include <net/ieee80211_radiotap.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/bitmap.h> | 23 | #include <linux/bitmap.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "rate.h" | 28 | #include "rate.h" |
29 | #include "mesh.h" | 29 | #include "mesh.h" |
30 | #include "wep.h" | 30 | #include "wep.h" |
31 | #include "wme.h" | 31 | #include "wme.h" |
32 | #include "aes_ccm.h" | 32 | #include "aes_ccm.h" |
33 | #include "led.h" | 33 | #include "led.h" |
34 | #include "cfg.h" | 34 | #include "cfg.h" |
35 | #include "debugfs.h" | 35 | #include "debugfs.h" |
36 | #include "debugfs_netdev.h" | 36 | #include "debugfs_netdev.h" |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * For seeing transmitted packets on monitor interfaces | 39 | * For seeing transmitted packets on monitor interfaces |
40 | * we have a radiotap header too. | 40 | * we have a radiotap header too. |
41 | */ | 41 | */ |
42 | struct ieee80211_tx_status_rtap_hdr { | 42 | struct ieee80211_tx_status_rtap_hdr { |
43 | struct ieee80211_radiotap_header hdr; | 43 | struct ieee80211_radiotap_header hdr; |
44 | u8 rate; | 44 | u8 rate; |
45 | u8 padding_for_rate; | 45 | u8 padding_for_rate; |
46 | __le16 tx_flags; | 46 | __le16 tx_flags; |
47 | u8 data_retries; | 47 | u8 data_retries; |
48 | } __attribute__ ((packed)); | 48 | } __attribute__ ((packed)); |
49 | 49 | ||
50 | 50 | ||
51 | /* must be called under mdev tx lock */ | 51 | /* must be called under mdev tx lock */ |
52 | void ieee80211_configure_filter(struct ieee80211_local *local) | 52 | void ieee80211_configure_filter(struct ieee80211_local *local) |
53 | { | 53 | { |
54 | unsigned int changed_flags; | 54 | unsigned int changed_flags; |
55 | unsigned int new_flags = 0; | 55 | unsigned int new_flags = 0; |
56 | 56 | ||
57 | if (atomic_read(&local->iff_promiscs)) | 57 | if (atomic_read(&local->iff_promiscs)) |
58 | new_flags |= FIF_PROMISC_IN_BSS; | 58 | new_flags |= FIF_PROMISC_IN_BSS; |
59 | 59 | ||
60 | if (atomic_read(&local->iff_allmultis)) | 60 | if (atomic_read(&local->iff_allmultis)) |
61 | new_flags |= FIF_ALLMULTI; | 61 | new_flags |= FIF_ALLMULTI; |
62 | 62 | ||
63 | if (local->monitors) | 63 | if (local->monitors) |
64 | new_flags |= FIF_BCN_PRBRESP_PROMISC; | 64 | new_flags |= FIF_BCN_PRBRESP_PROMISC; |
65 | 65 | ||
66 | if (local->fif_fcsfail) | 66 | if (local->fif_fcsfail) |
67 | new_flags |= FIF_FCSFAIL; | 67 | new_flags |= FIF_FCSFAIL; |
68 | 68 | ||
69 | if (local->fif_plcpfail) | 69 | if (local->fif_plcpfail) |
70 | new_flags |= FIF_PLCPFAIL; | 70 | new_flags |= FIF_PLCPFAIL; |
71 | 71 | ||
72 | if (local->fif_control) | 72 | if (local->fif_control) |
73 | new_flags |= FIF_CONTROL; | 73 | new_flags |= FIF_CONTROL; |
74 | 74 | ||
75 | if (local->fif_other_bss) | 75 | if (local->fif_other_bss) |
76 | new_flags |= FIF_OTHER_BSS; | 76 | new_flags |= FIF_OTHER_BSS; |
77 | 77 | ||
78 | changed_flags = local->filter_flags ^ new_flags; | 78 | changed_flags = local->filter_flags ^ new_flags; |
79 | 79 | ||
80 | /* be a bit nasty */ | 80 | /* be a bit nasty */ |
81 | new_flags |= (1<<31); | 81 | new_flags |= (1<<31); |
82 | 82 | ||
83 | local->ops->configure_filter(local_to_hw(local), | 83 | local->ops->configure_filter(local_to_hw(local), |
84 | changed_flags, &new_flags, | 84 | changed_flags, &new_flags, |
85 | local->mdev->mc_count, | 85 | local->mdev->mc_count, |
86 | local->mdev->mc_list); | 86 | local->mdev->mc_list); |
87 | 87 | ||
88 | WARN_ON(new_flags & (1<<31)); | 88 | WARN_ON(new_flags & (1<<31)); |
89 | 89 | ||
90 | local->filter_flags = new_flags & ~(1<<31); | 90 | local->filter_flags = new_flags & ~(1<<31); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* master interface */ | 93 | /* master interface */ |
94 | 94 | ||
95 | static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) | 95 | static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) |
96 | { | 96 | { |
97 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ | 97 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ |
98 | return ETH_ALEN; | 98 | return ETH_ALEN; |
99 | } | 99 | } |
100 | 100 | ||
101 | static const struct header_ops ieee80211_header_ops = { | 101 | static const struct header_ops ieee80211_header_ops = { |
102 | .create = eth_header, | 102 | .create = eth_header, |
103 | .parse = header_parse_80211, | 103 | .parse = header_parse_80211, |
104 | .rebuild = eth_rebuild_header, | 104 | .rebuild = eth_rebuild_header, |
105 | .cache = eth_header_cache, | 105 | .cache = eth_header_cache, |
106 | .cache_update = eth_header_cache_update, | 106 | .cache_update = eth_header_cache_update, |
107 | }; | 107 | }; |
108 | 108 | ||
109 | static int ieee80211_master_open(struct net_device *dev) | 109 | static int ieee80211_master_open(struct net_device *dev) |
110 | { | 110 | { |
111 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 111 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); |
112 | struct ieee80211_local *local = mpriv->local; | 112 | struct ieee80211_local *local = mpriv->local; |
113 | struct ieee80211_sub_if_data *sdata; | 113 | struct ieee80211_sub_if_data *sdata; |
114 | int res = -EOPNOTSUPP; | 114 | int res = -EOPNOTSUPP; |
115 | 115 | ||
116 | /* we hold the RTNL here so can safely walk the list */ | 116 | /* we hold the RTNL here so can safely walk the list */ |
117 | list_for_each_entry(sdata, &local->interfaces, list) { | 117 | list_for_each_entry(sdata, &local->interfaces, list) { |
118 | if (netif_running(sdata->dev)) { | 118 | if (netif_running(sdata->dev)) { |
119 | res = 0; | 119 | res = 0; |
120 | break; | 120 | break; |
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
124 | if (res) | 124 | if (res) |
125 | return res; | 125 | return res; |
126 | 126 | ||
127 | netif_tx_start_all_queues(local->mdev); | 127 | netif_tx_start_all_queues(local->mdev); |
128 | 128 | ||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int ieee80211_master_stop(struct net_device *dev) | 132 | static int ieee80211_master_stop(struct net_device *dev) |
133 | { | 133 | { |
134 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 134 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); |
135 | struct ieee80211_local *local = mpriv->local; | 135 | struct ieee80211_local *local = mpriv->local; |
136 | struct ieee80211_sub_if_data *sdata; | 136 | struct ieee80211_sub_if_data *sdata; |
137 | 137 | ||
138 | /* we hold the RTNL here so can safely walk the list */ | 138 | /* we hold the RTNL here so can safely walk the list */ |
139 | list_for_each_entry(sdata, &local->interfaces, list) | 139 | list_for_each_entry(sdata, &local->interfaces, list) |
140 | if (netif_running(sdata->dev)) | 140 | if (netif_running(sdata->dev)) |
141 | dev_close(sdata->dev); | 141 | dev_close(sdata->dev); |
142 | 142 | ||
143 | return 0; | 143 | return 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | static void ieee80211_master_set_multicast_list(struct net_device *dev) | 146 | static void ieee80211_master_set_multicast_list(struct net_device *dev) |
147 | { | 147 | { |
148 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 148 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); |
149 | struct ieee80211_local *local = mpriv->local; | 149 | struct ieee80211_local *local = mpriv->local; |
150 | 150 | ||
151 | ieee80211_configure_filter(local); | 151 | ieee80211_configure_filter(local); |
152 | } | 152 | } |
153 | 153 | ||
154 | /* everything else */ | 154 | /* everything else */ |
155 | 155 | ||
156 | int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | 156 | int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) |
157 | { | 157 | { |
158 | struct ieee80211_local *local = sdata->local; | 158 | struct ieee80211_local *local = sdata->local; |
159 | struct ieee80211_if_conf conf; | 159 | struct ieee80211_if_conf conf; |
160 | 160 | ||
161 | if (WARN_ON(!netif_running(sdata->dev))) | 161 | if (WARN_ON(!netif_running(sdata->dev))) |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | 164 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) |
165 | return -EINVAL; | 165 | return -EINVAL; |
166 | 166 | ||
167 | if (!local->ops->config_interface) | 167 | if (!local->ops->config_interface) |
168 | return 0; | 168 | return 0; |
169 | 169 | ||
170 | memset(&conf, 0, sizeof(conf)); | 170 | memset(&conf, 0, sizeof(conf)); |
171 | conf.changed = changed; | 171 | conf.changed = changed; |
172 | 172 | ||
173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
175 | conf.bssid = sdata->u.sta.bssid; | 175 | conf.bssid = sdata->u.sta.bssid; |
176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
177 | conf.bssid = sdata->dev->dev_addr; | 177 | conf.bssid = sdata->dev->dev_addr; |
178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
179 | u8 zero[ETH_ALEN] = { 0 }; | 179 | u8 zero[ETH_ALEN] = { 0 }; |
180 | conf.bssid = zero; | 180 | conf.bssid = zero; |
181 | } else { | 181 | } else { |
182 | WARN_ON(1); | 182 | WARN_ON(1); |
183 | return -EINVAL; | 183 | return -EINVAL; |
184 | } | 184 | } |
185 | 185 | ||
186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | 186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) |
187 | return -EINVAL; | 187 | return -EINVAL; |
188 | 188 | ||
189 | return local->ops->config_interface(local_to_hw(local), | 189 | return local->ops->config_interface(local_to_hw(local), |
190 | &sdata->vif, &conf); | 190 | &sdata->vif, &conf); |
191 | } | 191 | } |
192 | 192 | ||
193 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 193 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) |
194 | { | 194 | { |
195 | struct ieee80211_channel *chan; | 195 | struct ieee80211_channel *chan; |
196 | int ret = 0; | 196 | int ret = 0; |
197 | int power; | 197 | int power; |
198 | enum nl80211_sec_chan_offset sec_chan_offset; | 198 | enum nl80211_channel_type channel_type; |
199 | 199 | ||
200 | might_sleep(); | 200 | might_sleep(); |
201 | 201 | ||
202 | if (local->sw_scanning) { | 202 | if (local->sw_scanning) { |
203 | chan = local->scan_channel; | 203 | chan = local->scan_channel; |
204 | sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | 204 | channel_type = NL80211_CHAN_NO_HT; |
205 | } else { | 205 | } else { |
206 | chan = local->oper_channel; | 206 | chan = local->oper_channel; |
207 | sec_chan_offset = local->oper_sec_chan_offset; | 207 | channel_type = local->oper_channel_type; |
208 | } | 208 | } |
209 | 209 | ||
210 | if (chan != local->hw.conf.channel || | 210 | if (chan != local->hw.conf.channel || |
211 | sec_chan_offset != local->hw.conf.ht.sec_chan_offset) { | 211 | channel_type != local->hw.conf.ht.channel_type) { |
212 | local->hw.conf.channel = chan; | 212 | local->hw.conf.channel = chan; |
213 | switch (sec_chan_offset) { | 213 | local->hw.conf.ht.channel_type = channel_type; |
214 | case NL80211_SEC_CHAN_NO_HT: | 214 | switch (channel_type) { |
215 | case NL80211_CHAN_NO_HT: | ||
215 | local->hw.conf.ht.enabled = false; | 216 | local->hw.conf.ht.enabled = false; |
216 | local->hw.conf.ht.sec_chan_offset = 0; | ||
217 | break; | 217 | break; |
218 | case NL80211_SEC_CHAN_DISABLED: | 218 | case NL80211_CHAN_HT20: |
219 | case NL80211_CHAN_HT40MINUS: | ||
220 | case NL80211_CHAN_HT40PLUS: | ||
219 | local->hw.conf.ht.enabled = true; | 221 | local->hw.conf.ht.enabled = true; |
220 | local->hw.conf.ht.sec_chan_offset = 0; | ||
221 | break; | ||
222 | case NL80211_SEC_CHAN_BELOW: | ||
223 | local->hw.conf.ht.enabled = true; | ||
224 | local->hw.conf.ht.sec_chan_offset = -1; | ||
225 | break; | ||
226 | case NL80211_SEC_CHAN_ABOVE: | ||
227 | local->hw.conf.ht.enabled = true; | ||
228 | local->hw.conf.ht.sec_chan_offset = 1; | ||
229 | break; | 222 | break; |
230 | } | 223 | } |
231 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 224 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
232 | } | 225 | } |
233 | 226 | ||
234 | if (!local->hw.conf.power_level) | 227 | if (!local->hw.conf.power_level) |
235 | power = chan->max_power; | 228 | power = chan->max_power; |
236 | else | 229 | else |
237 | power = min(chan->max_power, local->hw.conf.power_level); | 230 | power = min(chan->max_power, local->hw.conf.power_level); |
238 | if (local->hw.conf.power_level != power) { | 231 | if (local->hw.conf.power_level != power) { |
239 | changed |= IEEE80211_CONF_CHANGE_POWER; | 232 | changed |= IEEE80211_CONF_CHANGE_POWER; |
240 | local->hw.conf.power_level = power; | 233 | local->hw.conf.power_level = power; |
241 | } | 234 | } |
242 | 235 | ||
243 | if (changed && local->open_count) { | 236 | if (changed && local->open_count) { |
244 | ret = local->ops->config(local_to_hw(local), changed); | 237 | ret = local->ops->config(local_to_hw(local), changed); |
245 | /* | 238 | /* |
246 | * Goal: | 239 | * Goal: |
247 | * HW reconfiguration should never fail, the driver has told | 240 | * HW reconfiguration should never fail, the driver has told |
248 | * us what it can support so it should live up to that promise. | 241 | * us what it can support so it should live up to that promise. |
249 | * | 242 | * |
250 | * Current status: | 243 | * Current status: |
251 | * rfkill is not integrated with mac80211 and a | 244 | * rfkill is not integrated with mac80211 and a |
252 | * configuration command can thus fail if hardware rfkill | 245 | * configuration command can thus fail if hardware rfkill |
253 | * is enabled | 246 | * is enabled |
254 | * | 247 | * |
255 | * FIXME: integrate rfkill with mac80211 and then add this | 248 | * FIXME: integrate rfkill with mac80211 and then add this |
256 | * WARN_ON() back | 249 | * WARN_ON() back |
257 | * | 250 | * |
258 | */ | 251 | */ |
259 | /* WARN_ON(ret); */ | 252 | /* WARN_ON(ret); */ |
260 | } | 253 | } |
261 | 254 | ||
262 | return ret; | 255 | return ret; |
263 | } | 256 | } |
264 | 257 | ||
265 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 258 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
266 | u32 changed) | 259 | u32 changed) |
267 | { | 260 | { |
268 | struct ieee80211_local *local = sdata->local; | 261 | struct ieee80211_local *local = sdata->local; |
269 | 262 | ||
270 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | 263 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) |
271 | return; | 264 | return; |
272 | 265 | ||
273 | if (!changed) | 266 | if (!changed) |
274 | return; | 267 | return; |
275 | 268 | ||
276 | if (local->ops->bss_info_changed) | 269 | if (local->ops->bss_info_changed) |
277 | local->ops->bss_info_changed(local_to_hw(local), | 270 | local->ops->bss_info_changed(local_to_hw(local), |
278 | &sdata->vif, | 271 | &sdata->vif, |
279 | &sdata->vif.bss_conf, | 272 | &sdata->vif.bss_conf, |
280 | changed); | 273 | changed); |
281 | } | 274 | } |
282 | 275 | ||
283 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 276 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
284 | { | 277 | { |
285 | sdata->vif.bss_conf.use_cts_prot = false; | 278 | sdata->vif.bss_conf.use_cts_prot = false; |
286 | sdata->vif.bss_conf.use_short_preamble = false; | 279 | sdata->vif.bss_conf.use_short_preamble = false; |
287 | sdata->vif.bss_conf.use_short_slot = false; | 280 | sdata->vif.bss_conf.use_short_slot = false; |
288 | return BSS_CHANGED_ERP_CTS_PROT | | 281 | return BSS_CHANGED_ERP_CTS_PROT | |
289 | BSS_CHANGED_ERP_PREAMBLE | | 282 | BSS_CHANGED_ERP_PREAMBLE | |
290 | BSS_CHANGED_ERP_SLOT; | 283 | BSS_CHANGED_ERP_SLOT; |
291 | } | 284 | } |
292 | 285 | ||
293 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | 286 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, |
294 | struct sk_buff *skb) | 287 | struct sk_buff *skb) |
295 | { | 288 | { |
296 | struct ieee80211_local *local = hw_to_local(hw); | 289 | struct ieee80211_local *local = hw_to_local(hw); |
297 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 290 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
298 | int tmp; | 291 | int tmp; |
299 | 292 | ||
300 | skb->dev = local->mdev; | 293 | skb->dev = local->mdev; |
301 | skb->pkt_type = IEEE80211_TX_STATUS_MSG; | 294 | skb->pkt_type = IEEE80211_TX_STATUS_MSG; |
302 | skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? | 295 | skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? |
303 | &local->skb_queue : &local->skb_queue_unreliable, skb); | 296 | &local->skb_queue : &local->skb_queue_unreliable, skb); |
304 | tmp = skb_queue_len(&local->skb_queue) + | 297 | tmp = skb_queue_len(&local->skb_queue) + |
305 | skb_queue_len(&local->skb_queue_unreliable); | 298 | skb_queue_len(&local->skb_queue_unreliable); |
306 | while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && | 299 | while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && |
307 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { | 300 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { |
308 | dev_kfree_skb_irq(skb); | 301 | dev_kfree_skb_irq(skb); |
309 | tmp--; | 302 | tmp--; |
310 | I802_DEBUG_INC(local->tx_status_drop); | 303 | I802_DEBUG_INC(local->tx_status_drop); |
311 | } | 304 | } |
312 | tasklet_schedule(&local->tasklet); | 305 | tasklet_schedule(&local->tasklet); |
313 | } | 306 | } |
314 | EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); | 307 | EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); |
315 | 308 | ||
316 | static void ieee80211_tasklet_handler(unsigned long data) | 309 | static void ieee80211_tasklet_handler(unsigned long data) |
317 | { | 310 | { |
318 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 311 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
319 | struct sk_buff *skb; | 312 | struct sk_buff *skb; |
320 | struct ieee80211_rx_status rx_status; | 313 | struct ieee80211_rx_status rx_status; |
321 | struct ieee80211_ra_tid *ra_tid; | 314 | struct ieee80211_ra_tid *ra_tid; |
322 | 315 | ||
323 | while ((skb = skb_dequeue(&local->skb_queue)) || | 316 | while ((skb = skb_dequeue(&local->skb_queue)) || |
324 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { | 317 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { |
325 | switch (skb->pkt_type) { | 318 | switch (skb->pkt_type) { |
326 | case IEEE80211_RX_MSG: | 319 | case IEEE80211_RX_MSG: |
327 | /* status is in skb->cb */ | 320 | /* status is in skb->cb */ |
328 | memcpy(&rx_status, skb->cb, sizeof(rx_status)); | 321 | memcpy(&rx_status, skb->cb, sizeof(rx_status)); |
329 | /* Clear skb->pkt_type in order to not confuse kernel | 322 | /* Clear skb->pkt_type in order to not confuse kernel |
330 | * netstack. */ | 323 | * netstack. */ |
331 | skb->pkt_type = 0; | 324 | skb->pkt_type = 0; |
332 | __ieee80211_rx(local_to_hw(local), skb, &rx_status); | 325 | __ieee80211_rx(local_to_hw(local), skb, &rx_status); |
333 | break; | 326 | break; |
334 | case IEEE80211_TX_STATUS_MSG: | 327 | case IEEE80211_TX_STATUS_MSG: |
335 | skb->pkt_type = 0; | 328 | skb->pkt_type = 0; |
336 | ieee80211_tx_status(local_to_hw(local), skb); | 329 | ieee80211_tx_status(local_to_hw(local), skb); |
337 | break; | 330 | break; |
338 | case IEEE80211_DELBA_MSG: | 331 | case IEEE80211_DELBA_MSG: |
339 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | 332 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; |
340 | ieee80211_stop_tx_ba_cb(local_to_hw(local), | 333 | ieee80211_stop_tx_ba_cb(local_to_hw(local), |
341 | ra_tid->ra, ra_tid->tid); | 334 | ra_tid->ra, ra_tid->tid); |
342 | dev_kfree_skb(skb); | 335 | dev_kfree_skb(skb); |
343 | break; | 336 | break; |
344 | case IEEE80211_ADDBA_MSG: | 337 | case IEEE80211_ADDBA_MSG: |
345 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | 338 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; |
346 | ieee80211_start_tx_ba_cb(local_to_hw(local), | 339 | ieee80211_start_tx_ba_cb(local_to_hw(local), |
347 | ra_tid->ra, ra_tid->tid); | 340 | ra_tid->ra, ra_tid->tid); |
348 | dev_kfree_skb(skb); | 341 | dev_kfree_skb(skb); |
349 | break ; | 342 | break ; |
350 | default: | 343 | default: |
351 | WARN_ON(1); | 344 | WARN_ON(1); |
352 | dev_kfree_skb(skb); | 345 | dev_kfree_skb(skb); |
353 | break; | 346 | break; |
354 | } | 347 | } |
355 | } | 348 | } |
356 | } | 349 | } |
357 | 350 | ||
358 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to | 351 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to |
359 | * make a prepared TX frame (one that has been given to hw) to look like brand | 352 | * make a prepared TX frame (one that has been given to hw) to look like brand |
360 | * new IEEE 802.11 frame that is ready to go through TX processing again. | 353 | * new IEEE 802.11 frame that is ready to go through TX processing again. |
361 | */ | 354 | */ |
362 | static void ieee80211_remove_tx_extra(struct ieee80211_local *local, | 355 | static void ieee80211_remove_tx_extra(struct ieee80211_local *local, |
363 | struct ieee80211_key *key, | 356 | struct ieee80211_key *key, |
364 | struct sk_buff *skb) | 357 | struct sk_buff *skb) |
365 | { | 358 | { |
366 | unsigned int hdrlen, iv_len, mic_len; | 359 | unsigned int hdrlen, iv_len, mic_len; |
367 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 360 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
368 | 361 | ||
369 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 362 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
370 | 363 | ||
371 | if (!key) | 364 | if (!key) |
372 | goto no_key; | 365 | goto no_key; |
373 | 366 | ||
374 | switch (key->conf.alg) { | 367 | switch (key->conf.alg) { |
375 | case ALG_WEP: | 368 | case ALG_WEP: |
376 | iv_len = WEP_IV_LEN; | 369 | iv_len = WEP_IV_LEN; |
377 | mic_len = WEP_ICV_LEN; | 370 | mic_len = WEP_ICV_LEN; |
378 | break; | 371 | break; |
379 | case ALG_TKIP: | 372 | case ALG_TKIP: |
380 | iv_len = TKIP_IV_LEN; | 373 | iv_len = TKIP_IV_LEN; |
381 | mic_len = TKIP_ICV_LEN; | 374 | mic_len = TKIP_ICV_LEN; |
382 | break; | 375 | break; |
383 | case ALG_CCMP: | 376 | case ALG_CCMP: |
384 | iv_len = CCMP_HDR_LEN; | 377 | iv_len = CCMP_HDR_LEN; |
385 | mic_len = CCMP_MIC_LEN; | 378 | mic_len = CCMP_MIC_LEN; |
386 | break; | 379 | break; |
387 | default: | 380 | default: |
388 | goto no_key; | 381 | goto no_key; |
389 | } | 382 | } |
390 | 383 | ||
391 | if (skb->len >= hdrlen + mic_len && | 384 | if (skb->len >= hdrlen + mic_len && |
392 | !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 385 | !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) |
393 | skb_trim(skb, skb->len - mic_len); | 386 | skb_trim(skb, skb->len - mic_len); |
394 | if (skb->len >= hdrlen + iv_len) { | 387 | if (skb->len >= hdrlen + iv_len) { |
395 | memmove(skb->data + iv_len, skb->data, hdrlen); | 388 | memmove(skb->data + iv_len, skb->data, hdrlen); |
396 | hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); | 389 | hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); |
397 | } | 390 | } |
398 | 391 | ||
399 | no_key: | 392 | no_key: |
400 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 393 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
401 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 394 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
402 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, | 395 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, |
403 | hdrlen - IEEE80211_QOS_CTL_LEN); | 396 | hdrlen - IEEE80211_QOS_CTL_LEN); |
404 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); | 397 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); |
405 | } | 398 | } |
406 | } | 399 | } |
407 | 400 | ||
408 | static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | 401 | static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, |
409 | struct sta_info *sta, | 402 | struct sta_info *sta, |
410 | struct sk_buff *skb) | 403 | struct sk_buff *skb) |
411 | { | 404 | { |
412 | sta->tx_filtered_count++; | 405 | sta->tx_filtered_count++; |
413 | 406 | ||
414 | /* | 407 | /* |
415 | * Clear the TX filter mask for this STA when sending the next | 408 | * Clear the TX filter mask for this STA when sending the next |
416 | * packet. If the STA went to power save mode, this will happen | 409 | * packet. If the STA went to power save mode, this will happen |
417 | * when it wakes up for the next time. | 410 | * when it wakes up for the next time. |
418 | */ | 411 | */ |
419 | set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); | 412 | set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); |
420 | 413 | ||
421 | /* | 414 | /* |
422 | * This code races in the following way: | 415 | * This code races in the following way: |
423 | * | 416 | * |
424 | * (1) STA sends frame indicating it will go to sleep and does so | 417 | * (1) STA sends frame indicating it will go to sleep and does so |
425 | * (2) hardware/firmware adds STA to filter list, passes frame up | 418 | * (2) hardware/firmware adds STA to filter list, passes frame up |
426 | * (3) hardware/firmware processes TX fifo and suppresses a frame | 419 | * (3) hardware/firmware processes TX fifo and suppresses a frame |
427 | * (4) we get TX status before having processed the frame and | 420 | * (4) we get TX status before having processed the frame and |
428 | * knowing that the STA has gone to sleep. | 421 | * knowing that the STA has gone to sleep. |
429 | * | 422 | * |
430 | * This is actually quite unlikely even when both those events are | 423 | * This is actually quite unlikely even when both those events are |
431 | * processed from interrupts coming in quickly after one another or | 424 | * processed from interrupts coming in quickly after one another or |
432 | * even at the same time because we queue both TX status events and | 425 | * even at the same time because we queue both TX status events and |
433 | * RX frames to be processed by a tasklet and process them in the | 426 | * RX frames to be processed by a tasklet and process them in the |
434 | * same order that they were received or TX status last. Hence, there | 427 | * same order that they were received or TX status last. Hence, there |
435 | * is no race as long as the frame RX is processed before the next TX | 428 | * is no race as long as the frame RX is processed before the next TX |
436 | * status, which drivers can ensure, see below. | 429 | * status, which drivers can ensure, see below. |
437 | * | 430 | * |
438 | * Note that this can only happen if the hardware or firmware can | 431 | * Note that this can only happen if the hardware or firmware can |
439 | * actually add STAs to the filter list, if this is done by the | 432 | * actually add STAs to the filter list, if this is done by the |
440 | * driver in response to set_tim() (which will only reduce the race | 433 | * driver in response to set_tim() (which will only reduce the race |
441 | * this whole filtering tries to solve, not completely solve it) | 434 | * this whole filtering tries to solve, not completely solve it) |
442 | * this situation cannot happen. | 435 | * this situation cannot happen. |
443 | * | 436 | * |
444 | * To completely solve this race drivers need to make sure that they | 437 | * To completely solve this race drivers need to make sure that they |
445 | * (a) don't mix the irq-safe/not irq-safe TX status/RX processing | 438 | * (a) don't mix the irq-safe/not irq-safe TX status/RX processing |
446 | * functions and | 439 | * functions and |
447 | * (b) always process RX events before TX status events if ordering | 440 | * (b) always process RX events before TX status events if ordering |
448 | * can be unknown, for example with different interrupt status | 441 | * can be unknown, for example with different interrupt status |
449 | * bits. | 442 | * bits. |
450 | */ | 443 | */ |
451 | if (test_sta_flags(sta, WLAN_STA_PS) && | 444 | if (test_sta_flags(sta, WLAN_STA_PS) && |
452 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 445 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { |
453 | ieee80211_remove_tx_extra(local, sta->key, skb); | 446 | ieee80211_remove_tx_extra(local, sta->key, skb); |
454 | skb_queue_tail(&sta->tx_filtered, skb); | 447 | skb_queue_tail(&sta->tx_filtered, skb); |
455 | return; | 448 | return; |
456 | } | 449 | } |
457 | 450 | ||
458 | if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { | 451 | if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { |
459 | /* Software retry the packet once */ | 452 | /* Software retry the packet once */ |
460 | skb->requeue = 1; | 453 | skb->requeue = 1; |
461 | ieee80211_remove_tx_extra(local, sta->key, skb); | 454 | ieee80211_remove_tx_extra(local, sta->key, skb); |
462 | dev_queue_xmit(skb); | 455 | dev_queue_xmit(skb); |
463 | return; | 456 | return; |
464 | } | 457 | } |
465 | 458 | ||
466 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 459 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
467 | if (net_ratelimit()) | 460 | if (net_ratelimit()) |
468 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 461 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " |
469 | "queue_len=%d PS=%d @%lu\n", | 462 | "queue_len=%d PS=%d @%lu\n", |
470 | wiphy_name(local->hw.wiphy), | 463 | wiphy_name(local->hw.wiphy), |
471 | skb_queue_len(&sta->tx_filtered), | 464 | skb_queue_len(&sta->tx_filtered), |
472 | !!test_sta_flags(sta, WLAN_STA_PS), jiffies); | 465 | !!test_sta_flags(sta, WLAN_STA_PS), jiffies); |
473 | #endif | 466 | #endif |
474 | dev_kfree_skb(skb); | 467 | dev_kfree_skb(skb); |
475 | } | 468 | } |
476 | 469 | ||
477 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 470 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) |
478 | { | 471 | { |
479 | struct sk_buff *skb2; | 472 | struct sk_buff *skb2; |
480 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 473 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
481 | struct ieee80211_local *local = hw_to_local(hw); | 474 | struct ieee80211_local *local = hw_to_local(hw); |
482 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 475 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
483 | u16 frag, type; | 476 | u16 frag, type; |
484 | __le16 fc; | 477 | __le16 fc; |
485 | struct ieee80211_supported_band *sband; | 478 | struct ieee80211_supported_band *sband; |
486 | struct ieee80211_tx_status_rtap_hdr *rthdr; | 479 | struct ieee80211_tx_status_rtap_hdr *rthdr; |
487 | struct ieee80211_sub_if_data *sdata; | 480 | struct ieee80211_sub_if_data *sdata; |
488 | struct net_device *prev_dev = NULL; | 481 | struct net_device *prev_dev = NULL; |
489 | struct sta_info *sta; | 482 | struct sta_info *sta; |
490 | int retry_count = -1, i; | 483 | int retry_count = -1, i; |
491 | 484 | ||
492 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 485 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
493 | /* the HW cannot have attempted that rate */ | 486 | /* the HW cannot have attempted that rate */ |
494 | if (i >= hw->max_rates) { | 487 | if (i >= hw->max_rates) { |
495 | info->status.rates[i].idx = -1; | 488 | info->status.rates[i].idx = -1; |
496 | info->status.rates[i].count = 0; | 489 | info->status.rates[i].count = 0; |
497 | } | 490 | } |
498 | 491 | ||
499 | retry_count += info->status.rates[i].count; | 492 | retry_count += info->status.rates[i].count; |
500 | } | 493 | } |
501 | if (retry_count < 0) | 494 | if (retry_count < 0) |
502 | retry_count = 0; | 495 | retry_count = 0; |
503 | 496 | ||
504 | rcu_read_lock(); | 497 | rcu_read_lock(); |
505 | 498 | ||
506 | sband = local->hw.wiphy->bands[info->band]; | 499 | sband = local->hw.wiphy->bands[info->band]; |
507 | 500 | ||
508 | sta = sta_info_get(local, hdr->addr1); | 501 | sta = sta_info_get(local, hdr->addr1); |
509 | 502 | ||
510 | if (sta) { | 503 | if (sta) { |
511 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 504 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
512 | test_sta_flags(sta, WLAN_STA_PS)) { | 505 | test_sta_flags(sta, WLAN_STA_PS)) { |
513 | /* | 506 | /* |
514 | * The STA is in power save mode, so assume | 507 | * The STA is in power save mode, so assume |
515 | * that this TX packet failed because of that. | 508 | * that this TX packet failed because of that. |
516 | */ | 509 | */ |
517 | ieee80211_handle_filtered_frame(local, sta, skb); | 510 | ieee80211_handle_filtered_frame(local, sta, skb); |
518 | rcu_read_unlock(); | 511 | rcu_read_unlock(); |
519 | return; | 512 | return; |
520 | } | 513 | } |
521 | 514 | ||
522 | fc = hdr->frame_control; | 515 | fc = hdr->frame_control; |
523 | 516 | ||
524 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 517 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
525 | (ieee80211_is_data_qos(fc))) { | 518 | (ieee80211_is_data_qos(fc))) { |
526 | u16 tid, ssn; | 519 | u16 tid, ssn; |
527 | u8 *qc; | 520 | u8 *qc; |
528 | 521 | ||
529 | qc = ieee80211_get_qos_ctl(hdr); | 522 | qc = ieee80211_get_qos_ctl(hdr); |
530 | tid = qc[0] & 0xf; | 523 | tid = qc[0] & 0xf; |
531 | ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) | 524 | ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) |
532 | & IEEE80211_SCTL_SEQ); | 525 | & IEEE80211_SCTL_SEQ); |
533 | ieee80211_send_bar(sta->sdata, hdr->addr1, | 526 | ieee80211_send_bar(sta->sdata, hdr->addr1, |
534 | tid, ssn); | 527 | tid, ssn); |
535 | } | 528 | } |
536 | 529 | ||
537 | if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { | 530 | if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { |
538 | ieee80211_handle_filtered_frame(local, sta, skb); | 531 | ieee80211_handle_filtered_frame(local, sta, skb); |
539 | rcu_read_unlock(); | 532 | rcu_read_unlock(); |
540 | return; | 533 | return; |
541 | } else { | 534 | } else { |
542 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) | 535 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) |
543 | sta->tx_retry_failed++; | 536 | sta->tx_retry_failed++; |
544 | sta->tx_retry_count += retry_count; | 537 | sta->tx_retry_count += retry_count; |
545 | } | 538 | } |
546 | 539 | ||
547 | rate_control_tx_status(local, sband, sta, skb); | 540 | rate_control_tx_status(local, sband, sta, skb); |
548 | } | 541 | } |
549 | 542 | ||
550 | rcu_read_unlock(); | 543 | rcu_read_unlock(); |
551 | 544 | ||
552 | ieee80211_led_tx(local, 0); | 545 | ieee80211_led_tx(local, 0); |
553 | 546 | ||
554 | /* SNMP counters | 547 | /* SNMP counters |
555 | * Fragments are passed to low-level drivers as separate skbs, so these | 548 | * Fragments are passed to low-level drivers as separate skbs, so these |
556 | * are actually fragments, not frames. Update frame counters only for | 549 | * are actually fragments, not frames. Update frame counters only for |
557 | * the first fragment of the frame. */ | 550 | * the first fragment of the frame. */ |
558 | 551 | ||
559 | frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; | 552 | frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; |
560 | type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; | 553 | type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; |
561 | 554 | ||
562 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 555 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
563 | if (frag == 0) { | 556 | if (frag == 0) { |
564 | local->dot11TransmittedFrameCount++; | 557 | local->dot11TransmittedFrameCount++; |
565 | if (is_multicast_ether_addr(hdr->addr1)) | 558 | if (is_multicast_ether_addr(hdr->addr1)) |
566 | local->dot11MulticastTransmittedFrameCount++; | 559 | local->dot11MulticastTransmittedFrameCount++; |
567 | if (retry_count > 0) | 560 | if (retry_count > 0) |
568 | local->dot11RetryCount++; | 561 | local->dot11RetryCount++; |
569 | if (retry_count > 1) | 562 | if (retry_count > 1) |
570 | local->dot11MultipleRetryCount++; | 563 | local->dot11MultipleRetryCount++; |
571 | } | 564 | } |
572 | 565 | ||
573 | /* This counter shall be incremented for an acknowledged MPDU | 566 | /* This counter shall be incremented for an acknowledged MPDU |
574 | * with an individual address in the address 1 field or an MPDU | 567 | * with an individual address in the address 1 field or an MPDU |
575 | * with a multicast address in the address 1 field of type Data | 568 | * with a multicast address in the address 1 field of type Data |
576 | * or Management. */ | 569 | * or Management. */ |
577 | if (!is_multicast_ether_addr(hdr->addr1) || | 570 | if (!is_multicast_ether_addr(hdr->addr1) || |
578 | type == IEEE80211_FTYPE_DATA || | 571 | type == IEEE80211_FTYPE_DATA || |
579 | type == IEEE80211_FTYPE_MGMT) | 572 | type == IEEE80211_FTYPE_MGMT) |
580 | local->dot11TransmittedFragmentCount++; | 573 | local->dot11TransmittedFragmentCount++; |
581 | } else { | 574 | } else { |
582 | if (frag == 0) | 575 | if (frag == 0) |
583 | local->dot11FailedCount++; | 576 | local->dot11FailedCount++; |
584 | } | 577 | } |
585 | 578 | ||
586 | /* this was a transmitted frame, but now we want to reuse it */ | 579 | /* this was a transmitted frame, but now we want to reuse it */ |
587 | skb_orphan(skb); | 580 | skb_orphan(skb); |
588 | 581 | ||
589 | /* | 582 | /* |
590 | * This is a bit racy but we can avoid a lot of work | 583 | * This is a bit racy but we can avoid a lot of work |
591 | * with this test... | 584 | * with this test... |
592 | */ | 585 | */ |
593 | if (!local->monitors && !local->cooked_mntrs) { | 586 | if (!local->monitors && !local->cooked_mntrs) { |
594 | dev_kfree_skb(skb); | 587 | dev_kfree_skb(skb); |
595 | return; | 588 | return; |
596 | } | 589 | } |
597 | 590 | ||
598 | /* send frame to monitor interfaces now */ | 591 | /* send frame to monitor interfaces now */ |
599 | 592 | ||
600 | if (skb_headroom(skb) < sizeof(*rthdr)) { | 593 | if (skb_headroom(skb) < sizeof(*rthdr)) { |
601 | printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); | 594 | printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); |
602 | dev_kfree_skb(skb); | 595 | dev_kfree_skb(skb); |
603 | return; | 596 | return; |
604 | } | 597 | } |
605 | 598 | ||
606 | rthdr = (struct ieee80211_tx_status_rtap_hdr *) | 599 | rthdr = (struct ieee80211_tx_status_rtap_hdr *) |
607 | skb_push(skb, sizeof(*rthdr)); | 600 | skb_push(skb, sizeof(*rthdr)); |
608 | 601 | ||
609 | memset(rthdr, 0, sizeof(*rthdr)); | 602 | memset(rthdr, 0, sizeof(*rthdr)); |
610 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); | 603 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); |
611 | rthdr->hdr.it_present = | 604 | rthdr->hdr.it_present = |
612 | cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | | 605 | cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | |
613 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | | 606 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | |
614 | (1 << IEEE80211_RADIOTAP_RATE)); | 607 | (1 << IEEE80211_RADIOTAP_RATE)); |
615 | 608 | ||
616 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 609 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
617 | !is_multicast_ether_addr(hdr->addr1)) | 610 | !is_multicast_ether_addr(hdr->addr1)) |
618 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); | 611 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); |
619 | 612 | ||
620 | /* | 613 | /* |
621 | * XXX: Once radiotap gets the bitmap reset thing the vendor | 614 | * XXX: Once radiotap gets the bitmap reset thing the vendor |
622 | * extensions proposal contains, we can actually report | 615 | * extensions proposal contains, we can actually report |
623 | * the whole set of tries we did. | 616 | * the whole set of tries we did. |
624 | */ | 617 | */ |
625 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || | 618 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || |
626 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) | 619 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) |
627 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); | 620 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); |
628 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) | 621 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) |
629 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); | 622 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); |
630 | if (info->status.rates[0].idx >= 0 && | 623 | if (info->status.rates[0].idx >= 0 && |
631 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) | 624 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) |
632 | rthdr->rate = sband->bitrates[ | 625 | rthdr->rate = sband->bitrates[ |
633 | info->status.rates[0].idx].bitrate / 5; | 626 | info->status.rates[0].idx].bitrate / 5; |
634 | 627 | ||
635 | /* for now report the total retry_count */ | 628 | /* for now report the total retry_count */ |
636 | rthdr->data_retries = retry_count; | 629 | rthdr->data_retries = retry_count; |
637 | 630 | ||
638 | /* XXX: is this sufficient for BPF? */ | 631 | /* XXX: is this sufficient for BPF? */ |
639 | skb_set_mac_header(skb, 0); | 632 | skb_set_mac_header(skb, 0); |
640 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 633 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
641 | skb->pkt_type = PACKET_OTHERHOST; | 634 | skb->pkt_type = PACKET_OTHERHOST; |
642 | skb->protocol = htons(ETH_P_802_2); | 635 | skb->protocol = htons(ETH_P_802_2); |
643 | memset(skb->cb, 0, sizeof(skb->cb)); | 636 | memset(skb->cb, 0, sizeof(skb->cb)); |
644 | 637 | ||
645 | rcu_read_lock(); | 638 | rcu_read_lock(); |
646 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 639 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
647 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { | 640 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { |
648 | if (!netif_running(sdata->dev)) | 641 | if (!netif_running(sdata->dev)) |
649 | continue; | 642 | continue; |
650 | 643 | ||
651 | if (prev_dev) { | 644 | if (prev_dev) { |
652 | skb2 = skb_clone(skb, GFP_ATOMIC); | 645 | skb2 = skb_clone(skb, GFP_ATOMIC); |
653 | if (skb2) { | 646 | if (skb2) { |
654 | skb2->dev = prev_dev; | 647 | skb2->dev = prev_dev; |
655 | netif_rx(skb2); | 648 | netif_rx(skb2); |
656 | } | 649 | } |
657 | } | 650 | } |
658 | 651 | ||
659 | prev_dev = sdata->dev; | 652 | prev_dev = sdata->dev; |
660 | } | 653 | } |
661 | } | 654 | } |
662 | if (prev_dev) { | 655 | if (prev_dev) { |
663 | skb->dev = prev_dev; | 656 | skb->dev = prev_dev; |
664 | netif_rx(skb); | 657 | netif_rx(skb); |
665 | skb = NULL; | 658 | skb = NULL; |
666 | } | 659 | } |
667 | rcu_read_unlock(); | 660 | rcu_read_unlock(); |
668 | dev_kfree_skb(skb); | 661 | dev_kfree_skb(skb); |
669 | } | 662 | } |
670 | EXPORT_SYMBOL(ieee80211_tx_status); | 663 | EXPORT_SYMBOL(ieee80211_tx_status); |
671 | 664 | ||
672 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 665 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
673 | const struct ieee80211_ops *ops) | 666 | const struct ieee80211_ops *ops) |
674 | { | 667 | { |
675 | struct ieee80211_local *local; | 668 | struct ieee80211_local *local; |
676 | int priv_size; | 669 | int priv_size; |
677 | struct wiphy *wiphy; | 670 | struct wiphy *wiphy; |
678 | 671 | ||
679 | /* Ensure 32-byte alignment of our private data and hw private data. | 672 | /* Ensure 32-byte alignment of our private data and hw private data. |
680 | * We use the wiphy priv data for both our ieee80211_local and for | 673 | * We use the wiphy priv data for both our ieee80211_local and for |
681 | * the driver's private data | 674 | * the driver's private data |
682 | * | 675 | * |
683 | * In memory it'll be like this: | 676 | * In memory it'll be like this: |
684 | * | 677 | * |
685 | * +-------------------------+ | 678 | * +-------------------------+ |
686 | * | struct wiphy | | 679 | * | struct wiphy | |
687 | * +-------------------------+ | 680 | * +-------------------------+ |
688 | * | struct ieee80211_local | | 681 | * | struct ieee80211_local | |
689 | * +-------------------------+ | 682 | * +-------------------------+ |
690 | * | driver's private data | | 683 | * | driver's private data | |
691 | * +-------------------------+ | 684 | * +-------------------------+ |
692 | * | 685 | * |
693 | */ | 686 | */ |
694 | priv_size = ((sizeof(struct ieee80211_local) + | 687 | priv_size = ((sizeof(struct ieee80211_local) + |
695 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + | 688 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + |
696 | priv_data_len; | 689 | priv_data_len; |
697 | 690 | ||
698 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); | 691 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); |
699 | 692 | ||
700 | if (!wiphy) | 693 | if (!wiphy) |
701 | return NULL; | 694 | return NULL; |
702 | 695 | ||
703 | wiphy->privid = mac80211_wiphy_privid; | 696 | wiphy->privid = mac80211_wiphy_privid; |
704 | 697 | ||
705 | local = wiphy_priv(wiphy); | 698 | local = wiphy_priv(wiphy); |
706 | local->hw.wiphy = wiphy; | 699 | local->hw.wiphy = wiphy; |
707 | 700 | ||
708 | local->hw.priv = (char *)local + | 701 | local->hw.priv = (char *)local + |
709 | ((sizeof(struct ieee80211_local) + | 702 | ((sizeof(struct ieee80211_local) + |
710 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); | 703 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); |
711 | 704 | ||
712 | BUG_ON(!ops->tx); | 705 | BUG_ON(!ops->tx); |
713 | BUG_ON(!ops->start); | 706 | BUG_ON(!ops->start); |
714 | BUG_ON(!ops->stop); | 707 | BUG_ON(!ops->stop); |
715 | BUG_ON(!ops->config); | 708 | BUG_ON(!ops->config); |
716 | BUG_ON(!ops->add_interface); | 709 | BUG_ON(!ops->add_interface); |
717 | BUG_ON(!ops->remove_interface); | 710 | BUG_ON(!ops->remove_interface); |
718 | BUG_ON(!ops->configure_filter); | 711 | BUG_ON(!ops->configure_filter); |
719 | local->ops = ops; | 712 | local->ops = ops; |
720 | 713 | ||
721 | /* set up some defaults */ | 714 | /* set up some defaults */ |
722 | local->hw.queues = 1; | 715 | local->hw.queues = 1; |
723 | local->hw.max_rates = 1; | 716 | local->hw.max_rates = 1; |
724 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 717 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
725 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | 718 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; |
726 | local->hw.conf.long_frame_max_tx_count = 4; | 719 | local->hw.conf.long_frame_max_tx_count = 4; |
727 | local->hw.conf.short_frame_max_tx_count = 7; | 720 | local->hw.conf.short_frame_max_tx_count = 7; |
728 | local->hw.conf.radio_enabled = true; | 721 | local->hw.conf.radio_enabled = true; |
729 | 722 | ||
730 | INIT_LIST_HEAD(&local->interfaces); | 723 | INIT_LIST_HEAD(&local->interfaces); |
731 | 724 | ||
732 | spin_lock_init(&local->key_lock); | 725 | spin_lock_init(&local->key_lock); |
733 | 726 | ||
734 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 727 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
735 | 728 | ||
736 | sta_info_init(local); | 729 | sta_info_init(local); |
737 | 730 | ||
738 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 731 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
739 | (unsigned long)local); | 732 | (unsigned long)local); |
740 | tasklet_disable(&local->tx_pending_tasklet); | 733 | tasklet_disable(&local->tx_pending_tasklet); |
741 | 734 | ||
742 | tasklet_init(&local->tasklet, | 735 | tasklet_init(&local->tasklet, |
743 | ieee80211_tasklet_handler, | 736 | ieee80211_tasklet_handler, |
744 | (unsigned long) local); | 737 | (unsigned long) local); |
745 | tasklet_disable(&local->tasklet); | 738 | tasklet_disable(&local->tasklet); |
746 | 739 | ||
747 | skb_queue_head_init(&local->skb_queue); | 740 | skb_queue_head_init(&local->skb_queue); |
748 | skb_queue_head_init(&local->skb_queue_unreliable); | 741 | skb_queue_head_init(&local->skb_queue_unreliable); |
749 | 742 | ||
750 | return local_to_hw(local); | 743 | return local_to_hw(local); |
751 | } | 744 | } |
752 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 745 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
753 | 746 | ||
754 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 747 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
755 | { | 748 | { |
756 | struct ieee80211_local *local = hw_to_local(hw); | 749 | struct ieee80211_local *local = hw_to_local(hw); |
757 | int result; | 750 | int result; |
758 | enum ieee80211_band band; | 751 | enum ieee80211_band band; |
759 | struct net_device *mdev; | 752 | struct net_device *mdev; |
760 | struct ieee80211_master_priv *mpriv; | 753 | struct ieee80211_master_priv *mpriv; |
761 | 754 | ||
762 | /* | 755 | /* |
763 | * generic code guarantees at least one band, | 756 | * generic code guarantees at least one band, |
764 | * set this very early because much code assumes | 757 | * set this very early because much code assumes |
765 | * that hw.conf.channel is assigned | 758 | * that hw.conf.channel is assigned |
766 | */ | 759 | */ |
767 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 760 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
768 | struct ieee80211_supported_band *sband; | 761 | struct ieee80211_supported_band *sband; |
769 | 762 | ||
770 | sband = local->hw.wiphy->bands[band]; | 763 | sband = local->hw.wiphy->bands[band]; |
771 | if (sband) { | 764 | if (sband) { |
772 | /* init channel we're on */ | 765 | /* init channel we're on */ |
773 | local->hw.conf.channel = | 766 | local->hw.conf.channel = |
774 | local->oper_channel = | 767 | local->oper_channel = |
775 | local->scan_channel = &sband->channels[0]; | 768 | local->scan_channel = &sband->channels[0]; |
776 | break; | 769 | break; |
777 | } | 770 | } |
778 | } | 771 | } |
779 | 772 | ||
780 | /* if low-level driver supports AP, we also support VLAN */ | 773 | /* if low-level driver supports AP, we also support VLAN */ |
781 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 774 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) |
782 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 775 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
783 | 776 | ||
784 | /* mac80211 always supports monitor */ | 777 | /* mac80211 always supports monitor */ |
785 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 778 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
786 | 779 | ||
787 | result = wiphy_register(local->hw.wiphy); | 780 | result = wiphy_register(local->hw.wiphy); |
788 | if (result < 0) | 781 | if (result < 0) |
789 | return result; | 782 | return result; |
790 | 783 | ||
791 | /* | 784 | /* |
792 | * We use the number of queues for feature tests (QoS, HT) internally | 785 | * We use the number of queues for feature tests (QoS, HT) internally |
793 | * so restrict them appropriately. | 786 | * so restrict them appropriately. |
794 | */ | 787 | */ |
795 | if (hw->queues > IEEE80211_MAX_QUEUES) | 788 | if (hw->queues > IEEE80211_MAX_QUEUES) |
796 | hw->queues = IEEE80211_MAX_QUEUES; | 789 | hw->queues = IEEE80211_MAX_QUEUES; |
797 | if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) | 790 | if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) |
798 | hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; | 791 | hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; |
799 | if (hw->queues < 4) | 792 | if (hw->queues < 4) |
800 | hw->ampdu_queues = 0; | 793 | hw->ampdu_queues = 0; |
801 | 794 | ||
802 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 795 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
803 | "wmaster%d", ether_setup, | 796 | "wmaster%d", ether_setup, |
804 | ieee80211_num_queues(hw)); | 797 | ieee80211_num_queues(hw)); |
805 | if (!mdev) | 798 | if (!mdev) |
806 | goto fail_mdev_alloc; | 799 | goto fail_mdev_alloc; |
807 | 800 | ||
808 | mpriv = netdev_priv(mdev); | 801 | mpriv = netdev_priv(mdev); |
809 | mpriv->local = local; | 802 | mpriv->local = local; |
810 | local->mdev = mdev; | 803 | local->mdev = mdev; |
811 | 804 | ||
812 | ieee80211_rx_bss_list_init(local); | 805 | ieee80211_rx_bss_list_init(local); |
813 | 806 | ||
814 | mdev->hard_start_xmit = ieee80211_master_start_xmit; | 807 | mdev->hard_start_xmit = ieee80211_master_start_xmit; |
815 | mdev->open = ieee80211_master_open; | 808 | mdev->open = ieee80211_master_open; |
816 | mdev->stop = ieee80211_master_stop; | 809 | mdev->stop = ieee80211_master_stop; |
817 | mdev->type = ARPHRD_IEEE80211; | 810 | mdev->type = ARPHRD_IEEE80211; |
818 | mdev->header_ops = &ieee80211_header_ops; | 811 | mdev->header_ops = &ieee80211_header_ops; |
819 | mdev->set_multicast_list = ieee80211_master_set_multicast_list; | 812 | mdev->set_multicast_list = ieee80211_master_set_multicast_list; |
820 | 813 | ||
821 | local->hw.workqueue = | 814 | local->hw.workqueue = |
822 | create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); | 815 | create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); |
823 | if (!local->hw.workqueue) { | 816 | if (!local->hw.workqueue) { |
824 | result = -ENOMEM; | 817 | result = -ENOMEM; |
825 | goto fail_workqueue; | 818 | goto fail_workqueue; |
826 | } | 819 | } |
827 | 820 | ||
828 | /* | 821 | /* |
829 | * The hardware needs headroom for sending the frame, | 822 | * The hardware needs headroom for sending the frame, |
830 | * and we need some headroom for passing the frame to monitor | 823 | * and we need some headroom for passing the frame to monitor |
831 | * interfaces, but never both at the same time. | 824 | * interfaces, but never both at the same time. |
832 | */ | 825 | */ |
833 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, | 826 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, |
834 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 827 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
835 | 828 | ||
836 | debugfs_hw_add(local); | 829 | debugfs_hw_add(local); |
837 | 830 | ||
838 | if (local->hw.conf.beacon_int < 10) | 831 | if (local->hw.conf.beacon_int < 10) |
839 | local->hw.conf.beacon_int = 100; | 832 | local->hw.conf.beacon_int = 100; |
840 | 833 | ||
841 | if (local->hw.max_listen_interval == 0) | 834 | if (local->hw.max_listen_interval == 0) |
842 | local->hw.max_listen_interval = 1; | 835 | local->hw.max_listen_interval = 1; |
843 | 836 | ||
844 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 837 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
845 | 838 | ||
846 | local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | 839 | local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | |
847 | IEEE80211_HW_SIGNAL_DB | | 840 | IEEE80211_HW_SIGNAL_DB | |
848 | IEEE80211_HW_SIGNAL_DBM) ? | 841 | IEEE80211_HW_SIGNAL_DBM) ? |
849 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | 842 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; |
850 | local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | 843 | local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? |
851 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | 844 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; |
852 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 845 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
853 | local->wstats_flags |= IW_QUAL_DBM; | 846 | local->wstats_flags |= IW_QUAL_DBM; |
854 | 847 | ||
855 | result = sta_info_start(local); | 848 | result = sta_info_start(local); |
856 | if (result < 0) | 849 | if (result < 0) |
857 | goto fail_sta_info; | 850 | goto fail_sta_info; |
858 | 851 | ||
859 | rtnl_lock(); | 852 | rtnl_lock(); |
860 | result = dev_alloc_name(local->mdev, local->mdev->name); | 853 | result = dev_alloc_name(local->mdev, local->mdev->name); |
861 | if (result < 0) | 854 | if (result < 0) |
862 | goto fail_dev; | 855 | goto fail_dev; |
863 | 856 | ||
864 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 857 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
865 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | 858 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); |
866 | 859 | ||
867 | result = register_netdevice(local->mdev); | 860 | result = register_netdevice(local->mdev); |
868 | if (result < 0) | 861 | if (result < 0) |
869 | goto fail_dev; | 862 | goto fail_dev; |
870 | 863 | ||
871 | result = ieee80211_init_rate_ctrl_alg(local, | 864 | result = ieee80211_init_rate_ctrl_alg(local, |
872 | hw->rate_control_algorithm); | 865 | hw->rate_control_algorithm); |
873 | if (result < 0) { | 866 | if (result < 0) { |
874 | printk(KERN_DEBUG "%s: Failed to initialize rate control " | 867 | printk(KERN_DEBUG "%s: Failed to initialize rate control " |
875 | "algorithm\n", wiphy_name(local->hw.wiphy)); | 868 | "algorithm\n", wiphy_name(local->hw.wiphy)); |
876 | goto fail_rate; | 869 | goto fail_rate; |
877 | } | 870 | } |
878 | 871 | ||
879 | result = ieee80211_wep_init(local); | 872 | result = ieee80211_wep_init(local); |
880 | 873 | ||
881 | if (result < 0) { | 874 | if (result < 0) { |
882 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", | 875 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", |
883 | wiphy_name(local->hw.wiphy), result); | 876 | wiphy_name(local->hw.wiphy), result); |
884 | goto fail_wep; | 877 | goto fail_wep; |
885 | } | 878 | } |
886 | 879 | ||
887 | local->mdev->select_queue = ieee80211_select_queue; | 880 | local->mdev->select_queue = ieee80211_select_queue; |
888 | 881 | ||
889 | /* add one default STA interface if supported */ | 882 | /* add one default STA interface if supported */ |
890 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 883 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { |
891 | result = ieee80211_if_add(local, "wlan%d", NULL, | 884 | result = ieee80211_if_add(local, "wlan%d", NULL, |
892 | NL80211_IFTYPE_STATION, NULL); | 885 | NL80211_IFTYPE_STATION, NULL); |
893 | if (result) | 886 | if (result) |
894 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", | 887 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", |
895 | wiphy_name(local->hw.wiphy)); | 888 | wiphy_name(local->hw.wiphy)); |
896 | } | 889 | } |
897 | 890 | ||
898 | rtnl_unlock(); | 891 | rtnl_unlock(); |
899 | 892 | ||
900 | ieee80211_led_init(local); | 893 | ieee80211_led_init(local); |
901 | 894 | ||
902 | return 0; | 895 | return 0; |
903 | 896 | ||
904 | fail_wep: | 897 | fail_wep: |
905 | rate_control_deinitialize(local); | 898 | rate_control_deinitialize(local); |
906 | fail_rate: | 899 | fail_rate: |
907 | unregister_netdevice(local->mdev); | 900 | unregister_netdevice(local->mdev); |
908 | local->mdev = NULL; | 901 | local->mdev = NULL; |
909 | fail_dev: | 902 | fail_dev: |
910 | rtnl_unlock(); | 903 | rtnl_unlock(); |
911 | sta_info_stop(local); | 904 | sta_info_stop(local); |
912 | fail_sta_info: | 905 | fail_sta_info: |
913 | debugfs_hw_del(local); | 906 | debugfs_hw_del(local); |
914 | destroy_workqueue(local->hw.workqueue); | 907 | destroy_workqueue(local->hw.workqueue); |
915 | fail_workqueue: | 908 | fail_workqueue: |
916 | if (local->mdev) | 909 | if (local->mdev) |
917 | free_netdev(local->mdev); | 910 | free_netdev(local->mdev); |
918 | fail_mdev_alloc: | 911 | fail_mdev_alloc: |
919 | wiphy_unregister(local->hw.wiphy); | 912 | wiphy_unregister(local->hw.wiphy); |
920 | return result; | 913 | return result; |
921 | } | 914 | } |
922 | EXPORT_SYMBOL(ieee80211_register_hw); | 915 | EXPORT_SYMBOL(ieee80211_register_hw); |
923 | 916 | ||
924 | void ieee80211_unregister_hw(struct ieee80211_hw *hw) | 917 | void ieee80211_unregister_hw(struct ieee80211_hw *hw) |
925 | { | 918 | { |
926 | struct ieee80211_local *local = hw_to_local(hw); | 919 | struct ieee80211_local *local = hw_to_local(hw); |
927 | 920 | ||
928 | tasklet_kill(&local->tx_pending_tasklet); | 921 | tasklet_kill(&local->tx_pending_tasklet); |
929 | tasklet_kill(&local->tasklet); | 922 | tasklet_kill(&local->tasklet); |
930 | 923 | ||
931 | rtnl_lock(); | 924 | rtnl_lock(); |
932 | 925 | ||
933 | /* | 926 | /* |
934 | * At this point, interface list manipulations are fine | 927 | * At this point, interface list manipulations are fine |
935 | * because the driver cannot be handing us frames any | 928 | * because the driver cannot be handing us frames any |
936 | * more and the tasklet is killed. | 929 | * more and the tasklet is killed. |
937 | */ | 930 | */ |
938 | 931 | ||
939 | /* First, we remove all virtual interfaces. */ | 932 | /* First, we remove all virtual interfaces. */ |
940 | ieee80211_remove_interfaces(local); | 933 | ieee80211_remove_interfaces(local); |
941 | 934 | ||
942 | /* then, finally, remove the master interface */ | 935 | /* then, finally, remove the master interface */ |
943 | unregister_netdevice(local->mdev); | 936 | unregister_netdevice(local->mdev); |
944 | 937 | ||
945 | rtnl_unlock(); | 938 | rtnl_unlock(); |
946 | 939 | ||
947 | ieee80211_rx_bss_list_deinit(local); | 940 | ieee80211_rx_bss_list_deinit(local); |
948 | ieee80211_clear_tx_pending(local); | 941 | ieee80211_clear_tx_pending(local); |
949 | sta_info_stop(local); | 942 | sta_info_stop(local); |
950 | rate_control_deinitialize(local); | 943 | rate_control_deinitialize(local); |
951 | debugfs_hw_del(local); | 944 | debugfs_hw_del(local); |
952 | 945 | ||
953 | if (skb_queue_len(&local->skb_queue) | 946 | if (skb_queue_len(&local->skb_queue) |
954 | || skb_queue_len(&local->skb_queue_unreliable)) | 947 | || skb_queue_len(&local->skb_queue_unreliable)) |
955 | printk(KERN_WARNING "%s: skb_queue not empty\n", | 948 | printk(KERN_WARNING "%s: skb_queue not empty\n", |
956 | wiphy_name(local->hw.wiphy)); | 949 | wiphy_name(local->hw.wiphy)); |
957 | skb_queue_purge(&local->skb_queue); | 950 | skb_queue_purge(&local->skb_queue); |
958 | skb_queue_purge(&local->skb_queue_unreliable); | 951 | skb_queue_purge(&local->skb_queue_unreliable); |
959 | 952 | ||
960 | destroy_workqueue(local->hw.workqueue); | 953 | destroy_workqueue(local->hw.workqueue); |
961 | wiphy_unregister(local->hw.wiphy); | 954 | wiphy_unregister(local->hw.wiphy); |
962 | ieee80211_wep_free(local); | 955 | ieee80211_wep_free(local); |
963 | ieee80211_led_exit(local); | 956 | ieee80211_led_exit(local); |
964 | free_netdev(local->mdev); | 957 | free_netdev(local->mdev); |
965 | } | 958 | } |
966 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 959 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
967 | 960 | ||
968 | void ieee80211_free_hw(struct ieee80211_hw *hw) | 961 | void ieee80211_free_hw(struct ieee80211_hw *hw) |
969 | { | 962 | { |
970 | struct ieee80211_local *local = hw_to_local(hw); | 963 | struct ieee80211_local *local = hw_to_local(hw); |
971 | 964 | ||
972 | wiphy_free(local->hw.wiphy); | 965 | wiphy_free(local->hw.wiphy); |
973 | } | 966 | } |
974 | EXPORT_SYMBOL(ieee80211_free_hw); | 967 | EXPORT_SYMBOL(ieee80211_free_hw); |
975 | 968 | ||
976 | static int __init ieee80211_init(void) | 969 | static int __init ieee80211_init(void) |
977 | { | 970 | { |
978 | struct sk_buff *skb; | 971 | struct sk_buff *skb; |
979 | int ret; | 972 | int ret; |
980 | 973 | ||
981 | BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); | 974 | BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); |
982 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + | 975 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + |
983 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); | 976 | IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); |
984 | 977 | ||
985 | ret = rc80211_minstrel_init(); | 978 | ret = rc80211_minstrel_init(); |
986 | if (ret) | 979 | if (ret) |
987 | return ret; | 980 | return ret; |
988 | 981 | ||
989 | ret = rc80211_pid_init(); | 982 | ret = rc80211_pid_init(); |
990 | if (ret) | 983 | if (ret) |
991 | return ret; | 984 | return ret; |
992 | 985 | ||
993 | ieee80211_debugfs_netdev_init(); | 986 | ieee80211_debugfs_netdev_init(); |
994 | 987 | ||
995 | return 0; | 988 | return 0; |
996 | } | 989 | } |
997 | 990 | ||
998 | static void __exit ieee80211_exit(void) | 991 | static void __exit ieee80211_exit(void) |
999 | { | 992 | { |
1000 | rc80211_pid_exit(); | 993 | rc80211_pid_exit(); |
1001 | rc80211_minstrel_exit(); | 994 | rc80211_minstrel_exit(); |
1002 | 995 | ||
1003 | /* | 996 | /* |
1004 | * For key todo, it'll be empty by now but the work | 997 | * For key todo, it'll be empty by now but the work |
1005 | * might still be scheduled. | 998 | * might still be scheduled. |
1006 | */ | 999 | */ |
1007 | flush_scheduled_work(); | 1000 | flush_scheduled_work(); |
1008 | 1001 | ||
1009 | if (mesh_allocated) | 1002 | if (mesh_allocated) |
1010 | ieee80211s_stop(); | 1003 | ieee80211s_stop(); |
1011 | 1004 | ||
1012 | ieee80211_debugfs_netdev_exit(); | 1005 | ieee80211_debugfs_netdev_exit(); |
1013 | } | 1006 | } |
1014 | 1007 | ||
1015 | 1008 | ||
1016 | subsys_initcall(ieee80211_init); | 1009 | subsys_initcall(ieee80211_init); |
1017 | module_exit(ieee80211_exit); | 1010 | module_exit(ieee80211_exit); |
1018 | 1011 |
net/mac80211/mlme.c
1 | /* | 1 | /* |
2 | * BSS client mode implementation | 2 | * BSS client mode implementation |
3 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | 3 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> |
4 | * Copyright 2004, Instant802 Networks, Inc. | 4 | * Copyright 2004, Instant802 Networks, Inc. |
5 | * Copyright 2005, Devicescape Software, Inc. | 5 | * Copyright 2005, Devicescape Software, Inc. |
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/if_ether.h> | 15 | #include <linux/if_ether.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
18 | #include <linux/wireless.h> | 18 | #include <linux/wireless.h> |
19 | #include <linux/random.h> | 19 | #include <linux/random.h> |
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/rtnetlink.h> | 21 | #include <linux/rtnetlink.h> |
22 | #include <net/iw_handler.h> | 22 | #include <net/iw_handler.h> |
23 | #include <net/mac80211.h> | 23 | #include <net/mac80211.h> |
24 | #include <asm/unaligned.h> | 24 | #include <asm/unaligned.h> |
25 | 25 | ||
26 | #include "ieee80211_i.h" | 26 | #include "ieee80211_i.h" |
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "led.h" | 28 | #include "led.h" |
29 | 29 | ||
30 | #define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 | 30 | #define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 |
31 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 31 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
32 | #define IEEE80211_AUTH_MAX_TRIES 3 | 32 | #define IEEE80211_AUTH_MAX_TRIES 3 |
33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 34 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 36 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) |
37 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 37 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
38 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | 38 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) |
39 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | 39 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) |
40 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | 40 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) |
41 | 41 | ||
42 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 42 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
43 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 43 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
44 | 44 | ||
45 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 45 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
46 | 46 | ||
47 | 47 | ||
48 | /* utils */ | 48 | /* utils */ |
49 | static int ecw2cw(int ecw) | 49 | static int ecw2cw(int ecw) |
50 | { | 50 | { |
51 | return (1 << ecw) - 1; | 51 | return (1 << ecw) - 1; |
52 | } | 52 | } |
53 | 53 | ||
54 | static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) | 54 | static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) |
55 | { | 55 | { |
56 | u8 *end, *pos; | 56 | u8 *end, *pos; |
57 | 57 | ||
58 | pos = bss->ies; | 58 | pos = bss->ies; |
59 | if (pos == NULL) | 59 | if (pos == NULL) |
60 | return NULL; | 60 | return NULL; |
61 | end = pos + bss->ies_len; | 61 | end = pos + bss->ies_len; |
62 | 62 | ||
63 | while (pos + 1 < end) { | 63 | while (pos + 1 < end) { |
64 | if (pos + 2 + pos[1] > end) | 64 | if (pos + 2 + pos[1] > end) |
65 | break; | 65 | break; |
66 | if (pos[0] == ie) | 66 | if (pos[0] == ie) |
67 | return pos; | 67 | return pos; |
68 | pos += 2 + pos[1]; | 68 | pos += 2 + pos[1]; |
69 | } | 69 | } |
70 | 70 | ||
71 | return NULL; | 71 | return NULL; |
72 | } | 72 | } |
73 | 73 | ||
74 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | 74 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, |
75 | struct ieee80211_supported_band *sband, | 75 | struct ieee80211_supported_band *sband, |
76 | u64 *rates) | 76 | u64 *rates) |
77 | { | 77 | { |
78 | int i, j, count; | 78 | int i, j, count; |
79 | *rates = 0; | 79 | *rates = 0; |
80 | count = 0; | 80 | count = 0; |
81 | for (i = 0; i < bss->supp_rates_len; i++) { | 81 | for (i = 0; i < bss->supp_rates_len; i++) { |
82 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | 82 | int rate = (bss->supp_rates[i] & 0x7F) * 5; |
83 | 83 | ||
84 | for (j = 0; j < sband->n_bitrates; j++) | 84 | for (j = 0; j < sband->n_bitrates; j++) |
85 | if (sband->bitrates[j].bitrate == rate) { | 85 | if (sband->bitrates[j].bitrate == rate) { |
86 | *rates |= BIT(j); | 86 | *rates |= BIT(j); |
87 | count++; | 87 | count++; |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | } | 90 | } |
91 | 91 | ||
92 | return count; | 92 | return count; |
93 | } | 93 | } |
94 | 94 | ||
95 | /* also used by mesh code */ | 95 | /* also used by mesh code */ |
96 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | 96 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, |
97 | struct ieee802_11_elems *elems, | 97 | struct ieee802_11_elems *elems, |
98 | enum ieee80211_band band) | 98 | enum ieee80211_band band) |
99 | { | 99 | { |
100 | struct ieee80211_supported_band *sband; | 100 | struct ieee80211_supported_band *sband; |
101 | struct ieee80211_rate *bitrates; | 101 | struct ieee80211_rate *bitrates; |
102 | size_t num_rates; | 102 | size_t num_rates; |
103 | u64 supp_rates; | 103 | u64 supp_rates; |
104 | int i, j; | 104 | int i, j; |
105 | sband = local->hw.wiphy->bands[band]; | 105 | sband = local->hw.wiphy->bands[band]; |
106 | 106 | ||
107 | if (!sband) { | 107 | if (!sband) { |
108 | WARN_ON(1); | 108 | WARN_ON(1); |
109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
110 | } | 110 | } |
111 | 111 | ||
112 | bitrates = sband->bitrates; | 112 | bitrates = sband->bitrates; |
113 | num_rates = sband->n_bitrates; | 113 | num_rates = sband->n_bitrates; |
114 | supp_rates = 0; | 114 | supp_rates = 0; |
115 | for (i = 0; i < elems->supp_rates_len + | 115 | for (i = 0; i < elems->supp_rates_len + |
116 | elems->ext_supp_rates_len; i++) { | 116 | elems->ext_supp_rates_len; i++) { |
117 | u8 rate = 0; | 117 | u8 rate = 0; |
118 | int own_rate; | 118 | int own_rate; |
119 | if (i < elems->supp_rates_len) | 119 | if (i < elems->supp_rates_len) |
120 | rate = elems->supp_rates[i]; | 120 | rate = elems->supp_rates[i]; |
121 | else if (elems->ext_supp_rates) | 121 | else if (elems->ext_supp_rates) |
122 | rate = elems->ext_supp_rates | 122 | rate = elems->ext_supp_rates |
123 | [i - elems->supp_rates_len]; | 123 | [i - elems->supp_rates_len]; |
124 | own_rate = 5 * (rate & 0x7f); | 124 | own_rate = 5 * (rate & 0x7f); |
125 | for (j = 0; j < num_rates; j++) | 125 | for (j = 0; j < num_rates; j++) |
126 | if (bitrates[j].bitrate == own_rate) | 126 | if (bitrates[j].bitrate == own_rate) |
127 | supp_rates |= BIT(j); | 127 | supp_rates |= BIT(j); |
128 | } | 128 | } |
129 | return supp_rates; | 129 | return supp_rates; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* frame sending functions */ | 132 | /* frame sending functions */ |
133 | 133 | ||
134 | /* also used by scanning code */ | 134 | /* also used by scanning code */ |
135 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 135 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
136 | u8 *ssid, size_t ssid_len) | 136 | u8 *ssid, size_t ssid_len) |
137 | { | 137 | { |
138 | struct ieee80211_local *local = sdata->local; | 138 | struct ieee80211_local *local = sdata->local; |
139 | struct ieee80211_supported_band *sband; | 139 | struct ieee80211_supported_band *sband; |
140 | struct sk_buff *skb; | 140 | struct sk_buff *skb; |
141 | struct ieee80211_mgmt *mgmt; | 141 | struct ieee80211_mgmt *mgmt; |
142 | u8 *pos, *supp_rates, *esupp_rates = NULL; | 142 | u8 *pos, *supp_rates, *esupp_rates = NULL; |
143 | int i; | 143 | int i; |
144 | 144 | ||
145 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | 145 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); |
146 | if (!skb) { | 146 | if (!skb) { |
147 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 147 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
148 | "request\n", sdata->dev->name); | 148 | "request\n", sdata->dev->name); |
149 | return; | 149 | return; |
150 | } | 150 | } |
151 | skb_reserve(skb, local->hw.extra_tx_headroom); | 151 | skb_reserve(skb, local->hw.extra_tx_headroom); |
152 | 152 | ||
153 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 153 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
154 | memset(mgmt, 0, 24); | 154 | memset(mgmt, 0, 24); |
155 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 155 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
156 | IEEE80211_STYPE_PROBE_REQ); | 156 | IEEE80211_STYPE_PROBE_REQ); |
157 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 157 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
158 | if (dst) { | 158 | if (dst) { |
159 | memcpy(mgmt->da, dst, ETH_ALEN); | 159 | memcpy(mgmt->da, dst, ETH_ALEN); |
160 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 160 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
161 | } else { | 161 | } else { |
162 | memset(mgmt->da, 0xff, ETH_ALEN); | 162 | memset(mgmt->da, 0xff, ETH_ALEN); |
163 | memset(mgmt->bssid, 0xff, ETH_ALEN); | 163 | memset(mgmt->bssid, 0xff, ETH_ALEN); |
164 | } | 164 | } |
165 | pos = skb_put(skb, 2 + ssid_len); | 165 | pos = skb_put(skb, 2 + ssid_len); |
166 | *pos++ = WLAN_EID_SSID; | 166 | *pos++ = WLAN_EID_SSID; |
167 | *pos++ = ssid_len; | 167 | *pos++ = ssid_len; |
168 | memcpy(pos, ssid, ssid_len); | 168 | memcpy(pos, ssid, ssid_len); |
169 | 169 | ||
170 | supp_rates = skb_put(skb, 2); | 170 | supp_rates = skb_put(skb, 2); |
171 | supp_rates[0] = WLAN_EID_SUPP_RATES; | 171 | supp_rates[0] = WLAN_EID_SUPP_RATES; |
172 | supp_rates[1] = 0; | 172 | supp_rates[1] = 0; |
173 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 173 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
174 | 174 | ||
175 | for (i = 0; i < sband->n_bitrates; i++) { | 175 | for (i = 0; i < sband->n_bitrates; i++) { |
176 | struct ieee80211_rate *rate = &sband->bitrates[i]; | 176 | struct ieee80211_rate *rate = &sband->bitrates[i]; |
177 | if (esupp_rates) { | 177 | if (esupp_rates) { |
178 | pos = skb_put(skb, 1); | 178 | pos = skb_put(skb, 1); |
179 | esupp_rates[1]++; | 179 | esupp_rates[1]++; |
180 | } else if (supp_rates[1] == 8) { | 180 | } else if (supp_rates[1] == 8) { |
181 | esupp_rates = skb_put(skb, 3); | 181 | esupp_rates = skb_put(skb, 3); |
182 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | 182 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; |
183 | esupp_rates[1] = 1; | 183 | esupp_rates[1] = 1; |
184 | pos = &esupp_rates[2]; | 184 | pos = &esupp_rates[2]; |
185 | } else { | 185 | } else { |
186 | pos = skb_put(skb, 1); | 186 | pos = skb_put(skb, 1); |
187 | supp_rates[1]++; | 187 | supp_rates[1]++; |
188 | } | 188 | } |
189 | *pos = rate->bitrate / 5; | 189 | *pos = rate->bitrate / 5; |
190 | } | 190 | } |
191 | 191 | ||
192 | ieee80211_tx_skb(sdata, skb, 0); | 192 | ieee80211_tx_skb(sdata, skb, 0); |
193 | } | 193 | } |
194 | 194 | ||
195 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 195 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
196 | struct ieee80211_if_sta *ifsta, | 196 | struct ieee80211_if_sta *ifsta, |
197 | int transaction, u8 *extra, size_t extra_len, | 197 | int transaction, u8 *extra, size_t extra_len, |
198 | int encrypt) | 198 | int encrypt) |
199 | { | 199 | { |
200 | struct ieee80211_local *local = sdata->local; | 200 | struct ieee80211_local *local = sdata->local; |
201 | struct sk_buff *skb; | 201 | struct sk_buff *skb; |
202 | struct ieee80211_mgmt *mgmt; | 202 | struct ieee80211_mgmt *mgmt; |
203 | 203 | ||
204 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 204 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
205 | sizeof(*mgmt) + 6 + extra_len); | 205 | sizeof(*mgmt) + 6 + extra_len); |
206 | if (!skb) { | 206 | if (!skb) { |
207 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 207 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
208 | "frame\n", sdata->dev->name); | 208 | "frame\n", sdata->dev->name); |
209 | return; | 209 | return; |
210 | } | 210 | } |
211 | skb_reserve(skb, local->hw.extra_tx_headroom); | 211 | skb_reserve(skb, local->hw.extra_tx_headroom); |
212 | 212 | ||
213 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | 213 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); |
214 | memset(mgmt, 0, 24 + 6); | 214 | memset(mgmt, 0, 24 + 6); |
215 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 215 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
216 | IEEE80211_STYPE_AUTH); | 216 | IEEE80211_STYPE_AUTH); |
217 | if (encrypt) | 217 | if (encrypt) |
218 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 218 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
219 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 219 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); |
220 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 220 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
221 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 221 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
222 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | 222 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); |
223 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 223 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); |
224 | ifsta->auth_transaction = transaction + 1; | 224 | ifsta->auth_transaction = transaction + 1; |
225 | mgmt->u.auth.status_code = cpu_to_le16(0); | 225 | mgmt->u.auth.status_code = cpu_to_le16(0); |
226 | if (extra) | 226 | if (extra) |
227 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 227 | memcpy(skb_put(skb, extra_len), extra, extra_len); |
228 | 228 | ||
229 | ieee80211_tx_skb(sdata, skb, encrypt); | 229 | ieee80211_tx_skb(sdata, skb, encrypt); |
230 | } | 230 | } |
231 | 231 | ||
232 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | 232 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
233 | struct ieee80211_if_sta *ifsta) | 233 | struct ieee80211_if_sta *ifsta) |
234 | { | 234 | { |
235 | struct ieee80211_local *local = sdata->local; | 235 | struct ieee80211_local *local = sdata->local; |
236 | struct sk_buff *skb; | 236 | struct sk_buff *skb; |
237 | struct ieee80211_mgmt *mgmt; | 237 | struct ieee80211_mgmt *mgmt; |
238 | u8 *pos, *ies, *ht_ie; | 238 | u8 *pos, *ies, *ht_ie; |
239 | int i, len, count, rates_len, supp_rates_len; | 239 | int i, len, count, rates_len, supp_rates_len; |
240 | u16 capab; | 240 | u16 capab; |
241 | struct ieee80211_bss *bss; | 241 | struct ieee80211_bss *bss; |
242 | int wmm = 0; | 242 | int wmm = 0; |
243 | struct ieee80211_supported_band *sband; | 243 | struct ieee80211_supported_band *sband; |
244 | u64 rates = 0; | 244 | u64 rates = 0; |
245 | 245 | ||
246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
247 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 247 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + |
248 | ifsta->ssid_len); | 248 | ifsta->ssid_len); |
249 | if (!skb) { | 249 | if (!skb) { |
250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
251 | "frame\n", sdata->dev->name); | 251 | "frame\n", sdata->dev->name); |
252 | return; | 252 | return; |
253 | } | 253 | } |
254 | skb_reserve(skb, local->hw.extra_tx_headroom); | 254 | skb_reserve(skb, local->hw.extra_tx_headroom); |
255 | 255 | ||
256 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 256 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
257 | 257 | ||
258 | capab = ifsta->capab; | 258 | capab = ifsta->capab; |
259 | 259 | ||
260 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | 260 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { |
261 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | 261 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
262 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | 262 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; |
263 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | 263 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) |
264 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | 264 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
265 | } | 265 | } |
266 | 266 | ||
267 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 267 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
268 | local->hw.conf.channel->center_freq, | 268 | local->hw.conf.channel->center_freq, |
269 | ifsta->ssid, ifsta->ssid_len); | 269 | ifsta->ssid, ifsta->ssid_len); |
270 | if (bss) { | 270 | if (bss) { |
271 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | 271 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) |
272 | capab |= WLAN_CAPABILITY_PRIVACY; | 272 | capab |= WLAN_CAPABILITY_PRIVACY; |
273 | if (bss->wmm_used) | 273 | if (bss->wmm_used) |
274 | wmm = 1; | 274 | wmm = 1; |
275 | 275 | ||
276 | /* get all rates supported by the device and the AP as | 276 | /* get all rates supported by the device and the AP as |
277 | * some APs don't like getting a superset of their rates | 277 | * some APs don't like getting a superset of their rates |
278 | * in the association request (e.g. D-Link DAP 1353 in | 278 | * in the association request (e.g. D-Link DAP 1353 in |
279 | * b-only mode) */ | 279 | * b-only mode) */ |
280 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | 280 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); |
281 | 281 | ||
282 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | 282 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
283 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | 283 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
284 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | 284 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
285 | 285 | ||
286 | ieee80211_rx_bss_put(local, bss); | 286 | ieee80211_rx_bss_put(local, bss); |
287 | } else { | 287 | } else { |
288 | rates = ~0; | 288 | rates = ~0; |
289 | rates_len = sband->n_bitrates; | 289 | rates_len = sband->n_bitrates; |
290 | } | 290 | } |
291 | 291 | ||
292 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 292 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
293 | memset(mgmt, 0, 24); | 293 | memset(mgmt, 0, 24); |
294 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 294 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); |
295 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 295 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
296 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 296 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
297 | 297 | ||
298 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 298 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { |
299 | skb_put(skb, 10); | 299 | skb_put(skb, 10); |
300 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 300 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
301 | IEEE80211_STYPE_REASSOC_REQ); | 301 | IEEE80211_STYPE_REASSOC_REQ); |
302 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | 302 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
303 | mgmt->u.reassoc_req.listen_interval = | 303 | mgmt->u.reassoc_req.listen_interval = |
304 | cpu_to_le16(local->hw.conf.listen_interval); | 304 | cpu_to_le16(local->hw.conf.listen_interval); |
305 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | 305 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, |
306 | ETH_ALEN); | 306 | ETH_ALEN); |
307 | } else { | 307 | } else { |
308 | skb_put(skb, 4); | 308 | skb_put(skb, 4); |
309 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 309 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
310 | IEEE80211_STYPE_ASSOC_REQ); | 310 | IEEE80211_STYPE_ASSOC_REQ); |
311 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | 311 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); |
312 | mgmt->u.reassoc_req.listen_interval = | 312 | mgmt->u.reassoc_req.listen_interval = |
313 | cpu_to_le16(local->hw.conf.listen_interval); | 313 | cpu_to_le16(local->hw.conf.listen_interval); |
314 | } | 314 | } |
315 | 315 | ||
316 | /* SSID */ | 316 | /* SSID */ |
317 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | 317 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); |
318 | *pos++ = WLAN_EID_SSID; | 318 | *pos++ = WLAN_EID_SSID; |
319 | *pos++ = ifsta->ssid_len; | 319 | *pos++ = ifsta->ssid_len; |
320 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 320 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); |
321 | 321 | ||
322 | /* add all rates which were marked to be used above */ | 322 | /* add all rates which were marked to be used above */ |
323 | supp_rates_len = rates_len; | 323 | supp_rates_len = rates_len; |
324 | if (supp_rates_len > 8) | 324 | if (supp_rates_len > 8) |
325 | supp_rates_len = 8; | 325 | supp_rates_len = 8; |
326 | 326 | ||
327 | len = sband->n_bitrates; | 327 | len = sband->n_bitrates; |
328 | pos = skb_put(skb, supp_rates_len + 2); | 328 | pos = skb_put(skb, supp_rates_len + 2); |
329 | *pos++ = WLAN_EID_SUPP_RATES; | 329 | *pos++ = WLAN_EID_SUPP_RATES; |
330 | *pos++ = supp_rates_len; | 330 | *pos++ = supp_rates_len; |
331 | 331 | ||
332 | count = 0; | 332 | count = 0; |
333 | for (i = 0; i < sband->n_bitrates; i++) { | 333 | for (i = 0; i < sband->n_bitrates; i++) { |
334 | if (BIT(i) & rates) { | 334 | if (BIT(i) & rates) { |
335 | int rate = sband->bitrates[i].bitrate; | 335 | int rate = sband->bitrates[i].bitrate; |
336 | *pos++ = (u8) (rate / 5); | 336 | *pos++ = (u8) (rate / 5); |
337 | if (++count == 8) | 337 | if (++count == 8) |
338 | break; | 338 | break; |
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | if (rates_len > count) { | 342 | if (rates_len > count) { |
343 | pos = skb_put(skb, rates_len - count + 2); | 343 | pos = skb_put(skb, rates_len - count + 2); |
344 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 344 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
345 | *pos++ = rates_len - count; | 345 | *pos++ = rates_len - count; |
346 | 346 | ||
347 | for (i++; i < sband->n_bitrates; i++) { | 347 | for (i++; i < sband->n_bitrates; i++) { |
348 | if (BIT(i) & rates) { | 348 | if (BIT(i) & rates) { |
349 | int rate = sband->bitrates[i].bitrate; | 349 | int rate = sband->bitrates[i].bitrate; |
350 | *pos++ = (u8) (rate / 5); | 350 | *pos++ = (u8) (rate / 5); |
351 | } | 351 | } |
352 | } | 352 | } |
353 | } | 353 | } |
354 | 354 | ||
355 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | 355 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { |
356 | /* 1. power capabilities */ | 356 | /* 1. power capabilities */ |
357 | pos = skb_put(skb, 4); | 357 | pos = skb_put(skb, 4); |
358 | *pos++ = WLAN_EID_PWR_CAPABILITY; | 358 | *pos++ = WLAN_EID_PWR_CAPABILITY; |
359 | *pos++ = 2; | 359 | *pos++ = 2; |
360 | *pos++ = 0; /* min tx power */ | 360 | *pos++ = 0; /* min tx power */ |
361 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | 361 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ |
362 | 362 | ||
363 | /* 2. supported channels */ | 363 | /* 2. supported channels */ |
364 | /* TODO: get this in reg domain format */ | 364 | /* TODO: get this in reg domain format */ |
365 | pos = skb_put(skb, 2 * sband->n_channels + 2); | 365 | pos = skb_put(skb, 2 * sband->n_channels + 2); |
366 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | 366 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; |
367 | *pos++ = 2 * sband->n_channels; | 367 | *pos++ = 2 * sband->n_channels; |
368 | for (i = 0; i < sband->n_channels; i++) { | 368 | for (i = 0; i < sband->n_channels; i++) { |
369 | *pos++ = ieee80211_frequency_to_channel( | 369 | *pos++ = ieee80211_frequency_to_channel( |
370 | sband->channels[i].center_freq); | 370 | sband->channels[i].center_freq); |
371 | *pos++ = 1; /* one channel in the subband*/ | 371 | *pos++ = 1; /* one channel in the subband*/ |
372 | } | 372 | } |
373 | } | 373 | } |
374 | 374 | ||
375 | if (ifsta->extra_ie) { | 375 | if (ifsta->extra_ie) { |
376 | pos = skb_put(skb, ifsta->extra_ie_len); | 376 | pos = skb_put(skb, ifsta->extra_ie_len); |
377 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | 377 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); |
378 | } | 378 | } |
379 | 379 | ||
380 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 380 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { |
381 | pos = skb_put(skb, 9); | 381 | pos = skb_put(skb, 9); |
382 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 382 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
383 | *pos++ = 7; /* len */ | 383 | *pos++ = 7; /* len */ |
384 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | 384 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ |
385 | *pos++ = 0x50; | 385 | *pos++ = 0x50; |
386 | *pos++ = 0xf2; | 386 | *pos++ = 0xf2; |
387 | *pos++ = 2; /* WME */ | 387 | *pos++ = 2; /* WME */ |
388 | *pos++ = 0; /* WME info */ | 388 | *pos++ = 0; /* WME info */ |
389 | *pos++ = 1; /* WME ver */ | 389 | *pos++ = 1; /* WME ver */ |
390 | *pos++ = 0; | 390 | *pos++ = 0; |
391 | } | 391 | } |
392 | 392 | ||
393 | /* wmm support is a must to HT */ | 393 | /* wmm support is a must to HT */ |
394 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 394 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && |
395 | sband->ht_cap.ht_supported && | 395 | sband->ht_cap.ht_supported && |
396 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | 396 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && |
397 | ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { | 397 | ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { |
398 | struct ieee80211_ht_info *ht_info = | 398 | struct ieee80211_ht_info *ht_info = |
399 | (struct ieee80211_ht_info *)(ht_ie + 2); | 399 | (struct ieee80211_ht_info *)(ht_ie + 2); |
400 | u16 cap = sband->ht_cap.cap; | 400 | u16 cap = sband->ht_cap.cap; |
401 | __le16 tmp; | 401 | __le16 tmp; |
402 | u32 flags = local->hw.conf.channel->flags; | 402 | u32 flags = local->hw.conf.channel->flags; |
403 | 403 | ||
404 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 404 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
405 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 405 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
406 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | 406 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { |
407 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 407 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
408 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 408 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
409 | } | 409 | } |
410 | break; | 410 | break; |
411 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 411 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
412 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | 412 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { |
413 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 413 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
414 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 414 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
415 | } | 415 | } |
416 | break; | 416 | break; |
417 | } | 417 | } |
418 | 418 | ||
419 | tmp = cpu_to_le16(cap); | 419 | tmp = cpu_to_le16(cap); |
420 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | 420 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); |
421 | *pos++ = WLAN_EID_HT_CAPABILITY; | 421 | *pos++ = WLAN_EID_HT_CAPABILITY; |
422 | *pos++ = sizeof(struct ieee80211_ht_cap); | 422 | *pos++ = sizeof(struct ieee80211_ht_cap); |
423 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | 423 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); |
424 | memcpy(pos, &tmp, sizeof(u16)); | 424 | memcpy(pos, &tmp, sizeof(u16)); |
425 | pos += sizeof(u16); | 425 | pos += sizeof(u16); |
426 | /* TODO: needs a define here for << 2 */ | 426 | /* TODO: needs a define here for << 2 */ |
427 | *pos++ = sband->ht_cap.ampdu_factor | | 427 | *pos++ = sband->ht_cap.ampdu_factor | |
428 | (sband->ht_cap.ampdu_density << 2); | 428 | (sband->ht_cap.ampdu_density << 2); |
429 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 429 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
430 | } | 430 | } |
431 | 431 | ||
432 | kfree(ifsta->assocreq_ies); | 432 | kfree(ifsta->assocreq_ies); |
433 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 433 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; |
434 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 434 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); |
435 | if (ifsta->assocreq_ies) | 435 | if (ifsta->assocreq_ies) |
436 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | 436 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); |
437 | 437 | ||
438 | ieee80211_tx_skb(sdata, skb, 0); | 438 | ieee80211_tx_skb(sdata, skb, 0); |
439 | } | 439 | } |
440 | 440 | ||
441 | 441 | ||
442 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 442 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
443 | u16 stype, u16 reason) | 443 | u16 stype, u16 reason) |
444 | { | 444 | { |
445 | struct ieee80211_local *local = sdata->local; | 445 | struct ieee80211_local *local = sdata->local; |
446 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 446 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
447 | struct sk_buff *skb; | 447 | struct sk_buff *skb; |
448 | struct ieee80211_mgmt *mgmt; | 448 | struct ieee80211_mgmt *mgmt; |
449 | 449 | ||
450 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | 450 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); |
451 | if (!skb) { | 451 | if (!skb) { |
452 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 452 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
453 | "deauth/disassoc frame\n", sdata->dev->name); | 453 | "deauth/disassoc frame\n", sdata->dev->name); |
454 | return; | 454 | return; |
455 | } | 455 | } |
456 | skb_reserve(skb, local->hw.extra_tx_headroom); | 456 | skb_reserve(skb, local->hw.extra_tx_headroom); |
457 | 457 | ||
458 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 458 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
459 | memset(mgmt, 0, 24); | 459 | memset(mgmt, 0, 24); |
460 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 460 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); |
461 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 461 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
462 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 462 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
463 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 463 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
464 | skb_put(skb, 2); | 464 | skb_put(skb, 2); |
465 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 465 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
466 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 466 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
467 | 467 | ||
468 | ieee80211_tx_skb(sdata, skb, 0); | 468 | ieee80211_tx_skb(sdata, skb, 0); |
469 | } | 469 | } |
470 | 470 | ||
471 | /* MLME */ | 471 | /* MLME */ |
472 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 472 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
473 | struct ieee80211_bss *bss) | 473 | struct ieee80211_bss *bss) |
474 | { | 474 | { |
475 | struct ieee80211_local *local = sdata->local; | 475 | struct ieee80211_local *local = sdata->local; |
476 | int i, have_higher_than_11mbit = 0; | 476 | int i, have_higher_than_11mbit = 0; |
477 | 477 | ||
478 | /* cf. IEEE 802.11 9.2.12 */ | 478 | /* cf. IEEE 802.11 9.2.12 */ |
479 | for (i = 0; i < bss->supp_rates_len; i++) | 479 | for (i = 0; i < bss->supp_rates_len; i++) |
480 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) | 480 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) |
481 | have_higher_than_11mbit = 1; | 481 | have_higher_than_11mbit = 1; |
482 | 482 | ||
483 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 483 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && |
484 | have_higher_than_11mbit) | 484 | have_higher_than_11mbit) |
485 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 485 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
486 | else | 486 | else |
487 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 487 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
488 | 488 | ||
489 | ieee80211_set_wmm_default(sdata); | 489 | ieee80211_set_wmm_default(sdata); |
490 | } | 490 | } |
491 | 491 | ||
492 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 492 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
493 | struct ieee80211_if_sta *ifsta, | 493 | struct ieee80211_if_sta *ifsta, |
494 | u8 *wmm_param, size_t wmm_param_len) | 494 | u8 *wmm_param, size_t wmm_param_len) |
495 | { | 495 | { |
496 | struct ieee80211_tx_queue_params params; | 496 | struct ieee80211_tx_queue_params params; |
497 | size_t left; | 497 | size_t left; |
498 | int count; | 498 | int count; |
499 | u8 *pos; | 499 | u8 *pos; |
500 | 500 | ||
501 | if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 501 | if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) |
502 | return; | 502 | return; |
503 | 503 | ||
504 | if (!wmm_param) | 504 | if (!wmm_param) |
505 | return; | 505 | return; |
506 | 506 | ||
507 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 507 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
508 | return; | 508 | return; |
509 | count = wmm_param[6] & 0x0f; | 509 | count = wmm_param[6] & 0x0f; |
510 | if (count == ifsta->wmm_last_param_set) | 510 | if (count == ifsta->wmm_last_param_set) |
511 | return; | 511 | return; |
512 | ifsta->wmm_last_param_set = count; | 512 | ifsta->wmm_last_param_set = count; |
513 | 513 | ||
514 | pos = wmm_param + 8; | 514 | pos = wmm_param + 8; |
515 | left = wmm_param_len - 8; | 515 | left = wmm_param_len - 8; |
516 | 516 | ||
517 | memset(¶ms, 0, sizeof(params)); | 517 | memset(¶ms, 0, sizeof(params)); |
518 | 518 | ||
519 | if (!local->ops->conf_tx) | 519 | if (!local->ops->conf_tx) |
520 | return; | 520 | return; |
521 | 521 | ||
522 | local->wmm_acm = 0; | 522 | local->wmm_acm = 0; |
523 | for (; left >= 4; left -= 4, pos += 4) { | 523 | for (; left >= 4; left -= 4, pos += 4) { |
524 | int aci = (pos[0] >> 5) & 0x03; | 524 | int aci = (pos[0] >> 5) & 0x03; |
525 | int acm = (pos[0] >> 4) & 0x01; | 525 | int acm = (pos[0] >> 4) & 0x01; |
526 | int queue; | 526 | int queue; |
527 | 527 | ||
528 | switch (aci) { | 528 | switch (aci) { |
529 | case 1: | 529 | case 1: |
530 | queue = 3; | 530 | queue = 3; |
531 | if (acm) | 531 | if (acm) |
532 | local->wmm_acm |= BIT(0) | BIT(3); | 532 | local->wmm_acm |= BIT(0) | BIT(3); |
533 | break; | 533 | break; |
534 | case 2: | 534 | case 2: |
535 | queue = 1; | 535 | queue = 1; |
536 | if (acm) | 536 | if (acm) |
537 | local->wmm_acm |= BIT(4) | BIT(5); | 537 | local->wmm_acm |= BIT(4) | BIT(5); |
538 | break; | 538 | break; |
539 | case 3: | 539 | case 3: |
540 | queue = 0; | 540 | queue = 0; |
541 | if (acm) | 541 | if (acm) |
542 | local->wmm_acm |= BIT(6) | BIT(7); | 542 | local->wmm_acm |= BIT(6) | BIT(7); |
543 | break; | 543 | break; |
544 | case 0: | 544 | case 0: |
545 | default: | 545 | default: |
546 | queue = 2; | 546 | queue = 2; |
547 | if (acm) | 547 | if (acm) |
548 | local->wmm_acm |= BIT(1) | BIT(2); | 548 | local->wmm_acm |= BIT(1) | BIT(2); |
549 | break; | 549 | break; |
550 | } | 550 | } |
551 | 551 | ||
552 | params.aifs = pos[0] & 0x0f; | 552 | params.aifs = pos[0] & 0x0f; |
553 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 553 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
554 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 554 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
555 | params.txop = get_unaligned_le16(pos + 2); | 555 | params.txop = get_unaligned_le16(pos + 2); |
556 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 556 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
557 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 557 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
558 | "cWmin=%d cWmax=%d txop=%d\n", | 558 | "cWmin=%d cWmax=%d txop=%d\n", |
559 | local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, | 559 | local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, |
560 | params.cw_max, params.txop); | 560 | params.cw_max, params.txop); |
561 | #endif | 561 | #endif |
562 | /* TODO: handle ACM (block TX, fallback to next lowest allowed | 562 | /* TODO: handle ACM (block TX, fallback to next lowest allowed |
563 | * AC for now) */ | 563 | * AC for now) */ |
564 | if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { | 564 | if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { |
565 | printk(KERN_DEBUG "%s: failed to set TX queue " | 565 | printk(KERN_DEBUG "%s: failed to set TX queue " |
566 | "parameters for queue %d\n", local->mdev->name, queue); | 566 | "parameters for queue %d\n", local->mdev->name, queue); |
567 | } | 567 | } |
568 | } | 568 | } |
569 | } | 569 | } |
570 | 570 | ||
571 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 571 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
572 | u16 capab, bool erp_valid, u8 erp) | 572 | u16 capab, bool erp_valid, u8 erp) |
573 | { | 573 | { |
574 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 574 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
575 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 575 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
576 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 576 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
577 | #endif | 577 | #endif |
578 | u32 changed = 0; | 578 | u32 changed = 0; |
579 | bool use_protection; | 579 | bool use_protection; |
580 | bool use_short_preamble; | 580 | bool use_short_preamble; |
581 | bool use_short_slot; | 581 | bool use_short_slot; |
582 | 582 | ||
583 | if (erp_valid) { | 583 | if (erp_valid) { |
584 | use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0; | 584 | use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0; |
585 | use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0; | 585 | use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0; |
586 | } else { | 586 | } else { |
587 | use_protection = false; | 587 | use_protection = false; |
588 | use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE); | 588 | use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE); |
589 | } | 589 | } |
590 | 590 | ||
591 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 591 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
592 | 592 | ||
593 | if (use_protection != bss_conf->use_cts_prot) { | 593 | if (use_protection != bss_conf->use_cts_prot) { |
594 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 594 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
595 | if (net_ratelimit()) { | 595 | if (net_ratelimit()) { |
596 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", | 596 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", |
597 | sdata->dev->name, | 597 | sdata->dev->name, |
598 | use_protection ? "enabled" : "disabled", | 598 | use_protection ? "enabled" : "disabled", |
599 | ifsta->bssid); | 599 | ifsta->bssid); |
600 | } | 600 | } |
601 | #endif | 601 | #endif |
602 | bss_conf->use_cts_prot = use_protection; | 602 | bss_conf->use_cts_prot = use_protection; |
603 | changed |= BSS_CHANGED_ERP_CTS_PROT; | 603 | changed |= BSS_CHANGED_ERP_CTS_PROT; |
604 | } | 604 | } |
605 | 605 | ||
606 | if (use_short_preamble != bss_conf->use_short_preamble) { | 606 | if (use_short_preamble != bss_conf->use_short_preamble) { |
607 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 607 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
608 | if (net_ratelimit()) { | 608 | if (net_ratelimit()) { |
609 | printk(KERN_DEBUG "%s: switched to %s barker preamble" | 609 | printk(KERN_DEBUG "%s: switched to %s barker preamble" |
610 | " (BSSID=%pM)\n", | 610 | " (BSSID=%pM)\n", |
611 | sdata->dev->name, | 611 | sdata->dev->name, |
612 | use_short_preamble ? "short" : "long", | 612 | use_short_preamble ? "short" : "long", |
613 | ifsta->bssid); | 613 | ifsta->bssid); |
614 | } | 614 | } |
615 | #endif | 615 | #endif |
616 | bss_conf->use_short_preamble = use_short_preamble; | 616 | bss_conf->use_short_preamble = use_short_preamble; |
617 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 617 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
618 | } | 618 | } |
619 | 619 | ||
620 | if (use_short_slot != bss_conf->use_short_slot) { | 620 | if (use_short_slot != bss_conf->use_short_slot) { |
621 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 621 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
622 | if (net_ratelimit()) { | 622 | if (net_ratelimit()) { |
623 | printk(KERN_DEBUG "%s: switched to %s slot" | 623 | printk(KERN_DEBUG "%s: switched to %s slot" |
624 | " (BSSID=%s)\n", | 624 | " (BSSID=%s)\n", |
625 | sdata->dev->name, | 625 | sdata->dev->name, |
626 | use_short_slot ? "short" : "long", | 626 | use_short_slot ? "short" : "long", |
627 | ifsta->bssid); | 627 | ifsta->bssid); |
628 | } | 628 | } |
629 | #endif | 629 | #endif |
630 | bss_conf->use_short_slot = use_short_slot; | 630 | bss_conf->use_short_slot = use_short_slot; |
631 | changed |= BSS_CHANGED_ERP_SLOT; | 631 | changed |= BSS_CHANGED_ERP_SLOT; |
632 | } | 632 | } |
633 | 633 | ||
634 | return changed; | 634 | return changed; |
635 | } | 635 | } |
636 | 636 | ||
637 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, | 637 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, |
638 | struct ieee80211_if_sta *ifsta) | 638 | struct ieee80211_if_sta *ifsta) |
639 | { | 639 | { |
640 | union iwreq_data wrqu; | 640 | union iwreq_data wrqu; |
641 | memset(&wrqu, 0, sizeof(wrqu)); | 641 | memset(&wrqu, 0, sizeof(wrqu)); |
642 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 642 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) |
643 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | 643 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); |
644 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 644 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
645 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 645 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
646 | } | 646 | } |
647 | 647 | ||
648 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | 648 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, |
649 | struct ieee80211_if_sta *ifsta) | 649 | struct ieee80211_if_sta *ifsta) |
650 | { | 650 | { |
651 | char *buf; | 651 | char *buf; |
652 | size_t len; | 652 | size_t len; |
653 | int i; | 653 | int i; |
654 | union iwreq_data wrqu; | 654 | union iwreq_data wrqu; |
655 | 655 | ||
656 | if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) | 656 | if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) |
657 | return; | 657 | return; |
658 | 658 | ||
659 | buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + | 659 | buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + |
660 | ifsta->assocresp_ies_len), GFP_KERNEL); | 660 | ifsta->assocresp_ies_len), GFP_KERNEL); |
661 | if (!buf) | 661 | if (!buf) |
662 | return; | 662 | return; |
663 | 663 | ||
664 | len = sprintf(buf, "ASSOCINFO("); | 664 | len = sprintf(buf, "ASSOCINFO("); |
665 | if (ifsta->assocreq_ies) { | 665 | if (ifsta->assocreq_ies) { |
666 | len += sprintf(buf + len, "ReqIEs="); | 666 | len += sprintf(buf + len, "ReqIEs="); |
667 | for (i = 0; i < ifsta->assocreq_ies_len; i++) { | 667 | for (i = 0; i < ifsta->assocreq_ies_len; i++) { |
668 | len += sprintf(buf + len, "%02x", | 668 | len += sprintf(buf + len, "%02x", |
669 | ifsta->assocreq_ies[i]); | 669 | ifsta->assocreq_ies[i]); |
670 | } | 670 | } |
671 | } | 671 | } |
672 | if (ifsta->assocresp_ies) { | 672 | if (ifsta->assocresp_ies) { |
673 | if (ifsta->assocreq_ies) | 673 | if (ifsta->assocreq_ies) |
674 | len += sprintf(buf + len, " "); | 674 | len += sprintf(buf + len, " "); |
675 | len += sprintf(buf + len, "RespIEs="); | 675 | len += sprintf(buf + len, "RespIEs="); |
676 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 676 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { |
677 | len += sprintf(buf + len, "%02x", | 677 | len += sprintf(buf + len, "%02x", |
678 | ifsta->assocresp_ies[i]); | 678 | ifsta->assocresp_ies[i]); |
679 | } | 679 | } |
680 | } | 680 | } |
681 | len += sprintf(buf + len, ")"); | 681 | len += sprintf(buf + len, ")"); |
682 | 682 | ||
683 | if (len > IW_CUSTOM_MAX) { | 683 | if (len > IW_CUSTOM_MAX) { |
684 | len = sprintf(buf, "ASSOCRESPIE="); | 684 | len = sprintf(buf, "ASSOCRESPIE="); |
685 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 685 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { |
686 | len += sprintf(buf + len, "%02x", | 686 | len += sprintf(buf + len, "%02x", |
687 | ifsta->assocresp_ies[i]); | 687 | ifsta->assocresp_ies[i]); |
688 | } | 688 | } |
689 | } | 689 | } |
690 | 690 | ||
691 | if (len <= IW_CUSTOM_MAX) { | 691 | if (len <= IW_CUSTOM_MAX) { |
692 | memset(&wrqu, 0, sizeof(wrqu)); | 692 | memset(&wrqu, 0, sizeof(wrqu)); |
693 | wrqu.data.length = len; | 693 | wrqu.data.length = len; |
694 | wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); | 694 | wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); |
695 | } | 695 | } |
696 | 696 | ||
697 | kfree(buf); | 697 | kfree(buf); |
698 | } | 698 | } |
699 | 699 | ||
700 | 700 | ||
701 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 701 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
702 | struct ieee80211_if_sta *ifsta, | 702 | struct ieee80211_if_sta *ifsta, |
703 | u32 bss_info_changed) | 703 | u32 bss_info_changed) |
704 | { | 704 | { |
705 | struct ieee80211_local *local = sdata->local; | 705 | struct ieee80211_local *local = sdata->local; |
706 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | 706 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; |
707 | 707 | ||
708 | struct ieee80211_bss *bss; | 708 | struct ieee80211_bss *bss; |
709 | 709 | ||
710 | bss_info_changed |= BSS_CHANGED_ASSOC; | 710 | bss_info_changed |= BSS_CHANGED_ASSOC; |
711 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 711 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; |
712 | 712 | ||
713 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 713 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
714 | return; | 714 | return; |
715 | 715 | ||
716 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 716 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
717 | conf->channel->center_freq, | 717 | conf->channel->center_freq, |
718 | ifsta->ssid, ifsta->ssid_len); | 718 | ifsta->ssid, ifsta->ssid_len); |
719 | if (bss) { | 719 | if (bss) { |
720 | /* set timing information */ | 720 | /* set timing information */ |
721 | sdata->vif.bss_conf.beacon_int = bss->beacon_int; | 721 | sdata->vif.bss_conf.beacon_int = bss->beacon_int; |
722 | sdata->vif.bss_conf.timestamp = bss->timestamp; | 722 | sdata->vif.bss_conf.timestamp = bss->timestamp; |
723 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | 723 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; |
724 | 724 | ||
725 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 725 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
726 | bss->capability, bss->has_erp_value, bss->erp_value); | 726 | bss->capability, bss->has_erp_value, bss->erp_value); |
727 | 727 | ||
728 | ieee80211_rx_bss_put(local, bss); | 728 | ieee80211_rx_bss_put(local, bss); |
729 | } | 729 | } |
730 | 730 | ||
731 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 731 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; |
732 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 732 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); |
733 | ieee80211_sta_send_associnfo(sdata, ifsta); | 733 | ieee80211_sta_send_associnfo(sdata, ifsta); |
734 | 734 | ||
735 | ifsta->last_probe = jiffies; | 735 | ifsta->last_probe = jiffies; |
736 | ieee80211_led_assoc(local, 1); | 736 | ieee80211_led_assoc(local, 1); |
737 | 737 | ||
738 | sdata->vif.bss_conf.assoc = 1; | 738 | sdata->vif.bss_conf.assoc = 1; |
739 | /* | 739 | /* |
740 | * For now just always ask the driver to update the basic rateset | 740 | * For now just always ask the driver to update the basic rateset |
741 | * when we have associated, we aren't checking whether it actually | 741 | * when we have associated, we aren't checking whether it actually |
742 | * changed or not. | 742 | * changed or not. |
743 | */ | 743 | */ |
744 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; | 744 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; |
745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
746 | 746 | ||
747 | netif_tx_start_all_queues(sdata->dev); | 747 | netif_tx_start_all_queues(sdata->dev); |
748 | netif_carrier_on(sdata->dev); | 748 | netif_carrier_on(sdata->dev); |
749 | 749 | ||
750 | ieee80211_sta_send_apinfo(sdata, ifsta); | 750 | ieee80211_sta_send_apinfo(sdata, ifsta); |
751 | } | 751 | } |
752 | 752 | ||
753 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 753 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, |
754 | struct ieee80211_if_sta *ifsta) | 754 | struct ieee80211_if_sta *ifsta) |
755 | { | 755 | { |
756 | ifsta->direct_probe_tries++; | 756 | ifsta->direct_probe_tries++; |
757 | if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 757 | if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { |
758 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 758 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
759 | sdata->dev->name, ifsta->bssid); | 759 | sdata->dev->name, ifsta->bssid); |
760 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 760 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
761 | ieee80211_sta_send_apinfo(sdata, ifsta); | 761 | ieee80211_sta_send_apinfo(sdata, ifsta); |
762 | return; | 762 | return; |
763 | } | 763 | } |
764 | 764 | ||
765 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", | 765 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", |
766 | sdata->dev->name, ifsta->bssid, | 766 | sdata->dev->name, ifsta->bssid, |
767 | ifsta->direct_probe_tries); | 767 | ifsta->direct_probe_tries); |
768 | 768 | ||
769 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 769 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
770 | 770 | ||
771 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); | 771 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); |
772 | 772 | ||
773 | /* Direct probe is sent to broadcast address as some APs | 773 | /* Direct probe is sent to broadcast address as some APs |
774 | * will not answer to direct packet in unassociated state. | 774 | * will not answer to direct packet in unassociated state. |
775 | */ | 775 | */ |
776 | ieee80211_send_probe_req(sdata, NULL, | 776 | ieee80211_send_probe_req(sdata, NULL, |
777 | ifsta->ssid, ifsta->ssid_len); | 777 | ifsta->ssid, ifsta->ssid_len); |
778 | 778 | ||
779 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 779 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
780 | } | 780 | } |
781 | 781 | ||
782 | 782 | ||
783 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | 783 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, |
784 | struct ieee80211_if_sta *ifsta) | 784 | struct ieee80211_if_sta *ifsta) |
785 | { | 785 | { |
786 | ifsta->auth_tries++; | 786 | ifsta->auth_tries++; |
787 | if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 787 | if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { |
788 | printk(KERN_DEBUG "%s: authentication with AP %pM" | 788 | printk(KERN_DEBUG "%s: authentication with AP %pM" |
789 | " timed out\n", | 789 | " timed out\n", |
790 | sdata->dev->name, ifsta->bssid); | 790 | sdata->dev->name, ifsta->bssid); |
791 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 791 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
792 | ieee80211_sta_send_apinfo(sdata, ifsta); | 792 | ieee80211_sta_send_apinfo(sdata, ifsta); |
793 | return; | 793 | return; |
794 | } | 794 | } |
795 | 795 | ||
796 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 796 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; |
797 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 797 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
798 | sdata->dev->name, ifsta->bssid); | 798 | sdata->dev->name, ifsta->bssid); |
799 | 799 | ||
800 | ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); | 800 | ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); |
801 | 801 | ||
802 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 802 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
803 | } | 803 | } |
804 | 804 | ||
805 | /* | 805 | /* |
806 | * The disassoc 'reason' argument can be either our own reason | 806 | * The disassoc 'reason' argument can be either our own reason |
807 | * if self disconnected or a reason code from the AP. | 807 | * if self disconnected or a reason code from the AP. |
808 | */ | 808 | */ |
809 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 809 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
810 | struct ieee80211_if_sta *ifsta, bool deauth, | 810 | struct ieee80211_if_sta *ifsta, bool deauth, |
811 | bool self_disconnected, u16 reason) | 811 | bool self_disconnected, u16 reason) |
812 | { | 812 | { |
813 | struct ieee80211_local *local = sdata->local; | 813 | struct ieee80211_local *local = sdata->local; |
814 | struct sta_info *sta; | 814 | struct sta_info *sta; |
815 | u32 changed = 0; | 815 | u32 changed = 0; |
816 | 816 | ||
817 | rcu_read_lock(); | 817 | rcu_read_lock(); |
818 | 818 | ||
819 | sta = sta_info_get(local, ifsta->bssid); | 819 | sta = sta_info_get(local, ifsta->bssid); |
820 | if (!sta) { | 820 | if (!sta) { |
821 | rcu_read_unlock(); | 821 | rcu_read_unlock(); |
822 | return; | 822 | return; |
823 | } | 823 | } |
824 | 824 | ||
825 | if (deauth) { | 825 | if (deauth) { |
826 | ifsta->direct_probe_tries = 0; | 826 | ifsta->direct_probe_tries = 0; |
827 | ifsta->auth_tries = 0; | 827 | ifsta->auth_tries = 0; |
828 | } | 828 | } |
829 | ifsta->assoc_scan_tries = 0; | 829 | ifsta->assoc_scan_tries = 0; |
830 | ifsta->assoc_tries = 0; | 830 | ifsta->assoc_tries = 0; |
831 | 831 | ||
832 | netif_tx_stop_all_queues(sdata->dev); | 832 | netif_tx_stop_all_queues(sdata->dev); |
833 | netif_carrier_off(sdata->dev); | 833 | netif_carrier_off(sdata->dev); |
834 | 834 | ||
835 | ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr); | 835 | ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr); |
836 | 836 | ||
837 | if (self_disconnected) { | 837 | if (self_disconnected) { |
838 | if (deauth) | 838 | if (deauth) |
839 | ieee80211_send_deauth_disassoc(sdata, | 839 | ieee80211_send_deauth_disassoc(sdata, |
840 | IEEE80211_STYPE_DEAUTH, reason); | 840 | IEEE80211_STYPE_DEAUTH, reason); |
841 | else | 841 | else |
842 | ieee80211_send_deauth_disassoc(sdata, | 842 | ieee80211_send_deauth_disassoc(sdata, |
843 | IEEE80211_STYPE_DISASSOC, reason); | 843 | IEEE80211_STYPE_DISASSOC, reason); |
844 | } | 844 | } |
845 | 845 | ||
846 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 846 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; |
847 | changed |= ieee80211_reset_erp_info(sdata); | 847 | changed |= ieee80211_reset_erp_info(sdata); |
848 | 848 | ||
849 | ieee80211_led_assoc(local, 0); | 849 | ieee80211_led_assoc(local, 0); |
850 | changed |= BSS_CHANGED_ASSOC; | 850 | changed |= BSS_CHANGED_ASSOC; |
851 | sdata->vif.bss_conf.assoc = false; | 851 | sdata->vif.bss_conf.assoc = false; |
852 | 852 | ||
853 | ieee80211_sta_send_apinfo(sdata, ifsta); | 853 | ieee80211_sta_send_apinfo(sdata, ifsta); |
854 | 854 | ||
855 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) | 855 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) |
856 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 856 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
857 | 857 | ||
858 | rcu_read_unlock(); | 858 | rcu_read_unlock(); |
859 | 859 | ||
860 | local->hw.conf.ht.enabled = false; | 860 | local->hw.conf.ht.enabled = false; |
861 | local->oper_channel_type = NL80211_CHAN_NO_HT; | ||
861 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 862 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); |
862 | 863 | ||
863 | ieee80211_bss_info_change_notify(sdata, changed); | 864 | ieee80211_bss_info_change_notify(sdata, changed); |
864 | 865 | ||
865 | rcu_read_lock(); | 866 | rcu_read_lock(); |
866 | 867 | ||
867 | sta = sta_info_get(local, ifsta->bssid); | 868 | sta = sta_info_get(local, ifsta->bssid); |
868 | if (!sta) { | 869 | if (!sta) { |
869 | rcu_read_unlock(); | 870 | rcu_read_unlock(); |
870 | return; | 871 | return; |
871 | } | 872 | } |
872 | 873 | ||
873 | sta_info_unlink(&sta); | 874 | sta_info_unlink(&sta); |
874 | 875 | ||
875 | rcu_read_unlock(); | 876 | rcu_read_unlock(); |
876 | 877 | ||
877 | sta_info_destroy(sta); | 878 | sta_info_destroy(sta); |
878 | } | 879 | } |
879 | 880 | ||
880 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | 881 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) |
881 | { | 882 | { |
882 | if (!sdata || !sdata->default_key || | 883 | if (!sdata || !sdata->default_key || |
883 | sdata->default_key->conf.alg != ALG_WEP) | 884 | sdata->default_key->conf.alg != ALG_WEP) |
884 | return 0; | 885 | return 0; |
885 | return 1; | 886 | return 1; |
886 | } | 887 | } |
887 | 888 | ||
888 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 889 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, |
889 | struct ieee80211_if_sta *ifsta) | 890 | struct ieee80211_if_sta *ifsta) |
890 | { | 891 | { |
891 | struct ieee80211_local *local = sdata->local; | 892 | struct ieee80211_local *local = sdata->local; |
892 | struct ieee80211_bss *bss; | 893 | struct ieee80211_bss *bss; |
893 | int bss_privacy; | 894 | int bss_privacy; |
894 | int wep_privacy; | 895 | int wep_privacy; |
895 | int privacy_invoked; | 896 | int privacy_invoked; |
896 | 897 | ||
897 | if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) | 898 | if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) |
898 | return 0; | 899 | return 0; |
899 | 900 | ||
900 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 901 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
901 | local->hw.conf.channel->center_freq, | 902 | local->hw.conf.channel->center_freq, |
902 | ifsta->ssid, ifsta->ssid_len); | 903 | ifsta->ssid, ifsta->ssid_len); |
903 | if (!bss) | 904 | if (!bss) |
904 | return 0; | 905 | return 0; |
905 | 906 | ||
906 | bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); | 907 | bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); |
907 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); | 908 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); |
908 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); | 909 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); |
909 | 910 | ||
910 | ieee80211_rx_bss_put(local, bss); | 911 | ieee80211_rx_bss_put(local, bss); |
911 | 912 | ||
912 | if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) | 913 | if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) |
913 | return 0; | 914 | return 0; |
914 | 915 | ||
915 | return 1; | 916 | return 1; |
916 | } | 917 | } |
917 | 918 | ||
918 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 919 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, |
919 | struct ieee80211_if_sta *ifsta) | 920 | struct ieee80211_if_sta *ifsta) |
920 | { | 921 | { |
921 | ifsta->assoc_tries++; | 922 | ifsta->assoc_tries++; |
922 | if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 923 | if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { |
923 | printk(KERN_DEBUG "%s: association with AP %pM" | 924 | printk(KERN_DEBUG "%s: association with AP %pM" |
924 | " timed out\n", | 925 | " timed out\n", |
925 | sdata->dev->name, ifsta->bssid); | 926 | sdata->dev->name, ifsta->bssid); |
926 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 927 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
927 | ieee80211_sta_send_apinfo(sdata, ifsta); | 928 | ieee80211_sta_send_apinfo(sdata, ifsta); |
928 | return; | 929 | return; |
929 | } | 930 | } |
930 | 931 | ||
931 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 932 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; |
932 | printk(KERN_DEBUG "%s: associate with AP %pM\n", | 933 | printk(KERN_DEBUG "%s: associate with AP %pM\n", |
933 | sdata->dev->name, ifsta->bssid); | 934 | sdata->dev->name, ifsta->bssid); |
934 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 935 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { |
935 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " | 936 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " |
936 | "mixed-cell disabled - abort association\n", sdata->dev->name); | 937 | "mixed-cell disabled - abort association\n", sdata->dev->name); |
937 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 938 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
938 | return; | 939 | return; |
939 | } | 940 | } |
940 | 941 | ||
941 | ieee80211_send_assoc(sdata, ifsta); | 942 | ieee80211_send_assoc(sdata, ifsta); |
942 | 943 | ||
943 | mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 944 | mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
944 | } | 945 | } |
945 | 946 | ||
946 | 947 | ||
947 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | 948 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, |
948 | struct ieee80211_if_sta *ifsta) | 949 | struct ieee80211_if_sta *ifsta) |
949 | { | 950 | { |
950 | struct ieee80211_local *local = sdata->local; | 951 | struct ieee80211_local *local = sdata->local; |
951 | struct sta_info *sta; | 952 | struct sta_info *sta; |
952 | int disassoc; | 953 | int disassoc; |
953 | 954 | ||
954 | /* TODO: start monitoring current AP signal quality and number of | 955 | /* TODO: start monitoring current AP signal quality and number of |
955 | * missed beacons. Scan other channels every now and then and search | 956 | * missed beacons. Scan other channels every now and then and search |
956 | * for better APs. */ | 957 | * for better APs. */ |
957 | /* TODO: remove expired BSSes */ | 958 | /* TODO: remove expired BSSes */ |
958 | 959 | ||
959 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATED; | 960 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATED; |
960 | 961 | ||
961 | rcu_read_lock(); | 962 | rcu_read_lock(); |
962 | 963 | ||
963 | sta = sta_info_get(local, ifsta->bssid); | 964 | sta = sta_info_get(local, ifsta->bssid); |
964 | if (!sta) { | 965 | if (!sta) { |
965 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 966 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
966 | sdata->dev->name, ifsta->bssid); | 967 | sdata->dev->name, ifsta->bssid); |
967 | disassoc = 1; | 968 | disassoc = 1; |
968 | } else { | 969 | } else { |
969 | disassoc = 0; | 970 | disassoc = 0; |
970 | if (time_after(jiffies, | 971 | if (time_after(jiffies, |
971 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | 972 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { |
972 | if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { | 973 | if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { |
973 | printk(KERN_DEBUG "%s: No ProbeResp from " | 974 | printk(KERN_DEBUG "%s: No ProbeResp from " |
974 | "current AP %pM - assume out of " | 975 | "current AP %pM - assume out of " |
975 | "range\n", | 976 | "range\n", |
976 | sdata->dev->name, ifsta->bssid); | 977 | sdata->dev->name, ifsta->bssid); |
977 | disassoc = 1; | 978 | disassoc = 1; |
978 | } else | 979 | } else |
979 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 980 | ieee80211_send_probe_req(sdata, ifsta->bssid, |
980 | ifsta->ssid, | 981 | ifsta->ssid, |
981 | ifsta->ssid_len); | 982 | ifsta->ssid_len); |
982 | ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; | 983 | ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; |
983 | } else { | 984 | } else { |
984 | ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 985 | ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
985 | if (time_after(jiffies, ifsta->last_probe + | 986 | if (time_after(jiffies, ifsta->last_probe + |
986 | IEEE80211_PROBE_INTERVAL)) { | 987 | IEEE80211_PROBE_INTERVAL)) { |
987 | ifsta->last_probe = jiffies; | 988 | ifsta->last_probe = jiffies; |
988 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 989 | ieee80211_send_probe_req(sdata, ifsta->bssid, |
989 | ifsta->ssid, | 990 | ifsta->ssid, |
990 | ifsta->ssid_len); | 991 | ifsta->ssid_len); |
991 | } | 992 | } |
992 | } | 993 | } |
993 | } | 994 | } |
994 | 995 | ||
995 | rcu_read_unlock(); | 996 | rcu_read_unlock(); |
996 | 997 | ||
997 | if (disassoc) | 998 | if (disassoc) |
998 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 999 | ieee80211_set_disassoc(sdata, ifsta, true, true, |
999 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 1000 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1000 | else | 1001 | else |
1001 | mod_timer(&ifsta->timer, jiffies + | 1002 | mod_timer(&ifsta->timer, jiffies + |
1002 | IEEE80211_MONITORING_INTERVAL); | 1003 | IEEE80211_MONITORING_INTERVAL); |
1003 | } | 1004 | } |
1004 | 1005 | ||
1005 | 1006 | ||
1006 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 1007 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, |
1007 | struct ieee80211_if_sta *ifsta) | 1008 | struct ieee80211_if_sta *ifsta) |
1008 | { | 1009 | { |
1009 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 1010 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
1010 | ifsta->flags |= IEEE80211_STA_AUTHENTICATED; | 1011 | ifsta->flags |= IEEE80211_STA_AUTHENTICATED; |
1011 | ieee80211_associate(sdata, ifsta); | 1012 | ieee80211_associate(sdata, ifsta); |
1012 | } | 1013 | } |
1013 | 1014 | ||
1014 | 1015 | ||
1015 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 1016 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1016 | struct ieee80211_if_sta *ifsta, | 1017 | struct ieee80211_if_sta *ifsta, |
1017 | struct ieee80211_mgmt *mgmt, | 1018 | struct ieee80211_mgmt *mgmt, |
1018 | size_t len) | 1019 | size_t len) |
1019 | { | 1020 | { |
1020 | u8 *pos; | 1021 | u8 *pos; |
1021 | struct ieee802_11_elems elems; | 1022 | struct ieee802_11_elems elems; |
1022 | 1023 | ||
1023 | pos = mgmt->u.auth.variable; | 1024 | pos = mgmt->u.auth.variable; |
1024 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 1025 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1025 | if (!elems.challenge) | 1026 | if (!elems.challenge) |
1026 | return; | 1027 | return; |
1027 | ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2, | 1028 | ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2, |
1028 | elems.challenge_len + 2, 1); | 1029 | elems.challenge_len + 2, 1); |
1029 | } | 1030 | } |
1030 | 1031 | ||
1031 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1032 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1032 | struct ieee80211_if_sta *ifsta, | 1033 | struct ieee80211_if_sta *ifsta, |
1033 | struct ieee80211_mgmt *mgmt, | 1034 | struct ieee80211_mgmt *mgmt, |
1034 | size_t len) | 1035 | size_t len) |
1035 | { | 1036 | { |
1036 | u16 auth_alg, auth_transaction, status_code; | 1037 | u16 auth_alg, auth_transaction, status_code; |
1037 | 1038 | ||
1038 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1039 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && |
1039 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 1040 | sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1040 | return; | 1041 | return; |
1041 | 1042 | ||
1042 | if (len < 24 + 6) | 1043 | if (len < 24 + 6) |
1043 | return; | 1044 | return; |
1044 | 1045 | ||
1045 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1046 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1046 | memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1047 | memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) |
1047 | return; | 1048 | return; |
1048 | 1049 | ||
1049 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1050 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1050 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1051 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1051 | return; | 1052 | return; |
1052 | 1053 | ||
1053 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1054 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1054 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1055 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1055 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1056 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1056 | 1057 | ||
1057 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1058 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
1058 | /* | 1059 | /* |
1059 | * IEEE 802.11 standard does not require authentication in IBSS | 1060 | * IEEE 802.11 standard does not require authentication in IBSS |
1060 | * networks and most implementations do not seem to use it. | 1061 | * networks and most implementations do not seem to use it. |
1061 | * However, try to reply to authentication attempts if someone | 1062 | * However, try to reply to authentication attempts if someone |
1062 | * has actually implemented this. | 1063 | * has actually implemented this. |
1063 | */ | 1064 | */ |
1064 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | 1065 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) |
1065 | return; | 1066 | return; |
1066 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | 1067 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); |
1067 | } | 1068 | } |
1068 | 1069 | ||
1069 | if (auth_alg != ifsta->auth_alg || | 1070 | if (auth_alg != ifsta->auth_alg || |
1070 | auth_transaction != ifsta->auth_transaction) | 1071 | auth_transaction != ifsta->auth_transaction) |
1071 | return; | 1072 | return; |
1072 | 1073 | ||
1073 | if (status_code != WLAN_STATUS_SUCCESS) { | 1074 | if (status_code != WLAN_STATUS_SUCCESS) { |
1074 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { | 1075 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { |
1075 | u8 algs[3]; | 1076 | u8 algs[3]; |
1076 | const int num_algs = ARRAY_SIZE(algs); | 1077 | const int num_algs = ARRAY_SIZE(algs); |
1077 | int i, pos; | 1078 | int i, pos; |
1078 | algs[0] = algs[1] = algs[2] = 0xff; | 1079 | algs[0] = algs[1] = algs[2] = 0xff; |
1079 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1080 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1080 | algs[0] = WLAN_AUTH_OPEN; | 1081 | algs[0] = WLAN_AUTH_OPEN; |
1081 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1082 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
1082 | algs[1] = WLAN_AUTH_SHARED_KEY; | 1083 | algs[1] = WLAN_AUTH_SHARED_KEY; |
1083 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1084 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1084 | algs[2] = WLAN_AUTH_LEAP; | 1085 | algs[2] = WLAN_AUTH_LEAP; |
1085 | if (ifsta->auth_alg == WLAN_AUTH_OPEN) | 1086 | if (ifsta->auth_alg == WLAN_AUTH_OPEN) |
1086 | pos = 0; | 1087 | pos = 0; |
1087 | else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) | 1088 | else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) |
1088 | pos = 1; | 1089 | pos = 1; |
1089 | else | 1090 | else |
1090 | pos = 2; | 1091 | pos = 2; |
1091 | for (i = 0; i < num_algs; i++) { | 1092 | for (i = 0; i < num_algs; i++) { |
1092 | pos++; | 1093 | pos++; |
1093 | if (pos >= num_algs) | 1094 | if (pos >= num_algs) |
1094 | pos = 0; | 1095 | pos = 0; |
1095 | if (algs[pos] == ifsta->auth_alg || | 1096 | if (algs[pos] == ifsta->auth_alg || |
1096 | algs[pos] == 0xff) | 1097 | algs[pos] == 0xff) |
1097 | continue; | 1098 | continue; |
1098 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && | 1099 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && |
1099 | !ieee80211_sta_wep_configured(sdata)) | 1100 | !ieee80211_sta_wep_configured(sdata)) |
1100 | continue; | 1101 | continue; |
1101 | ifsta->auth_alg = algs[pos]; | 1102 | ifsta->auth_alg = algs[pos]; |
1102 | break; | 1103 | break; |
1103 | } | 1104 | } |
1104 | } | 1105 | } |
1105 | return; | 1106 | return; |
1106 | } | 1107 | } |
1107 | 1108 | ||
1108 | switch (ifsta->auth_alg) { | 1109 | switch (ifsta->auth_alg) { |
1109 | case WLAN_AUTH_OPEN: | 1110 | case WLAN_AUTH_OPEN: |
1110 | case WLAN_AUTH_LEAP: | 1111 | case WLAN_AUTH_LEAP: |
1111 | ieee80211_auth_completed(sdata, ifsta); | 1112 | ieee80211_auth_completed(sdata, ifsta); |
1112 | break; | 1113 | break; |
1113 | case WLAN_AUTH_SHARED_KEY: | 1114 | case WLAN_AUTH_SHARED_KEY: |
1114 | if (ifsta->auth_transaction == 4) | 1115 | if (ifsta->auth_transaction == 4) |
1115 | ieee80211_auth_completed(sdata, ifsta); | 1116 | ieee80211_auth_completed(sdata, ifsta); |
1116 | else | 1117 | else |
1117 | ieee80211_auth_challenge(sdata, ifsta, mgmt, len); | 1118 | ieee80211_auth_challenge(sdata, ifsta, mgmt, len); |
1118 | break; | 1119 | break; |
1119 | } | 1120 | } |
1120 | } | 1121 | } |
1121 | 1122 | ||
1122 | 1123 | ||
1123 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1124 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1124 | struct ieee80211_if_sta *ifsta, | 1125 | struct ieee80211_if_sta *ifsta, |
1125 | struct ieee80211_mgmt *mgmt, | 1126 | struct ieee80211_mgmt *mgmt, |
1126 | size_t len) | 1127 | size_t len) |
1127 | { | 1128 | { |
1128 | u16 reason_code; | 1129 | u16 reason_code; |
1129 | 1130 | ||
1130 | if (len < 24 + 2) | 1131 | if (len < 24 + 2) |
1131 | return; | 1132 | return; |
1132 | 1133 | ||
1133 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1134 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) |
1134 | return; | 1135 | return; |
1135 | 1136 | ||
1136 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1137 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1137 | 1138 | ||
1138 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) | 1139 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) |
1139 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1140 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1140 | sdata->dev->name, reason_code); | 1141 | sdata->dev->name, reason_code); |
1141 | 1142 | ||
1142 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1143 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1143 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || | 1144 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || |
1144 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1145 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1145 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1146 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1146 | mod_timer(&ifsta->timer, jiffies + | 1147 | mod_timer(&ifsta->timer, jiffies + |
1147 | IEEE80211_RETRY_AUTH_INTERVAL); | 1148 | IEEE80211_RETRY_AUTH_INTERVAL); |
1148 | } | 1149 | } |
1149 | 1150 | ||
1150 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); | 1151 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); |
1151 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1152 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1152 | } | 1153 | } |
1153 | 1154 | ||
1154 | 1155 | ||
1155 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 1156 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
1156 | struct ieee80211_if_sta *ifsta, | 1157 | struct ieee80211_if_sta *ifsta, |
1157 | struct ieee80211_mgmt *mgmt, | 1158 | struct ieee80211_mgmt *mgmt, |
1158 | size_t len) | 1159 | size_t len) |
1159 | { | 1160 | { |
1160 | u16 reason_code; | 1161 | u16 reason_code; |
1161 | 1162 | ||
1162 | if (len < 24 + 2) | 1163 | if (len < 24 + 2) |
1163 | return; | 1164 | return; |
1164 | 1165 | ||
1165 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1166 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) |
1166 | return; | 1167 | return; |
1167 | 1168 | ||
1168 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1169 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1169 | 1170 | ||
1170 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 1171 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) |
1171 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1172 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1172 | sdata->dev->name, reason_code); | 1173 | sdata->dev->name, reason_code); |
1173 | 1174 | ||
1174 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1175 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1175 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 1176 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; |
1176 | mod_timer(&ifsta->timer, jiffies + | 1177 | mod_timer(&ifsta->timer, jiffies + |
1177 | IEEE80211_RETRY_AUTH_INTERVAL); | 1178 | IEEE80211_RETRY_AUTH_INTERVAL); |
1178 | } | 1179 | } |
1179 | 1180 | ||
1180 | ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); | 1181 | ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); |
1181 | } | 1182 | } |
1182 | 1183 | ||
1183 | 1184 | ||
1184 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1185 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
1185 | struct ieee80211_if_sta *ifsta, | 1186 | struct ieee80211_if_sta *ifsta, |
1186 | struct ieee80211_mgmt *mgmt, | 1187 | struct ieee80211_mgmt *mgmt, |
1187 | size_t len, | 1188 | size_t len, |
1188 | int reassoc) | 1189 | int reassoc) |
1189 | { | 1190 | { |
1190 | struct ieee80211_local *local = sdata->local; | 1191 | struct ieee80211_local *local = sdata->local; |
1191 | struct ieee80211_supported_band *sband; | 1192 | struct ieee80211_supported_band *sband; |
1192 | struct sta_info *sta; | 1193 | struct sta_info *sta; |
1193 | u64 rates, basic_rates; | 1194 | u64 rates, basic_rates; |
1194 | u16 capab_info, status_code, aid; | 1195 | u16 capab_info, status_code, aid; |
1195 | struct ieee802_11_elems elems; | 1196 | struct ieee802_11_elems elems; |
1196 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1197 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
1197 | u8 *pos; | 1198 | u8 *pos; |
1198 | u32 changed = 0; | 1199 | u32 changed = 0; |
1199 | int i, j; | 1200 | int i, j; |
1200 | bool have_higher_than_11mbit = false, newsta = false; | 1201 | bool have_higher_than_11mbit = false, newsta = false; |
1201 | u16 ap_ht_cap_flags; | 1202 | u16 ap_ht_cap_flags; |
1202 | 1203 | ||
1203 | /* AssocResp and ReassocResp have identical structure, so process both | 1204 | /* AssocResp and ReassocResp have identical structure, so process both |
1204 | * of them in this function. */ | 1205 | * of them in this function. */ |
1205 | 1206 | ||
1206 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE) | 1207 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE) |
1207 | return; | 1208 | return; |
1208 | 1209 | ||
1209 | if (len < 24 + 6) | 1210 | if (len < 24 + 6) |
1210 | return; | 1211 | return; |
1211 | 1212 | ||
1212 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1213 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) |
1213 | return; | 1214 | return; |
1214 | 1215 | ||
1215 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1216 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
1216 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 1217 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
1217 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | 1218 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
1218 | 1219 | ||
1219 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | 1220 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " |
1220 | "status=%d aid=%d)\n", | 1221 | "status=%d aid=%d)\n", |
1221 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, | 1222 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, |
1222 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | 1223 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); |
1223 | 1224 | ||
1224 | if (status_code != WLAN_STATUS_SUCCESS) { | 1225 | if (status_code != WLAN_STATUS_SUCCESS) { |
1225 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | 1226 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", |
1226 | sdata->dev->name, status_code); | 1227 | sdata->dev->name, status_code); |
1227 | /* if this was a reassociation, ensure we try a "full" | 1228 | /* if this was a reassociation, ensure we try a "full" |
1228 | * association next time. This works around some broken APs | 1229 | * association next time. This works around some broken APs |
1229 | * which do not correctly reject reassociation requests. */ | 1230 | * which do not correctly reject reassociation requests. */ |
1230 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1231 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1231 | return; | 1232 | return; |
1232 | } | 1233 | } |
1233 | 1234 | ||
1234 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 1235 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
1235 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | 1236 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " |
1236 | "set\n", sdata->dev->name, aid); | 1237 | "set\n", sdata->dev->name, aid); |
1237 | aid &= ~(BIT(15) | BIT(14)); | 1238 | aid &= ~(BIT(15) | BIT(14)); |
1238 | 1239 | ||
1239 | pos = mgmt->u.assoc_resp.variable; | 1240 | pos = mgmt->u.assoc_resp.variable; |
1240 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 1241 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1241 | 1242 | ||
1242 | if (!elems.supp_rates) { | 1243 | if (!elems.supp_rates) { |
1243 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1244 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1244 | sdata->dev->name); | 1245 | sdata->dev->name); |
1245 | return; | 1246 | return; |
1246 | } | 1247 | } |
1247 | 1248 | ||
1248 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | 1249 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); |
1249 | ifsta->aid = aid; | 1250 | ifsta->aid = aid; |
1250 | ifsta->ap_capab = capab_info; | 1251 | ifsta->ap_capab = capab_info; |
1251 | 1252 | ||
1252 | kfree(ifsta->assocresp_ies); | 1253 | kfree(ifsta->assocresp_ies); |
1253 | ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); | 1254 | ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); |
1254 | ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); | 1255 | ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); |
1255 | if (ifsta->assocresp_ies) | 1256 | if (ifsta->assocresp_ies) |
1256 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1257 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); |
1257 | 1258 | ||
1258 | rcu_read_lock(); | 1259 | rcu_read_lock(); |
1259 | 1260 | ||
1260 | /* Add STA entry for the AP */ | 1261 | /* Add STA entry for the AP */ |
1261 | sta = sta_info_get(local, ifsta->bssid); | 1262 | sta = sta_info_get(local, ifsta->bssid); |
1262 | if (!sta) { | 1263 | if (!sta) { |
1263 | struct ieee80211_bss *bss; | 1264 | struct ieee80211_bss *bss; |
1264 | 1265 | ||
1265 | newsta = true; | 1266 | newsta = true; |
1266 | 1267 | ||
1267 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); | 1268 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); |
1268 | if (!sta) { | 1269 | if (!sta) { |
1269 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1270 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1270 | " the AP\n", sdata->dev->name); | 1271 | " the AP\n", sdata->dev->name); |
1271 | rcu_read_unlock(); | 1272 | rcu_read_unlock(); |
1272 | return; | 1273 | return; |
1273 | } | 1274 | } |
1274 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 1275 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
1275 | local->hw.conf.channel->center_freq, | 1276 | local->hw.conf.channel->center_freq, |
1276 | ifsta->ssid, ifsta->ssid_len); | 1277 | ifsta->ssid, ifsta->ssid_len); |
1277 | if (bss) { | 1278 | if (bss) { |
1278 | sta->last_signal = bss->signal; | 1279 | sta->last_signal = bss->signal; |
1279 | sta->last_qual = bss->qual; | 1280 | sta->last_qual = bss->qual; |
1280 | sta->last_noise = bss->noise; | 1281 | sta->last_noise = bss->noise; |
1281 | ieee80211_rx_bss_put(local, bss); | 1282 | ieee80211_rx_bss_put(local, bss); |
1282 | } | 1283 | } |
1283 | 1284 | ||
1284 | /* update new sta with its last rx activity */ | 1285 | /* update new sta with its last rx activity */ |
1285 | sta->last_rx = jiffies; | 1286 | sta->last_rx = jiffies; |
1286 | } | 1287 | } |
1287 | 1288 | ||
1288 | /* | 1289 | /* |
1289 | * FIXME: Do we really need to update the sta_info's information here? | 1290 | * FIXME: Do we really need to update the sta_info's information here? |
1290 | * We already know about the AP (we found it in our list) so it | 1291 | * We already know about the AP (we found it in our list) so it |
1291 | * should already be filled with the right info, no? | 1292 | * should already be filled with the right info, no? |
1292 | * As is stands, all this is racy because typically we assume | 1293 | * As is stands, all this is racy because typically we assume |
1293 | * the information that is filled in here (except flags) doesn't | 1294 | * the information that is filled in here (except flags) doesn't |
1294 | * change while a STA structure is alive. As such, it should move | 1295 | * change while a STA structure is alive. As such, it should move |
1295 | * to between the sta_info_alloc() and sta_info_insert() above. | 1296 | * to between the sta_info_alloc() and sta_info_insert() above. |
1296 | */ | 1297 | */ |
1297 | 1298 | ||
1298 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | | 1299 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | |
1299 | WLAN_STA_AUTHORIZED); | 1300 | WLAN_STA_AUTHORIZED); |
1300 | 1301 | ||
1301 | rates = 0; | 1302 | rates = 0; |
1302 | basic_rates = 0; | 1303 | basic_rates = 0; |
1303 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1304 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1304 | 1305 | ||
1305 | for (i = 0; i < elems.supp_rates_len; i++) { | 1306 | for (i = 0; i < elems.supp_rates_len; i++) { |
1306 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1307 | int rate = (elems.supp_rates[i] & 0x7f) * 5; |
1307 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | 1308 | bool is_basic = !!(elems.supp_rates[i] & 0x80); |
1308 | 1309 | ||
1309 | if (rate > 110) | 1310 | if (rate > 110) |
1310 | have_higher_than_11mbit = true; | 1311 | have_higher_than_11mbit = true; |
1311 | 1312 | ||
1312 | for (j = 0; j < sband->n_bitrates; j++) { | 1313 | for (j = 0; j < sband->n_bitrates; j++) { |
1313 | if (sband->bitrates[j].bitrate == rate) { | 1314 | if (sband->bitrates[j].bitrate == rate) { |
1314 | rates |= BIT(j); | 1315 | rates |= BIT(j); |
1315 | if (is_basic) | 1316 | if (is_basic) |
1316 | basic_rates |= BIT(j); | 1317 | basic_rates |= BIT(j); |
1317 | break; | 1318 | break; |
1318 | } | 1319 | } |
1319 | } | 1320 | } |
1320 | } | 1321 | } |
1321 | 1322 | ||
1322 | for (i = 0; i < elems.ext_supp_rates_len; i++) { | 1323 | for (i = 0; i < elems.ext_supp_rates_len; i++) { |
1323 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; | 1324 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; |
1324 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | 1325 | bool is_basic = !!(elems.supp_rates[i] & 0x80); |
1325 | 1326 | ||
1326 | if (rate > 110) | 1327 | if (rate > 110) |
1327 | have_higher_than_11mbit = true; | 1328 | have_higher_than_11mbit = true; |
1328 | 1329 | ||
1329 | for (j = 0; j < sband->n_bitrates; j++) { | 1330 | for (j = 0; j < sband->n_bitrates; j++) { |
1330 | if (sband->bitrates[j].bitrate == rate) { | 1331 | if (sband->bitrates[j].bitrate == rate) { |
1331 | rates |= BIT(j); | 1332 | rates |= BIT(j); |
1332 | if (is_basic) | 1333 | if (is_basic) |
1333 | basic_rates |= BIT(j); | 1334 | basic_rates |= BIT(j); |
1334 | break; | 1335 | break; |
1335 | } | 1336 | } |
1336 | } | 1337 | } |
1337 | } | 1338 | } |
1338 | 1339 | ||
1339 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 1340 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
1340 | sdata->vif.bss_conf.basic_rates = basic_rates; | 1341 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1341 | 1342 | ||
1342 | /* cf. IEEE 802.11 9.2.12 */ | 1343 | /* cf. IEEE 802.11 9.2.12 */ |
1343 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 1344 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && |
1344 | have_higher_than_11mbit) | 1345 | have_higher_than_11mbit) |
1345 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 1346 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
1346 | else | 1347 | else |
1347 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 1348 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
1348 | 1349 | ||
1349 | if (elems.ht_cap_elem) | 1350 | if (elems.ht_cap_elem) |
1350 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1351 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, |
1351 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1352 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1352 | 1353 | ||
1353 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1354 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
1354 | 1355 | ||
1355 | rate_control_rate_init(sta); | 1356 | rate_control_rate_init(sta); |
1356 | 1357 | ||
1357 | if (elems.wmm_param) | 1358 | if (elems.wmm_param) |
1358 | set_sta_flags(sta, WLAN_STA_WME); | 1359 | set_sta_flags(sta, WLAN_STA_WME); |
1359 | 1360 | ||
1360 | if (newsta) { | 1361 | if (newsta) { |
1361 | int err = sta_info_insert(sta); | 1362 | int err = sta_info_insert(sta); |
1362 | if (err) { | 1363 | if (err) { |
1363 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1364 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
1364 | " the AP (error %d)\n", sdata->dev->name, err); | 1365 | " the AP (error %d)\n", sdata->dev->name, err); |
1365 | rcu_read_unlock(); | 1366 | rcu_read_unlock(); |
1366 | return; | 1367 | return; |
1367 | } | 1368 | } |
1368 | } | 1369 | } |
1369 | 1370 | ||
1370 | rcu_read_unlock(); | 1371 | rcu_read_unlock(); |
1371 | 1372 | ||
1372 | if (elems.wmm_param) | 1373 | if (elems.wmm_param) |
1373 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1374 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
1374 | elems.wmm_param_len); | 1375 | elems.wmm_param_len); |
1375 | 1376 | ||
1376 | if (elems.ht_info_elem && elems.wmm_param && | 1377 | if (elems.ht_info_elem && elems.wmm_param && |
1377 | (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 1378 | (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) |
1378 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1379 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1379 | ap_ht_cap_flags); | 1380 | ap_ht_cap_flags); |
1380 | 1381 | ||
1381 | /* set AID and assoc capability, | 1382 | /* set AID and assoc capability, |
1382 | * ieee80211_set_associated() will tell the driver */ | 1383 | * ieee80211_set_associated() will tell the driver */ |
1383 | bss_conf->aid = aid; | 1384 | bss_conf->aid = aid; |
1384 | bss_conf->assoc_capability = capab_info; | 1385 | bss_conf->assoc_capability = capab_info; |
1385 | ieee80211_set_associated(sdata, ifsta, changed); | 1386 | ieee80211_set_associated(sdata, ifsta, changed); |
1386 | 1387 | ||
1387 | ieee80211_associated(sdata, ifsta); | 1388 | ieee80211_associated(sdata, ifsta); |
1388 | } | 1389 | } |
1389 | 1390 | ||
1390 | 1391 | ||
1391 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 1392 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
1392 | struct ieee80211_if_sta *ifsta, | 1393 | struct ieee80211_if_sta *ifsta, |
1393 | struct ieee80211_bss *bss) | 1394 | struct ieee80211_bss *bss) |
1394 | { | 1395 | { |
1395 | struct ieee80211_local *local = sdata->local; | 1396 | struct ieee80211_local *local = sdata->local; |
1396 | int res, rates, i, j; | 1397 | int res, rates, i, j; |
1397 | struct sk_buff *skb; | 1398 | struct sk_buff *skb; |
1398 | struct ieee80211_mgmt *mgmt; | 1399 | struct ieee80211_mgmt *mgmt; |
1399 | u8 *pos; | 1400 | u8 *pos; |
1400 | struct ieee80211_supported_band *sband; | 1401 | struct ieee80211_supported_band *sband; |
1401 | union iwreq_data wrqu; | 1402 | union iwreq_data wrqu; |
1402 | 1403 | ||
1403 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 1404 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
1404 | if (!skb) { | 1405 | if (!skb) { |
1405 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1406 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
1406 | "response\n", sdata->dev->name); | 1407 | "response\n", sdata->dev->name); |
1407 | return -ENOMEM; | 1408 | return -ENOMEM; |
1408 | } | 1409 | } |
1409 | 1410 | ||
1410 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1411 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1411 | 1412 | ||
1412 | /* Remove possible STA entries from other IBSS networks. */ | 1413 | /* Remove possible STA entries from other IBSS networks. */ |
1413 | sta_info_flush_delayed(sdata); | 1414 | sta_info_flush_delayed(sdata); |
1414 | 1415 | ||
1415 | if (local->ops->reset_tsf) { | 1416 | if (local->ops->reset_tsf) { |
1416 | /* Reset own TSF to allow time synchronization work. */ | 1417 | /* Reset own TSF to allow time synchronization work. */ |
1417 | local->ops->reset_tsf(local_to_hw(local)); | 1418 | local->ops->reset_tsf(local_to_hw(local)); |
1418 | } | 1419 | } |
1419 | memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); | 1420 | memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); |
1420 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | 1421 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); |
1421 | if (res) | 1422 | if (res) |
1422 | return res; | 1423 | return res; |
1423 | 1424 | ||
1424 | local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; | 1425 | local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; |
1425 | 1426 | ||
1426 | sdata->drop_unencrypted = bss->capability & | 1427 | sdata->drop_unencrypted = bss->capability & |
1427 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 1428 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
1428 | 1429 | ||
1429 | res = ieee80211_set_freq(sdata, bss->freq); | 1430 | res = ieee80211_set_freq(sdata, bss->freq); |
1430 | 1431 | ||
1431 | if (res) | 1432 | if (res) |
1432 | return res; | 1433 | return res; |
1433 | 1434 | ||
1434 | /* Build IBSS probe response */ | 1435 | /* Build IBSS probe response */ |
1435 | 1436 | ||
1436 | skb_reserve(skb, local->hw.extra_tx_headroom); | 1437 | skb_reserve(skb, local->hw.extra_tx_headroom); |
1437 | 1438 | ||
1438 | mgmt = (struct ieee80211_mgmt *) | 1439 | mgmt = (struct ieee80211_mgmt *) |
1439 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | 1440 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); |
1440 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 1441 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); |
1441 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1442 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
1442 | IEEE80211_STYPE_PROBE_RESP); | 1443 | IEEE80211_STYPE_PROBE_RESP); |
1443 | memset(mgmt->da, 0xff, ETH_ALEN); | 1444 | memset(mgmt->da, 0xff, ETH_ALEN); |
1444 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 1445 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
1445 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 1446 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
1446 | mgmt->u.beacon.beacon_int = | 1447 | mgmt->u.beacon.beacon_int = |
1447 | cpu_to_le16(local->hw.conf.beacon_int); | 1448 | cpu_to_le16(local->hw.conf.beacon_int); |
1448 | mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp); | 1449 | mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp); |
1449 | mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); | 1450 | mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); |
1450 | 1451 | ||
1451 | pos = skb_put(skb, 2 + ifsta->ssid_len); | 1452 | pos = skb_put(skb, 2 + ifsta->ssid_len); |
1452 | *pos++ = WLAN_EID_SSID; | 1453 | *pos++ = WLAN_EID_SSID; |
1453 | *pos++ = ifsta->ssid_len; | 1454 | *pos++ = ifsta->ssid_len; |
1454 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 1455 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); |
1455 | 1456 | ||
1456 | rates = bss->supp_rates_len; | 1457 | rates = bss->supp_rates_len; |
1457 | if (rates > 8) | 1458 | if (rates > 8) |
1458 | rates = 8; | 1459 | rates = 8; |
1459 | pos = skb_put(skb, 2 + rates); | 1460 | pos = skb_put(skb, 2 + rates); |
1460 | *pos++ = WLAN_EID_SUPP_RATES; | 1461 | *pos++ = WLAN_EID_SUPP_RATES; |
1461 | *pos++ = rates; | 1462 | *pos++ = rates; |
1462 | memcpy(pos, bss->supp_rates, rates); | 1463 | memcpy(pos, bss->supp_rates, rates); |
1463 | 1464 | ||
1464 | if (bss->band == IEEE80211_BAND_2GHZ) { | 1465 | if (bss->band == IEEE80211_BAND_2GHZ) { |
1465 | pos = skb_put(skb, 2 + 1); | 1466 | pos = skb_put(skb, 2 + 1); |
1466 | *pos++ = WLAN_EID_DS_PARAMS; | 1467 | *pos++ = WLAN_EID_DS_PARAMS; |
1467 | *pos++ = 1; | 1468 | *pos++ = 1; |
1468 | *pos++ = ieee80211_frequency_to_channel(bss->freq); | 1469 | *pos++ = ieee80211_frequency_to_channel(bss->freq); |
1469 | } | 1470 | } |
1470 | 1471 | ||
1471 | pos = skb_put(skb, 2 + 2); | 1472 | pos = skb_put(skb, 2 + 2); |
1472 | *pos++ = WLAN_EID_IBSS_PARAMS; | 1473 | *pos++ = WLAN_EID_IBSS_PARAMS; |
1473 | *pos++ = 2; | 1474 | *pos++ = 2; |
1474 | /* FIX: set ATIM window based on scan results */ | 1475 | /* FIX: set ATIM window based on scan results */ |
1475 | *pos++ = 0; | 1476 | *pos++ = 0; |
1476 | *pos++ = 0; | 1477 | *pos++ = 0; |
1477 | 1478 | ||
1478 | if (bss->supp_rates_len > 8) { | 1479 | if (bss->supp_rates_len > 8) { |
1479 | rates = bss->supp_rates_len - 8; | 1480 | rates = bss->supp_rates_len - 8; |
1480 | pos = skb_put(skb, 2 + rates); | 1481 | pos = skb_put(skb, 2 + rates); |
1481 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 1482 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
1482 | *pos++ = rates; | 1483 | *pos++ = rates; |
1483 | memcpy(pos, &bss->supp_rates[8], rates); | 1484 | memcpy(pos, &bss->supp_rates[8], rates); |
1484 | } | 1485 | } |
1485 | 1486 | ||
1486 | ifsta->probe_resp = skb; | 1487 | ifsta->probe_resp = skb; |
1487 | 1488 | ||
1488 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 1489 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); |
1489 | 1490 | ||
1490 | 1491 | ||
1491 | rates = 0; | 1492 | rates = 0; |
1492 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1493 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1493 | for (i = 0; i < bss->supp_rates_len; i++) { | 1494 | for (i = 0; i < bss->supp_rates_len; i++) { |
1494 | int bitrate = (bss->supp_rates[i] & 0x7f) * 5; | 1495 | int bitrate = (bss->supp_rates[i] & 0x7f) * 5; |
1495 | for (j = 0; j < sband->n_bitrates; j++) | 1496 | for (j = 0; j < sband->n_bitrates; j++) |
1496 | if (sband->bitrates[j].bitrate == bitrate) | 1497 | if (sband->bitrates[j].bitrate == bitrate) |
1497 | rates |= BIT(j); | 1498 | rates |= BIT(j); |
1498 | } | 1499 | } |
1499 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | 1500 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; |
1500 | 1501 | ||
1501 | ieee80211_sta_def_wmm_params(sdata, bss); | 1502 | ieee80211_sta_def_wmm_params(sdata, bss); |
1502 | 1503 | ||
1503 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | 1504 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; |
1504 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 1505 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
1505 | 1506 | ||
1506 | ieee80211_led_assoc(local, true); | 1507 | ieee80211_led_assoc(local, true); |
1507 | 1508 | ||
1508 | memset(&wrqu, 0, sizeof(wrqu)); | 1509 | memset(&wrqu, 0, sizeof(wrqu)); |
1509 | memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); | 1510 | memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); |
1510 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 1511 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
1511 | 1512 | ||
1512 | return res; | 1513 | return res; |
1513 | } | 1514 | } |
1514 | 1515 | ||
1515 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 1516 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1516 | struct ieee80211_mgmt *mgmt, | 1517 | struct ieee80211_mgmt *mgmt, |
1517 | size_t len, | 1518 | size_t len, |
1518 | struct ieee80211_rx_status *rx_status, | 1519 | struct ieee80211_rx_status *rx_status, |
1519 | struct ieee802_11_elems *elems, | 1520 | struct ieee802_11_elems *elems, |
1520 | bool beacon) | 1521 | bool beacon) |
1521 | { | 1522 | { |
1522 | struct ieee80211_local *local = sdata->local; | 1523 | struct ieee80211_local *local = sdata->local; |
1523 | int freq; | 1524 | int freq; |
1524 | struct ieee80211_bss *bss; | 1525 | struct ieee80211_bss *bss; |
1525 | struct sta_info *sta; | 1526 | struct sta_info *sta; |
1526 | struct ieee80211_channel *channel; | 1527 | struct ieee80211_channel *channel; |
1527 | u64 beacon_timestamp, rx_timestamp; | 1528 | u64 beacon_timestamp, rx_timestamp; |
1528 | u64 supp_rates = 0; | 1529 | u64 supp_rates = 0; |
1529 | enum ieee80211_band band = rx_status->band; | 1530 | enum ieee80211_band band = rx_status->band; |
1530 | 1531 | ||
1531 | if (elems->ds_params && elems->ds_params_len == 1) | 1532 | if (elems->ds_params && elems->ds_params_len == 1) |
1532 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1533 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
1533 | else | 1534 | else |
1534 | freq = rx_status->freq; | 1535 | freq = rx_status->freq; |
1535 | 1536 | ||
1536 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | 1537 | channel = ieee80211_get_channel(local->hw.wiphy, freq); |
1537 | 1538 | ||
1538 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 1539 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
1539 | return; | 1540 | return; |
1540 | 1541 | ||
1541 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | 1542 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && |
1542 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | 1543 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { |
1543 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | 1544 | supp_rates = ieee80211_sta_get_rates(local, elems, band); |
1544 | 1545 | ||
1545 | rcu_read_lock(); | 1546 | rcu_read_lock(); |
1546 | 1547 | ||
1547 | sta = sta_info_get(local, mgmt->sa); | 1548 | sta = sta_info_get(local, mgmt->sa); |
1548 | if (sta) { | 1549 | if (sta) { |
1549 | u64 prev_rates; | 1550 | u64 prev_rates; |
1550 | 1551 | ||
1551 | prev_rates = sta->sta.supp_rates[band]; | 1552 | prev_rates = sta->sta.supp_rates[band]; |
1552 | /* make sure mandatory rates are always added */ | 1553 | /* make sure mandatory rates are always added */ |
1553 | sta->sta.supp_rates[band] = supp_rates | | 1554 | sta->sta.supp_rates[band] = supp_rates | |
1554 | ieee80211_mandatory_rates(local, band); | 1555 | ieee80211_mandatory_rates(local, band); |
1555 | 1556 | ||
1556 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1557 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1557 | if (sta->sta.supp_rates[band] != prev_rates) | 1558 | if (sta->sta.supp_rates[band] != prev_rates) |
1558 | printk(KERN_DEBUG "%s: updated supp_rates set " | 1559 | printk(KERN_DEBUG "%s: updated supp_rates set " |
1559 | "for %pM based on beacon info (0x%llx | " | 1560 | "for %pM based on beacon info (0x%llx | " |
1560 | "0x%llx -> 0x%llx)\n", | 1561 | "0x%llx -> 0x%llx)\n", |
1561 | sdata->dev->name, | 1562 | sdata->dev->name, |
1562 | sta->sta.addr, | 1563 | sta->sta.addr, |
1563 | (unsigned long long) prev_rates, | 1564 | (unsigned long long) prev_rates, |
1564 | (unsigned long long) supp_rates, | 1565 | (unsigned long long) supp_rates, |
1565 | (unsigned long long) sta->sta.supp_rates[band]); | 1566 | (unsigned long long) sta->sta.supp_rates[band]); |
1566 | #endif | 1567 | #endif |
1567 | } else { | 1568 | } else { |
1568 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 1569 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); |
1569 | } | 1570 | } |
1570 | 1571 | ||
1571 | rcu_read_unlock(); | 1572 | rcu_read_unlock(); |
1572 | } | 1573 | } |
1573 | 1574 | ||
1574 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1575 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1575 | freq, beacon); | 1576 | freq, beacon); |
1576 | if (!bss) | 1577 | if (!bss) |
1577 | return; | 1578 | return; |
1578 | 1579 | ||
1579 | /* was just updated in ieee80211_bss_info_update */ | 1580 | /* was just updated in ieee80211_bss_info_update */ |
1580 | beacon_timestamp = bss->timestamp; | 1581 | beacon_timestamp = bss->timestamp; |
1581 | 1582 | ||
1582 | /* | 1583 | /* |
1583 | * In STA mode, the remaining parameters should not be overridden | 1584 | * In STA mode, the remaining parameters should not be overridden |
1584 | * by beacons because they're not necessarily accurate there. | 1585 | * by beacons because they're not necessarily accurate there. |
1585 | */ | 1586 | */ |
1586 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1587 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1587 | bss->last_probe_resp && beacon) { | 1588 | bss->last_probe_resp && beacon) { |
1588 | ieee80211_rx_bss_put(local, bss); | 1589 | ieee80211_rx_bss_put(local, bss); |
1589 | return; | 1590 | return; |
1590 | } | 1591 | } |
1591 | 1592 | ||
1592 | /* check if we need to merge IBSS */ | 1593 | /* check if we need to merge IBSS */ |
1593 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && | 1594 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && |
1594 | bss->capability & WLAN_CAPABILITY_IBSS && | 1595 | bss->capability & WLAN_CAPABILITY_IBSS && |
1595 | bss->freq == local->oper_channel->center_freq && | 1596 | bss->freq == local->oper_channel->center_freq && |
1596 | elems->ssid_len == sdata->u.sta.ssid_len && | 1597 | elems->ssid_len == sdata->u.sta.ssid_len && |
1597 | memcmp(elems->ssid, sdata->u.sta.ssid, | 1598 | memcmp(elems->ssid, sdata->u.sta.ssid, |
1598 | sdata->u.sta.ssid_len) == 0) { | 1599 | sdata->u.sta.ssid_len) == 0) { |
1599 | if (rx_status->flag & RX_FLAG_TSFT) { | 1600 | if (rx_status->flag & RX_FLAG_TSFT) { |
1600 | /* in order for correct IBSS merging we need mactime | 1601 | /* in order for correct IBSS merging we need mactime |
1601 | * | 1602 | * |
1602 | * since mactime is defined as the time the first data | 1603 | * since mactime is defined as the time the first data |
1603 | * symbol of the frame hits the PHY, and the timestamp | 1604 | * symbol of the frame hits the PHY, and the timestamp |
1604 | * of the beacon is defined as "the time that the data | 1605 | * of the beacon is defined as "the time that the data |
1605 | * symbol containing the first bit of the timestamp is | 1606 | * symbol containing the first bit of the timestamp is |
1606 | * transmitted to the PHY plus the transmitting STAโs | 1607 | * transmitted to the PHY plus the transmitting STAโs |
1607 | * delays through its local PHY from the MAC-PHY | 1608 | * delays through its local PHY from the MAC-PHY |
1608 | * interface to its interface with the WM" | 1609 | * interface to its interface with the WM" |
1609 | * (802.11 11.1.2) - equals the time this bit arrives at | 1610 | * (802.11 11.1.2) - equals the time this bit arrives at |
1610 | * the receiver - we have to take into account the | 1611 | * the receiver - we have to take into account the |
1611 | * offset between the two. | 1612 | * offset between the two. |
1612 | * e.g: at 1 MBit that means mactime is 192 usec earlier | 1613 | * e.g: at 1 MBit that means mactime is 192 usec earlier |
1613 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | 1614 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. |
1614 | */ | 1615 | */ |
1615 | int rate = local->hw.wiphy->bands[band]-> | 1616 | int rate = local->hw.wiphy->bands[band]-> |
1616 | bitrates[rx_status->rate_idx].bitrate; | 1617 | bitrates[rx_status->rate_idx].bitrate; |
1617 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | 1618 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); |
1618 | } else if (local && local->ops && local->ops->get_tsf) | 1619 | } else if (local && local->ops && local->ops->get_tsf) |
1619 | /* second best option: get current TSF */ | 1620 | /* second best option: get current TSF */ |
1620 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | 1621 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); |
1621 | else | 1622 | else |
1622 | /* can't merge without knowing the TSF */ | 1623 | /* can't merge without knowing the TSF */ |
1623 | rx_timestamp = -1LLU; | 1624 | rx_timestamp = -1LLU; |
1624 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1625 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1625 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | 1626 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" |
1626 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | 1627 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", |
1627 | mgmt->sa, mgmt->bssid, | 1628 | mgmt->sa, mgmt->bssid, |
1628 | (unsigned long long)rx_timestamp, | 1629 | (unsigned long long)rx_timestamp, |
1629 | (unsigned long long)beacon_timestamp, | 1630 | (unsigned long long)beacon_timestamp, |
1630 | (unsigned long long)(rx_timestamp - beacon_timestamp), | 1631 | (unsigned long long)(rx_timestamp - beacon_timestamp), |
1631 | jiffies); | 1632 | jiffies); |
1632 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1633 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
1633 | if (beacon_timestamp > rx_timestamp) { | 1634 | if (beacon_timestamp > rx_timestamp) { |
1634 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1635 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1635 | printk(KERN_DEBUG "%s: beacon TSF higher than " | 1636 | printk(KERN_DEBUG "%s: beacon TSF higher than " |
1636 | "local TSF - IBSS merge with BSSID %pM\n", | 1637 | "local TSF - IBSS merge with BSSID %pM\n", |
1637 | sdata->dev->name, mgmt->bssid); | 1638 | sdata->dev->name, mgmt->bssid); |
1638 | #endif | 1639 | #endif |
1639 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | 1640 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); |
1640 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 1641 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); |
1641 | } | 1642 | } |
1642 | } | 1643 | } |
1643 | 1644 | ||
1644 | ieee80211_rx_bss_put(local, bss); | 1645 | ieee80211_rx_bss_put(local, bss); |
1645 | } | 1646 | } |
1646 | 1647 | ||
1647 | 1648 | ||
1648 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 1649 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
1649 | struct ieee80211_mgmt *mgmt, | 1650 | struct ieee80211_mgmt *mgmt, |
1650 | size_t len, | 1651 | size_t len, |
1651 | struct ieee80211_rx_status *rx_status) | 1652 | struct ieee80211_rx_status *rx_status) |
1652 | { | 1653 | { |
1653 | size_t baselen; | 1654 | size_t baselen; |
1654 | struct ieee802_11_elems elems; | 1655 | struct ieee802_11_elems elems; |
1655 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1656 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
1656 | 1657 | ||
1657 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1658 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1658 | return; /* ignore ProbeResp to foreign address */ | 1659 | return; /* ignore ProbeResp to foreign address */ |
1659 | 1660 | ||
1660 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 1661 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
1661 | if (baselen > len) | 1662 | if (baselen > len) |
1662 | return; | 1663 | return; |
1663 | 1664 | ||
1664 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 1665 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
1665 | &elems); | 1666 | &elems); |
1666 | 1667 | ||
1667 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1668 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1668 | 1669 | ||
1669 | /* direct probe may be part of the association flow */ | 1670 | /* direct probe may be part of the association flow */ |
1670 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1671 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1671 | &ifsta->request)) { | 1672 | &ifsta->request)) { |
1672 | printk(KERN_DEBUG "%s direct probe responded\n", | 1673 | printk(KERN_DEBUG "%s direct probe responded\n", |
1673 | sdata->dev->name); | 1674 | sdata->dev->name); |
1674 | ieee80211_authenticate(sdata, ifsta); | 1675 | ieee80211_authenticate(sdata, ifsta); |
1675 | } | 1676 | } |
1676 | } | 1677 | } |
1677 | 1678 | ||
1678 | 1679 | ||
1679 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1680 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
1680 | struct ieee80211_mgmt *mgmt, | 1681 | struct ieee80211_mgmt *mgmt, |
1681 | size_t len, | 1682 | size_t len, |
1682 | struct ieee80211_rx_status *rx_status) | 1683 | struct ieee80211_rx_status *rx_status) |
1683 | { | 1684 | { |
1684 | struct ieee80211_if_sta *ifsta; | 1685 | struct ieee80211_if_sta *ifsta; |
1685 | size_t baselen; | 1686 | size_t baselen; |
1686 | struct ieee802_11_elems elems; | 1687 | struct ieee802_11_elems elems; |
1687 | struct ieee80211_local *local = sdata->local; | 1688 | struct ieee80211_local *local = sdata->local; |
1688 | u32 changed = 0; | 1689 | u32 changed = 0; |
1689 | bool erp_valid; | 1690 | bool erp_valid; |
1690 | u8 erp_value = 0; | 1691 | u8 erp_value = 0; |
1691 | 1692 | ||
1692 | /* Process beacon from the current BSS */ | 1693 | /* Process beacon from the current BSS */ |
1693 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 1694 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
1694 | if (baselen > len) | 1695 | if (baselen > len) |
1695 | return; | 1696 | return; |
1696 | 1697 | ||
1697 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 1698 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); |
1698 | 1699 | ||
1699 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | 1700 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); |
1700 | 1701 | ||
1701 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1702 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1702 | return; | 1703 | return; |
1703 | ifsta = &sdata->u.sta; | 1704 | ifsta = &sdata->u.sta; |
1704 | 1705 | ||
1705 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || | 1706 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || |
1706 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1707 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1707 | return; | 1708 | return; |
1708 | 1709 | ||
1709 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1710 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
1710 | elems.wmm_param_len); | 1711 | elems.wmm_param_len); |
1711 | 1712 | ||
1712 | 1713 | ||
1713 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1714 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1714 | erp_valid = true; | 1715 | erp_valid = true; |
1715 | erp_value = elems.erp_info[0]; | 1716 | erp_value = elems.erp_info[0]; |
1716 | } else { | 1717 | } else { |
1717 | erp_valid = false; | 1718 | erp_valid = false; |
1718 | } | 1719 | } |
1719 | changed |= ieee80211_handle_bss_capability(sdata, | 1720 | changed |= ieee80211_handle_bss_capability(sdata, |
1720 | le16_to_cpu(mgmt->u.beacon.capab_info), | 1721 | le16_to_cpu(mgmt->u.beacon.capab_info), |
1721 | erp_valid, erp_value); | 1722 | erp_valid, erp_value); |
1722 | 1723 | ||
1723 | 1724 | ||
1724 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { | 1725 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { |
1725 | struct sta_info *sta; | 1726 | struct sta_info *sta; |
1726 | struct ieee80211_supported_band *sband; | 1727 | struct ieee80211_supported_band *sband; |
1727 | u16 ap_ht_cap_flags; | 1728 | u16 ap_ht_cap_flags; |
1728 | 1729 | ||
1729 | rcu_read_lock(); | 1730 | rcu_read_lock(); |
1730 | 1731 | ||
1731 | sta = sta_info_get(local, ifsta->bssid); | 1732 | sta = sta_info_get(local, ifsta->bssid); |
1732 | if (!sta) { | 1733 | if (!sta) { |
1733 | rcu_read_unlock(); | 1734 | rcu_read_unlock(); |
1734 | return; | 1735 | return; |
1735 | } | 1736 | } |
1736 | 1737 | ||
1737 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1738 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1738 | 1739 | ||
1739 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1740 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, |
1740 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1741 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1741 | 1742 | ||
1742 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1743 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
1743 | 1744 | ||
1744 | rcu_read_unlock(); | 1745 | rcu_read_unlock(); |
1745 | 1746 | ||
1746 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1747 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1747 | ap_ht_cap_flags); | 1748 | ap_ht_cap_flags); |
1748 | } | 1749 | } |
1749 | 1750 | ||
1750 | if (elems.country_elem) { | 1751 | if (elems.country_elem) { |
1751 | /* Note we are only reviewing this on beacons | 1752 | /* Note we are only reviewing this on beacons |
1752 | * for the BSSID we are associated to */ | 1753 | * for the BSSID we are associated to */ |
1753 | regulatory_hint_11d(local->hw.wiphy, | 1754 | regulatory_hint_11d(local->hw.wiphy, |
1754 | elems.country_elem, elems.country_elem_len); | 1755 | elems.country_elem, elems.country_elem_len); |
1755 | } | 1756 | } |
1756 | 1757 | ||
1757 | ieee80211_bss_info_change_notify(sdata, changed); | 1758 | ieee80211_bss_info_change_notify(sdata, changed); |
1758 | } | 1759 | } |
1759 | 1760 | ||
1760 | 1761 | ||
1761 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 1762 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, |
1762 | struct ieee80211_if_sta *ifsta, | 1763 | struct ieee80211_if_sta *ifsta, |
1763 | struct ieee80211_mgmt *mgmt, | 1764 | struct ieee80211_mgmt *mgmt, |
1764 | size_t len, | 1765 | size_t len, |
1765 | struct ieee80211_rx_status *rx_status) | 1766 | struct ieee80211_rx_status *rx_status) |
1766 | { | 1767 | { |
1767 | struct ieee80211_local *local = sdata->local; | 1768 | struct ieee80211_local *local = sdata->local; |
1768 | int tx_last_beacon; | 1769 | int tx_last_beacon; |
1769 | struct sk_buff *skb; | 1770 | struct sk_buff *skb; |
1770 | struct ieee80211_mgmt *resp; | 1771 | struct ieee80211_mgmt *resp; |
1771 | u8 *pos, *end; | 1772 | u8 *pos, *end; |
1772 | 1773 | ||
1773 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC || | 1774 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC || |
1774 | ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | 1775 | ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || |
1775 | len < 24 + 2 || !ifsta->probe_resp) | 1776 | len < 24 + 2 || !ifsta->probe_resp) |
1776 | return; | 1777 | return; |
1777 | 1778 | ||
1778 | if (local->ops->tx_last_beacon) | 1779 | if (local->ops->tx_last_beacon) |
1779 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | 1780 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); |
1780 | else | 1781 | else |
1781 | tx_last_beacon = 1; | 1782 | tx_last_beacon = 1; |
1782 | 1783 | ||
1783 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1784 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1784 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | 1785 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" |
1785 | " (tx_last_beacon=%d)\n", | 1786 | " (tx_last_beacon=%d)\n", |
1786 | sdata->dev->name, mgmt->sa, mgmt->da, | 1787 | sdata->dev->name, mgmt->sa, mgmt->da, |
1787 | mgmt->bssid, tx_last_beacon); | 1788 | mgmt->bssid, tx_last_beacon); |
1788 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1789 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
1789 | 1790 | ||
1790 | if (!tx_last_beacon) | 1791 | if (!tx_last_beacon) |
1791 | return; | 1792 | return; |
1792 | 1793 | ||
1793 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && | 1794 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && |
1794 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | 1795 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) |
1795 | return; | 1796 | return; |
1796 | 1797 | ||
1797 | end = ((u8 *) mgmt) + len; | 1798 | end = ((u8 *) mgmt) + len; |
1798 | pos = mgmt->u.probe_req.variable; | 1799 | pos = mgmt->u.probe_req.variable; |
1799 | if (pos[0] != WLAN_EID_SSID || | 1800 | if (pos[0] != WLAN_EID_SSID || |
1800 | pos + 2 + pos[1] > end) { | 1801 | pos + 2 + pos[1] > end) { |
1801 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1802 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1802 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | 1803 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " |
1803 | "from %pM\n", | 1804 | "from %pM\n", |
1804 | sdata->dev->name, mgmt->sa); | 1805 | sdata->dev->name, mgmt->sa); |
1805 | #endif | 1806 | #endif |
1806 | return; | 1807 | return; |
1807 | } | 1808 | } |
1808 | if (pos[1] != 0 && | 1809 | if (pos[1] != 0 && |
1809 | (pos[1] != ifsta->ssid_len || | 1810 | (pos[1] != ifsta->ssid_len || |
1810 | memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { | 1811 | memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { |
1811 | /* Ignore ProbeReq for foreign SSID */ | 1812 | /* Ignore ProbeReq for foreign SSID */ |
1812 | return; | 1813 | return; |
1813 | } | 1814 | } |
1814 | 1815 | ||
1815 | /* Reply with ProbeResp */ | 1816 | /* Reply with ProbeResp */ |
1816 | skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); | 1817 | skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); |
1817 | if (!skb) | 1818 | if (!skb) |
1818 | return; | 1819 | return; |
1819 | 1820 | ||
1820 | resp = (struct ieee80211_mgmt *) skb->data; | 1821 | resp = (struct ieee80211_mgmt *) skb->data; |
1821 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 1822 | memcpy(resp->da, mgmt->sa, ETH_ALEN); |
1822 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1823 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1823 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | 1824 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", |
1824 | sdata->dev->name, resp->da); | 1825 | sdata->dev->name, resp->da); |
1825 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1826 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
1826 | ieee80211_tx_skb(sdata, skb, 0); | 1827 | ieee80211_tx_skb(sdata, skb, 0); |
1827 | } | 1828 | } |
1828 | 1829 | ||
1829 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1830 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
1830 | struct ieee80211_rx_status *rx_status) | 1831 | struct ieee80211_rx_status *rx_status) |
1831 | { | 1832 | { |
1832 | struct ieee80211_local *local = sdata->local; | 1833 | struct ieee80211_local *local = sdata->local; |
1833 | struct ieee80211_if_sta *ifsta; | 1834 | struct ieee80211_if_sta *ifsta; |
1834 | struct ieee80211_mgmt *mgmt; | 1835 | struct ieee80211_mgmt *mgmt; |
1835 | u16 fc; | 1836 | u16 fc; |
1836 | 1837 | ||
1837 | if (skb->len < 24) | 1838 | if (skb->len < 24) |
1838 | goto fail; | 1839 | goto fail; |
1839 | 1840 | ||
1840 | ifsta = &sdata->u.sta; | 1841 | ifsta = &sdata->u.sta; |
1841 | 1842 | ||
1842 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1843 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1843 | fc = le16_to_cpu(mgmt->frame_control); | 1844 | fc = le16_to_cpu(mgmt->frame_control); |
1844 | 1845 | ||
1845 | switch (fc & IEEE80211_FCTL_STYPE) { | 1846 | switch (fc & IEEE80211_FCTL_STYPE) { |
1846 | case IEEE80211_STYPE_PROBE_REQ: | 1847 | case IEEE80211_STYPE_PROBE_REQ: |
1847 | case IEEE80211_STYPE_PROBE_RESP: | 1848 | case IEEE80211_STYPE_PROBE_RESP: |
1848 | case IEEE80211_STYPE_BEACON: | 1849 | case IEEE80211_STYPE_BEACON: |
1849 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | 1850 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); |
1850 | case IEEE80211_STYPE_AUTH: | 1851 | case IEEE80211_STYPE_AUTH: |
1851 | case IEEE80211_STYPE_ASSOC_RESP: | 1852 | case IEEE80211_STYPE_ASSOC_RESP: |
1852 | case IEEE80211_STYPE_REASSOC_RESP: | 1853 | case IEEE80211_STYPE_REASSOC_RESP: |
1853 | case IEEE80211_STYPE_DEAUTH: | 1854 | case IEEE80211_STYPE_DEAUTH: |
1854 | case IEEE80211_STYPE_DISASSOC: | 1855 | case IEEE80211_STYPE_DISASSOC: |
1855 | skb_queue_tail(&ifsta->skb_queue, skb); | 1856 | skb_queue_tail(&ifsta->skb_queue, skb); |
1856 | queue_work(local->hw.workqueue, &ifsta->work); | 1857 | queue_work(local->hw.workqueue, &ifsta->work); |
1857 | return; | 1858 | return; |
1858 | } | 1859 | } |
1859 | 1860 | ||
1860 | fail: | 1861 | fail: |
1861 | kfree_skb(skb); | 1862 | kfree_skb(skb); |
1862 | } | 1863 | } |
1863 | 1864 | ||
1864 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1865 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1865 | struct sk_buff *skb) | 1866 | struct sk_buff *skb) |
1866 | { | 1867 | { |
1867 | struct ieee80211_rx_status *rx_status; | 1868 | struct ieee80211_rx_status *rx_status; |
1868 | struct ieee80211_if_sta *ifsta; | 1869 | struct ieee80211_if_sta *ifsta; |
1869 | struct ieee80211_mgmt *mgmt; | 1870 | struct ieee80211_mgmt *mgmt; |
1870 | u16 fc; | 1871 | u16 fc; |
1871 | 1872 | ||
1872 | ifsta = &sdata->u.sta; | 1873 | ifsta = &sdata->u.sta; |
1873 | 1874 | ||
1874 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 1875 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
1875 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1876 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1876 | fc = le16_to_cpu(mgmt->frame_control); | 1877 | fc = le16_to_cpu(mgmt->frame_control); |
1877 | 1878 | ||
1878 | switch (fc & IEEE80211_FCTL_STYPE) { | 1879 | switch (fc & IEEE80211_FCTL_STYPE) { |
1879 | case IEEE80211_STYPE_PROBE_REQ: | 1880 | case IEEE80211_STYPE_PROBE_REQ: |
1880 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len, | 1881 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len, |
1881 | rx_status); | 1882 | rx_status); |
1882 | break; | 1883 | break; |
1883 | case IEEE80211_STYPE_PROBE_RESP: | 1884 | case IEEE80211_STYPE_PROBE_RESP: |
1884 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | 1885 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); |
1885 | break; | 1886 | break; |
1886 | case IEEE80211_STYPE_BEACON: | 1887 | case IEEE80211_STYPE_BEACON: |
1887 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 1888 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); |
1888 | break; | 1889 | break; |
1889 | case IEEE80211_STYPE_AUTH: | 1890 | case IEEE80211_STYPE_AUTH: |
1890 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | 1891 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); |
1891 | break; | 1892 | break; |
1892 | case IEEE80211_STYPE_ASSOC_RESP: | 1893 | case IEEE80211_STYPE_ASSOC_RESP: |
1893 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); | 1894 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); |
1894 | break; | 1895 | break; |
1895 | case IEEE80211_STYPE_REASSOC_RESP: | 1896 | case IEEE80211_STYPE_REASSOC_RESP: |
1896 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); | 1897 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); |
1897 | break; | 1898 | break; |
1898 | case IEEE80211_STYPE_DEAUTH: | 1899 | case IEEE80211_STYPE_DEAUTH: |
1899 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | 1900 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); |
1900 | break; | 1901 | break; |
1901 | case IEEE80211_STYPE_DISASSOC: | 1902 | case IEEE80211_STYPE_DISASSOC: |
1902 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len); | 1903 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len); |
1903 | break; | 1904 | break; |
1904 | } | 1905 | } |
1905 | 1906 | ||
1906 | kfree_skb(skb); | 1907 | kfree_skb(skb); |
1907 | } | 1908 | } |
1908 | 1909 | ||
1909 | 1910 | ||
1910 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | 1911 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) |
1911 | { | 1912 | { |
1912 | struct ieee80211_local *local = sdata->local; | 1913 | struct ieee80211_local *local = sdata->local; |
1913 | int active = 0; | 1914 | int active = 0; |
1914 | struct sta_info *sta; | 1915 | struct sta_info *sta; |
1915 | 1916 | ||
1916 | rcu_read_lock(); | 1917 | rcu_read_lock(); |
1917 | 1918 | ||
1918 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 1919 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
1919 | if (sta->sdata == sdata && | 1920 | if (sta->sdata == sdata && |
1920 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | 1921 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, |
1921 | jiffies)) { | 1922 | jiffies)) { |
1922 | active++; | 1923 | active++; |
1923 | break; | 1924 | break; |
1924 | } | 1925 | } |
1925 | } | 1926 | } |
1926 | 1927 | ||
1927 | rcu_read_unlock(); | 1928 | rcu_read_unlock(); |
1928 | 1929 | ||
1929 | return active; | 1930 | return active; |
1930 | } | 1931 | } |
1931 | 1932 | ||
1932 | 1933 | ||
1933 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | 1934 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, |
1934 | struct ieee80211_if_sta *ifsta) | 1935 | struct ieee80211_if_sta *ifsta) |
1935 | { | 1936 | { |
1936 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 1937 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
1937 | 1938 | ||
1938 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | 1939 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); |
1939 | if (ieee80211_sta_active_ibss(sdata)) | 1940 | if (ieee80211_sta_active_ibss(sdata)) |
1940 | return; | 1941 | return; |
1941 | 1942 | ||
1942 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 1943 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
1943 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 1944 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); |
1944 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); | 1945 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); |
1945 | } | 1946 | } |
1946 | 1947 | ||
1947 | 1948 | ||
1948 | static void ieee80211_sta_timer(unsigned long data) | 1949 | static void ieee80211_sta_timer(unsigned long data) |
1949 | { | 1950 | { |
1950 | struct ieee80211_sub_if_data *sdata = | 1951 | struct ieee80211_sub_if_data *sdata = |
1951 | (struct ieee80211_sub_if_data *) data; | 1952 | (struct ieee80211_sub_if_data *) data; |
1952 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1953 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
1953 | struct ieee80211_local *local = sdata->local; | 1954 | struct ieee80211_local *local = sdata->local; |
1954 | 1955 | ||
1955 | set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1956 | set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); |
1956 | queue_work(local->hw.workqueue, &ifsta->work); | 1957 | queue_work(local->hw.workqueue, &ifsta->work); |
1957 | } | 1958 | } |
1958 | 1959 | ||
1959 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 1960 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, |
1960 | struct ieee80211_if_sta *ifsta) | 1961 | struct ieee80211_if_sta *ifsta) |
1961 | { | 1962 | { |
1962 | struct ieee80211_local *local = sdata->local; | 1963 | struct ieee80211_local *local = sdata->local; |
1963 | 1964 | ||
1964 | if (local->ops->reset_tsf) { | 1965 | if (local->ops->reset_tsf) { |
1965 | /* Reset own TSF to allow time synchronization work. */ | 1966 | /* Reset own TSF to allow time synchronization work. */ |
1966 | local->ops->reset_tsf(local_to_hw(local)); | 1967 | local->ops->reset_tsf(local_to_hw(local)); |
1967 | } | 1968 | } |
1968 | 1969 | ||
1969 | ifsta->wmm_last_param_set = -1; /* allow any WMM update */ | 1970 | ifsta->wmm_last_param_set = -1; /* allow any WMM update */ |
1970 | 1971 | ||
1971 | 1972 | ||
1972 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1973 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1973 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1974 | ifsta->auth_alg = WLAN_AUTH_OPEN; |
1974 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1975 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
1975 | ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; | 1976 | ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; |
1976 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1977 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1977 | ifsta->auth_alg = WLAN_AUTH_LEAP; | 1978 | ifsta->auth_alg = WLAN_AUTH_LEAP; |
1978 | else | 1979 | else |
1979 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1980 | ifsta->auth_alg = WLAN_AUTH_OPEN; |
1980 | ifsta->auth_transaction = -1; | 1981 | ifsta->auth_transaction = -1; |
1981 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 1982 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; |
1982 | ifsta->assoc_scan_tries = 0; | 1983 | ifsta->assoc_scan_tries = 0; |
1983 | ifsta->direct_probe_tries = 0; | 1984 | ifsta->direct_probe_tries = 0; |
1984 | ifsta->auth_tries = 0; | 1985 | ifsta->auth_tries = 0; |
1985 | ifsta->assoc_tries = 0; | 1986 | ifsta->assoc_tries = 0; |
1986 | netif_tx_stop_all_queues(sdata->dev); | 1987 | netif_tx_stop_all_queues(sdata->dev); |
1987 | netif_carrier_off(sdata->dev); | 1988 | netif_carrier_off(sdata->dev); |
1988 | } | 1989 | } |
1989 | 1990 | ||
1990 | 1991 | ||
1991 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | 1992 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, |
1992 | const char *ssid, int ssid_len) | 1993 | const char *ssid, int ssid_len) |
1993 | { | 1994 | { |
1994 | int tmp, hidden_ssid; | 1995 | int tmp, hidden_ssid; |
1995 | 1996 | ||
1996 | if (ssid_len == ifsta->ssid_len && | 1997 | if (ssid_len == ifsta->ssid_len && |
1997 | !memcmp(ifsta->ssid, ssid, ssid_len)) | 1998 | !memcmp(ifsta->ssid, ssid, ssid_len)) |
1998 | return 1; | 1999 | return 1; |
1999 | 2000 | ||
2000 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) | 2001 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) |
2001 | return 0; | 2002 | return 0; |
2002 | 2003 | ||
2003 | hidden_ssid = 1; | 2004 | hidden_ssid = 1; |
2004 | tmp = ssid_len; | 2005 | tmp = ssid_len; |
2005 | while (tmp--) { | 2006 | while (tmp--) { |
2006 | if (ssid[tmp] != '\0') { | 2007 | if (ssid[tmp] != '\0') { |
2007 | hidden_ssid = 0; | 2008 | hidden_ssid = 0; |
2008 | break; | 2009 | break; |
2009 | } | 2010 | } |
2010 | } | 2011 | } |
2011 | 2012 | ||
2012 | if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) | 2013 | if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) |
2013 | return 1; | 2014 | return 1; |
2014 | 2015 | ||
2015 | if (ssid_len == 1 && ssid[0] == ' ') | 2016 | if (ssid_len == 1 && ssid[0] == ' ') |
2016 | return 1; | 2017 | return 1; |
2017 | 2018 | ||
2018 | return 0; | 2019 | return 0; |
2019 | } | 2020 | } |
2020 | 2021 | ||
2021 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 2022 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, |
2022 | struct ieee80211_if_sta *ifsta) | 2023 | struct ieee80211_if_sta *ifsta) |
2023 | { | 2024 | { |
2024 | struct ieee80211_local *local = sdata->local; | 2025 | struct ieee80211_local *local = sdata->local; |
2025 | struct ieee80211_bss *bss; | 2026 | struct ieee80211_bss *bss; |
2026 | struct ieee80211_supported_band *sband; | 2027 | struct ieee80211_supported_band *sband; |
2027 | u8 bssid[ETH_ALEN], *pos; | 2028 | u8 bssid[ETH_ALEN], *pos; |
2028 | int i; | 2029 | int i; |
2029 | int ret; | 2030 | int ret; |
2030 | 2031 | ||
2031 | #if 0 | 2032 | #if 0 |
2032 | /* Easier testing, use fixed BSSID. */ | 2033 | /* Easier testing, use fixed BSSID. */ |
2033 | memset(bssid, 0xfe, ETH_ALEN); | 2034 | memset(bssid, 0xfe, ETH_ALEN); |
2034 | #else | 2035 | #else |
2035 | /* Generate random, not broadcast, locally administered BSSID. Mix in | 2036 | /* Generate random, not broadcast, locally administered BSSID. Mix in |
2036 | * own MAC address to make sure that devices that do not have proper | 2037 | * own MAC address to make sure that devices that do not have proper |
2037 | * random number generator get different BSSID. */ | 2038 | * random number generator get different BSSID. */ |
2038 | get_random_bytes(bssid, ETH_ALEN); | 2039 | get_random_bytes(bssid, ETH_ALEN); |
2039 | for (i = 0; i < ETH_ALEN; i++) | 2040 | for (i = 0; i < ETH_ALEN; i++) |
2040 | bssid[i] ^= sdata->dev->dev_addr[i]; | 2041 | bssid[i] ^= sdata->dev->dev_addr[i]; |
2041 | bssid[0] &= ~0x01; | 2042 | bssid[0] &= ~0x01; |
2042 | bssid[0] |= 0x02; | 2043 | bssid[0] |= 0x02; |
2043 | #endif | 2044 | #endif |
2044 | 2045 | ||
2045 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 2046 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
2046 | sdata->dev->name, bssid); | 2047 | sdata->dev->name, bssid); |
2047 | 2048 | ||
2048 | bss = ieee80211_rx_bss_add(local, bssid, | 2049 | bss = ieee80211_rx_bss_add(local, bssid, |
2049 | local->hw.conf.channel->center_freq, | 2050 | local->hw.conf.channel->center_freq, |
2050 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | 2051 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); |
2051 | if (!bss) | 2052 | if (!bss) |
2052 | return -ENOMEM; | 2053 | return -ENOMEM; |
2053 | 2054 | ||
2054 | bss->band = local->hw.conf.channel->band; | 2055 | bss->band = local->hw.conf.channel->band; |
2055 | sband = local->hw.wiphy->bands[bss->band]; | 2056 | sband = local->hw.wiphy->bands[bss->band]; |
2056 | 2057 | ||
2057 | if (local->hw.conf.beacon_int == 0) | 2058 | if (local->hw.conf.beacon_int == 0) |
2058 | local->hw.conf.beacon_int = 100; | 2059 | local->hw.conf.beacon_int = 100; |
2059 | bss->beacon_int = local->hw.conf.beacon_int; | 2060 | bss->beacon_int = local->hw.conf.beacon_int; |
2060 | bss->last_update = jiffies; | 2061 | bss->last_update = jiffies; |
2061 | bss->capability = WLAN_CAPABILITY_IBSS; | 2062 | bss->capability = WLAN_CAPABILITY_IBSS; |
2062 | 2063 | ||
2063 | if (sdata->default_key) | 2064 | if (sdata->default_key) |
2064 | bss->capability |= WLAN_CAPABILITY_PRIVACY; | 2065 | bss->capability |= WLAN_CAPABILITY_PRIVACY; |
2065 | else | 2066 | else |
2066 | sdata->drop_unencrypted = 0; | 2067 | sdata->drop_unencrypted = 0; |
2067 | 2068 | ||
2068 | bss->supp_rates_len = sband->n_bitrates; | 2069 | bss->supp_rates_len = sband->n_bitrates; |
2069 | pos = bss->supp_rates; | 2070 | pos = bss->supp_rates; |
2070 | for (i = 0; i < sband->n_bitrates; i++) { | 2071 | for (i = 0; i < sband->n_bitrates; i++) { |
2071 | int rate = sband->bitrates[i].bitrate; | 2072 | int rate = sband->bitrates[i].bitrate; |
2072 | *pos++ = (u8) (rate / 5); | 2073 | *pos++ = (u8) (rate / 5); |
2073 | } | 2074 | } |
2074 | 2075 | ||
2075 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | 2076 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); |
2076 | ieee80211_rx_bss_put(local, bss); | 2077 | ieee80211_rx_bss_put(local, bss); |
2077 | return ret; | 2078 | return ret; |
2078 | } | 2079 | } |
2079 | 2080 | ||
2080 | 2081 | ||
2081 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | 2082 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, |
2082 | struct ieee80211_if_sta *ifsta) | 2083 | struct ieee80211_if_sta *ifsta) |
2083 | { | 2084 | { |
2084 | struct ieee80211_local *local = sdata->local; | 2085 | struct ieee80211_local *local = sdata->local; |
2085 | struct ieee80211_bss *bss; | 2086 | struct ieee80211_bss *bss; |
2086 | int found = 0; | 2087 | int found = 0; |
2087 | u8 bssid[ETH_ALEN]; | 2088 | u8 bssid[ETH_ALEN]; |
2088 | int active_ibss; | 2089 | int active_ibss; |
2089 | 2090 | ||
2090 | if (ifsta->ssid_len == 0) | 2091 | if (ifsta->ssid_len == 0) |
2091 | return -EINVAL; | 2092 | return -EINVAL; |
2092 | 2093 | ||
2093 | active_ibss = ieee80211_sta_active_ibss(sdata); | 2094 | active_ibss = ieee80211_sta_active_ibss(sdata); |
2094 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2095 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2095 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | 2096 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", |
2096 | sdata->dev->name, active_ibss); | 2097 | sdata->dev->name, active_ibss); |
2097 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2098 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2098 | spin_lock_bh(&local->bss_lock); | 2099 | spin_lock_bh(&local->bss_lock); |
2099 | list_for_each_entry(bss, &local->bss_list, list) { | 2100 | list_for_each_entry(bss, &local->bss_list, list) { |
2100 | if (ifsta->ssid_len != bss->ssid_len || | 2101 | if (ifsta->ssid_len != bss->ssid_len || |
2101 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 | 2102 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 |
2102 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) | 2103 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) |
2103 | continue; | 2104 | continue; |
2104 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2105 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2105 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); | 2106 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); |
2106 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2107 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2107 | memcpy(bssid, bss->bssid, ETH_ALEN); | 2108 | memcpy(bssid, bss->bssid, ETH_ALEN); |
2108 | found = 1; | 2109 | found = 1; |
2109 | if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) | 2110 | if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) |
2110 | break; | 2111 | break; |
2111 | } | 2112 | } |
2112 | spin_unlock_bh(&local->bss_lock); | 2113 | spin_unlock_bh(&local->bss_lock); |
2113 | 2114 | ||
2114 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2115 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2115 | if (found) | 2116 | if (found) |
2116 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | 2117 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " |
2117 | "%pM\n", bssid, ifsta->bssid); | 2118 | "%pM\n", bssid, ifsta->bssid); |
2118 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2119 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2119 | 2120 | ||
2120 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 2121 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { |
2121 | int ret; | 2122 | int ret; |
2122 | int search_freq; | 2123 | int search_freq; |
2123 | 2124 | ||
2124 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | 2125 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) |
2125 | search_freq = bss->freq; | 2126 | search_freq = bss->freq; |
2126 | else | 2127 | else |
2127 | search_freq = local->hw.conf.channel->center_freq; | 2128 | search_freq = local->hw.conf.channel->center_freq; |
2128 | 2129 | ||
2129 | bss = ieee80211_rx_bss_get(local, bssid, search_freq, | 2130 | bss = ieee80211_rx_bss_get(local, bssid, search_freq, |
2130 | ifsta->ssid, ifsta->ssid_len); | 2131 | ifsta->ssid, ifsta->ssid_len); |
2131 | if (!bss) | 2132 | if (!bss) |
2132 | goto dont_join; | 2133 | goto dont_join; |
2133 | 2134 | ||
2134 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | 2135 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" |
2135 | " based on configured SSID\n", | 2136 | " based on configured SSID\n", |
2136 | sdata->dev->name, bssid); | 2137 | sdata->dev->name, bssid); |
2137 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | 2138 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); |
2138 | ieee80211_rx_bss_put(local, bss); | 2139 | ieee80211_rx_bss_put(local, bss); |
2139 | return ret; | 2140 | return ret; |
2140 | } | 2141 | } |
2141 | 2142 | ||
2142 | dont_join: | 2143 | dont_join: |
2143 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2144 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2144 | printk(KERN_DEBUG " did not try to join ibss\n"); | 2145 | printk(KERN_DEBUG " did not try to join ibss\n"); |
2145 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2146 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2146 | 2147 | ||
2147 | /* Selected IBSS not found in current scan results - try to scan */ | 2148 | /* Selected IBSS not found in current scan results - try to scan */ |
2148 | if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED && | 2149 | if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED && |
2149 | !ieee80211_sta_active_ibss(sdata)) { | 2150 | !ieee80211_sta_active_ibss(sdata)) { |
2150 | mod_timer(&ifsta->timer, jiffies + | 2151 | mod_timer(&ifsta->timer, jiffies + |
2151 | IEEE80211_IBSS_MERGE_INTERVAL); | 2152 | IEEE80211_IBSS_MERGE_INTERVAL); |
2152 | } else if (time_after(jiffies, local->last_scan_completed + | 2153 | } else if (time_after(jiffies, local->last_scan_completed + |
2153 | IEEE80211_SCAN_INTERVAL)) { | 2154 | IEEE80211_SCAN_INTERVAL)) { |
2154 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 2155 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
2155 | "join\n", sdata->dev->name); | 2156 | "join\n", sdata->dev->name); |
2156 | return ieee80211_request_scan(sdata, ifsta->ssid, | 2157 | return ieee80211_request_scan(sdata, ifsta->ssid, |
2157 | ifsta->ssid_len); | 2158 | ifsta->ssid_len); |
2158 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { | 2159 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { |
2159 | int interval = IEEE80211_SCAN_INTERVAL; | 2160 | int interval = IEEE80211_SCAN_INTERVAL; |
2160 | 2161 | ||
2161 | if (time_after(jiffies, ifsta->ibss_join_req + | 2162 | if (time_after(jiffies, ifsta->ibss_join_req + |
2162 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | 2163 | IEEE80211_IBSS_JOIN_TIMEOUT)) { |
2163 | if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && | 2164 | if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && |
2164 | (!(local->oper_channel->flags & | 2165 | (!(local->oper_channel->flags & |
2165 | IEEE80211_CHAN_NO_IBSS))) | 2166 | IEEE80211_CHAN_NO_IBSS))) |
2166 | return ieee80211_sta_create_ibss(sdata, ifsta); | 2167 | return ieee80211_sta_create_ibss(sdata, ifsta); |
2167 | if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { | 2168 | if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { |
2168 | printk(KERN_DEBUG "%s: IBSS not allowed on" | 2169 | printk(KERN_DEBUG "%s: IBSS not allowed on" |
2169 | " %d MHz\n", sdata->dev->name, | 2170 | " %d MHz\n", sdata->dev->name, |
2170 | local->hw.conf.channel->center_freq); | 2171 | local->hw.conf.channel->center_freq); |
2171 | } | 2172 | } |
2172 | 2173 | ||
2173 | /* No IBSS found - decrease scan interval and continue | 2174 | /* No IBSS found - decrease scan interval and continue |
2174 | * scanning. */ | 2175 | * scanning. */ |
2175 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | 2176 | interval = IEEE80211_SCAN_INTERVAL_SLOW; |
2176 | } | 2177 | } |
2177 | 2178 | ||
2178 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 2179 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; |
2179 | mod_timer(&ifsta->timer, jiffies + interval); | 2180 | mod_timer(&ifsta->timer, jiffies + interval); |
2180 | return 0; | 2181 | return 0; |
2181 | } | 2182 | } |
2182 | 2183 | ||
2183 | return 0; | 2184 | return 0; |
2184 | } | 2185 | } |
2185 | 2186 | ||
2186 | 2187 | ||
2187 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | 2188 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, |
2188 | struct ieee80211_if_sta *ifsta) | 2189 | struct ieee80211_if_sta *ifsta) |
2189 | { | 2190 | { |
2190 | struct ieee80211_local *local = sdata->local; | 2191 | struct ieee80211_local *local = sdata->local; |
2191 | struct ieee80211_bss *bss, *selected = NULL; | 2192 | struct ieee80211_bss *bss, *selected = NULL; |
2192 | int top_rssi = 0, freq; | 2193 | int top_rssi = 0, freq; |
2193 | 2194 | ||
2194 | spin_lock_bh(&local->bss_lock); | 2195 | spin_lock_bh(&local->bss_lock); |
2195 | freq = local->oper_channel->center_freq; | 2196 | freq = local->oper_channel->center_freq; |
2196 | list_for_each_entry(bss, &local->bss_list, list) { | 2197 | list_for_each_entry(bss, &local->bss_list, list) { |
2197 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | 2198 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) |
2198 | continue; | 2199 | continue; |
2199 | 2200 | ||
2200 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 2201 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | |
2201 | IEEE80211_STA_AUTO_BSSID_SEL | | 2202 | IEEE80211_STA_AUTO_BSSID_SEL | |
2202 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | 2203 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && |
2203 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | 2204 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ |
2204 | !!sdata->default_key)) | 2205 | !!sdata->default_key)) |
2205 | continue; | 2206 | continue; |
2206 | 2207 | ||
2207 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | 2208 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && |
2208 | bss->freq != freq) | 2209 | bss->freq != freq) |
2209 | continue; | 2210 | continue; |
2210 | 2211 | ||
2211 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | 2212 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && |
2212 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | 2213 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) |
2213 | continue; | 2214 | continue; |
2214 | 2215 | ||
2215 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | 2216 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && |
2216 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | 2217 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) |
2217 | continue; | 2218 | continue; |
2218 | 2219 | ||
2219 | if (!selected || top_rssi < bss->signal) { | 2220 | if (!selected || top_rssi < bss->signal) { |
2220 | selected = bss; | 2221 | selected = bss; |
2221 | top_rssi = bss->signal; | 2222 | top_rssi = bss->signal; |
2222 | } | 2223 | } |
2223 | } | 2224 | } |
2224 | if (selected) | 2225 | if (selected) |
2225 | atomic_inc(&selected->users); | 2226 | atomic_inc(&selected->users); |
2226 | spin_unlock_bh(&local->bss_lock); | 2227 | spin_unlock_bh(&local->bss_lock); |
2227 | 2228 | ||
2228 | if (selected) { | 2229 | if (selected) { |
2229 | ieee80211_set_freq(sdata, selected->freq); | 2230 | ieee80211_set_freq(sdata, selected->freq); |
2230 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | 2231 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) |
2231 | ieee80211_sta_set_ssid(sdata, selected->ssid, | 2232 | ieee80211_sta_set_ssid(sdata, selected->ssid, |
2232 | selected->ssid_len); | 2233 | selected->ssid_len); |
2233 | ieee80211_sta_set_bssid(sdata, selected->bssid); | 2234 | ieee80211_sta_set_bssid(sdata, selected->bssid); |
2234 | ieee80211_sta_def_wmm_params(sdata, selected); | 2235 | ieee80211_sta_def_wmm_params(sdata, selected); |
2235 | 2236 | ||
2236 | /* Send out direct probe if no probe resp was received or | 2237 | /* Send out direct probe if no probe resp was received or |
2237 | * the one we have is outdated | 2238 | * the one we have is outdated |
2238 | */ | 2239 | */ |
2239 | if (!selected->last_probe_resp || | 2240 | if (!selected->last_probe_resp || |
2240 | time_after(jiffies, selected->last_probe_resp | 2241 | time_after(jiffies, selected->last_probe_resp |
2241 | + IEEE80211_SCAN_RESULT_EXPIRE)) | 2242 | + IEEE80211_SCAN_RESULT_EXPIRE)) |
2242 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 2243 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
2243 | else | 2244 | else |
2244 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2245 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2245 | 2246 | ||
2246 | ieee80211_rx_bss_put(local, selected); | 2247 | ieee80211_rx_bss_put(local, selected); |
2247 | ieee80211_sta_reset_auth(sdata, ifsta); | 2248 | ieee80211_sta_reset_auth(sdata, ifsta); |
2248 | return 0; | 2249 | return 0; |
2249 | } else { | 2250 | } else { |
2250 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 2251 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2251 | ifsta->assoc_scan_tries++; | 2252 | ifsta->assoc_scan_tries++; |
2252 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | 2253 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) |
2253 | ieee80211_start_scan(sdata, NULL, 0); | 2254 | ieee80211_start_scan(sdata, NULL, 0); |
2254 | else | 2255 | else |
2255 | ieee80211_start_scan(sdata, ifsta->ssid, | 2256 | ieee80211_start_scan(sdata, ifsta->ssid, |
2256 | ifsta->ssid_len); | 2257 | ifsta->ssid_len); |
2257 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2258 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2258 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 2259 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); |
2259 | } else | 2260 | } else |
2260 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 2261 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
2261 | } | 2262 | } |
2262 | return -1; | 2263 | return -1; |
2263 | } | 2264 | } |
2264 | 2265 | ||
2265 | 2266 | ||
2266 | static void ieee80211_sta_work(struct work_struct *work) | 2267 | static void ieee80211_sta_work(struct work_struct *work) |
2267 | { | 2268 | { |
2268 | struct ieee80211_sub_if_data *sdata = | 2269 | struct ieee80211_sub_if_data *sdata = |
2269 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | 2270 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); |
2270 | struct ieee80211_local *local = sdata->local; | 2271 | struct ieee80211_local *local = sdata->local; |
2271 | struct ieee80211_if_sta *ifsta; | 2272 | struct ieee80211_if_sta *ifsta; |
2272 | struct sk_buff *skb; | 2273 | struct sk_buff *skb; |
2273 | 2274 | ||
2274 | if (!netif_running(sdata->dev)) | 2275 | if (!netif_running(sdata->dev)) |
2275 | return; | 2276 | return; |
2276 | 2277 | ||
2277 | if (local->sw_scanning || local->hw_scanning) | 2278 | if (local->sw_scanning || local->hw_scanning) |
2278 | return; | 2279 | return; |
2279 | 2280 | ||
2280 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION && | 2281 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION && |
2281 | sdata->vif.type != NL80211_IFTYPE_ADHOC)) | 2282 | sdata->vif.type != NL80211_IFTYPE_ADHOC)) |
2282 | return; | 2283 | return; |
2283 | ifsta = &sdata->u.sta; | 2284 | ifsta = &sdata->u.sta; |
2284 | 2285 | ||
2285 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 2286 | while ((skb = skb_dequeue(&ifsta->skb_queue))) |
2286 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 2287 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
2287 | 2288 | ||
2288 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | 2289 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && |
2289 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 2290 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2290 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | 2291 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && |
2291 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 2292 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { |
2292 | ieee80211_start_scan(sdata, ifsta->scan_ssid, | 2293 | ieee80211_start_scan(sdata, ifsta->scan_ssid, |
2293 | ifsta->scan_ssid_len); | 2294 | ifsta->scan_ssid_len); |
2294 | return; | 2295 | return; |
2295 | } | 2296 | } |
2296 | 2297 | ||
2297 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | 2298 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { |
2298 | if (ieee80211_sta_config_auth(sdata, ifsta)) | 2299 | if (ieee80211_sta_config_auth(sdata, ifsta)) |
2299 | return; | 2300 | return; |
2300 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 2301 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); |
2301 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | 2302 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) |
2302 | return; | 2303 | return; |
2303 | 2304 | ||
2304 | switch (ifsta->state) { | 2305 | switch (ifsta->state) { |
2305 | case IEEE80211_STA_MLME_DISABLED: | 2306 | case IEEE80211_STA_MLME_DISABLED: |
2306 | break; | 2307 | break; |
2307 | case IEEE80211_STA_MLME_DIRECT_PROBE: | 2308 | case IEEE80211_STA_MLME_DIRECT_PROBE: |
2308 | ieee80211_direct_probe(sdata, ifsta); | 2309 | ieee80211_direct_probe(sdata, ifsta); |
2309 | break; | 2310 | break; |
2310 | case IEEE80211_STA_MLME_AUTHENTICATE: | 2311 | case IEEE80211_STA_MLME_AUTHENTICATE: |
2311 | ieee80211_authenticate(sdata, ifsta); | 2312 | ieee80211_authenticate(sdata, ifsta); |
2312 | break; | 2313 | break; |
2313 | case IEEE80211_STA_MLME_ASSOCIATE: | 2314 | case IEEE80211_STA_MLME_ASSOCIATE: |
2314 | ieee80211_associate(sdata, ifsta); | 2315 | ieee80211_associate(sdata, ifsta); |
2315 | break; | 2316 | break; |
2316 | case IEEE80211_STA_MLME_ASSOCIATED: | 2317 | case IEEE80211_STA_MLME_ASSOCIATED: |
2317 | ieee80211_associated(sdata, ifsta); | 2318 | ieee80211_associated(sdata, ifsta); |
2318 | break; | 2319 | break; |
2319 | case IEEE80211_STA_MLME_IBSS_SEARCH: | 2320 | case IEEE80211_STA_MLME_IBSS_SEARCH: |
2320 | ieee80211_sta_find_ibss(sdata, ifsta); | 2321 | ieee80211_sta_find_ibss(sdata, ifsta); |
2321 | break; | 2322 | break; |
2322 | case IEEE80211_STA_MLME_IBSS_JOINED: | 2323 | case IEEE80211_STA_MLME_IBSS_JOINED: |
2323 | ieee80211_sta_merge_ibss(sdata, ifsta); | 2324 | ieee80211_sta_merge_ibss(sdata, ifsta); |
2324 | break; | 2325 | break; |
2325 | default: | 2326 | default: |
2326 | WARN_ON(1); | 2327 | WARN_ON(1); |
2327 | break; | 2328 | break; |
2328 | } | 2329 | } |
2329 | 2330 | ||
2330 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 2331 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { |
2331 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | 2332 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " |
2332 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | 2333 | "mixed-cell disabled - disassociate\n", sdata->dev->name); |
2333 | 2334 | ||
2334 | ieee80211_set_disassoc(sdata, ifsta, false, true, | 2335 | ieee80211_set_disassoc(sdata, ifsta, false, true, |
2335 | WLAN_REASON_UNSPECIFIED); | 2336 | WLAN_REASON_UNSPECIFIED); |
2336 | } | 2337 | } |
2337 | } | 2338 | } |
2338 | 2339 | ||
2339 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | 2340 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) |
2340 | { | 2341 | { |
2341 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 2342 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
2342 | queue_work(sdata->local->hw.workqueue, | 2343 | queue_work(sdata->local->hw.workqueue, |
2343 | &sdata->u.sta.work); | 2344 | &sdata->u.sta.work); |
2344 | } | 2345 | } |
2345 | 2346 | ||
2346 | /* interface setup */ | 2347 | /* interface setup */ |
2347 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 2348 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2348 | { | 2349 | { |
2349 | struct ieee80211_if_sta *ifsta; | 2350 | struct ieee80211_if_sta *ifsta; |
2350 | 2351 | ||
2351 | ifsta = &sdata->u.sta; | 2352 | ifsta = &sdata->u.sta; |
2352 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | 2353 | INIT_WORK(&ifsta->work, ieee80211_sta_work); |
2353 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | 2354 | setup_timer(&ifsta->timer, ieee80211_sta_timer, |
2354 | (unsigned long) sdata); | 2355 | (unsigned long) sdata); |
2355 | skb_queue_head_init(&ifsta->skb_queue); | 2356 | skb_queue_head_init(&ifsta->skb_queue); |
2356 | 2357 | ||
2357 | ifsta->capab = WLAN_CAPABILITY_ESS; | 2358 | ifsta->capab = WLAN_CAPABILITY_ESS; |
2358 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | | 2359 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | |
2359 | IEEE80211_AUTH_ALG_SHARED_KEY; | 2360 | IEEE80211_AUTH_ALG_SHARED_KEY; |
2360 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | | 2361 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | |
2361 | IEEE80211_STA_AUTO_BSSID_SEL | | 2362 | IEEE80211_STA_AUTO_BSSID_SEL | |
2362 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 2363 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
2363 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 2364 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) |
2364 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; | 2365 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; |
2365 | } | 2366 | } |
2366 | 2367 | ||
2367 | /* | 2368 | /* |
2368 | * Add a new IBSS station, will also be called by the RX code when, | 2369 | * Add a new IBSS station, will also be called by the RX code when, |
2369 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | 2370 | * in IBSS mode, receiving a frame from a yet-unknown station, hence |
2370 | * must be callable in atomic context. | 2371 | * must be callable in atomic context. |
2371 | */ | 2372 | */ |
2372 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 2373 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
2373 | u8 *bssid,u8 *addr, u64 supp_rates) | 2374 | u8 *bssid,u8 *addr, u64 supp_rates) |
2374 | { | 2375 | { |
2375 | struct ieee80211_local *local = sdata->local; | 2376 | struct ieee80211_local *local = sdata->local; |
2376 | struct sta_info *sta; | 2377 | struct sta_info *sta; |
2377 | int band = local->hw.conf.channel->band; | 2378 | int band = local->hw.conf.channel->band; |
2378 | 2379 | ||
2379 | /* TODO: Could consider removing the least recently used entry and | 2380 | /* TODO: Could consider removing the least recently used entry and |
2380 | * allow new one to be added. */ | 2381 | * allow new one to be added. */ |
2381 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | 2382 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { |
2382 | if (net_ratelimit()) { | 2383 | if (net_ratelimit()) { |
2383 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | 2384 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " |
2384 | "entry %pM\n", sdata->dev->name, addr); | 2385 | "entry %pM\n", sdata->dev->name, addr); |
2385 | } | 2386 | } |
2386 | return NULL; | 2387 | return NULL; |
2387 | } | 2388 | } |
2388 | 2389 | ||
2389 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | 2390 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) |
2390 | return NULL; | 2391 | return NULL; |
2391 | 2392 | ||
2392 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2393 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2393 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | 2394 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", |
2394 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | 2395 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); |
2395 | #endif | 2396 | #endif |
2396 | 2397 | ||
2397 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 2398 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
2398 | if (!sta) | 2399 | if (!sta) |
2399 | return NULL; | 2400 | return NULL; |
2400 | 2401 | ||
2401 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | 2402 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); |
2402 | 2403 | ||
2403 | /* make sure mandatory rates are always added */ | 2404 | /* make sure mandatory rates are always added */ |
2404 | sta->sta.supp_rates[band] = supp_rates | | 2405 | sta->sta.supp_rates[band] = supp_rates | |
2405 | ieee80211_mandatory_rates(local, band); | 2406 | ieee80211_mandatory_rates(local, band); |
2406 | 2407 | ||
2407 | rate_control_rate_init(sta); | 2408 | rate_control_rate_init(sta); |
2408 | 2409 | ||
2409 | if (sta_info_insert(sta)) | 2410 | if (sta_info_insert(sta)) |
2410 | return NULL; | 2411 | return NULL; |
2411 | 2412 | ||
2412 | return sta; | 2413 | return sta; |
2413 | } | 2414 | } |
2414 | 2415 | ||
2415 | /* configuration hooks */ | 2416 | /* configuration hooks */ |
2416 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 2417 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, |
2417 | struct ieee80211_if_sta *ifsta) | 2418 | struct ieee80211_if_sta *ifsta) |
2418 | { | 2419 | { |
2419 | struct ieee80211_local *local = sdata->local; | 2420 | struct ieee80211_local *local = sdata->local; |
2420 | 2421 | ||
2421 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2422 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2422 | return; | 2423 | return; |
2423 | 2424 | ||
2424 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | 2425 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | |
2425 | IEEE80211_STA_AUTO_BSSID_SEL)) && | 2426 | IEEE80211_STA_AUTO_BSSID_SEL)) && |
2426 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | 2427 | (ifsta->flags & (IEEE80211_STA_SSID_SET | |
2427 | IEEE80211_STA_AUTO_SSID_SEL))) { | 2428 | IEEE80211_STA_AUTO_SSID_SEL))) { |
2428 | 2429 | ||
2429 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | 2430 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) |
2430 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 2431 | ieee80211_set_disassoc(sdata, ifsta, true, true, |
2431 | WLAN_REASON_DEAUTH_LEAVING); | 2432 | WLAN_REASON_DEAUTH_LEAVING); |
2432 | 2433 | ||
2433 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 2434 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); |
2434 | queue_work(local->hw.workqueue, &ifsta->work); | 2435 | queue_work(local->hw.workqueue, &ifsta->work); |
2435 | } | 2436 | } |
2436 | } | 2437 | } |
2437 | 2438 | ||
2438 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 2439 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
2439 | { | 2440 | { |
2440 | struct ieee80211_if_sta *ifsta; | 2441 | struct ieee80211_if_sta *ifsta; |
2441 | 2442 | ||
2442 | if (len > IEEE80211_MAX_SSID_LEN) | 2443 | if (len > IEEE80211_MAX_SSID_LEN) |
2443 | return -EINVAL; | 2444 | return -EINVAL; |
2444 | 2445 | ||
2445 | ifsta = &sdata->u.sta; | 2446 | ifsta = &sdata->u.sta; |
2446 | 2447 | ||
2447 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | 2448 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { |
2448 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | 2449 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); |
2449 | memcpy(ifsta->ssid, ssid, len); | 2450 | memcpy(ifsta->ssid, ssid, len); |
2450 | ifsta->ssid_len = len; | 2451 | ifsta->ssid_len = len; |
2451 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 2452 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
2452 | } | 2453 | } |
2453 | 2454 | ||
2454 | if (len) | 2455 | if (len) |
2455 | ifsta->flags |= IEEE80211_STA_SSID_SET; | 2456 | ifsta->flags |= IEEE80211_STA_SSID_SET; |
2456 | else | 2457 | else |
2457 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | 2458 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; |
2458 | 2459 | ||
2459 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 2460 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
2460 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { | 2461 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { |
2461 | ifsta->ibss_join_req = jiffies; | 2462 | ifsta->ibss_join_req = jiffies; |
2462 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 2463 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; |
2463 | return ieee80211_sta_find_ibss(sdata, ifsta); | 2464 | return ieee80211_sta_find_ibss(sdata, ifsta); |
2464 | } | 2465 | } |
2465 | 2466 | ||
2466 | return 0; | 2467 | return 0; |
2467 | } | 2468 | } |
2468 | 2469 | ||
2469 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | 2470 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) |
2470 | { | 2471 | { |
2471 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2472 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
2472 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | 2473 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); |
2473 | *len = ifsta->ssid_len; | 2474 | *len = ifsta->ssid_len; |
2474 | return 0; | 2475 | return 0; |
2475 | } | 2476 | } |
2476 | 2477 | ||
2477 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 2478 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) |
2478 | { | 2479 | { |
2479 | struct ieee80211_if_sta *ifsta; | 2480 | struct ieee80211_if_sta *ifsta; |
2480 | int res; | 2481 | int res; |
2481 | 2482 | ||
2482 | ifsta = &sdata->u.sta; | 2483 | ifsta = &sdata->u.sta; |
2483 | 2484 | ||
2484 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 2485 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { |
2485 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | 2486 | memcpy(ifsta->bssid, bssid, ETH_ALEN); |
2486 | res = 0; | 2487 | res = 0; |
2487 | /* | 2488 | /* |
2488 | * Hack! See also ieee80211_sta_set_ssid. | 2489 | * Hack! See also ieee80211_sta_set_ssid. |
2489 | */ | 2490 | */ |
2490 | if (netif_running(sdata->dev)) | 2491 | if (netif_running(sdata->dev)) |
2491 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | 2492 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); |
2492 | if (res) { | 2493 | if (res) { |
2493 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | 2494 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " |
2494 | "the low-level driver\n", sdata->dev->name); | 2495 | "the low-level driver\n", sdata->dev->name); |
2495 | return res; | 2496 | return res; |
2496 | } | 2497 | } |
2497 | } | 2498 | } |
2498 | 2499 | ||
2499 | if (is_valid_ether_addr(bssid)) | 2500 | if (is_valid_ether_addr(bssid)) |
2500 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | 2501 | ifsta->flags |= IEEE80211_STA_BSSID_SET; |
2501 | else | 2502 | else |
2502 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | 2503 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; |
2503 | 2504 | ||
2504 | return 0; | 2505 | return 0; |
2505 | } | 2506 | } |
2506 | 2507 | ||
2507 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2508 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) |
2508 | { | 2509 | { |
2509 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2510 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
2510 | 2511 | ||
2511 | kfree(ifsta->extra_ie); | 2512 | kfree(ifsta->extra_ie); |
2512 | if (len == 0) { | 2513 | if (len == 0) { |
2513 | ifsta->extra_ie = NULL; | 2514 | ifsta->extra_ie = NULL; |
2514 | ifsta->extra_ie_len = 0; | 2515 | ifsta->extra_ie_len = 0; |
2515 | return 0; | 2516 | return 0; |
2516 | } | 2517 | } |
2517 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | 2518 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); |
2518 | if (!ifsta->extra_ie) { | 2519 | if (!ifsta->extra_ie) { |
2519 | ifsta->extra_ie_len = 0; | 2520 | ifsta->extra_ie_len = 0; |
2520 | return -ENOMEM; | 2521 | return -ENOMEM; |
2521 | } | 2522 | } |
2522 | memcpy(ifsta->extra_ie, ie, len); | 2523 | memcpy(ifsta->extra_ie, ie, len); |
2523 | ifsta->extra_ie_len = len; | 2524 | ifsta->extra_ie_len = len; |
2524 | return 0; | 2525 | return 0; |
2525 | } | 2526 | } |
2526 | 2527 | ||
2527 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2528 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2528 | { | 2529 | { |
2529 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2530 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
2530 | 2531 | ||
2531 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 2532 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2532 | sdata->dev->name, reason); | 2533 | sdata->dev->name, reason); |
2533 | 2534 | ||
2534 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 2535 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
2535 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 2536 | sdata->vif.type != NL80211_IFTYPE_ADHOC) |
2536 | return -EINVAL; | 2537 | return -EINVAL; |
2537 | 2538 | ||
2538 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | 2539 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); |
2539 | return 0; | 2540 | return 0; |
2540 | } | 2541 | } |
2541 | 2542 | ||
2542 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2543 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2543 | { | 2544 | { |
2544 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2545 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
2545 | 2546 | ||
2546 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 2547 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2547 | sdata->dev->name, reason); | 2548 | sdata->dev->name, reason); |
2548 | 2549 | ||
2549 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2550 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2550 | return -EINVAL; | 2551 | return -EINVAL; |
2551 | 2552 | ||
2552 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | 2553 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) |
2553 | return -1; | 2554 | return -1; |
2554 | 2555 | ||
2555 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | 2556 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); |
2556 | return 0; | 2557 | return 0; |
2557 | } | 2558 | } |
2558 | 2559 | ||
2559 | /* scan finished notification */ | 2560 | /* scan finished notification */ |
2560 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 2561 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2561 | { | 2562 | { |
2562 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 2563 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
2563 | struct ieee80211_if_sta *ifsta; | 2564 | struct ieee80211_if_sta *ifsta; |
2564 | 2565 | ||
2565 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 2566 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2566 | ifsta = &sdata->u.sta; | 2567 | ifsta = &sdata->u.sta; |
2567 | if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || | 2568 | if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || |
2568 | (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) && | 2569 | (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) && |
2569 | !ieee80211_sta_active_ibss(sdata))) | 2570 | !ieee80211_sta_active_ibss(sdata))) |
2570 | ieee80211_sta_find_ibss(sdata, ifsta); | 2571 | ieee80211_sta_find_ibss(sdata, ifsta); |
2571 | } | 2572 | } |
2572 | 2573 | ||
2573 | /* Restart STA timers */ | 2574 | /* Restart STA timers */ |
2574 | rcu_read_lock(); | 2575 | rcu_read_lock(); |
2575 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 2576 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
2576 | ieee80211_restart_sta_timer(sdata); | 2577 | ieee80211_restart_sta_timer(sdata); |
2577 | rcu_read_unlock(); | 2578 | rcu_read_unlock(); |
2578 | } | 2579 | } |
2579 | 2580 |
net/mac80211/util.c
1 | /* | 1 | /* |
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | * | 10 | * |
11 | * utilities for mac80211 | 11 | * utilities for mac80211 |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <net/mac80211.h> | 14 | #include <net/mac80211.h> |
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
22 | #include <linux/bitmap.h> | 22 | #include <linux/bitmap.h> |
23 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
24 | #include <net/cfg80211.h> | 24 | #include <net/cfg80211.h> |
25 | #include <net/rtnetlink.h> | 25 | #include <net/rtnetlink.h> |
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "rate.h" | 28 | #include "rate.h" |
29 | #include "mesh.h" | 29 | #include "mesh.h" |
30 | #include "wme.h" | 30 | #include "wme.h" |
31 | 31 | ||
32 | /* privid for wiphys to determine whether they belong to us or not */ | 32 | /* privid for wiphys to determine whether they belong to us or not */ |
33 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 33 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
34 | 34 | ||
35 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | 35 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
36 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | 36 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
37 | const unsigned char rfc1042_header[] __aligned(2) = | 37 | const unsigned char rfc1042_header[] __aligned(2) = |
38 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | 38 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
39 | 39 | ||
40 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | 40 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ |
41 | const unsigned char bridge_tunnel_header[] __aligned(2) = | 41 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
43 | 43 | ||
44 | 44 | ||
45 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 45 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
46 | enum nl80211_iftype type) | 46 | enum nl80211_iftype type) |
47 | { | 47 | { |
48 | __le16 fc = hdr->frame_control; | 48 | __le16 fc = hdr->frame_control; |
49 | 49 | ||
50 | /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ | 50 | /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ |
51 | if (len < 16) | 51 | if (len < 16) |
52 | return NULL; | 52 | return NULL; |
53 | 53 | ||
54 | if (ieee80211_is_data(fc)) { | 54 | if (ieee80211_is_data(fc)) { |
55 | if (len < 24) /* drop incorrect hdr len (data) */ | 55 | if (len < 24) /* drop incorrect hdr len (data) */ |
56 | return NULL; | 56 | return NULL; |
57 | 57 | ||
58 | if (ieee80211_has_a4(fc)) | 58 | if (ieee80211_has_a4(fc)) |
59 | return NULL; | 59 | return NULL; |
60 | if (ieee80211_has_tods(fc)) | 60 | if (ieee80211_has_tods(fc)) |
61 | return hdr->addr1; | 61 | return hdr->addr1; |
62 | if (ieee80211_has_fromds(fc)) | 62 | if (ieee80211_has_fromds(fc)) |
63 | return hdr->addr2; | 63 | return hdr->addr2; |
64 | 64 | ||
65 | return hdr->addr3; | 65 | return hdr->addr3; |
66 | } | 66 | } |
67 | 67 | ||
68 | if (ieee80211_is_mgmt(fc)) { | 68 | if (ieee80211_is_mgmt(fc)) { |
69 | if (len < 24) /* drop incorrect hdr len (mgmt) */ | 69 | if (len < 24) /* drop incorrect hdr len (mgmt) */ |
70 | return NULL; | 70 | return NULL; |
71 | return hdr->addr3; | 71 | return hdr->addr3; |
72 | } | 72 | } |
73 | 73 | ||
74 | if (ieee80211_is_ctl(fc)) { | 74 | if (ieee80211_is_ctl(fc)) { |
75 | if(ieee80211_is_pspoll(fc)) | 75 | if(ieee80211_is_pspoll(fc)) |
76 | return hdr->addr1; | 76 | return hdr->addr1; |
77 | 77 | ||
78 | if (ieee80211_is_back_req(fc)) { | 78 | if (ieee80211_is_back_req(fc)) { |
79 | switch (type) { | 79 | switch (type) { |
80 | case NL80211_IFTYPE_STATION: | 80 | case NL80211_IFTYPE_STATION: |
81 | return hdr->addr2; | 81 | return hdr->addr2; |
82 | case NL80211_IFTYPE_AP: | 82 | case NL80211_IFTYPE_AP: |
83 | case NL80211_IFTYPE_AP_VLAN: | 83 | case NL80211_IFTYPE_AP_VLAN: |
84 | return hdr->addr1; | 84 | return hdr->addr1; |
85 | default: | 85 | default: |
86 | break; /* fall through to the return */ | 86 | break; /* fall through to the return */ |
87 | } | 87 | } |
88 | } | 88 | } |
89 | } | 89 | } |
90 | 90 | ||
91 | return NULL; | 91 | return NULL; |
92 | } | 92 | } |
93 | 93 | ||
94 | unsigned int ieee80211_hdrlen(__le16 fc) | 94 | unsigned int ieee80211_hdrlen(__le16 fc) |
95 | { | 95 | { |
96 | unsigned int hdrlen = 24; | 96 | unsigned int hdrlen = 24; |
97 | 97 | ||
98 | if (ieee80211_is_data(fc)) { | 98 | if (ieee80211_is_data(fc)) { |
99 | if (ieee80211_has_a4(fc)) | 99 | if (ieee80211_has_a4(fc)) |
100 | hdrlen = 30; | 100 | hdrlen = 30; |
101 | if (ieee80211_is_data_qos(fc)) | 101 | if (ieee80211_is_data_qos(fc)) |
102 | hdrlen += IEEE80211_QOS_CTL_LEN; | 102 | hdrlen += IEEE80211_QOS_CTL_LEN; |
103 | goto out; | 103 | goto out; |
104 | } | 104 | } |
105 | 105 | ||
106 | if (ieee80211_is_ctl(fc)) { | 106 | if (ieee80211_is_ctl(fc)) { |
107 | /* | 107 | /* |
108 | * ACK and CTS are 10 bytes, all others 16. To see how | 108 | * ACK and CTS are 10 bytes, all others 16. To see how |
109 | * to get this condition consider | 109 | * to get this condition consider |
110 | * subtype mask: 0b0000000011110000 (0x00F0) | 110 | * subtype mask: 0b0000000011110000 (0x00F0) |
111 | * ACK subtype: 0b0000000011010000 (0x00D0) | 111 | * ACK subtype: 0b0000000011010000 (0x00D0) |
112 | * CTS subtype: 0b0000000011000000 (0x00C0) | 112 | * CTS subtype: 0b0000000011000000 (0x00C0) |
113 | * bits that matter: ^^^ (0x00E0) | 113 | * bits that matter: ^^^ (0x00E0) |
114 | * value of those: 0b0000000011000000 (0x00C0) | 114 | * value of those: 0b0000000011000000 (0x00C0) |
115 | */ | 115 | */ |
116 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | 116 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) |
117 | hdrlen = 10; | 117 | hdrlen = 10; |
118 | else | 118 | else |
119 | hdrlen = 16; | 119 | hdrlen = 16; |
120 | } | 120 | } |
121 | out: | 121 | out: |
122 | return hdrlen; | 122 | return hdrlen; |
123 | } | 123 | } |
124 | EXPORT_SYMBOL(ieee80211_hdrlen); | 124 | EXPORT_SYMBOL(ieee80211_hdrlen); |
125 | 125 | ||
126 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | 126 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) |
127 | { | 127 | { |
128 | const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; | 128 | const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; |
129 | unsigned int hdrlen; | 129 | unsigned int hdrlen; |
130 | 130 | ||
131 | if (unlikely(skb->len < 10)) | 131 | if (unlikely(skb->len < 10)) |
132 | return 0; | 132 | return 0; |
133 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 133 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
134 | if (unlikely(hdrlen > skb->len)) | 134 | if (unlikely(hdrlen > skb->len)) |
135 | return 0; | 135 | return 0; |
136 | return hdrlen; | 136 | return hdrlen; |
137 | } | 137 | } |
138 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 138 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
139 | 139 | ||
140 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 140 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) |
141 | { | 141 | { |
142 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; | 142 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; |
143 | /* 7.1.3.5a.2 */ | 143 | /* 7.1.3.5a.2 */ |
144 | switch (ae) { | 144 | switch (ae) { |
145 | case 0: | 145 | case 0: |
146 | return 6; | 146 | return 6; |
147 | case 1: | 147 | case 1: |
148 | return 12; | 148 | return 12; |
149 | case 2: | 149 | case 2: |
150 | return 18; | 150 | return 18; |
151 | case 3: | 151 | case 3: |
152 | return 24; | 152 | return 24; |
153 | default: | 153 | default: |
154 | return 6; | 154 | return 6; |
155 | } | 155 | } |
156 | } | 156 | } |
157 | 157 | ||
158 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 158 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
159 | { | 159 | { |
160 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 160 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
161 | 161 | ||
162 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 162 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
163 | if (tx->extra_frag) { | 163 | if (tx->extra_frag) { |
164 | struct ieee80211_hdr *fhdr; | 164 | struct ieee80211_hdr *fhdr; |
165 | int i; | 165 | int i; |
166 | for (i = 0; i < tx->num_extra_frag; i++) { | 166 | for (i = 0; i < tx->num_extra_frag; i++) { |
167 | fhdr = (struct ieee80211_hdr *) | 167 | fhdr = (struct ieee80211_hdr *) |
168 | tx->extra_frag[i]->data; | 168 | tx->extra_frag[i]->data; |
169 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 169 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
170 | } | 170 | } |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 174 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
175 | int rate, int erp, int short_preamble) | 175 | int rate, int erp, int short_preamble) |
176 | { | 176 | { |
177 | int dur; | 177 | int dur; |
178 | 178 | ||
179 | /* calculate duration (in microseconds, rounded up to next higher | 179 | /* calculate duration (in microseconds, rounded up to next higher |
180 | * integer if it includes a fractional microsecond) to send frame of | 180 | * integer if it includes a fractional microsecond) to send frame of |
181 | * len bytes (does not include FCS) at the given rate. Duration will | 181 | * len bytes (does not include FCS) at the given rate. Duration will |
182 | * also include SIFS. | 182 | * also include SIFS. |
183 | * | 183 | * |
184 | * rate is in 100 kbps, so divident is multiplied by 10 in the | 184 | * rate is in 100 kbps, so divident is multiplied by 10 in the |
185 | * DIV_ROUND_UP() operations. | 185 | * DIV_ROUND_UP() operations. |
186 | */ | 186 | */ |
187 | 187 | ||
188 | if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { | 188 | if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { |
189 | /* | 189 | /* |
190 | * OFDM: | 190 | * OFDM: |
191 | * | 191 | * |
192 | * N_DBPS = DATARATE x 4 | 192 | * N_DBPS = DATARATE x 4 |
193 | * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) | 193 | * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) |
194 | * (16 = SIGNAL time, 6 = tail bits) | 194 | * (16 = SIGNAL time, 6 = tail bits) |
195 | * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext | 195 | * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext |
196 | * | 196 | * |
197 | * T_SYM = 4 usec | 197 | * T_SYM = 4 usec |
198 | * 802.11a - 17.5.2: aSIFSTime = 16 usec | 198 | * 802.11a - 17.5.2: aSIFSTime = 16 usec |
199 | * 802.11g - 19.8.4: aSIFSTime = 10 usec + | 199 | * 802.11g - 19.8.4: aSIFSTime = 10 usec + |
200 | * signal ext = 6 usec | 200 | * signal ext = 6 usec |
201 | */ | 201 | */ |
202 | dur = 16; /* SIFS + signal ext */ | 202 | dur = 16; /* SIFS + signal ext */ |
203 | dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ | 203 | dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ |
204 | dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ | 204 | dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ |
205 | dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, | 205 | dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, |
206 | 4 * rate); /* T_SYM x N_SYM */ | 206 | 4 * rate); /* T_SYM x N_SYM */ |
207 | } else { | 207 | } else { |
208 | /* | 208 | /* |
209 | * 802.11b or 802.11g with 802.11b compatibility: | 209 | * 802.11b or 802.11g with 802.11b compatibility: |
210 | * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + | 210 | * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + |
211 | * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. | 211 | * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. |
212 | * | 212 | * |
213 | * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 | 213 | * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 |
214 | * aSIFSTime = 10 usec | 214 | * aSIFSTime = 10 usec |
215 | * aPreambleLength = 144 usec or 72 usec with short preamble | 215 | * aPreambleLength = 144 usec or 72 usec with short preamble |
216 | * aPLCPHeaderLength = 48 usec or 24 usec with short preamble | 216 | * aPLCPHeaderLength = 48 usec or 24 usec with short preamble |
217 | */ | 217 | */ |
218 | dur = 10; /* aSIFSTime = 10 usec */ | 218 | dur = 10; /* aSIFSTime = 10 usec */ |
219 | dur += short_preamble ? (72 + 24) : (144 + 48); | 219 | dur += short_preamble ? (72 + 24) : (144 + 48); |
220 | 220 | ||
221 | dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); | 221 | dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); |
222 | } | 222 | } |
223 | 223 | ||
224 | return dur; | 224 | return dur; |
225 | } | 225 | } |
226 | 226 | ||
227 | /* Exported duration function for driver use */ | 227 | /* Exported duration function for driver use */ |
228 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | 228 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, |
229 | struct ieee80211_vif *vif, | 229 | struct ieee80211_vif *vif, |
230 | size_t frame_len, | 230 | size_t frame_len, |
231 | struct ieee80211_rate *rate) | 231 | struct ieee80211_rate *rate) |
232 | { | 232 | { |
233 | struct ieee80211_local *local = hw_to_local(hw); | 233 | struct ieee80211_local *local = hw_to_local(hw); |
234 | struct ieee80211_sub_if_data *sdata; | 234 | struct ieee80211_sub_if_data *sdata; |
235 | u16 dur; | 235 | u16 dur; |
236 | int erp; | 236 | int erp; |
237 | bool short_preamble = false; | 237 | bool short_preamble = false; |
238 | 238 | ||
239 | erp = 0; | 239 | erp = 0; |
240 | if (vif) { | 240 | if (vif) { |
241 | sdata = vif_to_sdata(vif); | 241 | sdata = vif_to_sdata(vif); |
242 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 242 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
243 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 243 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
244 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 244 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
245 | } | 245 | } |
246 | 246 | ||
247 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, | 247 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, |
248 | short_preamble); | 248 | short_preamble); |
249 | 249 | ||
250 | return cpu_to_le16(dur); | 250 | return cpu_to_le16(dur); |
251 | } | 251 | } |
252 | EXPORT_SYMBOL(ieee80211_generic_frame_duration); | 252 | EXPORT_SYMBOL(ieee80211_generic_frame_duration); |
253 | 253 | ||
254 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | 254 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, |
255 | struct ieee80211_vif *vif, size_t frame_len, | 255 | struct ieee80211_vif *vif, size_t frame_len, |
256 | const struct ieee80211_tx_info *frame_txctl) | 256 | const struct ieee80211_tx_info *frame_txctl) |
257 | { | 257 | { |
258 | struct ieee80211_local *local = hw_to_local(hw); | 258 | struct ieee80211_local *local = hw_to_local(hw); |
259 | struct ieee80211_rate *rate; | 259 | struct ieee80211_rate *rate; |
260 | struct ieee80211_sub_if_data *sdata; | 260 | struct ieee80211_sub_if_data *sdata; |
261 | bool short_preamble; | 261 | bool short_preamble; |
262 | int erp; | 262 | int erp; |
263 | u16 dur; | 263 | u16 dur; |
264 | struct ieee80211_supported_band *sband; | 264 | struct ieee80211_supported_band *sband; |
265 | 265 | ||
266 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 266 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
267 | 267 | ||
268 | short_preamble = false; | 268 | short_preamble = false; |
269 | 269 | ||
270 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; | 270 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; |
271 | 271 | ||
272 | erp = 0; | 272 | erp = 0; |
273 | if (vif) { | 273 | if (vif) { |
274 | sdata = vif_to_sdata(vif); | 274 | sdata = vif_to_sdata(vif); |
275 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 275 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
276 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 276 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
277 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 277 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
278 | } | 278 | } |
279 | 279 | ||
280 | /* CTS duration */ | 280 | /* CTS duration */ |
281 | dur = ieee80211_frame_duration(local, 10, rate->bitrate, | 281 | dur = ieee80211_frame_duration(local, 10, rate->bitrate, |
282 | erp, short_preamble); | 282 | erp, short_preamble); |
283 | /* Data frame duration */ | 283 | /* Data frame duration */ |
284 | dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, | 284 | dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, |
285 | erp, short_preamble); | 285 | erp, short_preamble); |
286 | /* ACK duration */ | 286 | /* ACK duration */ |
287 | dur += ieee80211_frame_duration(local, 10, rate->bitrate, | 287 | dur += ieee80211_frame_duration(local, 10, rate->bitrate, |
288 | erp, short_preamble); | 288 | erp, short_preamble); |
289 | 289 | ||
290 | return cpu_to_le16(dur); | 290 | return cpu_to_le16(dur); |
291 | } | 291 | } |
292 | EXPORT_SYMBOL(ieee80211_rts_duration); | 292 | EXPORT_SYMBOL(ieee80211_rts_duration); |
293 | 293 | ||
294 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | 294 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, |
295 | struct ieee80211_vif *vif, | 295 | struct ieee80211_vif *vif, |
296 | size_t frame_len, | 296 | size_t frame_len, |
297 | const struct ieee80211_tx_info *frame_txctl) | 297 | const struct ieee80211_tx_info *frame_txctl) |
298 | { | 298 | { |
299 | struct ieee80211_local *local = hw_to_local(hw); | 299 | struct ieee80211_local *local = hw_to_local(hw); |
300 | struct ieee80211_rate *rate; | 300 | struct ieee80211_rate *rate; |
301 | struct ieee80211_sub_if_data *sdata; | 301 | struct ieee80211_sub_if_data *sdata; |
302 | bool short_preamble; | 302 | bool short_preamble; |
303 | int erp; | 303 | int erp; |
304 | u16 dur; | 304 | u16 dur; |
305 | struct ieee80211_supported_band *sband; | 305 | struct ieee80211_supported_band *sband; |
306 | 306 | ||
307 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 307 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
308 | 308 | ||
309 | short_preamble = false; | 309 | short_preamble = false; |
310 | 310 | ||
311 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; | 311 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; |
312 | erp = 0; | 312 | erp = 0; |
313 | if (vif) { | 313 | if (vif) { |
314 | sdata = vif_to_sdata(vif); | 314 | sdata = vif_to_sdata(vif); |
315 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 315 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
316 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 316 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
317 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 317 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
318 | } | 318 | } |
319 | 319 | ||
320 | /* Data frame duration */ | 320 | /* Data frame duration */ |
321 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, | 321 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, |
322 | erp, short_preamble); | 322 | erp, short_preamble); |
323 | if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { | 323 | if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { |
324 | /* ACK duration */ | 324 | /* ACK duration */ |
325 | dur += ieee80211_frame_duration(local, 10, rate->bitrate, | 325 | dur += ieee80211_frame_duration(local, 10, rate->bitrate, |
326 | erp, short_preamble); | 326 | erp, short_preamble); |
327 | } | 327 | } |
328 | 328 | ||
329 | return cpu_to_le16(dur); | 329 | return cpu_to_le16(dur); |
330 | } | 330 | } |
331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); | 331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); |
332 | 332 | ||
333 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 333 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) |
334 | { | 334 | { |
335 | struct ieee80211_local *local = hw_to_local(hw); | 335 | struct ieee80211_local *local = hw_to_local(hw); |
336 | 336 | ||
337 | if (test_bit(queue, local->queues_pending)) { | 337 | if (test_bit(queue, local->queues_pending)) { |
338 | set_bit(queue, local->queues_pending_run); | 338 | set_bit(queue, local->queues_pending_run); |
339 | tasklet_schedule(&local->tx_pending_tasklet); | 339 | tasklet_schedule(&local->tx_pending_tasklet); |
340 | } else { | 340 | } else { |
341 | netif_wake_subqueue(local->mdev, queue); | 341 | netif_wake_subqueue(local->mdev, queue); |
342 | } | 342 | } |
343 | } | 343 | } |
344 | EXPORT_SYMBOL(ieee80211_wake_queue); | 344 | EXPORT_SYMBOL(ieee80211_wake_queue); |
345 | 345 | ||
346 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 346 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) |
347 | { | 347 | { |
348 | struct ieee80211_local *local = hw_to_local(hw); | 348 | struct ieee80211_local *local = hw_to_local(hw); |
349 | 349 | ||
350 | netif_stop_subqueue(local->mdev, queue); | 350 | netif_stop_subqueue(local->mdev, queue); |
351 | } | 351 | } |
352 | EXPORT_SYMBOL(ieee80211_stop_queue); | 352 | EXPORT_SYMBOL(ieee80211_stop_queue); |
353 | 353 | ||
354 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 354 | void ieee80211_stop_queues(struct ieee80211_hw *hw) |
355 | { | 355 | { |
356 | int i; | 356 | int i; |
357 | 357 | ||
358 | for (i = 0; i < ieee80211_num_queues(hw); i++) | 358 | for (i = 0; i < ieee80211_num_queues(hw); i++) |
359 | ieee80211_stop_queue(hw, i); | 359 | ieee80211_stop_queue(hw, i); |
360 | } | 360 | } |
361 | EXPORT_SYMBOL(ieee80211_stop_queues); | 361 | EXPORT_SYMBOL(ieee80211_stop_queues); |
362 | 362 | ||
363 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 363 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
364 | { | 364 | { |
365 | struct ieee80211_local *local = hw_to_local(hw); | 365 | struct ieee80211_local *local = hw_to_local(hw); |
366 | return __netif_subqueue_stopped(local->mdev, queue); | 366 | return __netif_subqueue_stopped(local->mdev, queue); |
367 | } | 367 | } |
368 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 368 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
369 | 369 | ||
370 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 370 | void ieee80211_wake_queues(struct ieee80211_hw *hw) |
371 | { | 371 | { |
372 | int i; | 372 | int i; |
373 | 373 | ||
374 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) | 374 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) |
375 | ieee80211_wake_queue(hw, i); | 375 | ieee80211_wake_queue(hw, i); |
376 | } | 376 | } |
377 | EXPORT_SYMBOL(ieee80211_wake_queues); | 377 | EXPORT_SYMBOL(ieee80211_wake_queues); |
378 | 378 | ||
379 | void ieee80211_iterate_active_interfaces( | 379 | void ieee80211_iterate_active_interfaces( |
380 | struct ieee80211_hw *hw, | 380 | struct ieee80211_hw *hw, |
381 | void (*iterator)(void *data, u8 *mac, | 381 | void (*iterator)(void *data, u8 *mac, |
382 | struct ieee80211_vif *vif), | 382 | struct ieee80211_vif *vif), |
383 | void *data) | 383 | void *data) |
384 | { | 384 | { |
385 | struct ieee80211_local *local = hw_to_local(hw); | 385 | struct ieee80211_local *local = hw_to_local(hw); |
386 | struct ieee80211_sub_if_data *sdata; | 386 | struct ieee80211_sub_if_data *sdata; |
387 | 387 | ||
388 | rtnl_lock(); | 388 | rtnl_lock(); |
389 | 389 | ||
390 | list_for_each_entry(sdata, &local->interfaces, list) { | 390 | list_for_each_entry(sdata, &local->interfaces, list) { |
391 | switch (sdata->vif.type) { | 391 | switch (sdata->vif.type) { |
392 | case __NL80211_IFTYPE_AFTER_LAST: | 392 | case __NL80211_IFTYPE_AFTER_LAST: |
393 | case NL80211_IFTYPE_UNSPECIFIED: | 393 | case NL80211_IFTYPE_UNSPECIFIED: |
394 | case NL80211_IFTYPE_MONITOR: | 394 | case NL80211_IFTYPE_MONITOR: |
395 | case NL80211_IFTYPE_AP_VLAN: | 395 | case NL80211_IFTYPE_AP_VLAN: |
396 | continue; | 396 | continue; |
397 | case NL80211_IFTYPE_AP: | 397 | case NL80211_IFTYPE_AP: |
398 | case NL80211_IFTYPE_STATION: | 398 | case NL80211_IFTYPE_STATION: |
399 | case NL80211_IFTYPE_ADHOC: | 399 | case NL80211_IFTYPE_ADHOC: |
400 | case NL80211_IFTYPE_WDS: | 400 | case NL80211_IFTYPE_WDS: |
401 | case NL80211_IFTYPE_MESH_POINT: | 401 | case NL80211_IFTYPE_MESH_POINT: |
402 | break; | 402 | break; |
403 | } | 403 | } |
404 | if (netif_running(sdata->dev)) | 404 | if (netif_running(sdata->dev)) |
405 | iterator(data, sdata->dev->dev_addr, | 405 | iterator(data, sdata->dev->dev_addr, |
406 | &sdata->vif); | 406 | &sdata->vif); |
407 | } | 407 | } |
408 | 408 | ||
409 | rtnl_unlock(); | 409 | rtnl_unlock(); |
410 | } | 410 | } |
411 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 411 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
412 | 412 | ||
413 | void ieee80211_iterate_active_interfaces_atomic( | 413 | void ieee80211_iterate_active_interfaces_atomic( |
414 | struct ieee80211_hw *hw, | 414 | struct ieee80211_hw *hw, |
415 | void (*iterator)(void *data, u8 *mac, | 415 | void (*iterator)(void *data, u8 *mac, |
416 | struct ieee80211_vif *vif), | 416 | struct ieee80211_vif *vif), |
417 | void *data) | 417 | void *data) |
418 | { | 418 | { |
419 | struct ieee80211_local *local = hw_to_local(hw); | 419 | struct ieee80211_local *local = hw_to_local(hw); |
420 | struct ieee80211_sub_if_data *sdata; | 420 | struct ieee80211_sub_if_data *sdata; |
421 | 421 | ||
422 | rcu_read_lock(); | 422 | rcu_read_lock(); |
423 | 423 | ||
424 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 424 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
425 | switch (sdata->vif.type) { | 425 | switch (sdata->vif.type) { |
426 | case __NL80211_IFTYPE_AFTER_LAST: | 426 | case __NL80211_IFTYPE_AFTER_LAST: |
427 | case NL80211_IFTYPE_UNSPECIFIED: | 427 | case NL80211_IFTYPE_UNSPECIFIED: |
428 | case NL80211_IFTYPE_MONITOR: | 428 | case NL80211_IFTYPE_MONITOR: |
429 | case NL80211_IFTYPE_AP_VLAN: | 429 | case NL80211_IFTYPE_AP_VLAN: |
430 | continue; | 430 | continue; |
431 | case NL80211_IFTYPE_AP: | 431 | case NL80211_IFTYPE_AP: |
432 | case NL80211_IFTYPE_STATION: | 432 | case NL80211_IFTYPE_STATION: |
433 | case NL80211_IFTYPE_ADHOC: | 433 | case NL80211_IFTYPE_ADHOC: |
434 | case NL80211_IFTYPE_WDS: | 434 | case NL80211_IFTYPE_WDS: |
435 | case NL80211_IFTYPE_MESH_POINT: | 435 | case NL80211_IFTYPE_MESH_POINT: |
436 | break; | 436 | break; |
437 | } | 437 | } |
438 | if (netif_running(sdata->dev)) | 438 | if (netif_running(sdata->dev)) |
439 | iterator(data, sdata->dev->dev_addr, | 439 | iterator(data, sdata->dev->dev_addr, |
440 | &sdata->vif); | 440 | &sdata->vif); |
441 | } | 441 | } |
442 | 442 | ||
443 | rcu_read_unlock(); | 443 | rcu_read_unlock(); |
444 | } | 444 | } |
445 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 445 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); |
446 | 446 | ||
447 | void ieee802_11_parse_elems(u8 *start, size_t len, | 447 | void ieee802_11_parse_elems(u8 *start, size_t len, |
448 | struct ieee802_11_elems *elems) | 448 | struct ieee802_11_elems *elems) |
449 | { | 449 | { |
450 | size_t left = len; | 450 | size_t left = len; |
451 | u8 *pos = start; | 451 | u8 *pos = start; |
452 | 452 | ||
453 | memset(elems, 0, sizeof(*elems)); | 453 | memset(elems, 0, sizeof(*elems)); |
454 | elems->ie_start = start; | 454 | elems->ie_start = start; |
455 | elems->total_len = len; | 455 | elems->total_len = len; |
456 | 456 | ||
457 | while (left >= 2) { | 457 | while (left >= 2) { |
458 | u8 id, elen; | 458 | u8 id, elen; |
459 | 459 | ||
460 | id = *pos++; | 460 | id = *pos++; |
461 | elen = *pos++; | 461 | elen = *pos++; |
462 | left -= 2; | 462 | left -= 2; |
463 | 463 | ||
464 | if (elen > left) | 464 | if (elen > left) |
465 | return; | 465 | return; |
466 | 466 | ||
467 | switch (id) { | 467 | switch (id) { |
468 | case WLAN_EID_SSID: | 468 | case WLAN_EID_SSID: |
469 | elems->ssid = pos; | 469 | elems->ssid = pos; |
470 | elems->ssid_len = elen; | 470 | elems->ssid_len = elen; |
471 | break; | 471 | break; |
472 | case WLAN_EID_SUPP_RATES: | 472 | case WLAN_EID_SUPP_RATES: |
473 | elems->supp_rates = pos; | 473 | elems->supp_rates = pos; |
474 | elems->supp_rates_len = elen; | 474 | elems->supp_rates_len = elen; |
475 | break; | 475 | break; |
476 | case WLAN_EID_FH_PARAMS: | 476 | case WLAN_EID_FH_PARAMS: |
477 | elems->fh_params = pos; | 477 | elems->fh_params = pos; |
478 | elems->fh_params_len = elen; | 478 | elems->fh_params_len = elen; |
479 | break; | 479 | break; |
480 | case WLAN_EID_DS_PARAMS: | 480 | case WLAN_EID_DS_PARAMS: |
481 | elems->ds_params = pos; | 481 | elems->ds_params = pos; |
482 | elems->ds_params_len = elen; | 482 | elems->ds_params_len = elen; |
483 | break; | 483 | break; |
484 | case WLAN_EID_CF_PARAMS: | 484 | case WLAN_EID_CF_PARAMS: |
485 | elems->cf_params = pos; | 485 | elems->cf_params = pos; |
486 | elems->cf_params_len = elen; | 486 | elems->cf_params_len = elen; |
487 | break; | 487 | break; |
488 | case WLAN_EID_TIM: | 488 | case WLAN_EID_TIM: |
489 | elems->tim = pos; | 489 | elems->tim = pos; |
490 | elems->tim_len = elen; | 490 | elems->tim_len = elen; |
491 | break; | 491 | break; |
492 | case WLAN_EID_IBSS_PARAMS: | 492 | case WLAN_EID_IBSS_PARAMS: |
493 | elems->ibss_params = pos; | 493 | elems->ibss_params = pos; |
494 | elems->ibss_params_len = elen; | 494 | elems->ibss_params_len = elen; |
495 | break; | 495 | break; |
496 | case WLAN_EID_CHALLENGE: | 496 | case WLAN_EID_CHALLENGE: |
497 | elems->challenge = pos; | 497 | elems->challenge = pos; |
498 | elems->challenge_len = elen; | 498 | elems->challenge_len = elen; |
499 | break; | 499 | break; |
500 | case WLAN_EID_WPA: | 500 | case WLAN_EID_WPA: |
501 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | 501 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && |
502 | pos[2] == 0xf2) { | 502 | pos[2] == 0xf2) { |
503 | /* Microsoft OUI (00:50:F2) */ | 503 | /* Microsoft OUI (00:50:F2) */ |
504 | if (pos[3] == 1) { | 504 | if (pos[3] == 1) { |
505 | /* OUI Type 1 - WPA IE */ | 505 | /* OUI Type 1 - WPA IE */ |
506 | elems->wpa = pos; | 506 | elems->wpa = pos; |
507 | elems->wpa_len = elen; | 507 | elems->wpa_len = elen; |
508 | } else if (elen >= 5 && pos[3] == 2) { | 508 | } else if (elen >= 5 && pos[3] == 2) { |
509 | if (pos[4] == 0) { | 509 | if (pos[4] == 0) { |
510 | elems->wmm_info = pos; | 510 | elems->wmm_info = pos; |
511 | elems->wmm_info_len = elen; | 511 | elems->wmm_info_len = elen; |
512 | } else if (pos[4] == 1) { | 512 | } else if (pos[4] == 1) { |
513 | elems->wmm_param = pos; | 513 | elems->wmm_param = pos; |
514 | elems->wmm_param_len = elen; | 514 | elems->wmm_param_len = elen; |
515 | } | 515 | } |
516 | } | 516 | } |
517 | } | 517 | } |
518 | break; | 518 | break; |
519 | case WLAN_EID_RSN: | 519 | case WLAN_EID_RSN: |
520 | elems->rsn = pos; | 520 | elems->rsn = pos; |
521 | elems->rsn_len = elen; | 521 | elems->rsn_len = elen; |
522 | break; | 522 | break; |
523 | case WLAN_EID_ERP_INFO: | 523 | case WLAN_EID_ERP_INFO: |
524 | elems->erp_info = pos; | 524 | elems->erp_info = pos; |
525 | elems->erp_info_len = elen; | 525 | elems->erp_info_len = elen; |
526 | break; | 526 | break; |
527 | case WLAN_EID_EXT_SUPP_RATES: | 527 | case WLAN_EID_EXT_SUPP_RATES: |
528 | elems->ext_supp_rates = pos; | 528 | elems->ext_supp_rates = pos; |
529 | elems->ext_supp_rates_len = elen; | 529 | elems->ext_supp_rates_len = elen; |
530 | break; | 530 | break; |
531 | case WLAN_EID_HT_CAPABILITY: | 531 | case WLAN_EID_HT_CAPABILITY: |
532 | if (elen >= sizeof(struct ieee80211_ht_cap)) | 532 | if (elen >= sizeof(struct ieee80211_ht_cap)) |
533 | elems->ht_cap_elem = (void *)pos; | 533 | elems->ht_cap_elem = (void *)pos; |
534 | break; | 534 | break; |
535 | case WLAN_EID_HT_INFORMATION: | 535 | case WLAN_EID_HT_INFORMATION: |
536 | if (elen >= sizeof(struct ieee80211_ht_info)) | 536 | if (elen >= sizeof(struct ieee80211_ht_info)) |
537 | elems->ht_info_elem = (void *)pos; | 537 | elems->ht_info_elem = (void *)pos; |
538 | break; | 538 | break; |
539 | case WLAN_EID_MESH_ID: | 539 | case WLAN_EID_MESH_ID: |
540 | elems->mesh_id = pos; | 540 | elems->mesh_id = pos; |
541 | elems->mesh_id_len = elen; | 541 | elems->mesh_id_len = elen; |
542 | break; | 542 | break; |
543 | case WLAN_EID_MESH_CONFIG: | 543 | case WLAN_EID_MESH_CONFIG: |
544 | elems->mesh_config = pos; | 544 | elems->mesh_config = pos; |
545 | elems->mesh_config_len = elen; | 545 | elems->mesh_config_len = elen; |
546 | break; | 546 | break; |
547 | case WLAN_EID_PEER_LINK: | 547 | case WLAN_EID_PEER_LINK: |
548 | elems->peer_link = pos; | 548 | elems->peer_link = pos; |
549 | elems->peer_link_len = elen; | 549 | elems->peer_link_len = elen; |
550 | break; | 550 | break; |
551 | case WLAN_EID_PREQ: | 551 | case WLAN_EID_PREQ: |
552 | elems->preq = pos; | 552 | elems->preq = pos; |
553 | elems->preq_len = elen; | 553 | elems->preq_len = elen; |
554 | break; | 554 | break; |
555 | case WLAN_EID_PREP: | 555 | case WLAN_EID_PREP: |
556 | elems->prep = pos; | 556 | elems->prep = pos; |
557 | elems->prep_len = elen; | 557 | elems->prep_len = elen; |
558 | break; | 558 | break; |
559 | case WLAN_EID_PERR: | 559 | case WLAN_EID_PERR: |
560 | elems->perr = pos; | 560 | elems->perr = pos; |
561 | elems->perr_len = elen; | 561 | elems->perr_len = elen; |
562 | break; | 562 | break; |
563 | case WLAN_EID_CHANNEL_SWITCH: | 563 | case WLAN_EID_CHANNEL_SWITCH: |
564 | elems->ch_switch_elem = pos; | 564 | elems->ch_switch_elem = pos; |
565 | elems->ch_switch_elem_len = elen; | 565 | elems->ch_switch_elem_len = elen; |
566 | break; | 566 | break; |
567 | case WLAN_EID_QUIET: | 567 | case WLAN_EID_QUIET: |
568 | if (!elems->quiet_elem) { | 568 | if (!elems->quiet_elem) { |
569 | elems->quiet_elem = pos; | 569 | elems->quiet_elem = pos; |
570 | elems->quiet_elem_len = elen; | 570 | elems->quiet_elem_len = elen; |
571 | } | 571 | } |
572 | elems->num_of_quiet_elem++; | 572 | elems->num_of_quiet_elem++; |
573 | break; | 573 | break; |
574 | case WLAN_EID_COUNTRY: | 574 | case WLAN_EID_COUNTRY: |
575 | elems->country_elem = pos; | 575 | elems->country_elem = pos; |
576 | elems->country_elem_len = elen; | 576 | elems->country_elem_len = elen; |
577 | break; | 577 | break; |
578 | case WLAN_EID_PWR_CONSTRAINT: | 578 | case WLAN_EID_PWR_CONSTRAINT: |
579 | elems->pwr_constr_elem = pos; | 579 | elems->pwr_constr_elem = pos; |
580 | elems->pwr_constr_elem_len = elen; | 580 | elems->pwr_constr_elem_len = elen; |
581 | break; | 581 | break; |
582 | default: | 582 | default: |
583 | break; | 583 | break; |
584 | } | 584 | } |
585 | 585 | ||
586 | left -= elen; | 586 | left -= elen; |
587 | pos += elen; | 587 | pos += elen; |
588 | } | 588 | } |
589 | } | 589 | } |
590 | 590 | ||
591 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | 591 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) |
592 | { | 592 | { |
593 | struct ieee80211_local *local = sdata->local; | 593 | struct ieee80211_local *local = sdata->local; |
594 | struct ieee80211_tx_queue_params qparam; | 594 | struct ieee80211_tx_queue_params qparam; |
595 | int i; | 595 | int i; |
596 | 596 | ||
597 | if (!local->ops->conf_tx) | 597 | if (!local->ops->conf_tx) |
598 | return; | 598 | return; |
599 | 599 | ||
600 | memset(&qparam, 0, sizeof(qparam)); | 600 | memset(&qparam, 0, sizeof(qparam)); |
601 | 601 | ||
602 | qparam.aifs = 2; | 602 | qparam.aifs = 2; |
603 | 603 | ||
604 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 604 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && |
605 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) | 605 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) |
606 | qparam.cw_min = 31; | 606 | qparam.cw_min = 31; |
607 | else | 607 | else |
608 | qparam.cw_min = 15; | 608 | qparam.cw_min = 15; |
609 | 609 | ||
610 | qparam.cw_max = 1023; | 610 | qparam.cw_max = 1023; |
611 | qparam.txop = 0; | 611 | qparam.txop = 0; |
612 | 612 | ||
613 | for (i = 0; i < local_to_hw(local)->queues; i++) | 613 | for (i = 0; i < local_to_hw(local)->queues; i++) |
614 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 614 | local->ops->conf_tx(local_to_hw(local), i, &qparam); |
615 | } | 615 | } |
616 | 616 | ||
617 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 617 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
618 | int encrypt) | 618 | int encrypt) |
619 | { | 619 | { |
620 | skb->dev = sdata->local->mdev; | 620 | skb->dev = sdata->local->mdev; |
621 | skb_set_mac_header(skb, 0); | 621 | skb_set_mac_header(skb, 0); |
622 | skb_set_network_header(skb, 0); | 622 | skb_set_network_header(skb, 0); |
623 | skb_set_transport_header(skb, 0); | 623 | skb_set_transport_header(skb, 0); |
624 | 624 | ||
625 | skb->iif = sdata->dev->ifindex; | 625 | skb->iif = sdata->dev->ifindex; |
626 | skb->do_not_encrypt = !encrypt; | 626 | skb->do_not_encrypt = !encrypt; |
627 | 627 | ||
628 | dev_queue_xmit(skb); | 628 | dev_queue_xmit(skb); |
629 | } | 629 | } |
630 | 630 | ||
631 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | 631 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) |
632 | { | 632 | { |
633 | int ret = -EINVAL; | 633 | int ret = -EINVAL; |
634 | struct ieee80211_channel *chan; | 634 | struct ieee80211_channel *chan; |
635 | struct ieee80211_local *local = sdata->local; | 635 | struct ieee80211_local *local = sdata->local; |
636 | 636 | ||
637 | chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); | 637 | chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); |
638 | 638 | ||
639 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { | 639 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { |
640 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 640 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
641 | chan->flags & IEEE80211_CHAN_NO_IBSS) | 641 | chan->flags & IEEE80211_CHAN_NO_IBSS) |
642 | return ret; | 642 | return ret; |
643 | local->oper_channel = chan; | 643 | local->oper_channel = chan; |
644 | local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | 644 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
645 | 645 | ||
646 | if (local->sw_scanning || local->hw_scanning) | 646 | if (local->sw_scanning || local->hw_scanning) |
647 | ret = 0; | 647 | ret = 0; |
648 | else | 648 | else |
649 | ret = ieee80211_hw_config( | 649 | ret = ieee80211_hw_config( |
650 | local, IEEE80211_CONF_CHANGE_CHANNEL); | 650 | local, IEEE80211_CONF_CHANGE_CHANNEL); |
651 | } | 651 | } |
652 | 652 | ||
653 | return ret; | 653 | return ret; |
654 | } | 654 | } |
655 | 655 | ||
656 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 656 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, |
657 | enum ieee80211_band band) | 657 | enum ieee80211_band band) |
658 | { | 658 | { |
659 | struct ieee80211_supported_band *sband; | 659 | struct ieee80211_supported_band *sband; |
660 | struct ieee80211_rate *bitrates; | 660 | struct ieee80211_rate *bitrates; |
661 | u64 mandatory_rates; | 661 | u64 mandatory_rates; |
662 | enum ieee80211_rate_flags mandatory_flag; | 662 | enum ieee80211_rate_flags mandatory_flag; |
663 | int i; | 663 | int i; |
664 | 664 | ||
665 | sband = local->hw.wiphy->bands[band]; | 665 | sband = local->hw.wiphy->bands[band]; |
666 | if (!sband) { | 666 | if (!sband) { |
667 | WARN_ON(1); | 667 | WARN_ON(1); |
668 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 668 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
669 | } | 669 | } |
670 | 670 | ||
671 | if (band == IEEE80211_BAND_2GHZ) | 671 | if (band == IEEE80211_BAND_2GHZ) |
672 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | 672 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; |
673 | else | 673 | else |
674 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; | 674 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; |
675 | 675 | ||
676 | bitrates = sband->bitrates; | 676 | bitrates = sband->bitrates; |
677 | mandatory_rates = 0; | 677 | mandatory_rates = 0; |
678 | for (i = 0; i < sband->n_bitrates; i++) | 678 | for (i = 0; i < sband->n_bitrates; i++) |
679 | if (bitrates[i].flags & mandatory_flag) | 679 | if (bitrates[i].flags & mandatory_flag) |
680 | mandatory_rates |= BIT(i); | 680 | mandatory_rates |= BIT(i); |
681 | return mandatory_rates; | 681 | return mandatory_rates; |
682 | } | 682 | } |
683 | 683 |
net/wireless/nl80211.c
1 | /* | 1 | /* |
2 | * This is the new netlink-based wireless configuration interface. | 2 | * This is the new netlink-based wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/mutex.h> | 10 | #include <linux/mutex.h> |
11 | #include <linux/list.h> | 11 | #include <linux/list.h> |
12 | #include <linux/if_ether.h> | 12 | #include <linux/if_ether.h> |
13 | #include <linux/ieee80211.h> | 13 | #include <linux/ieee80211.h> |
14 | #include <linux/nl80211.h> | 14 | #include <linux/nl80211.h> |
15 | #include <linux/rtnetlink.h> | 15 | #include <linux/rtnetlink.h> |
16 | #include <linux/netlink.h> | 16 | #include <linux/netlink.h> |
17 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
18 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
19 | #include "core.h" | 19 | #include "core.h" |
20 | #include "nl80211.h" | 20 | #include "nl80211.h" |
21 | #include "reg.h" | 21 | #include "reg.h" |
22 | 22 | ||
23 | /* the netlink family */ | 23 | /* the netlink family */ |
24 | static struct genl_family nl80211_fam = { | 24 | static struct genl_family nl80211_fam = { |
25 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 25 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
26 | .name = "nl80211", /* have users key off the name instead */ | 26 | .name = "nl80211", /* have users key off the name instead */ |
27 | .hdrsize = 0, /* no private header */ | 27 | .hdrsize = 0, /* no private header */ |
28 | .version = 1, /* no particular meaning now */ | 28 | .version = 1, /* no particular meaning now */ |
29 | .maxattr = NL80211_ATTR_MAX, | 29 | .maxattr = NL80211_ATTR_MAX, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | /* internal helper: get drv and dev */ | 32 | /* internal helper: get drv and dev */ |
33 | static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, | 33 | static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, |
34 | struct cfg80211_registered_device **drv, | 34 | struct cfg80211_registered_device **drv, |
35 | struct net_device **dev) | 35 | struct net_device **dev) |
36 | { | 36 | { |
37 | int ifindex; | 37 | int ifindex; |
38 | 38 | ||
39 | if (!attrs[NL80211_ATTR_IFINDEX]) | 39 | if (!attrs[NL80211_ATTR_IFINDEX]) |
40 | return -EINVAL; | 40 | return -EINVAL; |
41 | 41 | ||
42 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 42 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
43 | *dev = dev_get_by_index(&init_net, ifindex); | 43 | *dev = dev_get_by_index(&init_net, ifindex); |
44 | if (!*dev) | 44 | if (!*dev) |
45 | return -ENODEV; | 45 | return -ENODEV; |
46 | 46 | ||
47 | *drv = cfg80211_get_dev_from_ifindex(ifindex); | 47 | *drv = cfg80211_get_dev_from_ifindex(ifindex); |
48 | if (IS_ERR(*drv)) { | 48 | if (IS_ERR(*drv)) { |
49 | dev_put(*dev); | 49 | dev_put(*dev); |
50 | return PTR_ERR(*drv); | 50 | return PTR_ERR(*drv); |
51 | } | 51 | } |
52 | 52 | ||
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | 55 | ||
56 | /* policy for the attributes */ | 56 | /* policy for the attributes */ |
57 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | 57 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { |
58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
60 | .len = BUS_ID_SIZE-1 }, | 60 | .len = BUS_ID_SIZE-1 }, |
61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | 62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 }, | 63 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, |
64 | 64 | ||
65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
67 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 67 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
68 | 68 | ||
69 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 69 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, |
70 | 70 | ||
71 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 71 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
72 | .len = WLAN_MAX_KEY_LEN }, | 72 | .len = WLAN_MAX_KEY_LEN }, |
73 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 73 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
74 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 74 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
75 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 75 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
76 | 76 | ||
77 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 77 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
78 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 78 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
79 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, | 79 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, |
80 | .len = IEEE80211_MAX_DATA_LEN }, | 80 | .len = IEEE80211_MAX_DATA_LEN }, |
81 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, | 81 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, |
82 | .len = IEEE80211_MAX_DATA_LEN }, | 82 | .len = IEEE80211_MAX_DATA_LEN }, |
83 | [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, | 83 | [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, |
84 | [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, | 84 | [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, |
85 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, | 85 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, |
86 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | 86 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, |
87 | .len = NL80211_MAX_SUPP_RATES }, | 87 | .len = NL80211_MAX_SUPP_RATES }, |
88 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, | 88 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, |
89 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
90 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 90 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
91 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 91 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
92 | .len = IEEE80211_MAX_MESH_ID_LEN }, | 92 | .len = IEEE80211_MAX_MESH_ID_LEN }, |
93 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | 93 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, |
94 | 94 | ||
95 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, | 95 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, |
96 | [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, | 96 | [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, |
97 | 97 | ||
98 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, | 98 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, |
99 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, | 99 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, |
100 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, | 100 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, |
101 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, | 101 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, |
102 | .len = NL80211_MAX_SUPP_RATES }, | 102 | .len = NL80211_MAX_SUPP_RATES }, |
103 | 103 | ||
104 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 104 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, |
105 | 105 | ||
106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
107 | .len = NL80211_HT_CAPABILITY_LEN }, | 107 | .len = NL80211_HT_CAPABILITY_LEN }, |
108 | }; | 108 | }; |
109 | 109 | ||
110 | /* message building helper */ | 110 | /* message building helper */ |
111 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | 111 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, |
112 | int flags, u8 cmd) | 112 | int flags, u8 cmd) |
113 | { | 113 | { |
114 | /* since there is no private header just add the generic one */ | 114 | /* since there is no private header just add the generic one */ |
115 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); | 115 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); |
116 | } | 116 | } |
117 | 117 | ||
118 | /* netlink command implementations */ | 118 | /* netlink command implementations */ |
119 | 119 | ||
120 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 120 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
121 | struct cfg80211_registered_device *dev) | 121 | struct cfg80211_registered_device *dev) |
122 | { | 122 | { |
123 | void *hdr; | 123 | void *hdr; |
124 | struct nlattr *nl_bands, *nl_band; | 124 | struct nlattr *nl_bands, *nl_band; |
125 | struct nlattr *nl_freqs, *nl_freq; | 125 | struct nlattr *nl_freqs, *nl_freq; |
126 | struct nlattr *nl_rates, *nl_rate; | 126 | struct nlattr *nl_rates, *nl_rate; |
127 | struct nlattr *nl_modes; | 127 | struct nlattr *nl_modes; |
128 | enum ieee80211_band band; | 128 | enum ieee80211_band band; |
129 | struct ieee80211_channel *chan; | 129 | struct ieee80211_channel *chan; |
130 | struct ieee80211_rate *rate; | 130 | struct ieee80211_rate *rate; |
131 | int i; | 131 | int i; |
132 | u16 ifmodes = dev->wiphy.interface_modes; | 132 | u16 ifmodes = dev->wiphy.interface_modes; |
133 | 133 | ||
134 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 134 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
135 | if (!hdr) | 135 | if (!hdr) |
136 | return -1; | 136 | return -1; |
137 | 137 | ||
138 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); | 138 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); |
139 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 139 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
140 | 140 | ||
141 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 141 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
142 | if (!nl_modes) | 142 | if (!nl_modes) |
143 | goto nla_put_failure; | 143 | goto nla_put_failure; |
144 | 144 | ||
145 | i = 0; | 145 | i = 0; |
146 | while (ifmodes) { | 146 | while (ifmodes) { |
147 | if (ifmodes & 1) | 147 | if (ifmodes & 1) |
148 | NLA_PUT_FLAG(msg, i); | 148 | NLA_PUT_FLAG(msg, i); |
149 | ifmodes >>= 1; | 149 | ifmodes >>= 1; |
150 | i++; | 150 | i++; |
151 | } | 151 | } |
152 | 152 | ||
153 | nla_nest_end(msg, nl_modes); | 153 | nla_nest_end(msg, nl_modes); |
154 | 154 | ||
155 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 155 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
156 | if (!nl_bands) | 156 | if (!nl_bands) |
157 | goto nla_put_failure; | 157 | goto nla_put_failure; |
158 | 158 | ||
159 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 159 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
160 | if (!dev->wiphy.bands[band]) | 160 | if (!dev->wiphy.bands[band]) |
161 | continue; | 161 | continue; |
162 | 162 | ||
163 | nl_band = nla_nest_start(msg, band); | 163 | nl_band = nla_nest_start(msg, band); |
164 | if (!nl_band) | 164 | if (!nl_band) |
165 | goto nla_put_failure; | 165 | goto nla_put_failure; |
166 | 166 | ||
167 | /* add HT info */ | 167 | /* add HT info */ |
168 | if (dev->wiphy.bands[band]->ht_cap.ht_supported) { | 168 | if (dev->wiphy.bands[band]->ht_cap.ht_supported) { |
169 | NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, | 169 | NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, |
170 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), | 170 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), |
171 | &dev->wiphy.bands[band]->ht_cap.mcs); | 171 | &dev->wiphy.bands[band]->ht_cap.mcs); |
172 | NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, | 172 | NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, |
173 | dev->wiphy.bands[band]->ht_cap.cap); | 173 | dev->wiphy.bands[band]->ht_cap.cap); |
174 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 174 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
175 | dev->wiphy.bands[band]->ht_cap.ampdu_factor); | 175 | dev->wiphy.bands[band]->ht_cap.ampdu_factor); |
176 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 176 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
177 | dev->wiphy.bands[band]->ht_cap.ampdu_density); | 177 | dev->wiphy.bands[band]->ht_cap.ampdu_density); |
178 | } | 178 | } |
179 | 179 | ||
180 | /* add frequencies */ | 180 | /* add frequencies */ |
181 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 181 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
182 | if (!nl_freqs) | 182 | if (!nl_freqs) |
183 | goto nla_put_failure; | 183 | goto nla_put_failure; |
184 | 184 | ||
185 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { | 185 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { |
186 | nl_freq = nla_nest_start(msg, i); | 186 | nl_freq = nla_nest_start(msg, i); |
187 | if (!nl_freq) | 187 | if (!nl_freq) |
188 | goto nla_put_failure; | 188 | goto nla_put_failure; |
189 | 189 | ||
190 | chan = &dev->wiphy.bands[band]->channels[i]; | 190 | chan = &dev->wiphy.bands[band]->channels[i]; |
191 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, | 191 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, |
192 | chan->center_freq); | 192 | chan->center_freq); |
193 | 193 | ||
194 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 194 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
195 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); | 195 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); |
196 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 196 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
197 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); | 197 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); |
198 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | 198 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) |
199 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); | 199 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); |
200 | if (chan->flags & IEEE80211_CHAN_RADAR) | 200 | if (chan->flags & IEEE80211_CHAN_RADAR) |
201 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); | 201 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); |
202 | 202 | ||
203 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 203 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
204 | DBM_TO_MBM(chan->max_power)); | 204 | DBM_TO_MBM(chan->max_power)); |
205 | 205 | ||
206 | nla_nest_end(msg, nl_freq); | 206 | nla_nest_end(msg, nl_freq); |
207 | } | 207 | } |
208 | 208 | ||
209 | nla_nest_end(msg, nl_freqs); | 209 | nla_nest_end(msg, nl_freqs); |
210 | 210 | ||
211 | /* add bitrates */ | 211 | /* add bitrates */ |
212 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); | 212 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); |
213 | if (!nl_rates) | 213 | if (!nl_rates) |
214 | goto nla_put_failure; | 214 | goto nla_put_failure; |
215 | 215 | ||
216 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { | 216 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { |
217 | nl_rate = nla_nest_start(msg, i); | 217 | nl_rate = nla_nest_start(msg, i); |
218 | if (!nl_rate) | 218 | if (!nl_rate) |
219 | goto nla_put_failure; | 219 | goto nla_put_failure; |
220 | 220 | ||
221 | rate = &dev->wiphy.bands[band]->bitrates[i]; | 221 | rate = &dev->wiphy.bands[band]->bitrates[i]; |
222 | NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, | 222 | NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, |
223 | rate->bitrate); | 223 | rate->bitrate); |
224 | if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) | 224 | if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) |
225 | NLA_PUT_FLAG(msg, | 225 | NLA_PUT_FLAG(msg, |
226 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); | 226 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); |
227 | 227 | ||
228 | nla_nest_end(msg, nl_rate); | 228 | nla_nest_end(msg, nl_rate); |
229 | } | 229 | } |
230 | 230 | ||
231 | nla_nest_end(msg, nl_rates); | 231 | nla_nest_end(msg, nl_rates); |
232 | 232 | ||
233 | nla_nest_end(msg, nl_band); | 233 | nla_nest_end(msg, nl_band); |
234 | } | 234 | } |
235 | nla_nest_end(msg, nl_bands); | 235 | nla_nest_end(msg, nl_bands); |
236 | 236 | ||
237 | return genlmsg_end(msg, hdr); | 237 | return genlmsg_end(msg, hdr); |
238 | 238 | ||
239 | nla_put_failure: | 239 | nla_put_failure: |
240 | genlmsg_cancel(msg, hdr); | 240 | genlmsg_cancel(msg, hdr); |
241 | return -EMSGSIZE; | 241 | return -EMSGSIZE; |
242 | } | 242 | } |
243 | 243 | ||
244 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | 244 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) |
245 | { | 245 | { |
246 | int idx = 0; | 246 | int idx = 0; |
247 | int start = cb->args[0]; | 247 | int start = cb->args[0]; |
248 | struct cfg80211_registered_device *dev; | 248 | struct cfg80211_registered_device *dev; |
249 | 249 | ||
250 | mutex_lock(&cfg80211_drv_mutex); | 250 | mutex_lock(&cfg80211_drv_mutex); |
251 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 251 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
252 | if (++idx <= start) | 252 | if (++idx <= start) |
253 | continue; | 253 | continue; |
254 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, | 254 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, |
255 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 255 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
256 | dev) < 0) { | 256 | dev) < 0) { |
257 | idx--; | 257 | idx--; |
258 | break; | 258 | break; |
259 | } | 259 | } |
260 | } | 260 | } |
261 | mutex_unlock(&cfg80211_drv_mutex); | 261 | mutex_unlock(&cfg80211_drv_mutex); |
262 | 262 | ||
263 | cb->args[0] = idx; | 263 | cb->args[0] = idx; |
264 | 264 | ||
265 | return skb->len; | 265 | return skb->len; |
266 | } | 266 | } |
267 | 267 | ||
268 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 268 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
269 | { | 269 | { |
270 | struct sk_buff *msg; | 270 | struct sk_buff *msg; |
271 | struct cfg80211_registered_device *dev; | 271 | struct cfg80211_registered_device *dev; |
272 | 272 | ||
273 | dev = cfg80211_get_dev_from_info(info); | 273 | dev = cfg80211_get_dev_from_info(info); |
274 | if (IS_ERR(dev)) | 274 | if (IS_ERR(dev)) |
275 | return PTR_ERR(dev); | 275 | return PTR_ERR(dev); |
276 | 276 | ||
277 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 277 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
278 | if (!msg) | 278 | if (!msg) |
279 | goto out_err; | 279 | goto out_err; |
280 | 280 | ||
281 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | 281 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) |
282 | goto out_free; | 282 | goto out_free; |
283 | 283 | ||
284 | cfg80211_put_dev(dev); | 284 | cfg80211_put_dev(dev); |
285 | 285 | ||
286 | return genlmsg_unicast(msg, info->snd_pid); | 286 | return genlmsg_unicast(msg, info->snd_pid); |
287 | 287 | ||
288 | out_free: | 288 | out_free: |
289 | nlmsg_free(msg); | 289 | nlmsg_free(msg); |
290 | out_err: | 290 | out_err: |
291 | cfg80211_put_dev(dev); | 291 | cfg80211_put_dev(dev); |
292 | return -ENOBUFS; | 292 | return -ENOBUFS; |
293 | } | 293 | } |
294 | 294 | ||
295 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 295 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
296 | [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, | 296 | [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, |
297 | [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, | 297 | [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, |
298 | [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, | 298 | [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, |
299 | [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, | 299 | [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, |
300 | [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, | 300 | [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, |
301 | }; | 301 | }; |
302 | 302 | ||
303 | static int parse_txq_params(struct nlattr *tb[], | 303 | static int parse_txq_params(struct nlattr *tb[], |
304 | struct ieee80211_txq_params *txq_params) | 304 | struct ieee80211_txq_params *txq_params) |
305 | { | 305 | { |
306 | if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || | 306 | if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || |
307 | !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || | 307 | !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || |
308 | !tb[NL80211_TXQ_ATTR_AIFS]) | 308 | !tb[NL80211_TXQ_ATTR_AIFS]) |
309 | return -EINVAL; | 309 | return -EINVAL; |
310 | 310 | ||
311 | txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); | 311 | txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); |
312 | txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); | 312 | txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); |
313 | txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); | 313 | txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); |
314 | txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); | 314 | txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); |
315 | txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); | 315 | txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); |
316 | 316 | ||
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
319 | 319 | ||
320 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 320 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
321 | { | 321 | { |
322 | struct cfg80211_registered_device *rdev; | 322 | struct cfg80211_registered_device *rdev; |
323 | int result = 0, rem_txq_params = 0; | 323 | int result = 0, rem_txq_params = 0; |
324 | struct nlattr *nl_txq_params; | 324 | struct nlattr *nl_txq_params; |
325 | 325 | ||
326 | rdev = cfg80211_get_dev_from_info(info); | 326 | rdev = cfg80211_get_dev_from_info(info); |
327 | if (IS_ERR(rdev)) | 327 | if (IS_ERR(rdev)) |
328 | return PTR_ERR(rdev); | 328 | return PTR_ERR(rdev); |
329 | 329 | ||
330 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { | 330 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { |
331 | result = cfg80211_dev_rename( | 331 | result = cfg80211_dev_rename( |
332 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 332 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
333 | if (result) | 333 | if (result) |
334 | goto bad_res; | 334 | goto bad_res; |
335 | } | 335 | } |
336 | 336 | ||
337 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 337 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
338 | struct ieee80211_txq_params txq_params; | 338 | struct ieee80211_txq_params txq_params; |
339 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; | 339 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; |
340 | 340 | ||
341 | if (!rdev->ops->set_txq_params) { | 341 | if (!rdev->ops->set_txq_params) { |
342 | result = -EOPNOTSUPP; | 342 | result = -EOPNOTSUPP; |
343 | goto bad_res; | 343 | goto bad_res; |
344 | } | 344 | } |
345 | 345 | ||
346 | nla_for_each_nested(nl_txq_params, | 346 | nla_for_each_nested(nl_txq_params, |
347 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 347 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
348 | rem_txq_params) { | 348 | rem_txq_params) { |
349 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, | 349 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, |
350 | nla_data(nl_txq_params), | 350 | nla_data(nl_txq_params), |
351 | nla_len(nl_txq_params), | 351 | nla_len(nl_txq_params), |
352 | txq_params_policy); | 352 | txq_params_policy); |
353 | result = parse_txq_params(tb, &txq_params); | 353 | result = parse_txq_params(tb, &txq_params); |
354 | if (result) | 354 | if (result) |
355 | goto bad_res; | 355 | goto bad_res; |
356 | 356 | ||
357 | result = rdev->ops->set_txq_params(&rdev->wiphy, | 357 | result = rdev->ops->set_txq_params(&rdev->wiphy, |
358 | &txq_params); | 358 | &txq_params); |
359 | if (result) | 359 | if (result) |
360 | goto bad_res; | 360 | goto bad_res; |
361 | } | 361 | } |
362 | } | 362 | } |
363 | 363 | ||
364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
365 | enum nl80211_sec_chan_offset sec_chan_offset = | 365 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
366 | NL80211_SEC_CHAN_NO_HT; | ||
367 | struct ieee80211_channel *chan; | 366 | struct ieee80211_channel *chan; |
368 | struct ieee80211_sta_ht_cap *ht_cap; | 367 | struct ieee80211_sta_ht_cap *ht_cap; |
369 | u32 freq, sec_freq; | 368 | u32 freq, sec_freq; |
370 | 369 | ||
371 | if (!rdev->ops->set_channel) { | 370 | if (!rdev->ops->set_channel) { |
372 | result = -EOPNOTSUPP; | 371 | result = -EOPNOTSUPP; |
373 | goto bad_res; | 372 | goto bad_res; |
374 | } | 373 | } |
375 | 374 | ||
376 | result = -EINVAL; | 375 | result = -EINVAL; |
377 | 376 | ||
378 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { | 377 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
379 | sec_chan_offset = nla_get_u32(info->attrs[ | 378 | channel_type = nla_get_u32(info->attrs[ |
380 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); | 379 | NL80211_ATTR_WIPHY_CHANNEL_TYPE]); |
381 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | 380 | if (channel_type != NL80211_CHAN_NO_HT && |
382 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && | 381 | channel_type != NL80211_CHAN_HT20 && |
383 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && | 382 | channel_type != NL80211_CHAN_HT40PLUS && |
384 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) | 383 | channel_type != NL80211_CHAN_HT40MINUS) |
385 | goto bad_res; | 384 | goto bad_res; |
386 | } | 385 | } |
387 | 386 | ||
388 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 387 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
389 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | 388 | chan = ieee80211_get_channel(&rdev->wiphy, freq); |
390 | 389 | ||
391 | /* Primary channel not allowed */ | 390 | /* Primary channel not allowed */ |
392 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 391 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
393 | goto bad_res; | 392 | goto bad_res; |
394 | 393 | ||
395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) | 394 | if (channel_type == NL80211_CHAN_HT40MINUS) |
396 | sec_freq = freq - 20; | 395 | sec_freq = freq - 20; |
397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) | 396 | else if (channel_type == NL80211_CHAN_HT40PLUS) |
398 | sec_freq = freq + 20; | 397 | sec_freq = freq + 20; |
399 | else | 398 | else |
400 | sec_freq = 0; | 399 | sec_freq = 0; |
401 | 400 | ||
402 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | 401 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; |
403 | 402 | ||
404 | /* no HT capabilities */ | 403 | /* no HT capabilities */ |
405 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | 404 | if (channel_type != NL80211_CHAN_NO_HT && |
406 | !ht_cap->ht_supported) | 405 | !ht_cap->ht_supported) |
407 | goto bad_res; | 406 | goto bad_res; |
408 | 407 | ||
409 | if (sec_freq) { | 408 | if (sec_freq) { |
410 | struct ieee80211_channel *schan; | 409 | struct ieee80211_channel *schan; |
411 | 410 | ||
412 | /* no 40 MHz capabilities */ | 411 | /* no 40 MHz capabilities */ |
413 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 412 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || |
414 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | 413 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) |
415 | goto bad_res; | 414 | goto bad_res; |
416 | 415 | ||
417 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | 416 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); |
418 | 417 | ||
419 | /* Secondary channel not allowed */ | 418 | /* Secondary channel not allowed */ |
420 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) | 419 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) |
421 | goto bad_res; | 420 | goto bad_res; |
422 | } | 421 | } |
423 | 422 | ||
424 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 423 | result = rdev->ops->set_channel(&rdev->wiphy, chan, |
425 | sec_chan_offset); | 424 | channel_type); |
426 | if (result) | 425 | if (result) |
427 | goto bad_res; | 426 | goto bad_res; |
428 | } | 427 | } |
429 | 428 | ||
430 | 429 | ||
431 | bad_res: | 430 | bad_res: |
432 | cfg80211_put_dev(rdev); | 431 | cfg80211_put_dev(rdev); |
433 | return result; | 432 | return result; |
434 | } | 433 | } |
435 | 434 | ||
436 | 435 | ||
437 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 436 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
438 | struct net_device *dev) | 437 | struct net_device *dev) |
439 | { | 438 | { |
440 | void *hdr; | 439 | void *hdr; |
441 | 440 | ||
442 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 441 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
443 | if (!hdr) | 442 | if (!hdr) |
444 | return -1; | 443 | return -1; |
445 | 444 | ||
446 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 445 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
447 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 446 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
448 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 447 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
449 | return genlmsg_end(msg, hdr); | 448 | return genlmsg_end(msg, hdr); |
450 | 449 | ||
451 | nla_put_failure: | 450 | nla_put_failure: |
452 | genlmsg_cancel(msg, hdr); | 451 | genlmsg_cancel(msg, hdr); |
453 | return -EMSGSIZE; | 452 | return -EMSGSIZE; |
454 | } | 453 | } |
455 | 454 | ||
456 | static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) | 455 | static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) |
457 | { | 456 | { |
458 | int wp_idx = 0; | 457 | int wp_idx = 0; |
459 | int if_idx = 0; | 458 | int if_idx = 0; |
460 | int wp_start = cb->args[0]; | 459 | int wp_start = cb->args[0]; |
461 | int if_start = cb->args[1]; | 460 | int if_start = cb->args[1]; |
462 | struct cfg80211_registered_device *dev; | 461 | struct cfg80211_registered_device *dev; |
463 | struct wireless_dev *wdev; | 462 | struct wireless_dev *wdev; |
464 | 463 | ||
465 | mutex_lock(&cfg80211_drv_mutex); | 464 | mutex_lock(&cfg80211_drv_mutex); |
466 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 465 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
467 | if (wp_idx < wp_start) { | 466 | if (wp_idx < wp_start) { |
468 | wp_idx++; | 467 | wp_idx++; |
469 | continue; | 468 | continue; |
470 | } | 469 | } |
471 | if_idx = 0; | 470 | if_idx = 0; |
472 | 471 | ||
473 | mutex_lock(&dev->devlist_mtx); | 472 | mutex_lock(&dev->devlist_mtx); |
474 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 473 | list_for_each_entry(wdev, &dev->netdev_list, list) { |
475 | if (if_idx < if_start) { | 474 | if (if_idx < if_start) { |
476 | if_idx++; | 475 | if_idx++; |
477 | continue; | 476 | continue; |
478 | } | 477 | } |
479 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 478 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
480 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 479 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
481 | wdev->netdev) < 0) { | 480 | wdev->netdev) < 0) { |
482 | mutex_unlock(&dev->devlist_mtx); | 481 | mutex_unlock(&dev->devlist_mtx); |
483 | goto out; | 482 | goto out; |
484 | } | 483 | } |
485 | if_idx++; | 484 | if_idx++; |
486 | } | 485 | } |
487 | mutex_unlock(&dev->devlist_mtx); | 486 | mutex_unlock(&dev->devlist_mtx); |
488 | 487 | ||
489 | wp_idx++; | 488 | wp_idx++; |
490 | } | 489 | } |
491 | out: | 490 | out: |
492 | mutex_unlock(&cfg80211_drv_mutex); | 491 | mutex_unlock(&cfg80211_drv_mutex); |
493 | 492 | ||
494 | cb->args[0] = wp_idx; | 493 | cb->args[0] = wp_idx; |
495 | cb->args[1] = if_idx; | 494 | cb->args[1] = if_idx; |
496 | 495 | ||
497 | return skb->len; | 496 | return skb->len; |
498 | } | 497 | } |
499 | 498 | ||
500 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 499 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
501 | { | 500 | { |
502 | struct sk_buff *msg; | 501 | struct sk_buff *msg; |
503 | struct cfg80211_registered_device *dev; | 502 | struct cfg80211_registered_device *dev; |
504 | struct net_device *netdev; | 503 | struct net_device *netdev; |
505 | int err; | 504 | int err; |
506 | 505 | ||
507 | err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev); | 506 | err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev); |
508 | if (err) | 507 | if (err) |
509 | return err; | 508 | return err; |
510 | 509 | ||
511 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 510 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
512 | if (!msg) | 511 | if (!msg) |
513 | goto out_err; | 512 | goto out_err; |
514 | 513 | ||
515 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) | 514 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) |
516 | goto out_free; | 515 | goto out_free; |
517 | 516 | ||
518 | dev_put(netdev); | 517 | dev_put(netdev); |
519 | cfg80211_put_dev(dev); | 518 | cfg80211_put_dev(dev); |
520 | 519 | ||
521 | return genlmsg_unicast(msg, info->snd_pid); | 520 | return genlmsg_unicast(msg, info->snd_pid); |
522 | 521 | ||
523 | out_free: | 522 | out_free: |
524 | nlmsg_free(msg); | 523 | nlmsg_free(msg); |
525 | out_err: | 524 | out_err: |
526 | dev_put(netdev); | 525 | dev_put(netdev); |
527 | cfg80211_put_dev(dev); | 526 | cfg80211_put_dev(dev); |
528 | return -ENOBUFS; | 527 | return -ENOBUFS; |
529 | } | 528 | } |
530 | 529 | ||
531 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 530 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
532 | [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, | 531 | [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, |
533 | [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, | 532 | [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, |
534 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, | 533 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, |
535 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, | 534 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, |
536 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, | 535 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, |
537 | }; | 536 | }; |
538 | 537 | ||
539 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | 538 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) |
540 | { | 539 | { |
541 | struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; | 540 | struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; |
542 | int flag; | 541 | int flag; |
543 | 542 | ||
544 | *mntrflags = 0; | 543 | *mntrflags = 0; |
545 | 544 | ||
546 | if (!nla) | 545 | if (!nla) |
547 | return -EINVAL; | 546 | return -EINVAL; |
548 | 547 | ||
549 | if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, | 548 | if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, |
550 | nla, mntr_flags_policy)) | 549 | nla, mntr_flags_policy)) |
551 | return -EINVAL; | 550 | return -EINVAL; |
552 | 551 | ||
553 | for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) | 552 | for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) |
554 | if (flags[flag]) | 553 | if (flags[flag]) |
555 | *mntrflags |= (1<<flag); | 554 | *mntrflags |= (1<<flag); |
556 | 555 | ||
557 | return 0; | 556 | return 0; |
558 | } | 557 | } |
559 | 558 | ||
560 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 559 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
561 | { | 560 | { |
562 | struct cfg80211_registered_device *drv; | 561 | struct cfg80211_registered_device *drv; |
563 | struct vif_params params; | 562 | struct vif_params params; |
564 | int err, ifindex; | 563 | int err, ifindex; |
565 | enum nl80211_iftype type; | 564 | enum nl80211_iftype type; |
566 | struct net_device *dev; | 565 | struct net_device *dev; |
567 | u32 _flags, *flags = NULL; | 566 | u32 _flags, *flags = NULL; |
568 | 567 | ||
569 | memset(¶ms, 0, sizeof(params)); | 568 | memset(¶ms, 0, sizeof(params)); |
570 | 569 | ||
571 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 570 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
572 | if (err) | 571 | if (err) |
573 | return err; | 572 | return err; |
574 | ifindex = dev->ifindex; | 573 | ifindex = dev->ifindex; |
575 | type = dev->ieee80211_ptr->iftype; | 574 | type = dev->ieee80211_ptr->iftype; |
576 | dev_put(dev); | 575 | dev_put(dev); |
577 | 576 | ||
578 | err = -EINVAL; | 577 | err = -EINVAL; |
579 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 578 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
580 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 579 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
581 | if (type > NL80211_IFTYPE_MAX) | 580 | if (type > NL80211_IFTYPE_MAX) |
582 | goto unlock; | 581 | goto unlock; |
583 | } | 582 | } |
584 | 583 | ||
585 | if (!drv->ops->change_virtual_intf || | 584 | if (!drv->ops->change_virtual_intf || |
586 | !(drv->wiphy.interface_modes & (1 << type))) { | 585 | !(drv->wiphy.interface_modes & (1 << type))) { |
587 | err = -EOPNOTSUPP; | 586 | err = -EOPNOTSUPP; |
588 | goto unlock; | 587 | goto unlock; |
589 | } | 588 | } |
590 | 589 | ||
591 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 590 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
592 | if (type != NL80211_IFTYPE_MESH_POINT) { | 591 | if (type != NL80211_IFTYPE_MESH_POINT) { |
593 | err = -EINVAL; | 592 | err = -EINVAL; |
594 | goto unlock; | 593 | goto unlock; |
595 | } | 594 | } |
596 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 595 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
597 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 596 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
598 | } | 597 | } |
599 | 598 | ||
600 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 599 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
601 | if (type != NL80211_IFTYPE_MONITOR) { | 600 | if (type != NL80211_IFTYPE_MONITOR) { |
602 | err = -EINVAL; | 601 | err = -EINVAL; |
603 | goto unlock; | 602 | goto unlock; |
604 | } | 603 | } |
605 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 604 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
606 | &_flags); | 605 | &_flags); |
607 | if (!err) | 606 | if (!err) |
608 | flags = &_flags; | 607 | flags = &_flags; |
609 | } | 608 | } |
610 | rtnl_lock(); | 609 | rtnl_lock(); |
611 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 610 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
612 | type, flags, ¶ms); | 611 | type, flags, ¶ms); |
613 | 612 | ||
614 | dev = __dev_get_by_index(&init_net, ifindex); | 613 | dev = __dev_get_by_index(&init_net, ifindex); |
615 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | 614 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); |
616 | 615 | ||
617 | rtnl_unlock(); | 616 | rtnl_unlock(); |
618 | 617 | ||
619 | unlock: | 618 | unlock: |
620 | cfg80211_put_dev(drv); | 619 | cfg80211_put_dev(drv); |
621 | return err; | 620 | return err; |
622 | } | 621 | } |
623 | 622 | ||
624 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 623 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
625 | { | 624 | { |
626 | struct cfg80211_registered_device *drv; | 625 | struct cfg80211_registered_device *drv; |
627 | struct vif_params params; | 626 | struct vif_params params; |
628 | int err; | 627 | int err; |
629 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 628 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
630 | u32 flags; | 629 | u32 flags; |
631 | 630 | ||
632 | memset(¶ms, 0, sizeof(params)); | 631 | memset(¶ms, 0, sizeof(params)); |
633 | 632 | ||
634 | if (!info->attrs[NL80211_ATTR_IFNAME]) | 633 | if (!info->attrs[NL80211_ATTR_IFNAME]) |
635 | return -EINVAL; | 634 | return -EINVAL; |
636 | 635 | ||
637 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 636 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
638 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 637 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
639 | if (type > NL80211_IFTYPE_MAX) | 638 | if (type > NL80211_IFTYPE_MAX) |
640 | return -EINVAL; | 639 | return -EINVAL; |
641 | } | 640 | } |
642 | 641 | ||
643 | drv = cfg80211_get_dev_from_info(info); | 642 | drv = cfg80211_get_dev_from_info(info); |
644 | if (IS_ERR(drv)) | 643 | if (IS_ERR(drv)) |
645 | return PTR_ERR(drv); | 644 | return PTR_ERR(drv); |
646 | 645 | ||
647 | if (!drv->ops->add_virtual_intf || | 646 | if (!drv->ops->add_virtual_intf || |
648 | !(drv->wiphy.interface_modes & (1 << type))) { | 647 | !(drv->wiphy.interface_modes & (1 << type))) { |
649 | err = -EOPNOTSUPP; | 648 | err = -EOPNOTSUPP; |
650 | goto unlock; | 649 | goto unlock; |
651 | } | 650 | } |
652 | 651 | ||
653 | if (type == NL80211_IFTYPE_MESH_POINT && | 652 | if (type == NL80211_IFTYPE_MESH_POINT && |
654 | info->attrs[NL80211_ATTR_MESH_ID]) { | 653 | info->attrs[NL80211_ATTR_MESH_ID]) { |
655 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 654 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
656 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 655 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
657 | } | 656 | } |
658 | 657 | ||
659 | rtnl_lock(); | 658 | rtnl_lock(); |
660 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 659 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
661 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 660 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
662 | &flags); | 661 | &flags); |
663 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 662 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
664 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 663 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
665 | type, err ? NULL : &flags, ¶ms); | 664 | type, err ? NULL : &flags, ¶ms); |
666 | rtnl_unlock(); | 665 | rtnl_unlock(); |
667 | 666 | ||
668 | 667 | ||
669 | unlock: | 668 | unlock: |
670 | cfg80211_put_dev(drv); | 669 | cfg80211_put_dev(drv); |
671 | return err; | 670 | return err; |
672 | } | 671 | } |
673 | 672 | ||
674 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 673 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
675 | { | 674 | { |
676 | struct cfg80211_registered_device *drv; | 675 | struct cfg80211_registered_device *drv; |
677 | int ifindex, err; | 676 | int ifindex, err; |
678 | struct net_device *dev; | 677 | struct net_device *dev; |
679 | 678 | ||
680 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 679 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
681 | if (err) | 680 | if (err) |
682 | return err; | 681 | return err; |
683 | ifindex = dev->ifindex; | 682 | ifindex = dev->ifindex; |
684 | dev_put(dev); | 683 | dev_put(dev); |
685 | 684 | ||
686 | if (!drv->ops->del_virtual_intf) { | 685 | if (!drv->ops->del_virtual_intf) { |
687 | err = -EOPNOTSUPP; | 686 | err = -EOPNOTSUPP; |
688 | goto out; | 687 | goto out; |
689 | } | 688 | } |
690 | 689 | ||
691 | rtnl_lock(); | 690 | rtnl_lock(); |
692 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); | 691 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); |
693 | rtnl_unlock(); | 692 | rtnl_unlock(); |
694 | 693 | ||
695 | out: | 694 | out: |
696 | cfg80211_put_dev(drv); | 695 | cfg80211_put_dev(drv); |
697 | return err; | 696 | return err; |
698 | } | 697 | } |
699 | 698 | ||
700 | struct get_key_cookie { | 699 | struct get_key_cookie { |
701 | struct sk_buff *msg; | 700 | struct sk_buff *msg; |
702 | int error; | 701 | int error; |
703 | }; | 702 | }; |
704 | 703 | ||
705 | static void get_key_callback(void *c, struct key_params *params) | 704 | static void get_key_callback(void *c, struct key_params *params) |
706 | { | 705 | { |
707 | struct get_key_cookie *cookie = c; | 706 | struct get_key_cookie *cookie = c; |
708 | 707 | ||
709 | if (params->key) | 708 | if (params->key) |
710 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, | 709 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, |
711 | params->key_len, params->key); | 710 | params->key_len, params->key); |
712 | 711 | ||
713 | if (params->seq) | 712 | if (params->seq) |
714 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, | 713 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, |
715 | params->seq_len, params->seq); | 714 | params->seq_len, params->seq); |
716 | 715 | ||
717 | if (params->cipher) | 716 | if (params->cipher) |
718 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, | 717 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, |
719 | params->cipher); | 718 | params->cipher); |
720 | 719 | ||
721 | return; | 720 | return; |
722 | nla_put_failure: | 721 | nla_put_failure: |
723 | cookie->error = 1; | 722 | cookie->error = 1; |
724 | } | 723 | } |
725 | 724 | ||
726 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 725 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
727 | { | 726 | { |
728 | struct cfg80211_registered_device *drv; | 727 | struct cfg80211_registered_device *drv; |
729 | int err; | 728 | int err; |
730 | struct net_device *dev; | 729 | struct net_device *dev; |
731 | u8 key_idx = 0; | 730 | u8 key_idx = 0; |
732 | u8 *mac_addr = NULL; | 731 | u8 *mac_addr = NULL; |
733 | struct get_key_cookie cookie = { | 732 | struct get_key_cookie cookie = { |
734 | .error = 0, | 733 | .error = 0, |
735 | }; | 734 | }; |
736 | void *hdr; | 735 | void *hdr; |
737 | struct sk_buff *msg; | 736 | struct sk_buff *msg; |
738 | 737 | ||
739 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 738 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
740 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 739 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
741 | 740 | ||
742 | if (key_idx > 3) | 741 | if (key_idx > 3) |
743 | return -EINVAL; | 742 | return -EINVAL; |
744 | 743 | ||
745 | if (info->attrs[NL80211_ATTR_MAC]) | 744 | if (info->attrs[NL80211_ATTR_MAC]) |
746 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 745 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
747 | 746 | ||
748 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 747 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
749 | if (err) | 748 | if (err) |
750 | return err; | 749 | return err; |
751 | 750 | ||
752 | if (!drv->ops->get_key) { | 751 | if (!drv->ops->get_key) { |
753 | err = -EOPNOTSUPP; | 752 | err = -EOPNOTSUPP; |
754 | goto out; | 753 | goto out; |
755 | } | 754 | } |
756 | 755 | ||
757 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 756 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
758 | if (!msg) { | 757 | if (!msg) { |
759 | err = -ENOMEM; | 758 | err = -ENOMEM; |
760 | goto out; | 759 | goto out; |
761 | } | 760 | } |
762 | 761 | ||
763 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 762 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
764 | NL80211_CMD_NEW_KEY); | 763 | NL80211_CMD_NEW_KEY); |
765 | 764 | ||
766 | if (IS_ERR(hdr)) { | 765 | if (IS_ERR(hdr)) { |
767 | err = PTR_ERR(hdr); | 766 | err = PTR_ERR(hdr); |
768 | goto out; | 767 | goto out; |
769 | } | 768 | } |
770 | 769 | ||
771 | cookie.msg = msg; | 770 | cookie.msg = msg; |
772 | 771 | ||
773 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 772 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
774 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); | 773 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); |
775 | if (mac_addr) | 774 | if (mac_addr) |
776 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 775 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
777 | 776 | ||
778 | rtnl_lock(); | 777 | rtnl_lock(); |
779 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, | 778 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, |
780 | &cookie, get_key_callback); | 779 | &cookie, get_key_callback); |
781 | rtnl_unlock(); | 780 | rtnl_unlock(); |
782 | 781 | ||
783 | if (err) | 782 | if (err) |
784 | goto out; | 783 | goto out; |
785 | 784 | ||
786 | if (cookie.error) | 785 | if (cookie.error) |
787 | goto nla_put_failure; | 786 | goto nla_put_failure; |
788 | 787 | ||
789 | genlmsg_end(msg, hdr); | 788 | genlmsg_end(msg, hdr); |
790 | err = genlmsg_unicast(msg, info->snd_pid); | 789 | err = genlmsg_unicast(msg, info->snd_pid); |
791 | goto out; | 790 | goto out; |
792 | 791 | ||
793 | nla_put_failure: | 792 | nla_put_failure: |
794 | err = -ENOBUFS; | 793 | err = -ENOBUFS; |
795 | nlmsg_free(msg); | 794 | nlmsg_free(msg); |
796 | out: | 795 | out: |
797 | cfg80211_put_dev(drv); | 796 | cfg80211_put_dev(drv); |
798 | dev_put(dev); | 797 | dev_put(dev); |
799 | return err; | 798 | return err; |
800 | } | 799 | } |
801 | 800 | ||
802 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 801 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
803 | { | 802 | { |
804 | struct cfg80211_registered_device *drv; | 803 | struct cfg80211_registered_device *drv; |
805 | int err; | 804 | int err; |
806 | struct net_device *dev; | 805 | struct net_device *dev; |
807 | u8 key_idx; | 806 | u8 key_idx; |
808 | 807 | ||
809 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) | 808 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) |
810 | return -EINVAL; | 809 | return -EINVAL; |
811 | 810 | ||
812 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 811 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
813 | 812 | ||
814 | if (key_idx > 3) | 813 | if (key_idx > 3) |
815 | return -EINVAL; | 814 | return -EINVAL; |
816 | 815 | ||
817 | /* currently only support setting default key */ | 816 | /* currently only support setting default key */ |
818 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 817 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
819 | return -EINVAL; | 818 | return -EINVAL; |
820 | 819 | ||
821 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 820 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
822 | if (err) | 821 | if (err) |
823 | return err; | 822 | return err; |
824 | 823 | ||
825 | if (!drv->ops->set_default_key) { | 824 | if (!drv->ops->set_default_key) { |
826 | err = -EOPNOTSUPP; | 825 | err = -EOPNOTSUPP; |
827 | goto out; | 826 | goto out; |
828 | } | 827 | } |
829 | 828 | ||
830 | rtnl_lock(); | 829 | rtnl_lock(); |
831 | err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); | 830 | err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); |
832 | rtnl_unlock(); | 831 | rtnl_unlock(); |
833 | 832 | ||
834 | out: | 833 | out: |
835 | cfg80211_put_dev(drv); | 834 | cfg80211_put_dev(drv); |
836 | dev_put(dev); | 835 | dev_put(dev); |
837 | return err; | 836 | return err; |
838 | } | 837 | } |
839 | 838 | ||
840 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 839 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
841 | { | 840 | { |
842 | struct cfg80211_registered_device *drv; | 841 | struct cfg80211_registered_device *drv; |
843 | int err; | 842 | int err; |
844 | struct net_device *dev; | 843 | struct net_device *dev; |
845 | struct key_params params; | 844 | struct key_params params; |
846 | u8 key_idx = 0; | 845 | u8 key_idx = 0; |
847 | u8 *mac_addr = NULL; | 846 | u8 *mac_addr = NULL; |
848 | 847 | ||
849 | memset(¶ms, 0, sizeof(params)); | 848 | memset(¶ms, 0, sizeof(params)); |
850 | 849 | ||
851 | if (!info->attrs[NL80211_ATTR_KEY_CIPHER]) | 850 | if (!info->attrs[NL80211_ATTR_KEY_CIPHER]) |
852 | return -EINVAL; | 851 | return -EINVAL; |
853 | 852 | ||
854 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { | 853 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { |
855 | params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); | 854 | params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); |
856 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | 855 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); |
857 | } | 856 | } |
858 | 857 | ||
859 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 858 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
860 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 859 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
861 | 860 | ||
862 | params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); | 861 | params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); |
863 | 862 | ||
864 | if (info->attrs[NL80211_ATTR_MAC]) | 863 | if (info->attrs[NL80211_ATTR_MAC]) |
865 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 864 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
866 | 865 | ||
867 | if (key_idx > 3) | 866 | if (key_idx > 3) |
868 | return -EINVAL; | 867 | return -EINVAL; |
869 | 868 | ||
870 | /* | 869 | /* |
871 | * Disallow pairwise keys with non-zero index unless it's WEP | 870 | * Disallow pairwise keys with non-zero index unless it's WEP |
872 | * (because current deployments use pairwise WEP keys with | 871 | * (because current deployments use pairwise WEP keys with |
873 | * non-zero indizes but 802.11i clearly specifies to use zero) | 872 | * non-zero indizes but 802.11i clearly specifies to use zero) |
874 | */ | 873 | */ |
875 | if (mac_addr && key_idx && | 874 | if (mac_addr && key_idx && |
876 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && | 875 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && |
877 | params.cipher != WLAN_CIPHER_SUITE_WEP104) | 876 | params.cipher != WLAN_CIPHER_SUITE_WEP104) |
878 | return -EINVAL; | 877 | return -EINVAL; |
879 | 878 | ||
880 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | 879 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ |
881 | switch (params.cipher) { | 880 | switch (params.cipher) { |
882 | case WLAN_CIPHER_SUITE_WEP40: | 881 | case WLAN_CIPHER_SUITE_WEP40: |
883 | if (params.key_len != 5) | 882 | if (params.key_len != 5) |
884 | return -EINVAL; | 883 | return -EINVAL; |
885 | break; | 884 | break; |
886 | case WLAN_CIPHER_SUITE_TKIP: | 885 | case WLAN_CIPHER_SUITE_TKIP: |
887 | if (params.key_len != 32) | 886 | if (params.key_len != 32) |
888 | return -EINVAL; | 887 | return -EINVAL; |
889 | break; | 888 | break; |
890 | case WLAN_CIPHER_SUITE_CCMP: | 889 | case WLAN_CIPHER_SUITE_CCMP: |
891 | if (params.key_len != 16) | 890 | if (params.key_len != 16) |
892 | return -EINVAL; | 891 | return -EINVAL; |
893 | break; | 892 | break; |
894 | case WLAN_CIPHER_SUITE_WEP104: | 893 | case WLAN_CIPHER_SUITE_WEP104: |
895 | if (params.key_len != 13) | 894 | if (params.key_len != 13) |
896 | return -EINVAL; | 895 | return -EINVAL; |
897 | break; | 896 | break; |
898 | default: | 897 | default: |
899 | return -EINVAL; | 898 | return -EINVAL; |
900 | } | 899 | } |
901 | 900 | ||
902 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 901 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
903 | if (err) | 902 | if (err) |
904 | return err; | 903 | return err; |
905 | 904 | ||
906 | if (!drv->ops->add_key) { | 905 | if (!drv->ops->add_key) { |
907 | err = -EOPNOTSUPP; | 906 | err = -EOPNOTSUPP; |
908 | goto out; | 907 | goto out; |
909 | } | 908 | } |
910 | 909 | ||
911 | rtnl_lock(); | 910 | rtnl_lock(); |
912 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); | 911 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); |
913 | rtnl_unlock(); | 912 | rtnl_unlock(); |
914 | 913 | ||
915 | out: | 914 | out: |
916 | cfg80211_put_dev(drv); | 915 | cfg80211_put_dev(drv); |
917 | dev_put(dev); | 916 | dev_put(dev); |
918 | return err; | 917 | return err; |
919 | } | 918 | } |
920 | 919 | ||
921 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 920 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
922 | { | 921 | { |
923 | struct cfg80211_registered_device *drv; | 922 | struct cfg80211_registered_device *drv; |
924 | int err; | 923 | int err; |
925 | struct net_device *dev; | 924 | struct net_device *dev; |
926 | u8 key_idx = 0; | 925 | u8 key_idx = 0; |
927 | u8 *mac_addr = NULL; | 926 | u8 *mac_addr = NULL; |
928 | 927 | ||
929 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 928 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
930 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 929 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
931 | 930 | ||
932 | if (key_idx > 3) | 931 | if (key_idx > 3) |
933 | return -EINVAL; | 932 | return -EINVAL; |
934 | 933 | ||
935 | if (info->attrs[NL80211_ATTR_MAC]) | 934 | if (info->attrs[NL80211_ATTR_MAC]) |
936 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 935 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
937 | 936 | ||
938 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 937 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
939 | if (err) | 938 | if (err) |
940 | return err; | 939 | return err; |
941 | 940 | ||
942 | if (!drv->ops->del_key) { | 941 | if (!drv->ops->del_key) { |
943 | err = -EOPNOTSUPP; | 942 | err = -EOPNOTSUPP; |
944 | goto out; | 943 | goto out; |
945 | } | 944 | } |
946 | 945 | ||
947 | rtnl_lock(); | 946 | rtnl_lock(); |
948 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 947 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
949 | rtnl_unlock(); | 948 | rtnl_unlock(); |
950 | 949 | ||
951 | out: | 950 | out: |
952 | cfg80211_put_dev(drv); | 951 | cfg80211_put_dev(drv); |
953 | dev_put(dev); | 952 | dev_put(dev); |
954 | return err; | 953 | return err; |
955 | } | 954 | } |
956 | 955 | ||
957 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | 956 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) |
958 | { | 957 | { |
959 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 958 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
960 | struct beacon_parameters *info); | 959 | struct beacon_parameters *info); |
961 | struct cfg80211_registered_device *drv; | 960 | struct cfg80211_registered_device *drv; |
962 | int err; | 961 | int err; |
963 | struct net_device *dev; | 962 | struct net_device *dev; |
964 | struct beacon_parameters params; | 963 | struct beacon_parameters params; |
965 | int haveinfo = 0; | 964 | int haveinfo = 0; |
966 | 965 | ||
967 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 966 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
968 | if (err) | 967 | if (err) |
969 | return err; | 968 | return err; |
970 | 969 | ||
971 | switch (info->genlhdr->cmd) { | 970 | switch (info->genlhdr->cmd) { |
972 | case NL80211_CMD_NEW_BEACON: | 971 | case NL80211_CMD_NEW_BEACON: |
973 | /* these are required for NEW_BEACON */ | 972 | /* these are required for NEW_BEACON */ |
974 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 973 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
975 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 974 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
976 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 975 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
977 | err = -EINVAL; | 976 | err = -EINVAL; |
978 | goto out; | 977 | goto out; |
979 | } | 978 | } |
980 | 979 | ||
981 | call = drv->ops->add_beacon; | 980 | call = drv->ops->add_beacon; |
982 | break; | 981 | break; |
983 | case NL80211_CMD_SET_BEACON: | 982 | case NL80211_CMD_SET_BEACON: |
984 | call = drv->ops->set_beacon; | 983 | call = drv->ops->set_beacon; |
985 | break; | 984 | break; |
986 | default: | 985 | default: |
987 | WARN_ON(1); | 986 | WARN_ON(1); |
988 | err = -EOPNOTSUPP; | 987 | err = -EOPNOTSUPP; |
989 | goto out; | 988 | goto out; |
990 | } | 989 | } |
991 | 990 | ||
992 | if (!call) { | 991 | if (!call) { |
993 | err = -EOPNOTSUPP; | 992 | err = -EOPNOTSUPP; |
994 | goto out; | 993 | goto out; |
995 | } | 994 | } |
996 | 995 | ||
997 | memset(¶ms, 0, sizeof(params)); | 996 | memset(¶ms, 0, sizeof(params)); |
998 | 997 | ||
999 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | 998 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { |
1000 | params.interval = | 999 | params.interval = |
1001 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | 1000 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); |
1002 | haveinfo = 1; | 1001 | haveinfo = 1; |
1003 | } | 1002 | } |
1004 | 1003 | ||
1005 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | 1004 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { |
1006 | params.dtim_period = | 1005 | params.dtim_period = |
1007 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | 1006 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); |
1008 | haveinfo = 1; | 1007 | haveinfo = 1; |
1009 | } | 1008 | } |
1010 | 1009 | ||
1011 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1010 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
1012 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 1011 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1013 | params.head_len = | 1012 | params.head_len = |
1014 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 1013 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1015 | haveinfo = 1; | 1014 | haveinfo = 1; |
1016 | } | 1015 | } |
1017 | 1016 | ||
1018 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | 1017 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { |
1019 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 1018 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); |
1020 | params.tail_len = | 1019 | params.tail_len = |
1021 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 1020 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); |
1022 | haveinfo = 1; | 1021 | haveinfo = 1; |
1023 | } | 1022 | } |
1024 | 1023 | ||
1025 | if (!haveinfo) { | 1024 | if (!haveinfo) { |
1026 | err = -EINVAL; | 1025 | err = -EINVAL; |
1027 | goto out; | 1026 | goto out; |
1028 | } | 1027 | } |
1029 | 1028 | ||
1030 | rtnl_lock(); | 1029 | rtnl_lock(); |
1031 | err = call(&drv->wiphy, dev, ¶ms); | 1030 | err = call(&drv->wiphy, dev, ¶ms); |
1032 | rtnl_unlock(); | 1031 | rtnl_unlock(); |
1033 | 1032 | ||
1034 | out: | 1033 | out: |
1035 | cfg80211_put_dev(drv); | 1034 | cfg80211_put_dev(drv); |
1036 | dev_put(dev); | 1035 | dev_put(dev); |
1037 | return err; | 1036 | return err; |
1038 | } | 1037 | } |
1039 | 1038 | ||
1040 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1039 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1041 | { | 1040 | { |
1042 | struct cfg80211_registered_device *drv; | 1041 | struct cfg80211_registered_device *drv; |
1043 | int err; | 1042 | int err; |
1044 | struct net_device *dev; | 1043 | struct net_device *dev; |
1045 | 1044 | ||
1046 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1045 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1047 | if (err) | 1046 | if (err) |
1048 | return err; | 1047 | return err; |
1049 | 1048 | ||
1050 | if (!drv->ops->del_beacon) { | 1049 | if (!drv->ops->del_beacon) { |
1051 | err = -EOPNOTSUPP; | 1050 | err = -EOPNOTSUPP; |
1052 | goto out; | 1051 | goto out; |
1053 | } | 1052 | } |
1054 | 1053 | ||
1055 | rtnl_lock(); | 1054 | rtnl_lock(); |
1056 | err = drv->ops->del_beacon(&drv->wiphy, dev); | 1055 | err = drv->ops->del_beacon(&drv->wiphy, dev); |
1057 | rtnl_unlock(); | 1056 | rtnl_unlock(); |
1058 | 1057 | ||
1059 | out: | 1058 | out: |
1060 | cfg80211_put_dev(drv); | 1059 | cfg80211_put_dev(drv); |
1061 | dev_put(dev); | 1060 | dev_put(dev); |
1062 | return err; | 1061 | return err; |
1063 | } | 1062 | } |
1064 | 1063 | ||
1065 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1064 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
1066 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, | 1065 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, |
1067 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, | 1066 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, |
1068 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, | 1067 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, |
1069 | }; | 1068 | }; |
1070 | 1069 | ||
1071 | static int parse_station_flags(struct nlattr *nla, u32 *staflags) | 1070 | static int parse_station_flags(struct nlattr *nla, u32 *staflags) |
1072 | { | 1071 | { |
1073 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; | 1072 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; |
1074 | int flag; | 1073 | int flag; |
1075 | 1074 | ||
1076 | *staflags = 0; | 1075 | *staflags = 0; |
1077 | 1076 | ||
1078 | if (!nla) | 1077 | if (!nla) |
1079 | return 0; | 1078 | return 0; |
1080 | 1079 | ||
1081 | if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, | 1080 | if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, |
1082 | nla, sta_flags_policy)) | 1081 | nla, sta_flags_policy)) |
1083 | return -EINVAL; | 1082 | return -EINVAL; |
1084 | 1083 | ||
1085 | *staflags = STATION_FLAG_CHANGED; | 1084 | *staflags = STATION_FLAG_CHANGED; |
1086 | 1085 | ||
1087 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) | 1086 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) |
1088 | if (flags[flag]) | 1087 | if (flags[flag]) |
1089 | *staflags |= (1<<flag); | 1088 | *staflags |= (1<<flag); |
1090 | 1089 | ||
1091 | return 0; | 1090 | return 0; |
1092 | } | 1091 | } |
1093 | 1092 | ||
1094 | static u16 nl80211_calculate_bitrate(struct rate_info *rate) | 1093 | static u16 nl80211_calculate_bitrate(struct rate_info *rate) |
1095 | { | 1094 | { |
1096 | int modulation, streams, bitrate; | 1095 | int modulation, streams, bitrate; |
1097 | 1096 | ||
1098 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 1097 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
1099 | return rate->legacy; | 1098 | return rate->legacy; |
1100 | 1099 | ||
1101 | /* the formula below does only work for MCS values smaller than 32 */ | 1100 | /* the formula below does only work for MCS values smaller than 32 */ |
1102 | if (rate->mcs >= 32) | 1101 | if (rate->mcs >= 32) |
1103 | return 0; | 1102 | return 0; |
1104 | 1103 | ||
1105 | modulation = rate->mcs & 7; | 1104 | modulation = rate->mcs & 7; |
1106 | streams = (rate->mcs >> 3) + 1; | 1105 | streams = (rate->mcs >> 3) + 1; |
1107 | 1106 | ||
1108 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? | 1107 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? |
1109 | 13500000 : 6500000; | 1108 | 13500000 : 6500000; |
1110 | 1109 | ||
1111 | if (modulation < 4) | 1110 | if (modulation < 4) |
1112 | bitrate *= (modulation + 1); | 1111 | bitrate *= (modulation + 1); |
1113 | else if (modulation == 4) | 1112 | else if (modulation == 4) |
1114 | bitrate *= (modulation + 2); | 1113 | bitrate *= (modulation + 2); |
1115 | else | 1114 | else |
1116 | bitrate *= (modulation + 3); | 1115 | bitrate *= (modulation + 3); |
1117 | 1116 | ||
1118 | bitrate *= streams; | 1117 | bitrate *= streams; |
1119 | 1118 | ||
1120 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | 1119 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) |
1121 | bitrate = (bitrate / 9) * 10; | 1120 | bitrate = (bitrate / 9) * 10; |
1122 | 1121 | ||
1123 | /* do NOT round down here */ | 1122 | /* do NOT round down here */ |
1124 | return (bitrate + 50000) / 100000; | 1123 | return (bitrate + 50000) / 100000; |
1125 | } | 1124 | } |
1126 | 1125 | ||
1127 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 1126 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
1128 | int flags, struct net_device *dev, | 1127 | int flags, struct net_device *dev, |
1129 | u8 *mac_addr, struct station_info *sinfo) | 1128 | u8 *mac_addr, struct station_info *sinfo) |
1130 | { | 1129 | { |
1131 | void *hdr; | 1130 | void *hdr; |
1132 | struct nlattr *sinfoattr, *txrate; | 1131 | struct nlattr *sinfoattr, *txrate; |
1133 | u16 bitrate; | 1132 | u16 bitrate; |
1134 | 1133 | ||
1135 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 1134 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
1136 | if (!hdr) | 1135 | if (!hdr) |
1137 | return -1; | 1136 | return -1; |
1138 | 1137 | ||
1139 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1138 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1140 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1139 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1141 | 1140 | ||
1142 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1141 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1143 | if (!sinfoattr) | 1142 | if (!sinfoattr) |
1144 | goto nla_put_failure; | 1143 | goto nla_put_failure; |
1145 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) | 1144 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) |
1146 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 1145 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
1147 | sinfo->inactive_time); | 1146 | sinfo->inactive_time); |
1148 | if (sinfo->filled & STATION_INFO_RX_BYTES) | 1147 | if (sinfo->filled & STATION_INFO_RX_BYTES) |
1149 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, | 1148 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, |
1150 | sinfo->rx_bytes); | 1149 | sinfo->rx_bytes); |
1151 | if (sinfo->filled & STATION_INFO_TX_BYTES) | 1150 | if (sinfo->filled & STATION_INFO_TX_BYTES) |
1152 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, | 1151 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, |
1153 | sinfo->tx_bytes); | 1152 | sinfo->tx_bytes); |
1154 | if (sinfo->filled & STATION_INFO_LLID) | 1153 | if (sinfo->filled & STATION_INFO_LLID) |
1155 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, | 1154 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, |
1156 | sinfo->llid); | 1155 | sinfo->llid); |
1157 | if (sinfo->filled & STATION_INFO_PLID) | 1156 | if (sinfo->filled & STATION_INFO_PLID) |
1158 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, | 1157 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, |
1159 | sinfo->plid); | 1158 | sinfo->plid); |
1160 | if (sinfo->filled & STATION_INFO_PLINK_STATE) | 1159 | if (sinfo->filled & STATION_INFO_PLINK_STATE) |
1161 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, | 1160 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, |
1162 | sinfo->plink_state); | 1161 | sinfo->plink_state); |
1163 | if (sinfo->filled & STATION_INFO_SIGNAL) | 1162 | if (sinfo->filled & STATION_INFO_SIGNAL) |
1164 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, | 1163 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, |
1165 | sinfo->signal); | 1164 | sinfo->signal); |
1166 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 1165 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
1167 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); | 1166 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); |
1168 | if (!txrate) | 1167 | if (!txrate) |
1169 | goto nla_put_failure; | 1168 | goto nla_put_failure; |
1170 | 1169 | ||
1171 | /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ | 1170 | /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ |
1172 | bitrate = nl80211_calculate_bitrate(&sinfo->txrate); | 1171 | bitrate = nl80211_calculate_bitrate(&sinfo->txrate); |
1173 | if (bitrate > 0) | 1172 | if (bitrate > 0) |
1174 | NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); | 1173 | NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); |
1175 | 1174 | ||
1176 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) | 1175 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) |
1177 | NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, | 1176 | NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, |
1178 | sinfo->txrate.mcs); | 1177 | sinfo->txrate.mcs); |
1179 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) | 1178 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) |
1180 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); | 1179 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); |
1181 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) | 1180 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) |
1182 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); | 1181 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); |
1183 | 1182 | ||
1184 | nla_nest_end(msg, txrate); | 1183 | nla_nest_end(msg, txrate); |
1185 | } | 1184 | } |
1186 | nla_nest_end(msg, sinfoattr); | 1185 | nla_nest_end(msg, sinfoattr); |
1187 | 1186 | ||
1188 | return genlmsg_end(msg, hdr); | 1187 | return genlmsg_end(msg, hdr); |
1189 | 1188 | ||
1190 | nla_put_failure: | 1189 | nla_put_failure: |
1191 | genlmsg_cancel(msg, hdr); | 1190 | genlmsg_cancel(msg, hdr); |
1192 | return -EMSGSIZE; | 1191 | return -EMSGSIZE; |
1193 | } | 1192 | } |
1194 | 1193 | ||
1195 | static int nl80211_dump_station(struct sk_buff *skb, | 1194 | static int nl80211_dump_station(struct sk_buff *skb, |
1196 | struct netlink_callback *cb) | 1195 | struct netlink_callback *cb) |
1197 | { | 1196 | { |
1198 | struct station_info sinfo; | 1197 | struct station_info sinfo; |
1199 | struct cfg80211_registered_device *dev; | 1198 | struct cfg80211_registered_device *dev; |
1200 | struct net_device *netdev; | 1199 | struct net_device *netdev; |
1201 | u8 mac_addr[ETH_ALEN]; | 1200 | u8 mac_addr[ETH_ALEN]; |
1202 | int ifidx = cb->args[0]; | 1201 | int ifidx = cb->args[0]; |
1203 | int sta_idx = cb->args[1]; | 1202 | int sta_idx = cb->args[1]; |
1204 | int err; | 1203 | int err; |
1205 | 1204 | ||
1206 | if (!ifidx) { | 1205 | if (!ifidx) { |
1207 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1206 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
1208 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 1207 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
1209 | nl80211_policy); | 1208 | nl80211_policy); |
1210 | if (err) | 1209 | if (err) |
1211 | return err; | 1210 | return err; |
1212 | 1211 | ||
1213 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | 1212 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) |
1214 | return -EINVAL; | 1213 | return -EINVAL; |
1215 | 1214 | ||
1216 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | 1215 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); |
1217 | if (!ifidx) | 1216 | if (!ifidx) |
1218 | return -EINVAL; | 1217 | return -EINVAL; |
1219 | } | 1218 | } |
1220 | 1219 | ||
1221 | netdev = dev_get_by_index(&init_net, ifidx); | 1220 | netdev = dev_get_by_index(&init_net, ifidx); |
1222 | if (!netdev) | 1221 | if (!netdev) |
1223 | return -ENODEV; | 1222 | return -ENODEV; |
1224 | 1223 | ||
1225 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1224 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1226 | if (IS_ERR(dev)) { | 1225 | if (IS_ERR(dev)) { |
1227 | err = PTR_ERR(dev); | 1226 | err = PTR_ERR(dev); |
1228 | goto out_put_netdev; | 1227 | goto out_put_netdev; |
1229 | } | 1228 | } |
1230 | 1229 | ||
1231 | if (!dev->ops->dump_station) { | 1230 | if (!dev->ops->dump_station) { |
1232 | err = -ENOSYS; | 1231 | err = -ENOSYS; |
1233 | goto out_err; | 1232 | goto out_err; |
1234 | } | 1233 | } |
1235 | 1234 | ||
1236 | rtnl_lock(); | 1235 | rtnl_lock(); |
1237 | 1236 | ||
1238 | while (1) { | 1237 | while (1) { |
1239 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | 1238 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, |
1240 | mac_addr, &sinfo); | 1239 | mac_addr, &sinfo); |
1241 | if (err == -ENOENT) | 1240 | if (err == -ENOENT) |
1242 | break; | 1241 | break; |
1243 | if (err) | 1242 | if (err) |
1244 | goto out_err_rtnl; | 1243 | goto out_err_rtnl; |
1245 | 1244 | ||
1246 | if (nl80211_send_station(skb, | 1245 | if (nl80211_send_station(skb, |
1247 | NETLINK_CB(cb->skb).pid, | 1246 | NETLINK_CB(cb->skb).pid, |
1248 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1247 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1249 | netdev, mac_addr, | 1248 | netdev, mac_addr, |
1250 | &sinfo) < 0) | 1249 | &sinfo) < 0) |
1251 | goto out; | 1250 | goto out; |
1252 | 1251 | ||
1253 | sta_idx++; | 1252 | sta_idx++; |
1254 | } | 1253 | } |
1255 | 1254 | ||
1256 | 1255 | ||
1257 | out: | 1256 | out: |
1258 | cb->args[1] = sta_idx; | 1257 | cb->args[1] = sta_idx; |
1259 | err = skb->len; | 1258 | err = skb->len; |
1260 | out_err_rtnl: | 1259 | out_err_rtnl: |
1261 | rtnl_unlock(); | 1260 | rtnl_unlock(); |
1262 | out_err: | 1261 | out_err: |
1263 | cfg80211_put_dev(dev); | 1262 | cfg80211_put_dev(dev); |
1264 | out_put_netdev: | 1263 | out_put_netdev: |
1265 | dev_put(netdev); | 1264 | dev_put(netdev); |
1266 | 1265 | ||
1267 | return err; | 1266 | return err; |
1268 | } | 1267 | } |
1269 | 1268 | ||
1270 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1269 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
1271 | { | 1270 | { |
1272 | struct cfg80211_registered_device *drv; | 1271 | struct cfg80211_registered_device *drv; |
1273 | int err; | 1272 | int err; |
1274 | struct net_device *dev; | 1273 | struct net_device *dev; |
1275 | struct station_info sinfo; | 1274 | struct station_info sinfo; |
1276 | struct sk_buff *msg; | 1275 | struct sk_buff *msg; |
1277 | u8 *mac_addr = NULL; | 1276 | u8 *mac_addr = NULL; |
1278 | 1277 | ||
1279 | memset(&sinfo, 0, sizeof(sinfo)); | 1278 | memset(&sinfo, 0, sizeof(sinfo)); |
1280 | 1279 | ||
1281 | if (!info->attrs[NL80211_ATTR_MAC]) | 1280 | if (!info->attrs[NL80211_ATTR_MAC]) |
1282 | return -EINVAL; | 1281 | return -EINVAL; |
1283 | 1282 | ||
1284 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1283 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1285 | 1284 | ||
1286 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1285 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1287 | if (err) | 1286 | if (err) |
1288 | return err; | 1287 | return err; |
1289 | 1288 | ||
1290 | if (!drv->ops->get_station) { | 1289 | if (!drv->ops->get_station) { |
1291 | err = -EOPNOTSUPP; | 1290 | err = -EOPNOTSUPP; |
1292 | goto out; | 1291 | goto out; |
1293 | } | 1292 | } |
1294 | 1293 | ||
1295 | rtnl_lock(); | 1294 | rtnl_lock(); |
1296 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); | 1295 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); |
1297 | rtnl_unlock(); | 1296 | rtnl_unlock(); |
1298 | 1297 | ||
1299 | if (err) | 1298 | if (err) |
1300 | goto out; | 1299 | goto out; |
1301 | 1300 | ||
1302 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1301 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
1303 | if (!msg) | 1302 | if (!msg) |
1304 | goto out; | 1303 | goto out; |
1305 | 1304 | ||
1306 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1305 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
1307 | dev, mac_addr, &sinfo) < 0) | 1306 | dev, mac_addr, &sinfo) < 0) |
1308 | goto out_free; | 1307 | goto out_free; |
1309 | 1308 | ||
1310 | err = genlmsg_unicast(msg, info->snd_pid); | 1309 | err = genlmsg_unicast(msg, info->snd_pid); |
1311 | goto out; | 1310 | goto out; |
1312 | 1311 | ||
1313 | out_free: | 1312 | out_free: |
1314 | nlmsg_free(msg); | 1313 | nlmsg_free(msg); |
1315 | 1314 | ||
1316 | out: | 1315 | out: |
1317 | cfg80211_put_dev(drv); | 1316 | cfg80211_put_dev(drv); |
1318 | dev_put(dev); | 1317 | dev_put(dev); |
1319 | return err; | 1318 | return err; |
1320 | } | 1319 | } |
1321 | 1320 | ||
1322 | /* | 1321 | /* |
1323 | * Get vlan interface making sure it is on the right wiphy. | 1322 | * Get vlan interface making sure it is on the right wiphy. |
1324 | */ | 1323 | */ |
1325 | static int get_vlan(struct nlattr *vlanattr, | 1324 | static int get_vlan(struct nlattr *vlanattr, |
1326 | struct cfg80211_registered_device *rdev, | 1325 | struct cfg80211_registered_device *rdev, |
1327 | struct net_device **vlan) | 1326 | struct net_device **vlan) |
1328 | { | 1327 | { |
1329 | *vlan = NULL; | 1328 | *vlan = NULL; |
1330 | 1329 | ||
1331 | if (vlanattr) { | 1330 | if (vlanattr) { |
1332 | *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); | 1331 | *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); |
1333 | if (!*vlan) | 1332 | if (!*vlan) |
1334 | return -ENODEV; | 1333 | return -ENODEV; |
1335 | if (!(*vlan)->ieee80211_ptr) | 1334 | if (!(*vlan)->ieee80211_ptr) |
1336 | return -EINVAL; | 1335 | return -EINVAL; |
1337 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 1336 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) |
1338 | return -EINVAL; | 1337 | return -EINVAL; |
1339 | } | 1338 | } |
1340 | return 0; | 1339 | return 0; |
1341 | } | 1340 | } |
1342 | 1341 | ||
1343 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1342 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
1344 | { | 1343 | { |
1345 | struct cfg80211_registered_device *drv; | 1344 | struct cfg80211_registered_device *drv; |
1346 | int err; | 1345 | int err; |
1347 | struct net_device *dev; | 1346 | struct net_device *dev; |
1348 | struct station_parameters params; | 1347 | struct station_parameters params; |
1349 | u8 *mac_addr = NULL; | 1348 | u8 *mac_addr = NULL; |
1350 | 1349 | ||
1351 | memset(¶ms, 0, sizeof(params)); | 1350 | memset(¶ms, 0, sizeof(params)); |
1352 | 1351 | ||
1353 | params.listen_interval = -1; | 1352 | params.listen_interval = -1; |
1354 | 1353 | ||
1355 | if (info->attrs[NL80211_ATTR_STA_AID]) | 1354 | if (info->attrs[NL80211_ATTR_STA_AID]) |
1356 | return -EINVAL; | 1355 | return -EINVAL; |
1357 | 1356 | ||
1358 | if (!info->attrs[NL80211_ATTR_MAC]) | 1357 | if (!info->attrs[NL80211_ATTR_MAC]) |
1359 | return -EINVAL; | 1358 | return -EINVAL; |
1360 | 1359 | ||
1361 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1360 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1362 | 1361 | ||
1363 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { | 1362 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { |
1364 | params.supported_rates = | 1363 | params.supported_rates = |
1365 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1364 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1366 | params.supported_rates_len = | 1365 | params.supported_rates_len = |
1367 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1366 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1368 | } | 1367 | } |
1369 | 1368 | ||
1370 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1369 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
1371 | params.listen_interval = | 1370 | params.listen_interval = |
1372 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1371 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1373 | 1372 | ||
1374 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1373 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1375 | params.ht_capa = | 1374 | params.ht_capa = |
1376 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1375 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1377 | 1376 | ||
1378 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | 1377 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], |
1379 | ¶ms.station_flags)) | 1378 | ¶ms.station_flags)) |
1380 | return -EINVAL; | 1379 | return -EINVAL; |
1381 | 1380 | ||
1382 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 1381 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) |
1383 | params.plink_action = | 1382 | params.plink_action = |
1384 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1383 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
1385 | 1384 | ||
1386 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1385 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1387 | if (err) | 1386 | if (err) |
1388 | return err; | 1387 | return err; |
1389 | 1388 | ||
1390 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1389 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1391 | if (err) | 1390 | if (err) |
1392 | goto out; | 1391 | goto out; |
1393 | 1392 | ||
1394 | if (!drv->ops->change_station) { | 1393 | if (!drv->ops->change_station) { |
1395 | err = -EOPNOTSUPP; | 1394 | err = -EOPNOTSUPP; |
1396 | goto out; | 1395 | goto out; |
1397 | } | 1396 | } |
1398 | 1397 | ||
1399 | rtnl_lock(); | 1398 | rtnl_lock(); |
1400 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1399 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1401 | rtnl_unlock(); | 1400 | rtnl_unlock(); |
1402 | 1401 | ||
1403 | out: | 1402 | out: |
1404 | if (params.vlan) | 1403 | if (params.vlan) |
1405 | dev_put(params.vlan); | 1404 | dev_put(params.vlan); |
1406 | cfg80211_put_dev(drv); | 1405 | cfg80211_put_dev(drv); |
1407 | dev_put(dev); | 1406 | dev_put(dev); |
1408 | return err; | 1407 | return err; |
1409 | } | 1408 | } |
1410 | 1409 | ||
1411 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 1410 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
1412 | { | 1411 | { |
1413 | struct cfg80211_registered_device *drv; | 1412 | struct cfg80211_registered_device *drv; |
1414 | int err; | 1413 | int err; |
1415 | struct net_device *dev; | 1414 | struct net_device *dev; |
1416 | struct station_parameters params; | 1415 | struct station_parameters params; |
1417 | u8 *mac_addr = NULL; | 1416 | u8 *mac_addr = NULL; |
1418 | 1417 | ||
1419 | memset(¶ms, 0, sizeof(params)); | 1418 | memset(¶ms, 0, sizeof(params)); |
1420 | 1419 | ||
1421 | if (!info->attrs[NL80211_ATTR_MAC]) | 1420 | if (!info->attrs[NL80211_ATTR_MAC]) |
1422 | return -EINVAL; | 1421 | return -EINVAL; |
1423 | 1422 | ||
1424 | if (!info->attrs[NL80211_ATTR_STA_AID]) | 1423 | if (!info->attrs[NL80211_ATTR_STA_AID]) |
1425 | return -EINVAL; | 1424 | return -EINVAL; |
1426 | 1425 | ||
1427 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1426 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
1428 | return -EINVAL; | 1427 | return -EINVAL; |
1429 | 1428 | ||
1430 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | 1429 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) |
1431 | return -EINVAL; | 1430 | return -EINVAL; |
1432 | 1431 | ||
1433 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1432 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1434 | params.supported_rates = | 1433 | params.supported_rates = |
1435 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1434 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1436 | params.supported_rates_len = | 1435 | params.supported_rates_len = |
1437 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1436 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1438 | params.listen_interval = | 1437 | params.listen_interval = |
1439 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1438 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1440 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 1439 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
1441 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1440 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1442 | params.ht_capa = | 1441 | params.ht_capa = |
1443 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1442 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1444 | 1443 | ||
1445 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | 1444 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], |
1446 | ¶ms.station_flags)) | 1445 | ¶ms.station_flags)) |
1447 | return -EINVAL; | 1446 | return -EINVAL; |
1448 | 1447 | ||
1449 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1448 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1450 | if (err) | 1449 | if (err) |
1451 | return err; | 1450 | return err; |
1452 | 1451 | ||
1453 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1452 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1454 | if (err) | 1453 | if (err) |
1455 | goto out; | 1454 | goto out; |
1456 | 1455 | ||
1457 | if (!drv->ops->add_station) { | 1456 | if (!drv->ops->add_station) { |
1458 | err = -EOPNOTSUPP; | 1457 | err = -EOPNOTSUPP; |
1459 | goto out; | 1458 | goto out; |
1460 | } | 1459 | } |
1461 | 1460 | ||
1462 | rtnl_lock(); | 1461 | rtnl_lock(); |
1463 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1462 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1464 | rtnl_unlock(); | 1463 | rtnl_unlock(); |
1465 | 1464 | ||
1466 | out: | 1465 | out: |
1467 | if (params.vlan) | 1466 | if (params.vlan) |
1468 | dev_put(params.vlan); | 1467 | dev_put(params.vlan); |
1469 | cfg80211_put_dev(drv); | 1468 | cfg80211_put_dev(drv); |
1470 | dev_put(dev); | 1469 | dev_put(dev); |
1471 | return err; | 1470 | return err; |
1472 | } | 1471 | } |
1473 | 1472 | ||
1474 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 1473 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
1475 | { | 1474 | { |
1476 | struct cfg80211_registered_device *drv; | 1475 | struct cfg80211_registered_device *drv; |
1477 | int err; | 1476 | int err; |
1478 | struct net_device *dev; | 1477 | struct net_device *dev; |
1479 | u8 *mac_addr = NULL; | 1478 | u8 *mac_addr = NULL; |
1480 | 1479 | ||
1481 | if (info->attrs[NL80211_ATTR_MAC]) | 1480 | if (info->attrs[NL80211_ATTR_MAC]) |
1482 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1481 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1483 | 1482 | ||
1484 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1483 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1485 | if (err) | 1484 | if (err) |
1486 | return err; | 1485 | return err; |
1487 | 1486 | ||
1488 | if (!drv->ops->del_station) { | 1487 | if (!drv->ops->del_station) { |
1489 | err = -EOPNOTSUPP; | 1488 | err = -EOPNOTSUPP; |
1490 | goto out; | 1489 | goto out; |
1491 | } | 1490 | } |
1492 | 1491 | ||
1493 | rtnl_lock(); | 1492 | rtnl_lock(); |
1494 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); | 1493 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); |
1495 | rtnl_unlock(); | 1494 | rtnl_unlock(); |
1496 | 1495 | ||
1497 | out: | 1496 | out: |
1498 | cfg80211_put_dev(drv); | 1497 | cfg80211_put_dev(drv); |
1499 | dev_put(dev); | 1498 | dev_put(dev); |
1500 | return err; | 1499 | return err; |
1501 | } | 1500 | } |
1502 | 1501 | ||
1503 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 1502 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
1504 | int flags, struct net_device *dev, | 1503 | int flags, struct net_device *dev, |
1505 | u8 *dst, u8 *next_hop, | 1504 | u8 *dst, u8 *next_hop, |
1506 | struct mpath_info *pinfo) | 1505 | struct mpath_info *pinfo) |
1507 | { | 1506 | { |
1508 | void *hdr; | 1507 | void *hdr; |
1509 | struct nlattr *pinfoattr; | 1508 | struct nlattr *pinfoattr; |
1510 | 1509 | ||
1511 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 1510 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
1512 | if (!hdr) | 1511 | if (!hdr) |
1513 | return -1; | 1512 | return -1; |
1514 | 1513 | ||
1515 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1514 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1516 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 1515 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
1517 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 1516 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
1518 | 1517 | ||
1519 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 1518 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
1520 | if (!pinfoattr) | 1519 | if (!pinfoattr) |
1521 | goto nla_put_failure; | 1520 | goto nla_put_failure; |
1522 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | 1521 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) |
1523 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | 1522 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, |
1524 | pinfo->frame_qlen); | 1523 | pinfo->frame_qlen); |
1525 | if (pinfo->filled & MPATH_INFO_DSN) | 1524 | if (pinfo->filled & MPATH_INFO_DSN) |
1526 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, | 1525 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, |
1527 | pinfo->dsn); | 1526 | pinfo->dsn); |
1528 | if (pinfo->filled & MPATH_INFO_METRIC) | 1527 | if (pinfo->filled & MPATH_INFO_METRIC) |
1529 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | 1528 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, |
1530 | pinfo->metric); | 1529 | pinfo->metric); |
1531 | if (pinfo->filled & MPATH_INFO_EXPTIME) | 1530 | if (pinfo->filled & MPATH_INFO_EXPTIME) |
1532 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, | 1531 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, |
1533 | pinfo->exptime); | 1532 | pinfo->exptime); |
1534 | if (pinfo->filled & MPATH_INFO_FLAGS) | 1533 | if (pinfo->filled & MPATH_INFO_FLAGS) |
1535 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, | 1534 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, |
1536 | pinfo->flags); | 1535 | pinfo->flags); |
1537 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) | 1536 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) |
1538 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | 1537 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, |
1539 | pinfo->discovery_timeout); | 1538 | pinfo->discovery_timeout); |
1540 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) | 1539 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) |
1541 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, | 1540 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, |
1542 | pinfo->discovery_retries); | 1541 | pinfo->discovery_retries); |
1543 | 1542 | ||
1544 | nla_nest_end(msg, pinfoattr); | 1543 | nla_nest_end(msg, pinfoattr); |
1545 | 1544 | ||
1546 | return genlmsg_end(msg, hdr); | 1545 | return genlmsg_end(msg, hdr); |
1547 | 1546 | ||
1548 | nla_put_failure: | 1547 | nla_put_failure: |
1549 | genlmsg_cancel(msg, hdr); | 1548 | genlmsg_cancel(msg, hdr); |
1550 | return -EMSGSIZE; | 1549 | return -EMSGSIZE; |
1551 | } | 1550 | } |
1552 | 1551 | ||
1553 | static int nl80211_dump_mpath(struct sk_buff *skb, | 1552 | static int nl80211_dump_mpath(struct sk_buff *skb, |
1554 | struct netlink_callback *cb) | 1553 | struct netlink_callback *cb) |
1555 | { | 1554 | { |
1556 | struct mpath_info pinfo; | 1555 | struct mpath_info pinfo; |
1557 | struct cfg80211_registered_device *dev; | 1556 | struct cfg80211_registered_device *dev; |
1558 | struct net_device *netdev; | 1557 | struct net_device *netdev; |
1559 | u8 dst[ETH_ALEN]; | 1558 | u8 dst[ETH_ALEN]; |
1560 | u8 next_hop[ETH_ALEN]; | 1559 | u8 next_hop[ETH_ALEN]; |
1561 | int ifidx = cb->args[0]; | 1560 | int ifidx = cb->args[0]; |
1562 | int path_idx = cb->args[1]; | 1561 | int path_idx = cb->args[1]; |
1563 | int err; | 1562 | int err; |
1564 | 1563 | ||
1565 | if (!ifidx) { | 1564 | if (!ifidx) { |
1566 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1565 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
1567 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 1566 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
1568 | nl80211_policy); | 1567 | nl80211_policy); |
1569 | if (err) | 1568 | if (err) |
1570 | return err; | 1569 | return err; |
1571 | 1570 | ||
1572 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | 1571 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) |
1573 | return -EINVAL; | 1572 | return -EINVAL; |
1574 | 1573 | ||
1575 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | 1574 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); |
1576 | if (!ifidx) | 1575 | if (!ifidx) |
1577 | return -EINVAL; | 1576 | return -EINVAL; |
1578 | } | 1577 | } |
1579 | 1578 | ||
1580 | netdev = dev_get_by_index(&init_net, ifidx); | 1579 | netdev = dev_get_by_index(&init_net, ifidx); |
1581 | if (!netdev) | 1580 | if (!netdev) |
1582 | return -ENODEV; | 1581 | return -ENODEV; |
1583 | 1582 | ||
1584 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1583 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1585 | if (IS_ERR(dev)) { | 1584 | if (IS_ERR(dev)) { |
1586 | err = PTR_ERR(dev); | 1585 | err = PTR_ERR(dev); |
1587 | goto out_put_netdev; | 1586 | goto out_put_netdev; |
1588 | } | 1587 | } |
1589 | 1588 | ||
1590 | if (!dev->ops->dump_mpath) { | 1589 | if (!dev->ops->dump_mpath) { |
1591 | err = -ENOSYS; | 1590 | err = -ENOSYS; |
1592 | goto out_err; | 1591 | goto out_err; |
1593 | } | 1592 | } |
1594 | 1593 | ||
1595 | rtnl_lock(); | 1594 | rtnl_lock(); |
1596 | 1595 | ||
1597 | while (1) { | 1596 | while (1) { |
1598 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, | 1597 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, |
1599 | dst, next_hop, &pinfo); | 1598 | dst, next_hop, &pinfo); |
1600 | if (err == -ENOENT) | 1599 | if (err == -ENOENT) |
1601 | break; | 1600 | break; |
1602 | if (err) | 1601 | if (err) |
1603 | goto out_err_rtnl; | 1602 | goto out_err_rtnl; |
1604 | 1603 | ||
1605 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, | 1604 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, |
1606 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1605 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1607 | netdev, dst, next_hop, | 1606 | netdev, dst, next_hop, |
1608 | &pinfo) < 0) | 1607 | &pinfo) < 0) |
1609 | goto out; | 1608 | goto out; |
1610 | 1609 | ||
1611 | path_idx++; | 1610 | path_idx++; |
1612 | } | 1611 | } |
1613 | 1612 | ||
1614 | 1613 | ||
1615 | out: | 1614 | out: |
1616 | cb->args[1] = path_idx; | 1615 | cb->args[1] = path_idx; |
1617 | err = skb->len; | 1616 | err = skb->len; |
1618 | out_err_rtnl: | 1617 | out_err_rtnl: |
1619 | rtnl_unlock(); | 1618 | rtnl_unlock(); |
1620 | out_err: | 1619 | out_err: |
1621 | cfg80211_put_dev(dev); | 1620 | cfg80211_put_dev(dev); |
1622 | out_put_netdev: | 1621 | out_put_netdev: |
1623 | dev_put(netdev); | 1622 | dev_put(netdev); |
1624 | 1623 | ||
1625 | return err; | 1624 | return err; |
1626 | } | 1625 | } |
1627 | 1626 | ||
1628 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 1627 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
1629 | { | 1628 | { |
1630 | struct cfg80211_registered_device *drv; | 1629 | struct cfg80211_registered_device *drv; |
1631 | int err; | 1630 | int err; |
1632 | struct net_device *dev; | 1631 | struct net_device *dev; |
1633 | struct mpath_info pinfo; | 1632 | struct mpath_info pinfo; |
1634 | struct sk_buff *msg; | 1633 | struct sk_buff *msg; |
1635 | u8 *dst = NULL; | 1634 | u8 *dst = NULL; |
1636 | u8 next_hop[ETH_ALEN]; | 1635 | u8 next_hop[ETH_ALEN]; |
1637 | 1636 | ||
1638 | memset(&pinfo, 0, sizeof(pinfo)); | 1637 | memset(&pinfo, 0, sizeof(pinfo)); |
1639 | 1638 | ||
1640 | if (!info->attrs[NL80211_ATTR_MAC]) | 1639 | if (!info->attrs[NL80211_ATTR_MAC]) |
1641 | return -EINVAL; | 1640 | return -EINVAL; |
1642 | 1641 | ||
1643 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1642 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1644 | 1643 | ||
1645 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1644 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1646 | if (err) | 1645 | if (err) |
1647 | return err; | 1646 | return err; |
1648 | 1647 | ||
1649 | if (!drv->ops->get_mpath) { | 1648 | if (!drv->ops->get_mpath) { |
1650 | err = -EOPNOTSUPP; | 1649 | err = -EOPNOTSUPP; |
1651 | goto out; | 1650 | goto out; |
1652 | } | 1651 | } |
1653 | 1652 | ||
1654 | rtnl_lock(); | 1653 | rtnl_lock(); |
1655 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | 1654 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); |
1656 | rtnl_unlock(); | 1655 | rtnl_unlock(); |
1657 | 1656 | ||
1658 | if (err) | 1657 | if (err) |
1659 | goto out; | 1658 | goto out; |
1660 | 1659 | ||
1661 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1660 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
1662 | if (!msg) | 1661 | if (!msg) |
1663 | goto out; | 1662 | goto out; |
1664 | 1663 | ||
1665 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 1664 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
1666 | dev, dst, next_hop, &pinfo) < 0) | 1665 | dev, dst, next_hop, &pinfo) < 0) |
1667 | goto out_free; | 1666 | goto out_free; |
1668 | 1667 | ||
1669 | err = genlmsg_unicast(msg, info->snd_pid); | 1668 | err = genlmsg_unicast(msg, info->snd_pid); |
1670 | goto out; | 1669 | goto out; |
1671 | 1670 | ||
1672 | out_free: | 1671 | out_free: |
1673 | nlmsg_free(msg); | 1672 | nlmsg_free(msg); |
1674 | 1673 | ||
1675 | out: | 1674 | out: |
1676 | cfg80211_put_dev(drv); | 1675 | cfg80211_put_dev(drv); |
1677 | dev_put(dev); | 1676 | dev_put(dev); |
1678 | return err; | 1677 | return err; |
1679 | } | 1678 | } |
1680 | 1679 | ||
1681 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 1680 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
1682 | { | 1681 | { |
1683 | struct cfg80211_registered_device *drv; | 1682 | struct cfg80211_registered_device *drv; |
1684 | int err; | 1683 | int err; |
1685 | struct net_device *dev; | 1684 | struct net_device *dev; |
1686 | u8 *dst = NULL; | 1685 | u8 *dst = NULL; |
1687 | u8 *next_hop = NULL; | 1686 | u8 *next_hop = NULL; |
1688 | 1687 | ||
1689 | if (!info->attrs[NL80211_ATTR_MAC]) | 1688 | if (!info->attrs[NL80211_ATTR_MAC]) |
1690 | return -EINVAL; | 1689 | return -EINVAL; |
1691 | 1690 | ||
1692 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | 1691 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) |
1693 | return -EINVAL; | 1692 | return -EINVAL; |
1694 | 1693 | ||
1695 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1694 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1696 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1695 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1697 | 1696 | ||
1698 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1697 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1699 | if (err) | 1698 | if (err) |
1700 | return err; | 1699 | return err; |
1701 | 1700 | ||
1702 | if (!drv->ops->change_mpath) { | 1701 | if (!drv->ops->change_mpath) { |
1703 | err = -EOPNOTSUPP; | 1702 | err = -EOPNOTSUPP; |
1704 | goto out; | 1703 | goto out; |
1705 | } | 1704 | } |
1706 | 1705 | ||
1707 | rtnl_lock(); | 1706 | rtnl_lock(); |
1708 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); | 1707 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); |
1709 | rtnl_unlock(); | 1708 | rtnl_unlock(); |
1710 | 1709 | ||
1711 | out: | 1710 | out: |
1712 | cfg80211_put_dev(drv); | 1711 | cfg80211_put_dev(drv); |
1713 | dev_put(dev); | 1712 | dev_put(dev); |
1714 | return err; | 1713 | return err; |
1715 | } | 1714 | } |
1716 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 1715 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
1717 | { | 1716 | { |
1718 | struct cfg80211_registered_device *drv; | 1717 | struct cfg80211_registered_device *drv; |
1719 | int err; | 1718 | int err; |
1720 | struct net_device *dev; | 1719 | struct net_device *dev; |
1721 | u8 *dst = NULL; | 1720 | u8 *dst = NULL; |
1722 | u8 *next_hop = NULL; | 1721 | u8 *next_hop = NULL; |
1723 | 1722 | ||
1724 | if (!info->attrs[NL80211_ATTR_MAC]) | 1723 | if (!info->attrs[NL80211_ATTR_MAC]) |
1725 | return -EINVAL; | 1724 | return -EINVAL; |
1726 | 1725 | ||
1727 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | 1726 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) |
1728 | return -EINVAL; | 1727 | return -EINVAL; |
1729 | 1728 | ||
1730 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1729 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1731 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1730 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1732 | 1731 | ||
1733 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1732 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1734 | if (err) | 1733 | if (err) |
1735 | return err; | 1734 | return err; |
1736 | 1735 | ||
1737 | if (!drv->ops->add_mpath) { | 1736 | if (!drv->ops->add_mpath) { |
1738 | err = -EOPNOTSUPP; | 1737 | err = -EOPNOTSUPP; |
1739 | goto out; | 1738 | goto out; |
1740 | } | 1739 | } |
1741 | 1740 | ||
1742 | rtnl_lock(); | 1741 | rtnl_lock(); |
1743 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); | 1742 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); |
1744 | rtnl_unlock(); | 1743 | rtnl_unlock(); |
1745 | 1744 | ||
1746 | out: | 1745 | out: |
1747 | cfg80211_put_dev(drv); | 1746 | cfg80211_put_dev(drv); |
1748 | dev_put(dev); | 1747 | dev_put(dev); |
1749 | return err; | 1748 | return err; |
1750 | } | 1749 | } |
1751 | 1750 | ||
1752 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 1751 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
1753 | { | 1752 | { |
1754 | struct cfg80211_registered_device *drv; | 1753 | struct cfg80211_registered_device *drv; |
1755 | int err; | 1754 | int err; |
1756 | struct net_device *dev; | 1755 | struct net_device *dev; |
1757 | u8 *dst = NULL; | 1756 | u8 *dst = NULL; |
1758 | 1757 | ||
1759 | if (info->attrs[NL80211_ATTR_MAC]) | 1758 | if (info->attrs[NL80211_ATTR_MAC]) |
1760 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1759 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1761 | 1760 | ||
1762 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1761 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1763 | if (err) | 1762 | if (err) |
1764 | return err; | 1763 | return err; |
1765 | 1764 | ||
1766 | if (!drv->ops->del_mpath) { | 1765 | if (!drv->ops->del_mpath) { |
1767 | err = -EOPNOTSUPP; | 1766 | err = -EOPNOTSUPP; |
1768 | goto out; | 1767 | goto out; |
1769 | } | 1768 | } |
1770 | 1769 | ||
1771 | rtnl_lock(); | 1770 | rtnl_lock(); |
1772 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); | 1771 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); |
1773 | rtnl_unlock(); | 1772 | rtnl_unlock(); |
1774 | 1773 | ||
1775 | out: | 1774 | out: |
1776 | cfg80211_put_dev(drv); | 1775 | cfg80211_put_dev(drv); |
1777 | dev_put(dev); | 1776 | dev_put(dev); |
1778 | return err; | 1777 | return err; |
1779 | } | 1778 | } |
1780 | 1779 | ||
1781 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 1780 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
1782 | { | 1781 | { |
1783 | struct cfg80211_registered_device *drv; | 1782 | struct cfg80211_registered_device *drv; |
1784 | int err; | 1783 | int err; |
1785 | struct net_device *dev; | 1784 | struct net_device *dev; |
1786 | struct bss_parameters params; | 1785 | struct bss_parameters params; |
1787 | 1786 | ||
1788 | memset(¶ms, 0, sizeof(params)); | 1787 | memset(¶ms, 0, sizeof(params)); |
1789 | /* default to not changing parameters */ | 1788 | /* default to not changing parameters */ |
1790 | params.use_cts_prot = -1; | 1789 | params.use_cts_prot = -1; |
1791 | params.use_short_preamble = -1; | 1790 | params.use_short_preamble = -1; |
1792 | params.use_short_slot_time = -1; | 1791 | params.use_short_slot_time = -1; |
1793 | 1792 | ||
1794 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) | 1793 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) |
1795 | params.use_cts_prot = | 1794 | params.use_cts_prot = |
1796 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); | 1795 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); |
1797 | if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) | 1796 | if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) |
1798 | params.use_short_preamble = | 1797 | params.use_short_preamble = |
1799 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); | 1798 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); |
1800 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) | 1799 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) |
1801 | params.use_short_slot_time = | 1800 | params.use_short_slot_time = |
1802 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); | 1801 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); |
1803 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 1802 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
1804 | params.basic_rates = | 1803 | params.basic_rates = |
1805 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 1804 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
1806 | params.basic_rates_len = | 1805 | params.basic_rates_len = |
1807 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 1806 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
1808 | } | 1807 | } |
1809 | 1808 | ||
1810 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1809 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1811 | if (err) | 1810 | if (err) |
1812 | return err; | 1811 | return err; |
1813 | 1812 | ||
1814 | if (!drv->ops->change_bss) { | 1813 | if (!drv->ops->change_bss) { |
1815 | err = -EOPNOTSUPP; | 1814 | err = -EOPNOTSUPP; |
1816 | goto out; | 1815 | goto out; |
1817 | } | 1816 | } |
1818 | 1817 | ||
1819 | rtnl_lock(); | 1818 | rtnl_lock(); |
1820 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); | 1819 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); |
1821 | rtnl_unlock(); | 1820 | rtnl_unlock(); |
1822 | 1821 | ||
1823 | out: | 1822 | out: |
1824 | cfg80211_put_dev(drv); | 1823 | cfg80211_put_dev(drv); |
1825 | dev_put(dev); | 1824 | dev_put(dev); |
1826 | return err; | 1825 | return err; |
1827 | } | 1826 | } |
1828 | 1827 | ||
1829 | static const struct nla_policy | 1828 | static const struct nla_policy |
1830 | reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 1829 | reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
1831 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, | 1830 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, |
1832 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, | 1831 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, |
1833 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, | 1832 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, |
1834 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, | 1833 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, |
1835 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, | 1834 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, |
1836 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, | 1835 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, |
1837 | }; | 1836 | }; |
1838 | 1837 | ||
1839 | static int parse_reg_rule(struct nlattr *tb[], | 1838 | static int parse_reg_rule(struct nlattr *tb[], |
1840 | struct ieee80211_reg_rule *reg_rule) | 1839 | struct ieee80211_reg_rule *reg_rule) |
1841 | { | 1840 | { |
1842 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; | 1841 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; |
1843 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; | 1842 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; |
1844 | 1843 | ||
1845 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) | 1844 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) |
1846 | return -EINVAL; | 1845 | return -EINVAL; |
1847 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) | 1846 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) |
1848 | return -EINVAL; | 1847 | return -EINVAL; |
1849 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | 1848 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) |
1850 | return -EINVAL; | 1849 | return -EINVAL; |
1851 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | 1850 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) |
1852 | return -EINVAL; | 1851 | return -EINVAL; |
1853 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | 1852 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) |
1854 | return -EINVAL; | 1853 | return -EINVAL; |
1855 | 1854 | ||
1856 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); | 1855 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); |
1857 | 1856 | ||
1858 | freq_range->start_freq_khz = | 1857 | freq_range->start_freq_khz = |
1859 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | 1858 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); |
1860 | freq_range->end_freq_khz = | 1859 | freq_range->end_freq_khz = |
1861 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | 1860 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); |
1862 | freq_range->max_bandwidth_khz = | 1861 | freq_range->max_bandwidth_khz = |
1863 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | 1862 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); |
1864 | 1863 | ||
1865 | power_rule->max_eirp = | 1864 | power_rule->max_eirp = |
1866 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | 1865 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); |
1867 | 1866 | ||
1868 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) | 1867 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) |
1869 | power_rule->max_antenna_gain = | 1868 | power_rule->max_antenna_gain = |
1870 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); | 1869 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); |
1871 | 1870 | ||
1872 | return 0; | 1871 | return 0; |
1873 | } | 1872 | } |
1874 | 1873 | ||
1875 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | 1874 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) |
1876 | { | 1875 | { |
1877 | int r; | 1876 | int r; |
1878 | char *data = NULL; | 1877 | char *data = NULL; |
1879 | 1878 | ||
1880 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 1879 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
1881 | return -EINVAL; | 1880 | return -EINVAL; |
1882 | 1881 | ||
1883 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 1882 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
1884 | 1883 | ||
1885 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 1884 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
1886 | /* We ignore world regdom requests with the old regdom setup */ | 1885 | /* We ignore world regdom requests with the old regdom setup */ |
1887 | if (is_world_regdom(data)) | 1886 | if (is_world_regdom(data)) |
1888 | return -EINVAL; | 1887 | return -EINVAL; |
1889 | #endif | 1888 | #endif |
1890 | mutex_lock(&cfg80211_drv_mutex); | 1889 | mutex_lock(&cfg80211_drv_mutex); |
1891 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); | 1890 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); |
1892 | mutex_unlock(&cfg80211_drv_mutex); | 1891 | mutex_unlock(&cfg80211_drv_mutex); |
1893 | return r; | 1892 | return r; |
1894 | } | 1893 | } |
1895 | 1894 | ||
1896 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 1895 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
1897 | struct genl_info *info) | 1896 | struct genl_info *info) |
1898 | { | 1897 | { |
1899 | struct cfg80211_registered_device *drv; | 1898 | struct cfg80211_registered_device *drv; |
1900 | struct mesh_config cur_params; | 1899 | struct mesh_config cur_params; |
1901 | int err; | 1900 | int err; |
1902 | struct net_device *dev; | 1901 | struct net_device *dev; |
1903 | void *hdr; | 1902 | void *hdr; |
1904 | struct nlattr *pinfoattr; | 1903 | struct nlattr *pinfoattr; |
1905 | struct sk_buff *msg; | 1904 | struct sk_buff *msg; |
1906 | 1905 | ||
1907 | /* Look up our device */ | 1906 | /* Look up our device */ |
1908 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1907 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1909 | if (err) | 1908 | if (err) |
1910 | return err; | 1909 | return err; |
1911 | 1910 | ||
1912 | /* Get the mesh params */ | 1911 | /* Get the mesh params */ |
1913 | rtnl_lock(); | 1912 | rtnl_lock(); |
1914 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); | 1913 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); |
1915 | rtnl_unlock(); | 1914 | rtnl_unlock(); |
1916 | if (err) | 1915 | if (err) |
1917 | goto out; | 1916 | goto out; |
1918 | 1917 | ||
1919 | /* Draw up a netlink message to send back */ | 1918 | /* Draw up a netlink message to send back */ |
1920 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1919 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
1921 | if (!msg) { | 1920 | if (!msg) { |
1922 | err = -ENOBUFS; | 1921 | err = -ENOBUFS; |
1923 | goto out; | 1922 | goto out; |
1924 | } | 1923 | } |
1925 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1924 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1926 | NL80211_CMD_GET_MESH_PARAMS); | 1925 | NL80211_CMD_GET_MESH_PARAMS); |
1927 | if (!hdr) | 1926 | if (!hdr) |
1928 | goto nla_put_failure; | 1927 | goto nla_put_failure; |
1929 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); | 1928 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); |
1930 | if (!pinfoattr) | 1929 | if (!pinfoattr) |
1931 | goto nla_put_failure; | 1930 | goto nla_put_failure; |
1932 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1931 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1933 | NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, | 1932 | NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, |
1934 | cur_params.dot11MeshRetryTimeout); | 1933 | cur_params.dot11MeshRetryTimeout); |
1935 | NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, | 1934 | NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, |
1936 | cur_params.dot11MeshConfirmTimeout); | 1935 | cur_params.dot11MeshConfirmTimeout); |
1937 | NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, | 1936 | NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, |
1938 | cur_params.dot11MeshHoldingTimeout); | 1937 | cur_params.dot11MeshHoldingTimeout); |
1939 | NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, | 1938 | NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, |
1940 | cur_params.dot11MeshMaxPeerLinks); | 1939 | cur_params.dot11MeshMaxPeerLinks); |
1941 | NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, | 1940 | NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, |
1942 | cur_params.dot11MeshMaxRetries); | 1941 | cur_params.dot11MeshMaxRetries); |
1943 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, | 1942 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, |
1944 | cur_params.dot11MeshTTL); | 1943 | cur_params.dot11MeshTTL); |
1945 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, | 1944 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
1946 | cur_params.auto_open_plinks); | 1945 | cur_params.auto_open_plinks); |
1947 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 1946 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
1948 | cur_params.dot11MeshHWMPmaxPREQretries); | 1947 | cur_params.dot11MeshHWMPmaxPREQretries); |
1949 | NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, | 1948 | NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, |
1950 | cur_params.path_refresh_time); | 1949 | cur_params.path_refresh_time); |
1951 | NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 1950 | NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
1952 | cur_params.min_discovery_timeout); | 1951 | cur_params.min_discovery_timeout); |
1953 | NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 1952 | NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
1954 | cur_params.dot11MeshHWMPactivePathTimeout); | 1953 | cur_params.dot11MeshHWMPactivePathTimeout); |
1955 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 1954 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
1956 | cur_params.dot11MeshHWMPpreqMinInterval); | 1955 | cur_params.dot11MeshHWMPpreqMinInterval); |
1957 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 1956 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
1958 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); | 1957 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); |
1959 | nla_nest_end(msg, pinfoattr); | 1958 | nla_nest_end(msg, pinfoattr); |
1960 | genlmsg_end(msg, hdr); | 1959 | genlmsg_end(msg, hdr); |
1961 | err = genlmsg_unicast(msg, info->snd_pid); | 1960 | err = genlmsg_unicast(msg, info->snd_pid); |
1962 | goto out; | 1961 | goto out; |
1963 | 1962 | ||
1964 | nla_put_failure: | 1963 | nla_put_failure: |
1965 | genlmsg_cancel(msg, hdr); | 1964 | genlmsg_cancel(msg, hdr); |
1966 | err = -EMSGSIZE; | 1965 | err = -EMSGSIZE; |
1967 | out: | 1966 | out: |
1968 | /* Cleanup */ | 1967 | /* Cleanup */ |
1969 | cfg80211_put_dev(drv); | 1968 | cfg80211_put_dev(drv); |
1970 | dev_put(dev); | 1969 | dev_put(dev); |
1971 | return err; | 1970 | return err; |
1972 | } | 1971 | } |
1973 | 1972 | ||
1974 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 1973 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
1975 | do {\ | 1974 | do {\ |
1976 | if (table[attr_num]) {\ | 1975 | if (table[attr_num]) {\ |
1977 | cfg.param = nla_fn(table[attr_num]); \ | 1976 | cfg.param = nla_fn(table[attr_num]); \ |
1978 | mask |= (1 << (attr_num - 1)); \ | 1977 | mask |= (1 << (attr_num - 1)); \ |
1979 | } \ | 1978 | } \ |
1980 | } while (0);\ | 1979 | } while (0);\ |
1981 | 1980 | ||
1982 | static struct nla_policy | 1981 | static struct nla_policy |
1983 | nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = { | 1982 | nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = { |
1984 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, | 1983 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, |
1985 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, | 1984 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, |
1986 | [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, | 1985 | [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, |
1987 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, | 1986 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, |
1988 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, | 1987 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, |
1989 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, | 1988 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, |
1990 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 1989 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
1991 | 1990 | ||
1992 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 1991 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
1993 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, | 1992 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, |
1994 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, | 1993 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, |
1995 | [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, | 1994 | [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, |
1996 | [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, | 1995 | [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, |
1997 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, | 1996 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, |
1998 | }; | 1997 | }; |
1999 | 1998 | ||
2000 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 1999 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2001 | { | 2000 | { |
2002 | int err; | 2001 | int err; |
2003 | u32 mask; | 2002 | u32 mask; |
2004 | struct cfg80211_registered_device *drv; | 2003 | struct cfg80211_registered_device *drv; |
2005 | struct net_device *dev; | 2004 | struct net_device *dev; |
2006 | struct mesh_config cfg; | 2005 | struct mesh_config cfg; |
2007 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2006 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2008 | struct nlattr *parent_attr; | 2007 | struct nlattr *parent_attr; |
2009 | 2008 | ||
2010 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; | 2009 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; |
2011 | if (!parent_attr) | 2010 | if (!parent_attr) |
2012 | return -EINVAL; | 2011 | return -EINVAL; |
2013 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, | 2012 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, |
2014 | parent_attr, nl80211_meshconf_params_policy)) | 2013 | parent_attr, nl80211_meshconf_params_policy)) |
2015 | return -EINVAL; | 2014 | return -EINVAL; |
2016 | 2015 | ||
2017 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2016 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2018 | if (err) | 2017 | if (err) |
2019 | return err; | 2018 | return err; |
2020 | 2019 | ||
2021 | /* This makes sure that there aren't more than 32 mesh config | 2020 | /* This makes sure that there aren't more than 32 mesh config |
2022 | * parameters (otherwise our bitfield scheme would not work.) */ | 2021 | * parameters (otherwise our bitfield scheme would not work.) */ |
2023 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); | 2022 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); |
2024 | 2023 | ||
2025 | /* Fill in the params struct */ | 2024 | /* Fill in the params struct */ |
2026 | mask = 0; | 2025 | mask = 0; |
2027 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 2026 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
2028 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 2027 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); |
2029 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 2028 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
2030 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); | 2029 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); |
2031 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, | 2030 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, |
2032 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); | 2031 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); |
2033 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, | 2032 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, |
2034 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); | 2033 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); |
2035 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, | 2034 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, |
2036 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 2035 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); |
2037 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 2036 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
2038 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 2037 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
2039 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 2038 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
2040 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 2039 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); |
2041 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 2040 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
2042 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 2041 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
2043 | nla_get_u8); | 2042 | nla_get_u8); |
2044 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, | 2043 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, |
2045 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); | 2044 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); |
2046 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, | 2045 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, |
2047 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 2046 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
2048 | nla_get_u16); | 2047 | nla_get_u16); |
2049 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, | 2048 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, |
2050 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 2049 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
2051 | nla_get_u32); | 2050 | nla_get_u32); |
2052 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, | 2051 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, |
2053 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 2052 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
2054 | nla_get_u16); | 2053 | nla_get_u16); |
2055 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 2054 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
2056 | dot11MeshHWMPnetDiameterTraversalTime, | 2055 | dot11MeshHWMPnetDiameterTraversalTime, |
2057 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2056 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2058 | nla_get_u16); | 2057 | nla_get_u16); |
2059 | 2058 | ||
2060 | /* Apply changes */ | 2059 | /* Apply changes */ |
2061 | rtnl_lock(); | 2060 | rtnl_lock(); |
2062 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); | 2061 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); |
2063 | rtnl_unlock(); | 2062 | rtnl_unlock(); |
2064 | 2063 | ||
2065 | /* cleanup */ | 2064 | /* cleanup */ |
2066 | cfg80211_put_dev(drv); | 2065 | cfg80211_put_dev(drv); |
2067 | dev_put(dev); | 2066 | dev_put(dev); |
2068 | return err; | 2067 | return err; |
2069 | } | 2068 | } |
2070 | 2069 | ||
2071 | #undef FILL_IN_MESH_PARAM_IF_SET | 2070 | #undef FILL_IN_MESH_PARAM_IF_SET |
2072 | 2071 | ||
2073 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 2072 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
2074 | { | 2073 | { |
2075 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 2074 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
2076 | struct nlattr *nl_reg_rule; | 2075 | struct nlattr *nl_reg_rule; |
2077 | char *alpha2 = NULL; | 2076 | char *alpha2 = NULL; |
2078 | int rem_reg_rules = 0, r = 0; | 2077 | int rem_reg_rules = 0, r = 0; |
2079 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 2078 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
2080 | struct ieee80211_regdomain *rd = NULL; | 2079 | struct ieee80211_regdomain *rd = NULL; |
2081 | 2080 | ||
2082 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 2081 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
2083 | return -EINVAL; | 2082 | return -EINVAL; |
2084 | 2083 | ||
2085 | if (!info->attrs[NL80211_ATTR_REG_RULES]) | 2084 | if (!info->attrs[NL80211_ATTR_REG_RULES]) |
2086 | return -EINVAL; | 2085 | return -EINVAL; |
2087 | 2086 | ||
2088 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 2087 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
2089 | 2088 | ||
2090 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 2089 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
2091 | rem_reg_rules) { | 2090 | rem_reg_rules) { |
2092 | num_rules++; | 2091 | num_rules++; |
2093 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 2092 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
2094 | goto bad_reg; | 2093 | goto bad_reg; |
2095 | } | 2094 | } |
2096 | 2095 | ||
2097 | if (!reg_is_valid_request(alpha2)) | 2096 | if (!reg_is_valid_request(alpha2)) |
2098 | return -EINVAL; | 2097 | return -EINVAL; |
2099 | 2098 | ||
2100 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 2099 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
2101 | (num_rules * sizeof(struct ieee80211_reg_rule)); | 2100 | (num_rules * sizeof(struct ieee80211_reg_rule)); |
2102 | 2101 | ||
2103 | rd = kzalloc(size_of_regd, GFP_KERNEL); | 2102 | rd = kzalloc(size_of_regd, GFP_KERNEL); |
2104 | if (!rd) | 2103 | if (!rd) |
2105 | return -ENOMEM; | 2104 | return -ENOMEM; |
2106 | 2105 | ||
2107 | rd->n_reg_rules = num_rules; | 2106 | rd->n_reg_rules = num_rules; |
2108 | rd->alpha2[0] = alpha2[0]; | 2107 | rd->alpha2[0] = alpha2[0]; |
2109 | rd->alpha2[1] = alpha2[1]; | 2108 | rd->alpha2[1] = alpha2[1]; |
2110 | 2109 | ||
2111 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 2110 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
2112 | rem_reg_rules) { | 2111 | rem_reg_rules) { |
2113 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 2112 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
2114 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), | 2113 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), |
2115 | reg_rule_policy); | 2114 | reg_rule_policy); |
2116 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); | 2115 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); |
2117 | if (r) | 2116 | if (r) |
2118 | goto bad_reg; | 2117 | goto bad_reg; |
2119 | 2118 | ||
2120 | rule_idx++; | 2119 | rule_idx++; |
2121 | 2120 | ||
2122 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) | 2121 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) |
2123 | goto bad_reg; | 2122 | goto bad_reg; |
2124 | } | 2123 | } |
2125 | 2124 | ||
2126 | BUG_ON(rule_idx != num_rules); | 2125 | BUG_ON(rule_idx != num_rules); |
2127 | 2126 | ||
2128 | mutex_lock(&cfg80211_drv_mutex); | 2127 | mutex_lock(&cfg80211_drv_mutex); |
2129 | r = set_regdom(rd); | 2128 | r = set_regdom(rd); |
2130 | mutex_unlock(&cfg80211_drv_mutex); | 2129 | mutex_unlock(&cfg80211_drv_mutex); |
2131 | return r; | 2130 | return r; |
2132 | 2131 | ||
2133 | bad_reg: | 2132 | bad_reg: |
2134 | kfree(rd); | 2133 | kfree(rd); |
2135 | return -EINVAL; | 2134 | return -EINVAL; |
2136 | } | 2135 | } |
2137 | 2136 | ||
2138 | static struct genl_ops nl80211_ops[] = { | 2137 | static struct genl_ops nl80211_ops[] = { |
2139 | { | 2138 | { |
2140 | .cmd = NL80211_CMD_GET_WIPHY, | 2139 | .cmd = NL80211_CMD_GET_WIPHY, |
2141 | .doit = nl80211_get_wiphy, | 2140 | .doit = nl80211_get_wiphy, |
2142 | .dumpit = nl80211_dump_wiphy, | 2141 | .dumpit = nl80211_dump_wiphy, |
2143 | .policy = nl80211_policy, | 2142 | .policy = nl80211_policy, |
2144 | /* can be retrieved by unprivileged users */ | 2143 | /* can be retrieved by unprivileged users */ |
2145 | }, | 2144 | }, |
2146 | { | 2145 | { |
2147 | .cmd = NL80211_CMD_SET_WIPHY, | 2146 | .cmd = NL80211_CMD_SET_WIPHY, |
2148 | .doit = nl80211_set_wiphy, | 2147 | .doit = nl80211_set_wiphy, |
2149 | .policy = nl80211_policy, | 2148 | .policy = nl80211_policy, |
2150 | .flags = GENL_ADMIN_PERM, | 2149 | .flags = GENL_ADMIN_PERM, |
2151 | }, | 2150 | }, |
2152 | { | 2151 | { |
2153 | .cmd = NL80211_CMD_GET_INTERFACE, | 2152 | .cmd = NL80211_CMD_GET_INTERFACE, |
2154 | .doit = nl80211_get_interface, | 2153 | .doit = nl80211_get_interface, |
2155 | .dumpit = nl80211_dump_interface, | 2154 | .dumpit = nl80211_dump_interface, |
2156 | .policy = nl80211_policy, | 2155 | .policy = nl80211_policy, |
2157 | /* can be retrieved by unprivileged users */ | 2156 | /* can be retrieved by unprivileged users */ |
2158 | }, | 2157 | }, |
2159 | { | 2158 | { |
2160 | .cmd = NL80211_CMD_SET_INTERFACE, | 2159 | .cmd = NL80211_CMD_SET_INTERFACE, |
2161 | .doit = nl80211_set_interface, | 2160 | .doit = nl80211_set_interface, |
2162 | .policy = nl80211_policy, | 2161 | .policy = nl80211_policy, |
2163 | .flags = GENL_ADMIN_PERM, | 2162 | .flags = GENL_ADMIN_PERM, |
2164 | }, | 2163 | }, |
2165 | { | 2164 | { |
2166 | .cmd = NL80211_CMD_NEW_INTERFACE, | 2165 | .cmd = NL80211_CMD_NEW_INTERFACE, |
2167 | .doit = nl80211_new_interface, | 2166 | .doit = nl80211_new_interface, |
2168 | .policy = nl80211_policy, | 2167 | .policy = nl80211_policy, |
2169 | .flags = GENL_ADMIN_PERM, | 2168 | .flags = GENL_ADMIN_PERM, |
2170 | }, | 2169 | }, |
2171 | { | 2170 | { |
2172 | .cmd = NL80211_CMD_DEL_INTERFACE, | 2171 | .cmd = NL80211_CMD_DEL_INTERFACE, |
2173 | .doit = nl80211_del_interface, | 2172 | .doit = nl80211_del_interface, |
2174 | .policy = nl80211_policy, | 2173 | .policy = nl80211_policy, |
2175 | .flags = GENL_ADMIN_PERM, | 2174 | .flags = GENL_ADMIN_PERM, |
2176 | }, | 2175 | }, |
2177 | { | 2176 | { |
2178 | .cmd = NL80211_CMD_GET_KEY, | 2177 | .cmd = NL80211_CMD_GET_KEY, |
2179 | .doit = nl80211_get_key, | 2178 | .doit = nl80211_get_key, |
2180 | .policy = nl80211_policy, | 2179 | .policy = nl80211_policy, |
2181 | .flags = GENL_ADMIN_PERM, | 2180 | .flags = GENL_ADMIN_PERM, |
2182 | }, | 2181 | }, |
2183 | { | 2182 | { |
2184 | .cmd = NL80211_CMD_SET_KEY, | 2183 | .cmd = NL80211_CMD_SET_KEY, |
2185 | .doit = nl80211_set_key, | 2184 | .doit = nl80211_set_key, |
2186 | .policy = nl80211_policy, | 2185 | .policy = nl80211_policy, |
2187 | .flags = GENL_ADMIN_PERM, | 2186 | .flags = GENL_ADMIN_PERM, |
2188 | }, | 2187 | }, |
2189 | { | 2188 | { |
2190 | .cmd = NL80211_CMD_NEW_KEY, | 2189 | .cmd = NL80211_CMD_NEW_KEY, |
2191 | .doit = nl80211_new_key, | 2190 | .doit = nl80211_new_key, |
2192 | .policy = nl80211_policy, | 2191 | .policy = nl80211_policy, |
2193 | .flags = GENL_ADMIN_PERM, | 2192 | .flags = GENL_ADMIN_PERM, |
2194 | }, | 2193 | }, |
2195 | { | 2194 | { |
2196 | .cmd = NL80211_CMD_DEL_KEY, | 2195 | .cmd = NL80211_CMD_DEL_KEY, |
2197 | .doit = nl80211_del_key, | 2196 | .doit = nl80211_del_key, |
2198 | .policy = nl80211_policy, | 2197 | .policy = nl80211_policy, |
2199 | .flags = GENL_ADMIN_PERM, | 2198 | .flags = GENL_ADMIN_PERM, |
2200 | }, | 2199 | }, |
2201 | { | 2200 | { |
2202 | .cmd = NL80211_CMD_SET_BEACON, | 2201 | .cmd = NL80211_CMD_SET_BEACON, |
2203 | .policy = nl80211_policy, | 2202 | .policy = nl80211_policy, |
2204 | .flags = GENL_ADMIN_PERM, | 2203 | .flags = GENL_ADMIN_PERM, |
2205 | .doit = nl80211_addset_beacon, | 2204 | .doit = nl80211_addset_beacon, |
2206 | }, | 2205 | }, |
2207 | { | 2206 | { |
2208 | .cmd = NL80211_CMD_NEW_BEACON, | 2207 | .cmd = NL80211_CMD_NEW_BEACON, |
2209 | .policy = nl80211_policy, | 2208 | .policy = nl80211_policy, |
2210 | .flags = GENL_ADMIN_PERM, | 2209 | .flags = GENL_ADMIN_PERM, |
2211 | .doit = nl80211_addset_beacon, | 2210 | .doit = nl80211_addset_beacon, |
2212 | }, | 2211 | }, |
2213 | { | 2212 | { |
2214 | .cmd = NL80211_CMD_DEL_BEACON, | 2213 | .cmd = NL80211_CMD_DEL_BEACON, |
2215 | .policy = nl80211_policy, | 2214 | .policy = nl80211_policy, |
2216 | .flags = GENL_ADMIN_PERM, | 2215 | .flags = GENL_ADMIN_PERM, |
2217 | .doit = nl80211_del_beacon, | 2216 | .doit = nl80211_del_beacon, |
2218 | }, | 2217 | }, |
2219 | { | 2218 | { |
2220 | .cmd = NL80211_CMD_GET_STATION, | 2219 | .cmd = NL80211_CMD_GET_STATION, |
2221 | .doit = nl80211_get_station, | 2220 | .doit = nl80211_get_station, |
2222 | .dumpit = nl80211_dump_station, | 2221 | .dumpit = nl80211_dump_station, |
2223 | .policy = nl80211_policy, | 2222 | .policy = nl80211_policy, |
2224 | .flags = GENL_ADMIN_PERM, | 2223 | .flags = GENL_ADMIN_PERM, |
2225 | }, | 2224 | }, |
2226 | { | 2225 | { |
2227 | .cmd = NL80211_CMD_SET_STATION, | 2226 | .cmd = NL80211_CMD_SET_STATION, |
2228 | .doit = nl80211_set_station, | 2227 | .doit = nl80211_set_station, |
2229 | .policy = nl80211_policy, | 2228 | .policy = nl80211_policy, |
2230 | .flags = GENL_ADMIN_PERM, | 2229 | .flags = GENL_ADMIN_PERM, |
2231 | }, | 2230 | }, |
2232 | { | 2231 | { |
2233 | .cmd = NL80211_CMD_NEW_STATION, | 2232 | .cmd = NL80211_CMD_NEW_STATION, |
2234 | .doit = nl80211_new_station, | 2233 | .doit = nl80211_new_station, |
2235 | .policy = nl80211_policy, | 2234 | .policy = nl80211_policy, |
2236 | .flags = GENL_ADMIN_PERM, | 2235 | .flags = GENL_ADMIN_PERM, |
2237 | }, | 2236 | }, |
2238 | { | 2237 | { |
2239 | .cmd = NL80211_CMD_DEL_STATION, | 2238 | .cmd = NL80211_CMD_DEL_STATION, |
2240 | .doit = nl80211_del_station, | 2239 | .doit = nl80211_del_station, |
2241 | .policy = nl80211_policy, | 2240 | .policy = nl80211_policy, |
2242 | .flags = GENL_ADMIN_PERM, | 2241 | .flags = GENL_ADMIN_PERM, |
2243 | }, | 2242 | }, |
2244 | { | 2243 | { |
2245 | .cmd = NL80211_CMD_GET_MPATH, | 2244 | .cmd = NL80211_CMD_GET_MPATH, |
2246 | .doit = nl80211_get_mpath, | 2245 | .doit = nl80211_get_mpath, |
2247 | .dumpit = nl80211_dump_mpath, | 2246 | .dumpit = nl80211_dump_mpath, |
2248 | .policy = nl80211_policy, | 2247 | .policy = nl80211_policy, |
2249 | .flags = GENL_ADMIN_PERM, | 2248 | .flags = GENL_ADMIN_PERM, |
2250 | }, | 2249 | }, |
2251 | { | 2250 | { |
2252 | .cmd = NL80211_CMD_SET_MPATH, | 2251 | .cmd = NL80211_CMD_SET_MPATH, |
2253 | .doit = nl80211_set_mpath, | 2252 | .doit = nl80211_set_mpath, |
2254 | .policy = nl80211_policy, | 2253 | .policy = nl80211_policy, |
2255 | .flags = GENL_ADMIN_PERM, | 2254 | .flags = GENL_ADMIN_PERM, |
2256 | }, | 2255 | }, |
2257 | { | 2256 | { |
2258 | .cmd = NL80211_CMD_NEW_MPATH, | 2257 | .cmd = NL80211_CMD_NEW_MPATH, |
2259 | .doit = nl80211_new_mpath, | 2258 | .doit = nl80211_new_mpath, |
2260 | .policy = nl80211_policy, | 2259 | .policy = nl80211_policy, |
2261 | .flags = GENL_ADMIN_PERM, | 2260 | .flags = GENL_ADMIN_PERM, |
2262 | }, | 2261 | }, |
2263 | { | 2262 | { |
2264 | .cmd = NL80211_CMD_DEL_MPATH, | 2263 | .cmd = NL80211_CMD_DEL_MPATH, |
2265 | .doit = nl80211_del_mpath, | 2264 | .doit = nl80211_del_mpath, |
2266 | .policy = nl80211_policy, | 2265 | .policy = nl80211_policy, |
2267 | .flags = GENL_ADMIN_PERM, | 2266 | .flags = GENL_ADMIN_PERM, |
2268 | }, | 2267 | }, |
2269 | { | 2268 | { |
2270 | .cmd = NL80211_CMD_SET_BSS, | 2269 | .cmd = NL80211_CMD_SET_BSS, |
2271 | .doit = nl80211_set_bss, | 2270 | .doit = nl80211_set_bss, |
2272 | .policy = nl80211_policy, | 2271 | .policy = nl80211_policy, |
2273 | .flags = GENL_ADMIN_PERM, | 2272 | .flags = GENL_ADMIN_PERM, |
2274 | }, | 2273 | }, |
2275 | { | 2274 | { |
2276 | .cmd = NL80211_CMD_SET_REG, | 2275 | .cmd = NL80211_CMD_SET_REG, |
2277 | .doit = nl80211_set_reg, | 2276 | .doit = nl80211_set_reg, |
2278 | .policy = nl80211_policy, | 2277 | .policy = nl80211_policy, |
2279 | .flags = GENL_ADMIN_PERM, | 2278 | .flags = GENL_ADMIN_PERM, |
2280 | }, | 2279 | }, |
2281 | { | 2280 | { |
2282 | .cmd = NL80211_CMD_REQ_SET_REG, | 2281 | .cmd = NL80211_CMD_REQ_SET_REG, |
2283 | .doit = nl80211_req_set_reg, | 2282 | .doit = nl80211_req_set_reg, |
2284 | .policy = nl80211_policy, | 2283 | .policy = nl80211_policy, |
2285 | .flags = GENL_ADMIN_PERM, | 2284 | .flags = GENL_ADMIN_PERM, |
2286 | }, | 2285 | }, |
2287 | { | 2286 | { |
2288 | .cmd = NL80211_CMD_GET_MESH_PARAMS, | 2287 | .cmd = NL80211_CMD_GET_MESH_PARAMS, |
2289 | .doit = nl80211_get_mesh_params, | 2288 | .doit = nl80211_get_mesh_params, |
2290 | .policy = nl80211_policy, | 2289 | .policy = nl80211_policy, |
2291 | /* can be retrieved by unprivileged users */ | 2290 | /* can be retrieved by unprivileged users */ |
2292 | }, | 2291 | }, |
2293 | { | 2292 | { |
2294 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 2293 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
2295 | .doit = nl80211_set_mesh_params, | 2294 | .doit = nl80211_set_mesh_params, |
2296 | .policy = nl80211_policy, | 2295 | .policy = nl80211_policy, |
2297 | .flags = GENL_ADMIN_PERM, | 2296 | .flags = GENL_ADMIN_PERM, |
2298 | }, | 2297 | }, |
2299 | }; | 2298 | }; |
2300 | 2299 | ||
2301 | /* multicast groups */ | 2300 | /* multicast groups */ |
2302 | static struct genl_multicast_group nl80211_config_mcgrp = { | 2301 | static struct genl_multicast_group nl80211_config_mcgrp = { |
2303 | .name = "config", | 2302 | .name = "config", |
2304 | }; | 2303 | }; |
2305 | 2304 | ||
2306 | /* notification functions */ | 2305 | /* notification functions */ |
2307 | 2306 | ||
2308 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | 2307 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) |
2309 | { | 2308 | { |
2310 | struct sk_buff *msg; | 2309 | struct sk_buff *msg; |
2311 | 2310 | ||
2312 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2311 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
2313 | if (!msg) | 2312 | if (!msg) |
2314 | return; | 2313 | return; |
2315 | 2314 | ||
2316 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { | 2315 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { |
2317 | nlmsg_free(msg); | 2316 | nlmsg_free(msg); |
2318 | return; | 2317 | return; |
2319 | } | 2318 | } |
2320 | 2319 | ||
2321 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 2320 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); |
2322 | } | 2321 | } |
2323 | 2322 | ||
2324 | /* initialisation/exit functions */ | 2323 | /* initialisation/exit functions */ |
2325 | 2324 | ||
2326 | int nl80211_init(void) | 2325 | int nl80211_init(void) |
2327 | { | 2326 | { |
2328 | int err, i; | 2327 | int err, i; |
2329 | 2328 | ||
2330 | err = genl_register_family(&nl80211_fam); | 2329 | err = genl_register_family(&nl80211_fam); |
2331 | if (err) | 2330 | if (err) |
2332 | return err; | 2331 | return err; |
2333 | 2332 | ||
2334 | for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { | 2333 | for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { |
2335 | err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); | 2334 | err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); |
2336 | if (err) | 2335 | if (err) |
2337 | goto err_out; | 2336 | goto err_out; |
2338 | } | 2337 | } |
2339 | 2338 | ||
2340 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); | 2339 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); |
2341 | if (err) | 2340 | if (err) |
2342 | goto err_out; | 2341 | goto err_out; |
2343 | 2342 | ||
2344 | return 0; | 2343 | return 0; |
2345 | err_out: | 2344 | err_out: |
2346 | genl_unregister_family(&nl80211_fam); | 2345 | genl_unregister_family(&nl80211_fam); |
2347 | return err; | 2346 | return err; |
2348 | } | 2347 | } |
2349 | 2348 | ||
2350 | void nl80211_exit(void) | 2349 | void nl80211_exit(void) |
2351 | { | 2350 | { |
2352 | genl_unregister_family(&nl80211_fam); | 2351 | genl_unregister_family(&nl80211_fam); |
2353 | } | 2352 | } |
2354 | 2353 |