Commit | Line | Data |
---|---|---|
dad0d04f FF |
1 | /** |
2 | * Copyright (c) 2014 Redpine Signals Inc. | |
3 | * | |
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 | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
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 | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include <linux/etherdevice.h> | |
18 | #include "rsi_debugfs.h" | |
19 | #include "rsi_mgmt.h" | |
20 | #include "rsi_common.h" | |
21 | ||
22 | static const struct ieee80211_channel rsi_2ghz_channels[] = { | |
57fbcce3 | 23 | { .band = NL80211_BAND_2GHZ, .center_freq = 2412, |
dad0d04f | 24 | .hw_value = 1 }, /* Channel 1 */ |
57fbcce3 | 25 | { .band = NL80211_BAND_2GHZ, .center_freq = 2417, |
dad0d04f | 26 | .hw_value = 2 }, /* Channel 2 */ |
57fbcce3 | 27 | { .band = NL80211_BAND_2GHZ, .center_freq = 2422, |
dad0d04f | 28 | .hw_value = 3 }, /* Channel 3 */ |
57fbcce3 | 29 | { .band = NL80211_BAND_2GHZ, .center_freq = 2427, |
dad0d04f | 30 | .hw_value = 4 }, /* Channel 4 */ |
57fbcce3 | 31 | { .band = NL80211_BAND_2GHZ, .center_freq = 2432, |
dad0d04f | 32 | .hw_value = 5 }, /* Channel 5 */ |
57fbcce3 | 33 | { .band = NL80211_BAND_2GHZ, .center_freq = 2437, |
dad0d04f | 34 | .hw_value = 6 }, /* Channel 6 */ |
57fbcce3 | 35 | { .band = NL80211_BAND_2GHZ, .center_freq = 2442, |
dad0d04f | 36 | .hw_value = 7 }, /* Channel 7 */ |
57fbcce3 | 37 | { .band = NL80211_BAND_2GHZ, .center_freq = 2447, |
dad0d04f | 38 | .hw_value = 8 }, /* Channel 8 */ |
57fbcce3 | 39 | { .band = NL80211_BAND_2GHZ, .center_freq = 2452, |
dad0d04f | 40 | .hw_value = 9 }, /* Channel 9 */ |
57fbcce3 | 41 | { .band = NL80211_BAND_2GHZ, .center_freq = 2457, |
dad0d04f | 42 | .hw_value = 10 }, /* Channel 10 */ |
57fbcce3 | 43 | { .band = NL80211_BAND_2GHZ, .center_freq = 2462, |
dad0d04f | 44 | .hw_value = 11 }, /* Channel 11 */ |
57fbcce3 | 45 | { .band = NL80211_BAND_2GHZ, .center_freq = 2467, |
dad0d04f | 46 | .hw_value = 12 }, /* Channel 12 */ |
57fbcce3 | 47 | { .band = NL80211_BAND_2GHZ, .center_freq = 2472, |
dad0d04f | 48 | .hw_value = 13 }, /* Channel 13 */ |
57fbcce3 | 49 | { .band = NL80211_BAND_2GHZ, .center_freq = 2484, |
dad0d04f FF |
50 | .hw_value = 14 }, /* Channel 14 */ |
51 | }; | |
52 | ||
53 | static const struct ieee80211_channel rsi_5ghz_channels[] = { | |
57fbcce3 | 54 | { .band = NL80211_BAND_5GHZ, .center_freq = 5180, |
dad0d04f | 55 | .hw_value = 36, }, /* Channel 36 */ |
57fbcce3 | 56 | { .band = NL80211_BAND_5GHZ, .center_freq = 5200, |
dad0d04f | 57 | .hw_value = 40, }, /* Channel 40 */ |
57fbcce3 | 58 | { .band = NL80211_BAND_5GHZ, .center_freq = 5220, |
dad0d04f | 59 | .hw_value = 44, }, /* Channel 44 */ |
57fbcce3 | 60 | { .band = NL80211_BAND_5GHZ, .center_freq = 5240, |
dad0d04f | 61 | .hw_value = 48, }, /* Channel 48 */ |
57fbcce3 | 62 | { .band = NL80211_BAND_5GHZ, .center_freq = 5260, |
dad0d04f | 63 | .hw_value = 52, }, /* Channel 52 */ |
57fbcce3 | 64 | { .band = NL80211_BAND_5GHZ, .center_freq = 5280, |
dad0d04f | 65 | .hw_value = 56, }, /* Channel 56 */ |
57fbcce3 | 66 | { .band = NL80211_BAND_5GHZ, .center_freq = 5300, |
dad0d04f | 67 | .hw_value = 60, }, /* Channel 60 */ |
57fbcce3 | 68 | { .band = NL80211_BAND_5GHZ, .center_freq = 5320, |
dad0d04f | 69 | .hw_value = 64, }, /* Channel 64 */ |
57fbcce3 | 70 | { .band = NL80211_BAND_5GHZ, .center_freq = 5500, |
dad0d04f | 71 | .hw_value = 100, }, /* Channel 100 */ |
57fbcce3 | 72 | { .band = NL80211_BAND_5GHZ, .center_freq = 5520, |
dad0d04f | 73 | .hw_value = 104, }, /* Channel 104 */ |
57fbcce3 | 74 | { .band = NL80211_BAND_5GHZ, .center_freq = 5540, |
dad0d04f | 75 | .hw_value = 108, }, /* Channel 108 */ |
57fbcce3 | 76 | { .band = NL80211_BAND_5GHZ, .center_freq = 5560, |
dad0d04f | 77 | .hw_value = 112, }, /* Channel 112 */ |
57fbcce3 | 78 | { .band = NL80211_BAND_5GHZ, .center_freq = 5580, |
dad0d04f | 79 | .hw_value = 116, }, /* Channel 116 */ |
57fbcce3 | 80 | { .band = NL80211_BAND_5GHZ, .center_freq = 5600, |
dad0d04f | 81 | .hw_value = 120, }, /* Channel 120 */ |
57fbcce3 | 82 | { .band = NL80211_BAND_5GHZ, .center_freq = 5620, |
dad0d04f | 83 | .hw_value = 124, }, /* Channel 124 */ |
57fbcce3 | 84 | { .band = NL80211_BAND_5GHZ, .center_freq = 5640, |
dad0d04f | 85 | .hw_value = 128, }, /* Channel 128 */ |
57fbcce3 | 86 | { .band = NL80211_BAND_5GHZ, .center_freq = 5660, |
dad0d04f | 87 | .hw_value = 132, }, /* Channel 132 */ |
57fbcce3 | 88 | { .band = NL80211_BAND_5GHZ, .center_freq = 5680, |
dad0d04f | 89 | .hw_value = 136, }, /* Channel 136 */ |
57fbcce3 | 90 | { .band = NL80211_BAND_5GHZ, .center_freq = 5700, |
dad0d04f | 91 | .hw_value = 140, }, /* Channel 140 */ |
57fbcce3 | 92 | { .band = NL80211_BAND_5GHZ, .center_freq = 5745, |
dad0d04f | 93 | .hw_value = 149, }, /* Channel 149 */ |
57fbcce3 | 94 | { .band = NL80211_BAND_5GHZ, .center_freq = 5765, |
dad0d04f | 95 | .hw_value = 153, }, /* Channel 153 */ |
57fbcce3 | 96 | { .band = NL80211_BAND_5GHZ, .center_freq = 5785, |
dad0d04f | 97 | .hw_value = 157, }, /* Channel 157 */ |
57fbcce3 | 98 | { .band = NL80211_BAND_5GHZ, .center_freq = 5805, |
dad0d04f | 99 | .hw_value = 161, }, /* Channel 161 */ |
57fbcce3 | 100 | { .band = NL80211_BAND_5GHZ, .center_freq = 5825, |
dad0d04f FF |
101 | .hw_value = 165, }, /* Channel 165 */ |
102 | }; | |
103 | ||
104 | struct ieee80211_rate rsi_rates[12] = { | |
105 | { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 }, | |
106 | { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 }, | |
107 | { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 }, | |
108 | { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 }, | |
109 | { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 }, | |
110 | { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 }, | |
111 | { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 }, | |
112 | { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 }, | |
113 | { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 }, | |
114 | { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 }, | |
115 | { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 }, | |
116 | { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 }, | |
117 | }; | |
118 | ||
119 | const u16 rsi_mcsrates[8] = { | |
120 | RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3, | |
121 | RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 | |
122 | }; | |
123 | ||
124 | /** | |
125 | * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. | |
126 | * @common: Pointer to the driver private structure. | |
127 | * | |
128 | * Return: If cipher type is WEP, a value of 1 is returned, else 0. | |
129 | */ | |
130 | ||
131 | bool rsi_is_cipher_wep(struct rsi_common *common) | |
132 | { | |
133 | if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) || | |
134 | (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) && | |
135 | (!common->secinfo.ptk_cipher)) | |
136 | return true; | |
137 | else | |
138 | return false; | |
139 | } | |
140 | ||
141 | /** | |
142 | * rsi_register_rates_channels() - This function registers channels and rates. | |
143 | * @adapter: Pointer to the adapter structure. | |
144 | * @band: Operating band to be set. | |
145 | * | |
146 | * Return: None. | |
147 | */ | |
148 | static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) | |
149 | { | |
150 | struct ieee80211_supported_band *sbands = &adapter->sbands[band]; | |
151 | void *channels = NULL; | |
152 | ||
57fbcce3 | 153 | if (band == NL80211_BAND_2GHZ) { |
dad0d04f FF |
154 | channels = kmalloc(sizeof(rsi_2ghz_channels), GFP_KERNEL); |
155 | memcpy(channels, | |
156 | rsi_2ghz_channels, | |
157 | sizeof(rsi_2ghz_channels)); | |
57fbcce3 | 158 | sbands->band = NL80211_BAND_2GHZ; |
dad0d04f FF |
159 | sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels); |
160 | sbands->bitrates = rsi_rates; | |
161 | sbands->n_bitrates = ARRAY_SIZE(rsi_rates); | |
162 | } else { | |
163 | channels = kmalloc(sizeof(rsi_5ghz_channels), GFP_KERNEL); | |
164 | memcpy(channels, | |
165 | rsi_5ghz_channels, | |
166 | sizeof(rsi_5ghz_channels)); | |
57fbcce3 | 167 | sbands->band = NL80211_BAND_5GHZ; |
dad0d04f FF |
168 | sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels); |
169 | sbands->bitrates = &rsi_rates[4]; | |
170 | sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4; | |
171 | } | |
172 | ||
173 | sbands->channels = channels; | |
174 | ||
175 | memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap)); | |
176 | sbands->ht_cap.ht_supported = true; | |
177 | sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | |
178 | IEEE80211_HT_CAP_SGI_20 | | |
179 | IEEE80211_HT_CAP_SGI_40); | |
e8c58e7a | 180 | sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; |
dad0d04f FF |
181 | sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; |
182 | sbands->ht_cap.mcs.rx_mask[0] = 0xff; | |
183 | sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | |
184 | /* sbands->ht_cap.mcs.rx_highest = 0x82; */ | |
185 | } | |
186 | ||
187 | /** | |
19d2e619 | 188 | * rsi_mac80211_detach() - This function is used to de-initialize the |
dad0d04f FF |
189 | * Mac80211 stack. |
190 | * @adapter: Pointer to the adapter structure. | |
191 | * | |
192 | * Return: None. | |
193 | */ | |
194 | void rsi_mac80211_detach(struct rsi_hw *adapter) | |
195 | { | |
196 | struct ieee80211_hw *hw = adapter->hw; | |
197 | ||
198 | if (hw) { | |
199 | ieee80211_stop_queues(hw); | |
200 | ieee80211_unregister_hw(hw); | |
201 | ieee80211_free_hw(hw); | |
202 | } | |
203 | ||
204 | rsi_remove_dbgfs(adapter); | |
205 | } | |
206 | EXPORT_SYMBOL_GPL(rsi_mac80211_detach); | |
207 | ||
208 | /** | |
209 | * rsi_indicate_tx_status() - This function indicates the transmit status. | |
210 | * @adapter: Pointer to the adapter structure. | |
211 | * @skb: Pointer to the socket buffer structure. | |
212 | * @status: Status | |
213 | * | |
214 | * Return: None. | |
215 | */ | |
216 | void rsi_indicate_tx_status(struct rsi_hw *adapter, | |
217 | struct sk_buff *skb, | |
218 | int status) | |
219 | { | |
220 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
221 | ||
222 | memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); | |
223 | ||
224 | if (!status) | |
225 | info->flags |= IEEE80211_TX_STAT_ACK; | |
226 | ||
227 | ieee80211_tx_status_irqsafe(adapter->hw, skb); | |
228 | } | |
229 | ||
230 | /** | |
231 | * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each | |
232 | * transmitted frame.SKB contains the buffer starting | |
233 | * from the IEEE 802.11 header. | |
234 | * @hw: Pointer to the ieee80211_hw structure. | |
235 | * @control: Pointer to the ieee80211_tx_control structure | |
236 | * @skb: Pointer to the socket buffer structure. | |
237 | * | |
238 | * Return: None | |
239 | */ | |
240 | static void rsi_mac80211_tx(struct ieee80211_hw *hw, | |
241 | struct ieee80211_tx_control *control, | |
242 | struct sk_buff *skb) | |
243 | { | |
244 | struct rsi_hw *adapter = hw->priv; | |
245 | struct rsi_common *common = adapter->priv; | |
246 | ||
247 | rsi_core_xmit(common, skb); | |
248 | } | |
249 | ||
250 | /** | |
251 | * rsi_mac80211_start() - This is first handler that 802.11 module calls, since | |
252 | * the driver init is complete by then, just | |
253 | * returns success. | |
254 | * @hw: Pointer to the ieee80211_hw structure. | |
255 | * | |
256 | * Return: 0 as success. | |
257 | */ | |
258 | static int rsi_mac80211_start(struct ieee80211_hw *hw) | |
259 | { | |
260 | struct rsi_hw *adapter = hw->priv; | |
261 | struct rsi_common *common = adapter->priv; | |
262 | ||
263 | mutex_lock(&common->mutex); | |
264 | common->iface_down = false; | |
265 | mutex_unlock(&common->mutex); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /** | |
271 | * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. | |
272 | * @hw: Pointer to the ieee80211_hw structure. | |
273 | * | |
274 | * Return: None. | |
275 | */ | |
276 | static void rsi_mac80211_stop(struct ieee80211_hw *hw) | |
277 | { | |
278 | struct rsi_hw *adapter = hw->priv; | |
279 | struct rsi_common *common = adapter->priv; | |
280 | ||
281 | mutex_lock(&common->mutex); | |
282 | common->iface_down = true; | |
283 | mutex_unlock(&common->mutex); | |
284 | } | |
285 | ||
286 | /** | |
287 | * rsi_mac80211_add_interface() - This function is called when a netdevice | |
288 | * attached to the hardware is enabled. | |
289 | * @hw: Pointer to the ieee80211_hw structure. | |
290 | * @vif: Pointer to the ieee80211_vif structure. | |
291 | * | |
292 | * Return: ret: 0 on success, negative error code on failure. | |
293 | */ | |
294 | static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, | |
295 | struct ieee80211_vif *vif) | |
296 | { | |
297 | struct rsi_hw *adapter = hw->priv; | |
298 | struct rsi_common *common = adapter->priv; | |
299 | int ret = -EOPNOTSUPP; | |
300 | ||
301 | mutex_lock(&common->mutex); | |
302 | switch (vif->type) { | |
303 | case NL80211_IFTYPE_STATION: | |
304 | if (!adapter->sc_nvifs) { | |
305 | ++adapter->sc_nvifs; | |
306 | adapter->vifs[0] = vif; | |
307 | ret = rsi_set_vap_capabilities(common, STA_OPMODE); | |
308 | } | |
309 | break; | |
310 | default: | |
311 | rsi_dbg(ERR_ZONE, | |
312 | "%s: Interface type %d not supported\n", __func__, | |
313 | vif->type); | |
314 | } | |
315 | mutex_unlock(&common->mutex); | |
316 | ||
317 | return ret; | |
318 | } | |
319 | ||
320 | /** | |
321 | * rsi_mac80211_remove_interface() - This function notifies driver that an | |
322 | * interface is going down. | |
323 | * @hw: Pointer to the ieee80211_hw structure. | |
324 | * @vif: Pointer to the ieee80211_vif structure. | |
325 | * | |
326 | * Return: None. | |
327 | */ | |
328 | static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, | |
329 | struct ieee80211_vif *vif) | |
330 | { | |
331 | struct rsi_hw *adapter = hw->priv; | |
332 | struct rsi_common *common = adapter->priv; | |
333 | ||
334 | mutex_lock(&common->mutex); | |
335 | if (vif->type == NL80211_IFTYPE_STATION) | |
336 | adapter->sc_nvifs--; | |
337 | ||
338 | if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) | |
339 | adapter->vifs[0] = NULL; | |
340 | mutex_unlock(&common->mutex); | |
341 | } | |
342 | ||
686a2541 JM |
343 | /** |
344 | * rsi_channel_change() - This function is a performs the checks | |
345 | * required for changing a channel and sets | |
346 | * the channel accordingly. | |
347 | * @hw: Pointer to the ieee80211_hw structure. | |
348 | * | |
349 | * Return: 0 on success, negative error code on failure. | |
350 | */ | |
351 | static int rsi_channel_change(struct ieee80211_hw *hw) | |
352 | { | |
353 | struct rsi_hw *adapter = hw->priv; | |
354 | struct rsi_common *common = adapter->priv; | |
355 | int status = -EOPNOTSUPP; | |
356 | struct ieee80211_channel *curchan = hw->conf.chandef.chan; | |
357 | u16 channel = curchan->hw_value; | |
358 | struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; | |
359 | ||
360 | rsi_dbg(INFO_ZONE, | |
361 | "%s: Set channel: %d MHz type: %d channel_no %d\n", | |
362 | __func__, curchan->center_freq, | |
363 | curchan->flags, channel); | |
364 | ||
365 | if (bss->assoc) { | |
366 | if (!common->hw_data_qs_blocked && | |
367 | (rsi_get_connected_channel(adapter) != channel)) { | |
368 | rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); | |
369 | if (!rsi_send_block_unblock_frame(common, true)) | |
370 | common->hw_data_qs_blocked = true; | |
371 | } | |
372 | } | |
373 | ||
374 | status = rsi_band_check(common); | |
375 | if (!status) | |
376 | status = rsi_set_channel(adapter->priv, channel); | |
377 | ||
378 | if (bss->assoc) { | |
379 | if (common->hw_data_qs_blocked && | |
380 | (rsi_get_connected_channel(adapter) == channel)) { | |
381 | rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); | |
382 | if (!rsi_send_block_unblock_frame(common, false)) | |
383 | common->hw_data_qs_blocked = false; | |
384 | } | |
385 | } else { | |
386 | if (common->hw_data_qs_blocked) { | |
387 | rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); | |
388 | if (!rsi_send_block_unblock_frame(common, false)) | |
389 | common->hw_data_qs_blocked = false; | |
390 | } | |
391 | } | |
392 | ||
393 | return status; | |
394 | } | |
395 | ||
dad0d04f FF |
396 | /** |
397 | * rsi_mac80211_config() - This function is a handler for configuration | |
398 | * requests. The stack calls this function to | |
399 | * change hardware configuration, e.g., channel. | |
400 | * @hw: Pointer to the ieee80211_hw structure. | |
401 | * @changed: Changed flags set. | |
402 | * | |
403 | * Return: 0 on success, negative error code on failure. | |
404 | */ | |
405 | static int rsi_mac80211_config(struct ieee80211_hw *hw, | |
406 | u32 changed) | |
407 | { | |
408 | struct rsi_hw *adapter = hw->priv; | |
409 | struct rsi_common *common = adapter->priv; | |
410 | int status = -EOPNOTSUPP; | |
411 | ||
412 | mutex_lock(&common->mutex); | |
686a2541 JM |
413 | |
414 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) | |
415 | status = rsi_channel_change(hw); | |
416 | ||
dad0d04f FF |
417 | mutex_unlock(&common->mutex); |
418 | ||
419 | return status; | |
420 | } | |
421 | ||
422 | /** | |
423 | * rsi_get_connected_channel() - This function is used to get the current | |
424 | * connected channel number. | |
425 | * @adapter: Pointer to the adapter structure. | |
426 | * | |
427 | * Return: Current connected AP's channel number is returned. | |
428 | */ | |
429 | u16 rsi_get_connected_channel(struct rsi_hw *adapter) | |
430 | { | |
431 | struct ieee80211_vif *vif = adapter->vifs[0]; | |
432 | if (vif) { | |
433 | struct ieee80211_bss_conf *bss = &vif->bss_conf; | |
434 | struct ieee80211_channel *channel = bss->chandef.chan; | |
435 | return channel->hw_value; | |
436 | } | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
441 | /** | |
442 | * rsi_mac80211_bss_info_changed() - This function is a handler for config | |
443 | * requests related to BSS parameters that | |
444 | * may vary during BSS's lifespan. | |
445 | * @hw: Pointer to the ieee80211_hw structure. | |
446 | * @vif: Pointer to the ieee80211_vif structure. | |
447 | * @bss_conf: Pointer to the ieee80211_bss_conf structure. | |
448 | * @changed: Changed flags set. | |
449 | * | |
450 | * Return: None. | |
451 | */ | |
452 | static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, | |
453 | struct ieee80211_vif *vif, | |
454 | struct ieee80211_bss_conf *bss_conf, | |
455 | u32 changed) | |
456 | { | |
457 | struct rsi_hw *adapter = hw->priv; | |
458 | struct rsi_common *common = adapter->priv; | |
459 | ||
460 | mutex_lock(&common->mutex); | |
461 | if (changed & BSS_CHANGED_ASSOC) { | |
462 | rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", | |
463 | __func__, bss_conf->assoc); | |
464 | rsi_inform_bss_status(common, | |
465 | bss_conf->assoc, | |
466 | bss_conf->bssid, | |
467 | bss_conf->qos, | |
468 | bss_conf->aid); | |
469 | } | |
686a2541 JM |
470 | |
471 | if (changed & BSS_CHANGED_CQM) { | |
472 | common->cqm_info.last_cqm_event_rssi = 0; | |
473 | common->cqm_info.rssi_thold = bss_conf->cqm_rssi_thold; | |
474 | common->cqm_info.rssi_hyst = bss_conf->cqm_rssi_hyst; | |
475 | rsi_dbg(INFO_ZONE, "RSSI throld & hysteresis are: %d %d\n", | |
476 | common->cqm_info.rssi_thold, | |
477 | common->cqm_info.rssi_hyst); | |
478 | } | |
dad0d04f FF |
479 | mutex_unlock(&common->mutex); |
480 | } | |
481 | ||
482 | /** | |
483 | * rsi_mac80211_conf_filter() - This function configure the device's RX filter. | |
484 | * @hw: Pointer to the ieee80211_hw structure. | |
485 | * @changed: Changed flags set. | |
486 | * @total_flags: Total initial flags set. | |
487 | * @multicast: Multicast. | |
488 | * | |
489 | * Return: None. | |
490 | */ | |
491 | static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, | |
492 | u32 changed_flags, | |
493 | u32 *total_flags, | |
494 | u64 multicast) | |
495 | { | |
496 | /* Not doing much here as of now */ | |
497 | *total_flags &= RSI_SUPP_FILTERS; | |
498 | } | |
499 | ||
500 | /** | |
501 | * rsi_mac80211_conf_tx() - This function configures TX queue parameters | |
502 | * (EDCF (aifs, cw_min, cw_max), bursting) | |
503 | * for a hardware TX queue. | |
504 | * @hw: Pointer to the ieee80211_hw structure | |
505 | * @vif: Pointer to the ieee80211_vif structure. | |
506 | * @queue: Queue number. | |
507 | * @params: Pointer to ieee80211_tx_queue_params structure. | |
508 | * | |
509 | * Return: 0 on success, negative error code on failure. | |
510 | */ | |
511 | static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, | |
512 | struct ieee80211_vif *vif, u16 queue, | |
513 | const struct ieee80211_tx_queue_params *params) | |
514 | { | |
515 | struct rsi_hw *adapter = hw->priv; | |
516 | struct rsi_common *common = adapter->priv; | |
517 | u8 idx = 0; | |
518 | ||
519 | if (queue >= IEEE80211_NUM_ACS) | |
520 | return 0; | |
521 | ||
522 | rsi_dbg(INFO_ZONE, | |
523 | "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", | |
524 | __func__, queue, params->aifs, | |
525 | params->cw_min, params->cw_max, params->txop); | |
526 | ||
527 | mutex_lock(&common->mutex); | |
528 | /* Map into the way the f/w expects */ | |
529 | switch (queue) { | |
530 | case IEEE80211_AC_VO: | |
531 | idx = VO_Q; | |
532 | break; | |
533 | case IEEE80211_AC_VI: | |
534 | idx = VI_Q; | |
535 | break; | |
536 | case IEEE80211_AC_BE: | |
537 | idx = BE_Q; | |
538 | break; | |
539 | case IEEE80211_AC_BK: | |
540 | idx = BK_Q; | |
541 | break; | |
542 | default: | |
543 | idx = BE_Q; | |
544 | break; | |
545 | } | |
546 | ||
547 | memcpy(&common->edca_params[idx], | |
548 | params, | |
549 | sizeof(struct ieee80211_tx_queue_params)); | |
550 | mutex_unlock(&common->mutex); | |
551 | ||
552 | return 0; | |
553 | } | |
554 | ||
555 | /** | |
556 | * rsi_hal_key_config() - This function loads the keys into the firmware. | |
557 | * @hw: Pointer to the ieee80211_hw structure. | |
558 | * @vif: Pointer to the ieee80211_vif structure. | |
559 | * @key: Pointer to the ieee80211_key_conf structure. | |
560 | * | |
561 | * Return: status: 0 on success, -1 on failure. | |
562 | */ | |
563 | static int rsi_hal_key_config(struct ieee80211_hw *hw, | |
564 | struct ieee80211_vif *vif, | |
565 | struct ieee80211_key_conf *key) | |
566 | { | |
567 | struct rsi_hw *adapter = hw->priv; | |
568 | int status; | |
569 | u8 key_type; | |
570 | ||
571 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
572 | key_type = RSI_PAIRWISE_KEY; | |
573 | else | |
574 | key_type = RSI_GROUP_KEY; | |
575 | ||
576 | rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", | |
577 | __func__, key->cipher, key_type, key->keylen); | |
578 | ||
579 | if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || | |
580 | (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { | |
581 | status = rsi_hal_load_key(adapter->priv, | |
582 | key->key, | |
583 | key->keylen, | |
584 | RSI_PAIRWISE_KEY, | |
585 | key->keyidx, | |
586 | key->cipher); | |
587 | if (status) | |
588 | return status; | |
589 | } | |
590 | return rsi_hal_load_key(adapter->priv, | |
591 | key->key, | |
592 | key->keylen, | |
593 | key_type, | |
594 | key->keyidx, | |
595 | key->cipher); | |
596 | } | |
597 | ||
598 | /** | |
599 | * rsi_mac80211_set_key() - This function sets type of key to be loaded. | |
600 | * @hw: Pointer to the ieee80211_hw structure. | |
601 | * @cmd: enum set_key_cmd. | |
602 | * @vif: Pointer to the ieee80211_vif structure. | |
603 | * @sta: Pointer to the ieee80211_sta structure. | |
604 | * @key: Pointer to the ieee80211_key_conf structure. | |
605 | * | |
606 | * Return: status: 0 on success, negative error code on failure. | |
607 | */ | |
608 | static int rsi_mac80211_set_key(struct ieee80211_hw *hw, | |
609 | enum set_key_cmd cmd, | |
610 | struct ieee80211_vif *vif, | |
611 | struct ieee80211_sta *sta, | |
612 | struct ieee80211_key_conf *key) | |
613 | { | |
614 | struct rsi_hw *adapter = hw->priv; | |
615 | struct rsi_common *common = adapter->priv; | |
616 | struct security_info *secinfo = &common->secinfo; | |
617 | int status; | |
618 | ||
619 | mutex_lock(&common->mutex); | |
620 | switch (cmd) { | |
621 | case SET_KEY: | |
622 | secinfo->security_enable = true; | |
623 | status = rsi_hal_key_config(hw, vif, key); | |
624 | if (status) { | |
625 | mutex_unlock(&common->mutex); | |
626 | return status; | |
627 | } | |
628 | ||
629 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
630 | secinfo->ptk_cipher = key->cipher; | |
631 | else | |
632 | secinfo->gtk_cipher = key->cipher; | |
633 | ||
634 | key->hw_key_idx = key->keyidx; | |
635 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | |
636 | ||
637 | rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); | |
638 | break; | |
639 | ||
640 | case DISABLE_KEY: | |
641 | secinfo->security_enable = false; | |
642 | rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); | |
643 | memset(key, 0, sizeof(struct ieee80211_key_conf)); | |
644 | status = rsi_hal_key_config(hw, vif, key); | |
645 | break; | |
646 | ||
647 | default: | |
648 | status = -EOPNOTSUPP; | |
649 | break; | |
650 | } | |
651 | ||
652 | mutex_unlock(&common->mutex); | |
653 | return status; | |
654 | } | |
655 | ||
656 | /** | |
657 | * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for | |
658 | * the corresponding mlme_action flag and | |
659 | * informs the f/w regarding this. | |
660 | * @hw: Pointer to the ieee80211_hw structure. | |
661 | * @vif: Pointer to the ieee80211_vif structure. | |
50ea05ef | 662 | * @params: Pointer to A-MPDU action parameters |
dad0d04f FF |
663 | * |
664 | * Return: status: 0 on success, negative error code on failure. | |
665 | */ | |
666 | static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, | |
667 | struct ieee80211_vif *vif, | |
50ea05ef | 668 | struct ieee80211_ampdu_params *params) |
dad0d04f FF |
669 | { |
670 | int status = -EOPNOTSUPP; | |
671 | struct rsi_hw *adapter = hw->priv; | |
672 | struct rsi_common *common = adapter->priv; | |
673 | u16 seq_no = 0; | |
674 | u8 ii = 0; | |
50ea05ef SS |
675 | struct ieee80211_sta *sta = params->sta; |
676 | enum ieee80211_ampdu_mlme_action action = params->action; | |
677 | u16 tid = params->tid; | |
678 | u16 *ssn = ¶ms->ssn; | |
679 | u8 buf_size = params->buf_size; | |
dad0d04f FF |
680 | |
681 | for (ii = 0; ii < RSI_MAX_VIFS; ii++) { | |
682 | if (vif == adapter->vifs[ii]) | |
683 | break; | |
684 | } | |
685 | ||
686 | mutex_lock(&common->mutex); | |
687 | rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action); | |
688 | if (ssn != NULL) | |
689 | seq_no = *ssn; | |
690 | ||
691 | switch (action) { | |
692 | case IEEE80211_AMPDU_RX_START: | |
693 | status = rsi_send_aggregation_params_frame(common, | |
694 | tid, | |
695 | seq_no, | |
696 | buf_size, | |
697 | STA_RX_ADDBA_DONE); | |
698 | break; | |
699 | ||
700 | case IEEE80211_AMPDU_RX_STOP: | |
701 | status = rsi_send_aggregation_params_frame(common, | |
702 | tid, | |
703 | 0, | |
704 | buf_size, | |
705 | STA_RX_DELBA); | |
706 | break; | |
707 | ||
708 | case IEEE80211_AMPDU_TX_START: | |
709 | common->vif_info[ii].seq_start = seq_no; | |
710 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
5f407acb | 711 | status = 0; |
dad0d04f FF |
712 | break; |
713 | ||
714 | case IEEE80211_AMPDU_TX_STOP_CONT: | |
715 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | |
716 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | |
717 | status = rsi_send_aggregation_params_frame(common, | |
718 | tid, | |
719 | seq_no, | |
720 | buf_size, | |
721 | STA_TX_DELBA); | |
722 | if (!status) | |
723 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
724 | break; | |
725 | ||
726 | case IEEE80211_AMPDU_TX_OPERATIONAL: | |
727 | status = rsi_send_aggregation_params_frame(common, | |
728 | tid, | |
729 | common->vif_info[ii] | |
730 | .seq_start, | |
731 | buf_size, | |
732 | STA_TX_ADDBA_DONE); | |
733 | break; | |
734 | ||
735 | default: | |
736 | rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__); | |
737 | break; | |
738 | } | |
739 | ||
740 | mutex_unlock(&common->mutex); | |
741 | return status; | |
742 | } | |
743 | ||
744 | /** | |
745 | * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. | |
746 | * @hw: Pointer to the ieee80211_hw structure. | |
747 | * @value: Rts threshold value. | |
748 | * | |
749 | * Return: 0 on success. | |
750 | */ | |
751 | static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, | |
752 | u32 value) | |
753 | { | |
754 | struct rsi_hw *adapter = hw->priv; | |
755 | struct rsi_common *common = adapter->priv; | |
756 | ||
757 | mutex_lock(&common->mutex); | |
758 | common->rts_threshold = value; | |
759 | mutex_unlock(&common->mutex); | |
760 | ||
761 | return 0; | |
762 | } | |
763 | ||
764 | /** | |
765 | * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. | |
766 | * @hw: Pointer to the ieee80211_hw structure | |
767 | * @vif: Pointer to the ieee80211_vif structure. | |
768 | * @mask: Pointer to the cfg80211_bitrate_mask structure. | |
769 | * | |
770 | * Return: 0 on success. | |
771 | */ | |
772 | static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, | |
773 | struct ieee80211_vif *vif, | |
774 | const struct cfg80211_bitrate_mask *mask) | |
775 | { | |
776 | struct rsi_hw *adapter = hw->priv; | |
777 | struct rsi_common *common = adapter->priv; | |
57fbcce3 | 778 | enum nl80211_band band = hw->conf.chandef.chan->band; |
dad0d04f FF |
779 | |
780 | mutex_lock(&common->mutex); | |
85af5bf8 | 781 | common->fixedrate_mask[band] = 0; |
dad0d04f | 782 | |
85af5bf8 JM |
783 | if (mask->control[band].legacy == 0xfff) { |
784 | common->fixedrate_mask[band] = | |
785 | (mask->control[band].ht_mcs[0] << 12); | |
dad0d04f | 786 | } else { |
85af5bf8 JM |
787 | common->fixedrate_mask[band] = |
788 | mask->control[band].legacy; | |
dad0d04f FF |
789 | } |
790 | mutex_unlock(&common->mutex); | |
791 | ||
792 | return 0; | |
793 | } | |
794 | ||
686a2541 JM |
795 | /** |
796 | * rsi_perform_cqm() - This function performs cqm. | |
797 | * @common: Pointer to the driver private structure. | |
798 | * @bssid: pointer to the bssid. | |
799 | * @rssi: RSSI value. | |
800 | */ | |
801 | static void rsi_perform_cqm(struct rsi_common *common, | |
802 | u8 *bssid, | |
803 | s8 rssi) | |
804 | { | |
805 | struct rsi_hw *adapter = common->priv; | |
806 | s8 last_event = common->cqm_info.last_cqm_event_rssi; | |
807 | int thold = common->cqm_info.rssi_thold; | |
808 | u32 hyst = common->cqm_info.rssi_hyst; | |
809 | enum nl80211_cqm_rssi_threshold_event event; | |
810 | ||
811 | if (rssi < thold && (last_event == 0 || rssi < (last_event - hyst))) | |
812 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; | |
813 | else if (rssi > thold && | |
814 | (last_event == 0 || rssi > (last_event + hyst))) | |
815 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | |
816 | else | |
817 | return; | |
818 | ||
819 | common->cqm_info.last_cqm_event_rssi = rssi; | |
820 | rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); | |
821 | ieee80211_cqm_rssi_notify(adapter->vifs[0], event, GFP_KERNEL); | |
822 | ||
823 | return; | |
824 | } | |
825 | ||
dad0d04f FF |
826 | /** |
827 | * rsi_fill_rx_status() - This function fills rx status in | |
828 | * ieee80211_rx_status structure. | |
829 | * @hw: Pointer to the ieee80211_hw structure. | |
830 | * @skb: Pointer to the socket buffer structure. | |
831 | * @common: Pointer to the driver private structure. | |
832 | * @rxs: Pointer to the ieee80211_rx_status structure. | |
833 | * | |
834 | * Return: None. | |
835 | */ | |
836 | static void rsi_fill_rx_status(struct ieee80211_hw *hw, | |
837 | struct sk_buff *skb, | |
838 | struct rsi_common *common, | |
839 | struct ieee80211_rx_status *rxs) | |
840 | { | |
686a2541 | 841 | struct ieee80211_bss_conf *bss = &common->priv->vifs[0]->bss_conf; |
dad0d04f FF |
842 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
843 | struct skb_info *rx_params = (struct skb_info *)info->driver_data; | |
844 | struct ieee80211_hdr *hdr; | |
845 | char rssi = rx_params->rssi; | |
846 | u8 hdrlen = 0; | |
847 | u8 channel = rx_params->channel; | |
848 | s32 freq; | |
849 | ||
850 | hdr = ((struct ieee80211_hdr *)(skb->data)); | |
851 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | |
852 | ||
853 | memset(info, 0, sizeof(struct ieee80211_tx_info)); | |
854 | ||
855 | rxs->signal = -(rssi); | |
856 | ||
aabd3ad4 | 857 | rxs->band = common->band; |
dad0d04f FF |
858 | |
859 | freq = ieee80211_channel_to_frequency(channel, rxs->band); | |
860 | ||
861 | if (freq) | |
862 | rxs->freq = freq; | |
863 | ||
864 | if (ieee80211_has_protected(hdr->frame_control)) { | |
865 | if (rsi_is_cipher_wep(common)) { | |
866 | memmove(skb->data + 4, skb->data, hdrlen); | |
867 | skb_pull(skb, 4); | |
868 | } else { | |
869 | memmove(skb->data + 8, skb->data, hdrlen); | |
870 | skb_pull(skb, 8); | |
871 | rxs->flag |= RX_FLAG_MMIC_STRIPPED; | |
872 | } | |
873 | rxs->flag |= RX_FLAG_DECRYPTED; | |
874 | rxs->flag |= RX_FLAG_IV_STRIPPED; | |
875 | } | |
686a2541 JM |
876 | |
877 | /* CQM only for connected AP beacons, the RSSI is a weighted avg */ | |
878 | if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { | |
879 | if (ieee80211_is_beacon(hdr->frame_control)) | |
880 | rsi_perform_cqm(common, hdr->addr2, rxs->signal); | |
881 | } | |
882 | ||
883 | return; | |
dad0d04f FF |
884 | } |
885 | ||
886 | /** | |
887 | * rsi_indicate_pkt_to_os() - This function sends recieved packet to mac80211. | |
888 | * @common: Pointer to the driver private structure. | |
889 | * @skb: Pointer to the socket buffer structure. | |
890 | * | |
891 | * Return: None. | |
892 | */ | |
893 | void rsi_indicate_pkt_to_os(struct rsi_common *common, | |
894 | struct sk_buff *skb) | |
895 | { | |
896 | struct rsi_hw *adapter = common->priv; | |
897 | struct ieee80211_hw *hw = adapter->hw; | |
898 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | |
899 | ||
900 | if ((common->iface_down) || (!adapter->sc_nvifs)) { | |
901 | dev_kfree_skb(skb); | |
902 | return; | |
903 | } | |
904 | ||
905 | /* filling in the ieee80211_rx_status flags */ | |
906 | rsi_fill_rx_status(hw, skb, common, rx_status); | |
907 | ||
908 | ieee80211_rx_irqsafe(hw, skb); | |
909 | } | |
910 | ||
911 | static void rsi_set_min_rate(struct ieee80211_hw *hw, | |
912 | struct ieee80211_sta *sta, | |
913 | struct rsi_common *common) | |
914 | { | |
915 | u8 band = hw->conf.chandef.chan->band; | |
916 | u8 ii; | |
917 | u32 rate_bitmap; | |
918 | bool matched = false; | |
919 | ||
920 | common->bitrate_mask[band] = sta->supp_rates[band]; | |
921 | ||
922 | rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]); | |
923 | ||
924 | if (rate_bitmap & 0xfff) { | |
925 | /* Find out the min rate */ | |
926 | for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { | |
927 | if (rate_bitmap & BIT(ii)) { | |
928 | common->min_rate = rsi_rates[ii].hw_value; | |
929 | matched = true; | |
930 | break; | |
931 | } | |
932 | } | |
933 | } | |
934 | ||
935 | common->vif_info[0].is_ht = sta->ht_cap.ht_supported; | |
936 | ||
937 | if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) { | |
938 | for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) { | |
939 | if ((rate_bitmap >> 12) & BIT(ii)) { | |
940 | common->min_rate = rsi_mcsrates[ii]; | |
941 | matched = true; | |
942 | break; | |
943 | } | |
944 | } | |
945 | } | |
946 | ||
947 | if (!matched) | |
948 | common->min_rate = 0xffff; | |
949 | } | |
950 | ||
951 | /** | |
952 | * rsi_mac80211_sta_add() - This function notifies driver about a peer getting | |
953 | * connected. | |
954 | * @hw: pointer to the ieee80211_hw structure. | |
955 | * @vif: Pointer to the ieee80211_vif structure. | |
956 | * @sta: Pointer to the ieee80211_sta structure. | |
957 | * | |
958 | * Return: 0 on success, -1 on failure. | |
959 | */ | |
960 | static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, | |
961 | struct ieee80211_vif *vif, | |
962 | struct ieee80211_sta *sta) | |
963 | { | |
964 | struct rsi_hw *adapter = hw->priv; | |
965 | struct rsi_common *common = adapter->priv; | |
966 | ||
967 | mutex_lock(&common->mutex); | |
968 | ||
969 | rsi_set_min_rate(hw, sta, common); | |
970 | ||
971 | if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || | |
972 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) { | |
973 | common->vif_info[0].sgi = true; | |
974 | } | |
975 | ||
976 | if (sta->ht_cap.ht_supported) | |
977 | ieee80211_start_tx_ba_session(sta, 0, 0); | |
978 | ||
979 | mutex_unlock(&common->mutex); | |
980 | ||
981 | return 0; | |
982 | } | |
983 | ||
984 | /** | |
985 | * rsi_mac80211_sta_remove() - This function notifies driver about a peer | |
986 | * getting disconnected. | |
987 | * @hw: Pointer to the ieee80211_hw structure. | |
988 | * @vif: Pointer to the ieee80211_vif structure. | |
989 | * @sta: Pointer to the ieee80211_sta structure. | |
990 | * | |
991 | * Return: 0 on success, -1 on failure. | |
992 | */ | |
993 | static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, | |
994 | struct ieee80211_vif *vif, | |
995 | struct ieee80211_sta *sta) | |
996 | { | |
997 | struct rsi_hw *adapter = hw->priv; | |
998 | struct rsi_common *common = adapter->priv; | |
999 | ||
1000 | mutex_lock(&common->mutex); | |
1001 | /* Resetting all the fields to default values */ | |
57fbcce3 JB |
1002 | common->bitrate_mask[NL80211_BAND_2GHZ] = 0; |
1003 | common->bitrate_mask[NL80211_BAND_5GHZ] = 0; | |
dad0d04f FF |
1004 | common->min_rate = 0xffff; |
1005 | common->vif_info[0].is_ht = false; | |
1006 | common->vif_info[0].sgi = false; | |
1007 | common->vif_info[0].seq_start = 0; | |
1008 | common->secinfo.ptk_cipher = 0; | |
1009 | common->secinfo.gtk_cipher = 0; | |
1010 | mutex_unlock(&common->mutex); | |
1011 | ||
1012 | return 0; | |
1013 | } | |
1014 | ||
1015 | static struct ieee80211_ops mac80211_ops = { | |
1016 | .tx = rsi_mac80211_tx, | |
1017 | .start = rsi_mac80211_start, | |
1018 | .stop = rsi_mac80211_stop, | |
1019 | .add_interface = rsi_mac80211_add_interface, | |
1020 | .remove_interface = rsi_mac80211_remove_interface, | |
1021 | .config = rsi_mac80211_config, | |
1022 | .bss_info_changed = rsi_mac80211_bss_info_changed, | |
1023 | .conf_tx = rsi_mac80211_conf_tx, | |
1024 | .configure_filter = rsi_mac80211_conf_filter, | |
1025 | .set_key = rsi_mac80211_set_key, | |
1026 | .set_rts_threshold = rsi_mac80211_set_rts_threshold, | |
1027 | .set_bitrate_mask = rsi_mac80211_set_rate_mask, | |
1028 | .ampdu_action = rsi_mac80211_ampdu_action, | |
1029 | .sta_add = rsi_mac80211_sta_add, | |
1030 | .sta_remove = rsi_mac80211_sta_remove, | |
1031 | }; | |
1032 | ||
1033 | /** | |
1034 | * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. | |
1035 | * @common: Pointer to the driver private structure. | |
1036 | * | |
1037 | * Return: 0 on success, -1 on failure. | |
1038 | */ | |
1039 | int rsi_mac80211_attach(struct rsi_common *common) | |
1040 | { | |
1041 | int status = 0; | |
1042 | struct ieee80211_hw *hw = NULL; | |
1043 | struct wiphy *wiphy = NULL; | |
1044 | struct rsi_hw *adapter = common->priv; | |
1045 | u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; | |
1046 | ||
1047 | rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); | |
1048 | ||
1049 | hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); | |
1050 | if (!hw) { | |
1051 | rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); | |
1052 | return -ENOMEM; | |
1053 | } | |
1054 | ||
1055 | wiphy = hw->wiphy; | |
1056 | ||
1057 | SET_IEEE80211_DEV(hw, adapter->device); | |
1058 | ||
1059 | hw->priv = adapter; | |
1060 | adapter->hw = hw; | |
1061 | ||
30686bf7 JB |
1062 | ieee80211_hw_set(hw, SIGNAL_DBM); |
1063 | ieee80211_hw_set(hw, HAS_RATE_CONTROL); | |
1064 | ieee80211_hw_set(hw, AMPDU_AGGREGATION); | |
dad0d04f FF |
1065 | |
1066 | hw->queues = MAX_HW_QUEUES; | |
1067 | hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; | |
1068 | ||
1069 | hw->max_rates = 1; | |
1070 | hw->max_rate_tries = MAX_RETRIES; | |
1071 | ||
1072 | hw->max_tx_aggregation_subframes = 6; | |
57fbcce3 JB |
1073 | rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); |
1074 | rsi_register_rates_channels(adapter, NL80211_BAND_5GHZ); | |
dad0d04f FF |
1075 | hw->rate_control_algorithm = "AARF"; |
1076 | ||
1077 | SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); | |
1078 | ether_addr_copy(hw->wiphy->addr_mask, addr_mask); | |
1079 | ||
1080 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
1081 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | |
1082 | wiphy->retry_short = RETRY_SHORT; | |
1083 | wiphy->retry_long = RETRY_LONG; | |
1084 | wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | |
1085 | wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | |
1086 | wiphy->flags = 0; | |
1087 | ||
1088 | wiphy->available_antennas_rx = 1; | |
1089 | wiphy->available_antennas_tx = 1; | |
57fbcce3 JB |
1090 | wiphy->bands[NL80211_BAND_2GHZ] = |
1091 | &adapter->sbands[NL80211_BAND_2GHZ]; | |
1092 | wiphy->bands[NL80211_BAND_5GHZ] = | |
1093 | &adapter->sbands[NL80211_BAND_5GHZ]; | |
dad0d04f FF |
1094 | |
1095 | status = ieee80211_register_hw(hw); | |
1096 | if (status) | |
1097 | return status; | |
1098 | ||
1099 | return rsi_init_dbgfs(adapter); | |
1100 | } |