2 * Marvell Wireless LAN device driver: station event handling
4 * Copyright (C) 2011-2014, Marvell International Ltd.
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
28 #define MWIFIEX_IBSS_CONNECT_EVT_FIX_SIZE 12
30 static int mwifiex_check_ibss_peer_capabilties(struct mwifiex_private
*priv
,
31 struct mwifiex_sta_node
*sta_ptr
,
32 struct sk_buff
*event
)
36 struct ieee_types_header
*ele_hdr
;
37 struct mwifiex_ie_types_mgmt_frame
*tlv_mgmt_frame
;
38 const struct ieee80211_ht_cap
*ht_cap
;
39 const struct ieee80211_vht_cap
*vht_cap
;
41 skb_pull(event
, MWIFIEX_IBSS_CONNECT_EVT_FIX_SIZE
);
45 mwifiex_dbg_dump(priv
->adapter
, EVT_D
, "ibss peer capabilties:",
46 event
->data
, event
->len
);
48 skb_push(event
, MWIFIEX_IBSS_CONNECT_EVT_FIX_SIZE
);
50 tlv_mgmt_frame
= (void *)curr
;
51 if (evt_len
>= sizeof(*tlv_mgmt_frame
) &&
52 le16_to_cpu(tlv_mgmt_frame
->header
.type
) ==
53 TLV_TYPE_UAP_MGMT_FRAME
) {
54 /* Locate curr pointer to the start of beacon tlv,
55 * timestamp 8 bytes, beacon intervel 2 bytes,
56 * capability info 2 bytes, totally 12 byte beacon header
58 evt_len
= le16_to_cpu(tlv_mgmt_frame
->header
.len
);
59 curr
+= (sizeof(*tlv_mgmt_frame
) + 12);
61 mwifiex_dbg(priv
->adapter
, MSG
,
62 "management frame tlv not found!\n");
66 while (evt_len
>= sizeof(*ele_hdr
)) {
67 ele_hdr
= (struct ieee_types_header
*)curr
;
68 ele_len
= ele_hdr
->len
;
70 if (evt_len
< ele_len
+ sizeof(*ele_hdr
))
73 switch (ele_hdr
->element_id
) {
74 case WLAN_EID_HT_CAPABILITY
:
75 sta_ptr
->is_11n_enabled
= true;
76 ht_cap
= (void *)(ele_hdr
+ 2);
77 sta_ptr
->max_amsdu
= le16_to_cpu(ht_cap
->cap_info
) &
78 IEEE80211_HT_CAP_MAX_AMSDU
?
79 MWIFIEX_TX_DATA_BUF_SIZE_8K
:
80 MWIFIEX_TX_DATA_BUF_SIZE_4K
;
81 mwifiex_dbg(priv
->adapter
, INFO
,
82 "11n enabled!, max_amsdu : %d\n",
86 case WLAN_EID_VHT_CAPABILITY
:
87 sta_ptr
->is_11ac_enabled
= true;
88 vht_cap
= (void *)(ele_hdr
+ 2);
89 /* check VHT MAXMPDU capability */
90 switch (le32_to_cpu(vht_cap
->vht_cap_info
) & 0x3) {
91 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
:
93 MWIFIEX_TX_DATA_BUF_SIZE_12K
;
95 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
:
97 MWIFIEX_TX_DATA_BUF_SIZE_8K
;
99 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895
:
101 MWIFIEX_TX_DATA_BUF_SIZE_4K
;
106 mwifiex_dbg(priv
->adapter
, INFO
,
107 "11ac enabled!, max_amsdu : %d\n",
114 curr
+= (ele_len
+ sizeof(*ele_hdr
));
115 evt_len
-= (ele_len
+ sizeof(*ele_hdr
));
122 * This function resets the connection state.
124 * The function is invoked after receiving a disconnect event from firmware,
125 * and performs the following actions -
126 * - Set media status to disconnected
127 * - Clean up Tx and Rx packets
128 * - Resets SNR/NF/RSSI value in driver
129 * - Resets security configurations in driver
130 * - Enables auto data rate
131 * - Saves the previous SSID and BSSID so that they can
132 * be used for re-association, if required
133 * - Erases current SSID and BSSID information
134 * - Sends a disconnect event to upper layers/applications.
136 void mwifiex_reset_connect_state(struct mwifiex_private
*priv
, u16 reason_code
,
139 struct mwifiex_adapter
*adapter
= priv
->adapter
;
141 if (!priv
->media_connected
)
144 mwifiex_dbg(adapter
, INFO
,
145 "info: handles disconnect event\n");
147 priv
->media_connected
= false;
149 priv
->scan_block
= false;
150 priv
->port_open
= false;
152 if ((GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_STA
) &&
153 ISSUPP_TDLS_ENABLED(priv
->adapter
->fw_cap_info
)) {
154 mwifiex_disable_all_tdls_links(priv
);
156 if (priv
->adapter
->auto_tdls
)
157 mwifiex_clean_auto_tdls(priv
);
160 /* Free Tx and Rx packets, report disconnect to upper layer */
161 mwifiex_clean_txrx(priv
);
163 /* Reset SNR/NF/RSSI values */
164 priv
->data_rssi_last
= 0;
165 priv
->data_nf_last
= 0;
166 priv
->data_rssi_avg
= 0;
167 priv
->data_nf_avg
= 0;
168 priv
->bcn_rssi_last
= 0;
169 priv
->bcn_nf_last
= 0;
170 priv
->bcn_rssi_avg
= 0;
171 priv
->bcn_nf_avg
= 0;
173 priv
->rxpd_htinfo
= 0;
174 priv
->sec_info
.wpa_enabled
= false;
175 priv
->sec_info
.wpa2_enabled
= false;
176 priv
->wpa_ie_len
= 0;
178 priv
->sec_info
.wapi_enabled
= false;
179 priv
->wapi_ie_len
= 0;
180 priv
->sec_info
.wapi_key_on
= false;
182 priv
->sec_info
.encryption_mode
= 0;
184 /* Enable auto data rate */
185 priv
->is_data_rate_auto
= true;
188 priv
->assoc_resp_ht_param
= 0;
189 priv
->ht_param_present
= false;
191 if ((GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_STA
||
192 GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
) && priv
->hist_data
)
193 mwifiex_hist_data_reset(priv
);
195 if (priv
->bss_mode
== NL80211_IFTYPE_ADHOC
) {
196 priv
->adhoc_state
= ADHOC_IDLE
;
197 priv
->adhoc_is_link_sensed
= false;
201 * Memorize the previous SSID and BSSID so
202 * it could be used for re-assoc
205 mwifiex_dbg(adapter
, INFO
,
206 "info: previous SSID=%s, SSID len=%u\n",
207 priv
->prev_ssid
.ssid
, priv
->prev_ssid
.ssid_len
);
209 mwifiex_dbg(adapter
, INFO
,
210 "info: current SSID=%s, SSID len=%u\n",
211 priv
->curr_bss_params
.bss_descriptor
.ssid
.ssid
,
212 priv
->curr_bss_params
.bss_descriptor
.ssid
.ssid_len
);
214 memcpy(&priv
->prev_ssid
,
215 &priv
->curr_bss_params
.bss_descriptor
.ssid
,
216 sizeof(struct cfg80211_ssid
));
218 memcpy(priv
->prev_bssid
,
219 priv
->curr_bss_params
.bss_descriptor
.mac_address
, ETH_ALEN
);
221 /* Need to erase the current SSID and BSSID info */
222 memset(&priv
->curr_bss_params
, 0x00, sizeof(priv
->curr_bss_params
));
224 adapter
->tx_lock_flag
= false;
225 adapter
->pps_uapsd_mode
= false;
227 if (adapter
->is_cmd_timedout
&& adapter
->curr_cmd
)
229 priv
->media_connected
= false;
230 mwifiex_dbg(adapter
, MSG
,
231 "info: successfully disconnected from %pM: reason code %d\n",
232 priv
->cfg_bssid
, reason_code
);
233 if (priv
->bss_mode
== NL80211_IFTYPE_STATION
||
234 priv
->bss_mode
== NL80211_IFTYPE_P2P_CLIENT
) {
235 cfg80211_disconnected(priv
->netdev
, reason_code
, NULL
, 0,
236 !from_ap
, GFP_KERNEL
);
238 eth_zero_addr(priv
->cfg_bssid
);
240 mwifiex_stop_net_dev_queue(priv
->netdev
, adapter
);
241 if (netif_carrier_ok(priv
->netdev
))
242 netif_carrier_off(priv
->netdev
);
244 if (!ISSUPP_FIRMWARE_SUPPLICANT(priv
->adapter
->fw_cap_info
))
247 mwifiex_send_cmd(priv
, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG
,
248 HostCmd_ACT_GEN_REMOVE
, 0, NULL
, false);
251 static int mwifiex_parse_tdls_event(struct mwifiex_private
*priv
,
252 struct sk_buff
*event_skb
)
255 struct mwifiex_adapter
*adapter
= priv
->adapter
;
256 struct mwifiex_sta_node
*sta_ptr
;
257 struct mwifiex_tdls_generic_event
*tdls_evt
=
258 (void *)event_skb
->data
+ sizeof(adapter
->event_cause
);
259 u8
*mac
= tdls_evt
->peer_mac
;
261 /* reserved 2 bytes are not mandatory in tdls event */
262 if (event_skb
->len
< (sizeof(struct mwifiex_tdls_generic_event
) -
263 sizeof(u16
) - sizeof(adapter
->event_cause
))) {
264 mwifiex_dbg(adapter
, ERROR
, "Invalid event length!\n");
268 sta_ptr
= mwifiex_get_sta_entry(priv
, tdls_evt
->peer_mac
);
270 mwifiex_dbg(adapter
, ERROR
, "cannot get sta entry!\n");
274 switch (le16_to_cpu(tdls_evt
->type
)) {
275 case TDLS_EVENT_LINK_TEAR_DOWN
:
276 cfg80211_tdls_oper_request(priv
->netdev
,
278 NL80211_TDLS_TEARDOWN
,
279 le16_to_cpu(tdls_evt
->u
.reason_code
),
282 case TDLS_EVENT_CHAN_SWITCH_RESULT
:
283 mwifiex_dbg(adapter
, EVENT
, "tdls channel switch result :\n");
284 mwifiex_dbg(adapter
, EVENT
,
285 "status=0x%x, reason=0x%x cur_chan=%d\n",
286 tdls_evt
->u
.switch_result
.status
,
287 tdls_evt
->u
.switch_result
.reason
,
288 tdls_evt
->u
.switch_result
.cur_chan
);
290 /* tdls channel switch failed */
291 if (tdls_evt
->u
.switch_result
.status
!= 0) {
292 switch (tdls_evt
->u
.switch_result
.cur_chan
) {
293 case TDLS_BASE_CHANNEL
:
294 sta_ptr
->tdls_status
= TDLS_IN_BASE_CHAN
;
296 case TDLS_OFF_CHANNEL
:
297 sta_ptr
->tdls_status
= TDLS_IN_OFF_CHAN
;
305 /* tdls channel switch success */
306 switch (tdls_evt
->u
.switch_result
.cur_chan
) {
307 case TDLS_BASE_CHANNEL
:
308 if (sta_ptr
->tdls_status
== TDLS_IN_BASE_CHAN
)
310 mwifiex_update_ralist_tx_pause_in_tdls_cs(priv
, mac
,
312 sta_ptr
->tdls_status
= TDLS_IN_BASE_CHAN
;
314 case TDLS_OFF_CHANNEL
:
315 if (sta_ptr
->tdls_status
== TDLS_IN_OFF_CHAN
)
317 mwifiex_update_ralist_tx_pause_in_tdls_cs(priv
, mac
,
319 sta_ptr
->tdls_status
= TDLS_IN_OFF_CHAN
;
326 case TDLS_EVENT_START_CHAN_SWITCH
:
327 mwifiex_dbg(adapter
, EVENT
, "tdls start channel switch...\n");
328 sta_ptr
->tdls_status
= TDLS_CHAN_SWITCHING
;
330 case TDLS_EVENT_CHAN_SWITCH_STOPPED
:
331 mwifiex_dbg(adapter
, EVENT
,
332 "tdls chan switch stopped, reason=%d\n",
333 tdls_evt
->u
.cs_stop_reason
);
342 static void mwifiex_process_uap_tx_pause(struct mwifiex_private
*priv
,
343 struct mwifiex_ie_types_header
*tlv
)
345 struct mwifiex_tx_pause_tlv
*tp
;
346 struct mwifiex_sta_node
*sta_ptr
;
350 mwifiex_dbg(priv
->adapter
, EVENT
,
351 "uap tx_pause: %pM pause=%d, pkts=%d\n",
352 tp
->peermac
, tp
->tx_pause
,
355 if (ether_addr_equal(tp
->peermac
, priv
->netdev
->dev_addr
)) {
357 priv
->port_open
= false;
359 priv
->port_open
= true;
360 } else if (is_multicast_ether_addr(tp
->peermac
)) {
361 mwifiex_update_ralist_tx_pause(priv
, tp
->peermac
, tp
->tx_pause
);
363 spin_lock_irqsave(&priv
->sta_list_spinlock
, flags
);
364 sta_ptr
= mwifiex_get_sta_entry(priv
, tp
->peermac
);
365 if (sta_ptr
&& sta_ptr
->tx_pause
!= tp
->tx_pause
) {
366 sta_ptr
->tx_pause
= tp
->tx_pause
;
367 mwifiex_update_ralist_tx_pause(priv
, tp
->peermac
,
370 spin_unlock_irqrestore(&priv
->sta_list_spinlock
, flags
);
374 static void mwifiex_process_sta_tx_pause(struct mwifiex_private
*priv
,
375 struct mwifiex_ie_types_header
*tlv
)
377 struct mwifiex_tx_pause_tlv
*tp
;
378 struct mwifiex_sta_node
*sta_ptr
;
383 mwifiex_dbg(priv
->adapter
, EVENT
,
384 "sta tx_pause: %pM pause=%d, pkts=%d\n",
385 tp
->peermac
, tp
->tx_pause
,
388 if (ether_addr_equal(tp
->peermac
, priv
->cfg_bssid
)) {
390 priv
->port_open
= false;
392 priv
->port_open
= true;
394 if (!ISSUPP_TDLS_ENABLED(priv
->adapter
->fw_cap_info
))
397 status
= mwifiex_get_tdls_link_status(priv
, tp
->peermac
);
398 if (mwifiex_is_tdls_link_setup(status
)) {
399 spin_lock_irqsave(&priv
->sta_list_spinlock
, flags
);
400 sta_ptr
= mwifiex_get_sta_entry(priv
, tp
->peermac
);
401 if (sta_ptr
&& sta_ptr
->tx_pause
!= tp
->tx_pause
) {
402 sta_ptr
->tx_pause
= tp
->tx_pause
;
403 mwifiex_update_ralist_tx_pause(priv
,
407 spin_unlock_irqrestore(&priv
->sta_list_spinlock
, flags
);
412 void mwifiex_process_multi_chan_event(struct mwifiex_private
*priv
,
413 struct sk_buff
*event_skb
)
415 struct mwifiex_ie_types_multi_chan_info
*chan_info
;
416 struct mwifiex_ie_types_mc_group_info
*grp_info
;
417 struct mwifiex_adapter
*adapter
= priv
->adapter
;
418 struct mwifiex_ie_types_header
*tlv
;
419 u16 tlv_buf_left
, tlv_type
, tlv_len
;
420 int intf_num
, bss_type
, bss_num
, i
;
421 struct mwifiex_private
*intf_priv
;
423 tlv_buf_left
= event_skb
->len
- sizeof(u32
);
424 chan_info
= (void *)event_skb
->data
+ sizeof(u32
);
426 if (le16_to_cpu(chan_info
->header
.type
) != TLV_TYPE_MULTI_CHAN_INFO
||
427 tlv_buf_left
< sizeof(struct mwifiex_ie_types_multi_chan_info
)) {
428 mwifiex_dbg(adapter
, ERROR
,
429 "unknown TLV in chan_info event\n");
433 adapter
->usb_mc_status
= le16_to_cpu(chan_info
->status
);
434 mwifiex_dbg(adapter
, EVENT
, "multi chan operation %s\n",
435 adapter
->usb_mc_status
? "started" : "over");
437 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_multi_chan_info
);
438 tlv
= (struct mwifiex_ie_types_header
*)chan_info
->tlv_buffer
;
440 while (tlv_buf_left
>= (int)sizeof(struct mwifiex_ie_types_header
)) {
441 tlv_type
= le16_to_cpu(tlv
->type
);
442 tlv_len
= le16_to_cpu(tlv
->len
);
443 if ((sizeof(struct mwifiex_ie_types_header
) + tlv_len
) >
445 mwifiex_dbg(adapter
, ERROR
, "wrong tlv: tlvLen=%d,\t"
446 "tlvBufLeft=%d\n", tlv_len
, tlv_buf_left
);
449 if (tlv_type
!= TLV_TYPE_MC_GROUP_INFO
) {
450 mwifiex_dbg(adapter
, ERROR
, "wrong tlv type: 0x%x\n",
455 grp_info
= (struct mwifiex_ie_types_mc_group_info
*)tlv
;
456 intf_num
= grp_info
->intf_num
;
457 for (i
= 0; i
< intf_num
; i
++) {
458 bss_type
= grp_info
->bss_type_numlist
[i
] >> 4;
459 bss_num
= grp_info
->bss_type_numlist
[i
] & BSS_NUM_MASK
;
460 intf_priv
= mwifiex_get_priv_by_id(adapter
, bss_num
,
463 mwifiex_dbg(adapter
, ERROR
,
464 "Invalid bss_type bss_num\t"
465 "in multi channel event\n");
468 if (adapter
->iface_type
== MWIFIEX_USB
) {
471 ep
= grp_info
->hid_num
.usb_ep_num
;
472 if (ep
== MWIFIEX_USB_EP_DATA
||
473 ep
== MWIFIEX_USB_EP_DATA_CH2
)
474 intf_priv
->usb_port
= ep
;
478 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_header
) +
480 tlv
= (void *)((u8
*)tlv
+ tlv_len
+
481 sizeof(struct mwifiex_ie_types_header
));
484 if (adapter
->iface_type
== MWIFIEX_USB
) {
485 adapter
->tx_lock_flag
= true;
486 adapter
->usb_mc_setup
= true;
487 mwifiex_multi_chan_resync(adapter
);
491 void mwifiex_process_tx_pause_event(struct mwifiex_private
*priv
,
492 struct sk_buff
*event_skb
)
494 struct mwifiex_ie_types_header
*tlv
;
495 u16 tlv_type
, tlv_len
;
498 if (!priv
->media_connected
) {
499 mwifiex_dbg(priv
->adapter
, ERROR
,
500 "tx_pause event while disconnected; bss_role=%d\n",
505 tlv_buf_left
= event_skb
->len
- sizeof(u32
);
506 tlv
= (void *)event_skb
->data
+ sizeof(u32
);
508 while (tlv_buf_left
>= (int)sizeof(struct mwifiex_ie_types_header
)) {
509 tlv_type
= le16_to_cpu(tlv
->type
);
510 tlv_len
= le16_to_cpu(tlv
->len
);
511 if ((sizeof(struct mwifiex_ie_types_header
) + tlv_len
) >
513 mwifiex_dbg(priv
->adapter
, ERROR
,
514 "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
515 tlv_len
, tlv_buf_left
);
518 if (tlv_type
== TLV_TYPE_TX_PAUSE
) {
519 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_STA
)
520 mwifiex_process_sta_tx_pause(priv
, tlv
);
522 mwifiex_process_uap_tx_pause(priv
, tlv
);
525 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_header
) +
527 tlv
= (void *)((u8
*)tlv
+ tlv_len
+
528 sizeof(struct mwifiex_ie_types_header
));
534 * This function handles coex events generated by firmware
536 void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private
*priv
,
537 struct sk_buff
*event_skb
)
539 struct mwifiex_adapter
*adapter
= priv
->adapter
;
540 struct mwifiex_ie_types_header
*tlv
;
541 struct mwifiex_ie_types_btcoex_aggr_win_size
*winsizetlv
;
542 struct mwifiex_ie_types_btcoex_scan_time
*scantlv
;
543 s32 len
= event_skb
->len
- sizeof(u32
);
544 u8
*cur_ptr
= event_skb
->data
+ sizeof(u32
);
545 u16 tlv_type
, tlv_len
;
547 while (len
>= sizeof(struct mwifiex_ie_types_header
)) {
548 tlv
= (struct mwifiex_ie_types_header
*)cur_ptr
;
549 tlv_len
= le16_to_cpu(tlv
->len
);
550 tlv_type
= le16_to_cpu(tlv
->type
);
552 if ((tlv_len
+ sizeof(struct mwifiex_ie_types_header
)) > len
)
555 case TLV_BTCOEX_WL_AGGR_WINSIZE
:
557 (struct mwifiex_ie_types_btcoex_aggr_win_size
*)tlv
;
558 adapter
->coex_win_size
= winsizetlv
->coex_win_size
;
559 adapter
->coex_tx_win_size
=
560 winsizetlv
->tx_win_size
;
561 adapter
->coex_rx_win_size
=
562 winsizetlv
->rx_win_size
;
563 mwifiex_coex_ampdu_rxwinsize(adapter
);
564 mwifiex_update_ampdu_txwinsize(adapter
);
567 case TLV_BTCOEX_WL_SCANTIME
:
569 (struct mwifiex_ie_types_btcoex_scan_time
*)tlv
;
570 adapter
->coex_scan
= scantlv
->coex_scan
;
571 adapter
->coex_min_scan_time
= le16_to_cpu(scantlv
->min_scan_time
);
572 adapter
->coex_max_scan_time
= le16_to_cpu(scantlv
->max_scan_time
);
579 len
-= tlv_len
+ sizeof(struct mwifiex_ie_types_header
);
581 sizeof(struct mwifiex_ie_types_header
);
584 dev_dbg(adapter
->dev
, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
585 adapter
->coex_scan
, adapter
->coex_min_scan_time
,
586 adapter
->coex_win_size
, adapter
->coex_tx_win_size
,
587 adapter
->coex_rx_win_size
);
591 mwifiex_fw_dump_info_event(struct mwifiex_private
*priv
,
592 struct sk_buff
*event_skb
)
594 struct mwifiex_adapter
*adapter
= priv
->adapter
;
595 struct mwifiex_fw_dump_header
*fw_dump_hdr
=
596 (void *)adapter
->event_body
;
598 if (adapter
->iface_type
!= MWIFIEX_USB
) {
599 mwifiex_dbg(adapter
, MSG
,
600 "event is not on usb interface, ignore it\n");
604 if (!adapter
->devdump_data
) {
605 /* When receive the first event, allocate device dump
606 * buffer, dump driver info.
608 adapter
->devdump_data
= vzalloc(MWIFIEX_FW_DUMP_SIZE
);
609 if (!adapter
->devdump_data
) {
610 mwifiex_dbg(adapter
, ERROR
,
611 "vzalloc devdump data failure!\n");
615 mwifiex_drv_info_dump(adapter
);
617 /* If no proceeded event arrive in 10s, upload device
618 * dump data, this will be useful if the end of
619 * transmission event get lost, in this cornel case,
620 * user would still get partial of the dump.
622 mod_timer(&adapter
->devdump_timer
,
623 jiffies
+ msecs_to_jiffies(MWIFIEX_TIMER_10S
));
627 if (adapter
->devdump_len
+ event_skb
->len
>= MWIFIEX_FW_DUMP_SIZE
)
630 memmove(adapter
->devdump_data
+ adapter
->devdump_len
,
631 adapter
->event_skb
->data
, event_skb
->len
);
632 adapter
->devdump_len
+= event_skb
->len
;
634 if (le16_to_cpu(fw_dump_hdr
->type
== FW_DUMP_INFO_ENDED
)) {
635 mwifiex_dbg(adapter
, MSG
,
636 "receive end of transmission flag event!\n");
642 del_timer_sync(&adapter
->devdump_timer
);
643 mwifiex_upload_device_dump(adapter
);
647 * This function handles events generated by firmware.
649 * This is a generic function and handles all events.
651 * Event specific routines are called by this function based
652 * upon the generated event cause.
654 * For the following events, the function just forwards them to upper
655 * layers, optionally recording the change -
656 * - EVENT_LINK_SENSED
657 * - EVENT_MIC_ERR_UNICAST
658 * - EVENT_MIC_ERR_MULTICAST
659 * - EVENT_PORT_RELEASE
665 * - EVENT_DATA_RSSI_LOW
666 * - EVENT_DATA_SNR_LOW
667 * - EVENT_DATA_RSSI_HIGH
668 * - EVENT_DATA_SNR_HIGH
669 * - EVENT_LINK_QUALITY
670 * - EVENT_PRE_BEACON_LOST
671 * - EVENT_IBSS_COALESCED
672 * - EVENT_IBSS_STA_CONNECT
673 * - EVENT_IBSS_STA_DISCONNECT
674 * - EVENT_WEP_ICV_ERR
676 * - EVENT_HOSTWAKE_STAIE
678 * For the following events, no action is taken -
679 * - EVENT_MIB_CHANGED
681 * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL
683 * Rest of the supported events requires driver handling -
684 * - EVENT_DEAUTHENTICATED
685 * - EVENT_DISASSOCIATED
689 * - EVENT_DEEP_SLEEP_AWAKE
691 * - EVENT_ADHOC_BCN_LOST
692 * - EVENT_BG_SCAN_REPORT
693 * - EVENT_WMM_STATUS_CHANGE
696 * - EVENT_BA_STREAM_TIEMOUT
697 * - EVENT_AMSDU_AGGR_CTRL
698 * - EVENT_FW_DUMP_INFO
700 int mwifiex_process_sta_event(struct mwifiex_private
*priv
)
702 struct mwifiex_adapter
*adapter
= priv
->adapter
;
704 u32 eventcause
= adapter
->event_cause
;
705 u16 ctrl
, reason_code
;
706 u8 ibss_sta_addr
[ETH_ALEN
];
707 struct mwifiex_sta_node
*sta_ptr
;
709 switch (eventcause
) {
710 case EVENT_DUMMY_HOST_WAKEUP_SIGNAL
:
711 mwifiex_dbg(adapter
, ERROR
,
712 "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
714 case EVENT_LINK_SENSED
:
715 mwifiex_dbg(adapter
, EVENT
, "event: LINK_SENSED\n");
716 if (!netif_carrier_ok(priv
->netdev
))
717 netif_carrier_on(priv
->netdev
);
718 mwifiex_wake_up_net_dev_queue(priv
->netdev
, adapter
);
721 case EVENT_DEAUTHENTICATED
:
722 mwifiex_dbg(adapter
, EVENT
, "event: Deauthenticated\n");
723 if (priv
->wps
.session_enable
) {
724 mwifiex_dbg(adapter
, INFO
,
725 "info: receive deauth event in wps session\n");
728 adapter
->dbg
.num_event_deauth
++;
729 if (priv
->media_connected
) {
731 get_unaligned_le16(adapter
->event_body
);
732 mwifiex_reset_connect_state(priv
, reason_code
, true);
736 case EVENT_DISASSOCIATED
:
737 mwifiex_dbg(adapter
, EVENT
, "event: Disassociated\n");
738 if (priv
->wps
.session_enable
) {
739 mwifiex_dbg(adapter
, INFO
,
740 "info: receive disassoc event in wps session\n");
743 adapter
->dbg
.num_event_disassoc
++;
744 if (priv
->media_connected
) {
746 get_unaligned_le16(adapter
->event_body
);
747 mwifiex_reset_connect_state(priv
, reason_code
, true);
751 case EVENT_LINK_LOST
:
752 mwifiex_dbg(adapter
, EVENT
, "event: Link lost\n");
753 adapter
->dbg
.num_event_link_lost
++;
754 if (priv
->media_connected
) {
756 get_unaligned_le16(adapter
->event_body
);
757 mwifiex_reset_connect_state(priv
, reason_code
, true);
762 mwifiex_dbg(adapter
, EVENT
, "info: EVENT: SLEEP\n");
764 adapter
->ps_state
= PS_STATE_PRE_SLEEP
;
766 mwifiex_check_ps_cond(adapter
);
770 mwifiex_dbg(adapter
, EVENT
, "info: EVENT: AWAKE\n");
771 if (!adapter
->pps_uapsd_mode
&&
773 (priv
->bss_mode
== NL80211_IFTYPE_ADHOC
)) &&
774 priv
->media_connected
&& adapter
->sleep_period
.period
) {
775 adapter
->pps_uapsd_mode
= true;
776 mwifiex_dbg(adapter
, EVENT
,
777 "event: PPS/UAPSD mode activated\n");
779 adapter
->tx_lock_flag
= false;
780 if (adapter
->pps_uapsd_mode
&& adapter
->gen_null_pkt
) {
781 if (mwifiex_check_last_packet_indication(priv
)) {
782 if (adapter
->data_sent
||
783 (adapter
->if_ops
.is_port_ready
&&
784 !adapter
->if_ops
.is_port_ready(priv
))) {
785 adapter
->ps_state
= PS_STATE_AWAKE
;
786 adapter
->pm_wakeup_card_req
= false;
787 adapter
->pm_wakeup_fw_try
= false;
788 del_timer(&adapter
->wakeup_timer
);
791 if (!mwifiex_send_null_packet
793 MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET
|
794 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET
))
800 adapter
->ps_state
= PS_STATE_AWAKE
;
801 adapter
->pm_wakeup_card_req
= false;
802 adapter
->pm_wakeup_fw_try
= false;
803 del_timer(&adapter
->wakeup_timer
);
807 case EVENT_DEEP_SLEEP_AWAKE
:
808 adapter
->if_ops
.wakeup_complete(adapter
);
809 mwifiex_dbg(adapter
, EVENT
, "event: DS_AWAKE\n");
810 if (adapter
->is_deep_sleep
)
811 adapter
->is_deep_sleep
= false;
814 case EVENT_HS_ACT_REQ
:
815 mwifiex_dbg(adapter
, EVENT
, "event: HS_ACT_REQ\n");
816 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_HS_CFG_ENH
,
820 case EVENT_MIC_ERR_UNICAST
:
821 mwifiex_dbg(adapter
, EVENT
, "event: UNICAST MIC ERROR\n");
822 cfg80211_michael_mic_failure(priv
->netdev
, priv
->cfg_bssid
,
823 NL80211_KEYTYPE_PAIRWISE
,
824 -1, NULL
, GFP_KERNEL
);
827 case EVENT_MIC_ERR_MULTICAST
:
828 mwifiex_dbg(adapter
, EVENT
, "event: MULTICAST MIC ERROR\n");
829 cfg80211_michael_mic_failure(priv
->netdev
, priv
->cfg_bssid
,
830 NL80211_KEYTYPE_GROUP
,
831 -1, NULL
, GFP_KERNEL
);
833 case EVENT_MIB_CHANGED
:
834 case EVENT_INIT_DONE
:
837 case EVENT_ADHOC_BCN_LOST
:
838 mwifiex_dbg(adapter
, EVENT
, "event: ADHOC_BCN_LOST\n");
839 priv
->adhoc_is_link_sensed
= false;
840 mwifiex_clean_txrx(priv
);
841 mwifiex_stop_net_dev_queue(priv
->netdev
, adapter
);
842 if (netif_carrier_ok(priv
->netdev
))
843 netif_carrier_off(priv
->netdev
);
846 case EVENT_BG_SCAN_REPORT
:
847 mwifiex_dbg(adapter
, EVENT
, "event: BGS_REPORT\n");
848 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_BG_SCAN_QUERY
,
849 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
852 case EVENT_BG_SCAN_STOPPED
:
853 dev_dbg(adapter
->dev
, "event: BGS_STOPPED\n");
854 cfg80211_sched_scan_stopped(priv
->wdev
.wiphy
, 0);
855 if (priv
->sched_scanning
)
856 priv
->sched_scanning
= false;
859 case EVENT_PORT_RELEASE
:
860 mwifiex_dbg(adapter
, EVENT
, "event: PORT RELEASE\n");
861 priv
->port_open
= true;
864 case EVENT_EXT_SCAN_REPORT
:
865 mwifiex_dbg(adapter
, EVENT
, "event: EXT_SCAN Report\n");
866 /* We intend to skip this event during suspend, but handle
867 * it in interface disabled case
869 if (adapter
->ext_scan
&& (!priv
->scan_aborting
||
870 !netif_running(priv
->netdev
)))
871 ret
= mwifiex_handle_event_ext_scan_report(priv
,
872 adapter
->event_skb
->data
);
876 case EVENT_WMM_STATUS_CHANGE
:
877 mwifiex_dbg(adapter
, EVENT
, "event: WMM status changed\n");
878 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_WMM_GET_STATUS
,
883 cfg80211_cqm_rssi_notify(priv
->netdev
,
884 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
,
886 mwifiex_send_cmd(priv
, HostCmd_CMD_RSSI_INFO
,
887 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
888 priv
->subsc_evt_rssi_state
= RSSI_LOW_RECVD
;
889 mwifiex_dbg(adapter
, EVENT
, "event: Beacon RSSI_LOW\n");
892 mwifiex_dbg(adapter
, EVENT
, "event: Beacon SNR_LOW\n");
895 mwifiex_dbg(adapter
, EVENT
, "event: MAX_FAIL\n");
897 case EVENT_RSSI_HIGH
:
898 cfg80211_cqm_rssi_notify(priv
->netdev
,
899 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
,
901 mwifiex_send_cmd(priv
, HostCmd_CMD_RSSI_INFO
,
902 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
903 priv
->subsc_evt_rssi_state
= RSSI_HIGH_RECVD
;
904 mwifiex_dbg(adapter
, EVENT
, "event: Beacon RSSI_HIGH\n");
907 mwifiex_dbg(adapter
, EVENT
, "event: Beacon SNR_HIGH\n");
909 case EVENT_DATA_RSSI_LOW
:
910 mwifiex_dbg(adapter
, EVENT
, "event: Data RSSI_LOW\n");
912 case EVENT_DATA_SNR_LOW
:
913 mwifiex_dbg(adapter
, EVENT
, "event: Data SNR_LOW\n");
915 case EVENT_DATA_RSSI_HIGH
:
916 mwifiex_dbg(adapter
, EVENT
, "event: Data RSSI_HIGH\n");
918 case EVENT_DATA_SNR_HIGH
:
919 mwifiex_dbg(adapter
, EVENT
, "event: Data SNR_HIGH\n");
921 case EVENT_LINK_QUALITY
:
922 mwifiex_dbg(adapter
, EVENT
, "event: Link Quality\n");
924 case EVENT_PRE_BEACON_LOST
:
925 mwifiex_dbg(adapter
, EVENT
, "event: Pre-Beacon Lost\n");
927 case EVENT_IBSS_COALESCED
:
928 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_COALESCED\n");
929 ret
= mwifiex_send_cmd(priv
,
930 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS
,
931 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
933 case EVENT_IBSS_STA_CONNECT
:
934 ether_addr_copy(ibss_sta_addr
, adapter
->event_body
+ 2);
935 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_STA_CONNECT %pM\n",
937 sta_ptr
= mwifiex_add_sta_entry(priv
, ibss_sta_addr
);
938 if (sta_ptr
&& adapter
->adhoc_11n_enabled
) {
939 mwifiex_check_ibss_peer_capabilties(priv
, sta_ptr
,
941 if (sta_ptr
->is_11n_enabled
)
942 for (i
= 0; i
< MAX_NUM_TID
; i
++)
943 sta_ptr
->ampdu_sta
[i
] =
944 priv
->aggr_prio_tbl
[i
].ampdu_user
;
946 for (i
= 0; i
< MAX_NUM_TID
; i
++)
947 sta_ptr
->ampdu_sta
[i
] =
948 BA_STREAM_NOT_ALLOWED
;
949 memset(sta_ptr
->rx_seq
, 0xff, sizeof(sta_ptr
->rx_seq
));
953 case EVENT_IBSS_STA_DISCONNECT
:
954 ether_addr_copy(ibss_sta_addr
, adapter
->event_body
+ 2);
955 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_STA_DISCONNECT %pM\n",
957 sta_ptr
= mwifiex_get_sta_entry(priv
, ibss_sta_addr
);
958 if (sta_ptr
&& sta_ptr
->is_11n_enabled
) {
959 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv
,
961 mwifiex_del_tx_ba_stream_tbl_by_ra(priv
, ibss_sta_addr
);
963 mwifiex_wmm_del_peer_ra_list(priv
, ibss_sta_addr
);
964 mwifiex_del_sta_entry(priv
, ibss_sta_addr
);
967 mwifiex_dbg(adapter
, EVENT
, "event: ADDBA Request\n");
968 mwifiex_send_cmd(priv
, HostCmd_CMD_11N_ADDBA_RSP
,
969 HostCmd_ACT_GEN_SET
, 0,
970 adapter
->event_body
, false);
973 mwifiex_dbg(adapter
, EVENT
, "event: DELBA Request\n");
974 mwifiex_11n_delete_ba_stream(priv
, adapter
->event_body
);
976 case EVENT_BA_STREAM_TIEMOUT
:
977 mwifiex_dbg(adapter
, EVENT
, "event: BA Stream timeout\n");
978 mwifiex_11n_ba_stream_timeout(priv
,
979 (struct host_cmd_ds_11n_batimeout
981 adapter
->event_body
);
983 case EVENT_AMSDU_AGGR_CTRL
:
984 ctrl
= get_unaligned_le16(adapter
->event_body
);
985 mwifiex_dbg(adapter
, EVENT
,
986 "event: AMSDU_AGGR_CTRL %d\n", ctrl
);
988 adapter
->tx_buf_size
=
989 min_t(u16
, adapter
->curr_tx_buf_size
, ctrl
);
990 mwifiex_dbg(adapter
, EVENT
, "event: tx_buf_size %d\n",
991 adapter
->tx_buf_size
);
994 case EVENT_WEP_ICV_ERR
:
995 mwifiex_dbg(adapter
, EVENT
, "event: WEP ICV error\n");
998 case EVENT_BW_CHANGE
:
999 mwifiex_dbg(adapter
, EVENT
, "event: BW Change\n");
1002 case EVENT_HOSTWAKE_STAIE
:
1003 mwifiex_dbg(adapter
, EVENT
,
1004 "event: HOSTWAKE_STAIE %d\n", eventcause
);
1007 case EVENT_REMAIN_ON_CHAN_EXPIRED
:
1008 mwifiex_dbg(adapter
, EVENT
,
1009 "event: Remain on channel expired\n");
1010 cfg80211_remain_on_channel_expired(&priv
->wdev
,
1011 priv
->roc_cfg
.cookie
,
1012 &priv
->roc_cfg
.chan
,
1015 memset(&priv
->roc_cfg
, 0x00, sizeof(struct mwifiex_roc_cfg
));
1019 case EVENT_CHANNEL_SWITCH_ANN
:
1020 mwifiex_dbg(adapter
, EVENT
, "event: Channel Switch Announcement\n");
1021 priv
->csa_expire_time
=
1022 jiffies
+ msecs_to_jiffies(DFS_CHAN_MOVE_TIME
);
1023 priv
->csa_chan
= priv
->curr_bss_params
.bss_descriptor
.channel
;
1024 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_DEAUTHENTICATE
,
1025 HostCmd_ACT_GEN_SET
, 0,
1026 priv
->curr_bss_params
.bss_descriptor
.mac_address
,
1030 case EVENT_TDLS_GENERIC_EVENT
:
1031 ret
= mwifiex_parse_tdls_event(priv
, adapter
->event_skb
);
1034 case EVENT_TX_DATA_PAUSE
:
1035 mwifiex_dbg(adapter
, EVENT
, "event: TX DATA PAUSE\n");
1036 mwifiex_process_tx_pause_event(priv
, adapter
->event_skb
);
1039 case EVENT_MULTI_CHAN_INFO
:
1040 mwifiex_dbg(adapter
, EVENT
, "event: multi-chan info\n");
1041 mwifiex_process_multi_chan_event(priv
, adapter
->event_skb
);
1044 case EVENT_TX_STATUS_REPORT
:
1045 mwifiex_dbg(adapter
, EVENT
, "event: TX_STATUS Report\n");
1046 mwifiex_parse_tx_status_event(priv
, adapter
->event_body
);
1049 case EVENT_CHANNEL_REPORT_RDY
:
1050 mwifiex_dbg(adapter
, EVENT
, "event: Channel Report\n");
1051 ret
= mwifiex_11h_handle_chanrpt_ready(priv
,
1052 adapter
->event_skb
);
1054 case EVENT_RADAR_DETECTED
:
1055 mwifiex_dbg(adapter
, EVENT
, "event: Radar detected\n");
1056 ret
= mwifiex_11h_handle_radar_detected(priv
,
1057 adapter
->event_skb
);
1059 case EVENT_BT_COEX_WLAN_PARA_CHANGE
:
1060 dev_dbg(adapter
->dev
, "EVENT: BT coex wlan param update\n");
1061 mwifiex_bt_coex_wlan_param_update_event(priv
,
1062 adapter
->event_skb
);
1064 case EVENT_RXBA_SYNC
:
1065 dev_dbg(adapter
->dev
, "EVENT: RXBA_SYNC\n");
1066 mwifiex_11n_rxba_sync_event(priv
, adapter
->event_body
,
1067 adapter
->event_skb
->len
-
1068 sizeof(eventcause
));
1070 case EVENT_FW_DUMP_INFO
:
1071 mwifiex_dbg(adapter
, EVENT
, "event: firmware debug info\n");
1072 mwifiex_fw_dump_info_event(priv
, adapter
->event_skb
);
1074 /* Debugging event; not used, but let's not print an ERROR for it. */
1075 case EVENT_UNKNOWN_DEBUG
:
1076 mwifiex_dbg(adapter
, EVENT
, "event: debug\n");
1079 mwifiex_dbg(adapter
, ERROR
, "event: unknown event id: %#x\n",