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 mwifiex_send_cmd(priv
, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG
,
245 HostCmd_ACT_GEN_REMOVE
, 0, NULL
, false);
248 static int mwifiex_parse_tdls_event(struct mwifiex_private
*priv
,
249 struct sk_buff
*event_skb
)
252 struct mwifiex_adapter
*adapter
= priv
->adapter
;
253 struct mwifiex_sta_node
*sta_ptr
;
254 struct mwifiex_tdls_generic_event
*tdls_evt
=
255 (void *)event_skb
->data
+ sizeof(adapter
->event_cause
);
256 u8
*mac
= tdls_evt
->peer_mac
;
258 /* reserved 2 bytes are not mandatory in tdls event */
259 if (event_skb
->len
< (sizeof(struct mwifiex_tdls_generic_event
) -
260 sizeof(u16
) - sizeof(adapter
->event_cause
))) {
261 mwifiex_dbg(adapter
, ERROR
, "Invalid event length!\n");
265 sta_ptr
= mwifiex_get_sta_entry(priv
, tdls_evt
->peer_mac
);
267 mwifiex_dbg(adapter
, ERROR
, "cannot get sta entry!\n");
271 switch (le16_to_cpu(tdls_evt
->type
)) {
272 case TDLS_EVENT_LINK_TEAR_DOWN
:
273 cfg80211_tdls_oper_request(priv
->netdev
,
275 NL80211_TDLS_TEARDOWN
,
276 le16_to_cpu(tdls_evt
->u
.reason_code
),
279 case TDLS_EVENT_CHAN_SWITCH_RESULT
:
280 mwifiex_dbg(adapter
, EVENT
, "tdls channel switch result :\n");
281 mwifiex_dbg(adapter
, EVENT
,
282 "status=0x%x, reason=0x%x cur_chan=%d\n",
283 tdls_evt
->u
.switch_result
.status
,
284 tdls_evt
->u
.switch_result
.reason
,
285 tdls_evt
->u
.switch_result
.cur_chan
);
287 /* tdls channel switch failed */
288 if (tdls_evt
->u
.switch_result
.status
!= 0) {
289 switch (tdls_evt
->u
.switch_result
.cur_chan
) {
290 case TDLS_BASE_CHANNEL
:
291 sta_ptr
->tdls_status
= TDLS_IN_BASE_CHAN
;
293 case TDLS_OFF_CHANNEL
:
294 sta_ptr
->tdls_status
= TDLS_IN_OFF_CHAN
;
302 /* tdls channel switch success */
303 switch (tdls_evt
->u
.switch_result
.cur_chan
) {
304 case TDLS_BASE_CHANNEL
:
305 if (sta_ptr
->tdls_status
== TDLS_IN_BASE_CHAN
)
307 mwifiex_update_ralist_tx_pause_in_tdls_cs(priv
, mac
,
309 sta_ptr
->tdls_status
= TDLS_IN_BASE_CHAN
;
311 case TDLS_OFF_CHANNEL
:
312 if (sta_ptr
->tdls_status
== TDLS_IN_OFF_CHAN
)
314 mwifiex_update_ralist_tx_pause_in_tdls_cs(priv
, mac
,
316 sta_ptr
->tdls_status
= TDLS_IN_OFF_CHAN
;
323 case TDLS_EVENT_START_CHAN_SWITCH
:
324 mwifiex_dbg(adapter
, EVENT
, "tdls start channel switch...\n");
325 sta_ptr
->tdls_status
= TDLS_CHAN_SWITCHING
;
327 case TDLS_EVENT_CHAN_SWITCH_STOPPED
:
328 mwifiex_dbg(adapter
, EVENT
,
329 "tdls chan switch stopped, reason=%d\n",
330 tdls_evt
->u
.cs_stop_reason
);
339 static void mwifiex_process_uap_tx_pause(struct mwifiex_private
*priv
,
340 struct mwifiex_ie_types_header
*tlv
)
342 struct mwifiex_tx_pause_tlv
*tp
;
343 struct mwifiex_sta_node
*sta_ptr
;
347 mwifiex_dbg(priv
->adapter
, EVENT
,
348 "uap tx_pause: %pM pause=%d, pkts=%d\n",
349 tp
->peermac
, tp
->tx_pause
,
352 if (ether_addr_equal(tp
->peermac
, priv
->netdev
->dev_addr
)) {
354 priv
->port_open
= false;
356 priv
->port_open
= true;
357 } else if (is_multicast_ether_addr(tp
->peermac
)) {
358 mwifiex_update_ralist_tx_pause(priv
, tp
->peermac
, tp
->tx_pause
);
360 spin_lock_irqsave(&priv
->sta_list_spinlock
, flags
);
361 sta_ptr
= mwifiex_get_sta_entry(priv
, tp
->peermac
);
362 spin_unlock_irqrestore(&priv
->sta_list_spinlock
, flags
);
364 if (sta_ptr
&& sta_ptr
->tx_pause
!= tp
->tx_pause
) {
365 sta_ptr
->tx_pause
= tp
->tx_pause
;
366 mwifiex_update_ralist_tx_pause(priv
, tp
->peermac
,
372 static void mwifiex_process_sta_tx_pause(struct mwifiex_private
*priv
,
373 struct mwifiex_ie_types_header
*tlv
)
375 struct mwifiex_tx_pause_tlv
*tp
;
376 struct mwifiex_sta_node
*sta_ptr
;
381 mwifiex_dbg(priv
->adapter
, EVENT
,
382 "sta tx_pause: %pM pause=%d, pkts=%d\n",
383 tp
->peermac
, tp
->tx_pause
,
386 if (ether_addr_equal(tp
->peermac
, priv
->cfg_bssid
)) {
388 priv
->port_open
= false;
390 priv
->port_open
= true;
392 if (!ISSUPP_TDLS_ENABLED(priv
->adapter
->fw_cap_info
))
395 status
= mwifiex_get_tdls_link_status(priv
, tp
->peermac
);
396 if (mwifiex_is_tdls_link_setup(status
)) {
397 spin_lock_irqsave(&priv
->sta_list_spinlock
, flags
);
398 sta_ptr
= mwifiex_get_sta_entry(priv
, tp
->peermac
);
399 spin_unlock_irqrestore(&priv
->sta_list_spinlock
, flags
);
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
,
411 void mwifiex_process_multi_chan_event(struct mwifiex_private
*priv
,
412 struct sk_buff
*event_skb
)
414 struct mwifiex_ie_types_multi_chan_info
*chan_info
;
415 struct mwifiex_ie_types_mc_group_info
*grp_info
;
416 struct mwifiex_adapter
*adapter
= priv
->adapter
;
417 struct mwifiex_ie_types_header
*tlv
;
418 u16 tlv_buf_left
, tlv_type
, tlv_len
;
419 int intf_num
, bss_type
, bss_num
, i
;
420 struct mwifiex_private
*intf_priv
;
422 tlv_buf_left
= event_skb
->len
- sizeof(u32
);
423 chan_info
= (void *)event_skb
->data
+ sizeof(u32
);
425 if (le16_to_cpu(chan_info
->header
.type
) != TLV_TYPE_MULTI_CHAN_INFO
||
426 tlv_buf_left
< sizeof(struct mwifiex_ie_types_multi_chan_info
)) {
427 mwifiex_dbg(adapter
, ERROR
,
428 "unknown TLV in chan_info event\n");
432 adapter
->usb_mc_status
= le16_to_cpu(chan_info
->status
);
433 mwifiex_dbg(adapter
, EVENT
, "multi chan operation %s\n",
434 adapter
->usb_mc_status
? "started" : "over");
436 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_multi_chan_info
);
437 tlv
= (struct mwifiex_ie_types_header
*)chan_info
->tlv_buffer
;
439 while (tlv_buf_left
>= (int)sizeof(struct mwifiex_ie_types_header
)) {
440 tlv_type
= le16_to_cpu(tlv
->type
);
441 tlv_len
= le16_to_cpu(tlv
->len
);
442 if ((sizeof(struct mwifiex_ie_types_header
) + tlv_len
) >
444 mwifiex_dbg(adapter
, ERROR
, "wrong tlv: tlvLen=%d,\t"
445 "tlvBufLeft=%d\n", tlv_len
, tlv_buf_left
);
448 if (tlv_type
!= TLV_TYPE_MC_GROUP_INFO
) {
449 mwifiex_dbg(adapter
, ERROR
, "wrong tlv type: 0x%x\n",
454 grp_info
= (struct mwifiex_ie_types_mc_group_info
*)tlv
;
455 intf_num
= grp_info
->intf_num
;
456 for (i
= 0; i
< intf_num
; i
++) {
457 bss_type
= grp_info
->bss_type_numlist
[i
] >> 4;
458 bss_num
= grp_info
->bss_type_numlist
[i
] & BSS_NUM_MASK
;
459 intf_priv
= mwifiex_get_priv_by_id(adapter
, bss_num
,
462 mwifiex_dbg(adapter
, ERROR
,
463 "Invalid bss_type bss_num\t"
464 "in multi channel event\n");
467 if (adapter
->iface_type
== MWIFIEX_USB
) {
470 ep
= grp_info
->hid_num
.usb_ep_num
;
471 if (ep
== MWIFIEX_USB_EP_DATA
||
472 ep
== MWIFIEX_USB_EP_DATA_CH2
)
473 intf_priv
->usb_port
= ep
;
477 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_header
) +
479 tlv
= (void *)((u8
*)tlv
+ tlv_len
+
480 sizeof(struct mwifiex_ie_types_header
));
483 if (adapter
->iface_type
== MWIFIEX_USB
) {
484 adapter
->tx_lock_flag
= true;
485 adapter
->usb_mc_setup
= true;
486 mwifiex_multi_chan_resync(adapter
);
490 void mwifiex_process_tx_pause_event(struct mwifiex_private
*priv
,
491 struct sk_buff
*event_skb
)
493 struct mwifiex_ie_types_header
*tlv
;
494 u16 tlv_type
, tlv_len
;
497 if (!priv
->media_connected
) {
498 mwifiex_dbg(priv
->adapter
, ERROR
,
499 "tx_pause event while disconnected; bss_role=%d\n",
504 tlv_buf_left
= event_skb
->len
- sizeof(u32
);
505 tlv
= (void *)event_skb
->data
+ sizeof(u32
);
507 while (tlv_buf_left
>= (int)sizeof(struct mwifiex_ie_types_header
)) {
508 tlv_type
= le16_to_cpu(tlv
->type
);
509 tlv_len
= le16_to_cpu(tlv
->len
);
510 if ((sizeof(struct mwifiex_ie_types_header
) + tlv_len
) >
512 mwifiex_dbg(priv
->adapter
, ERROR
,
513 "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
514 tlv_len
, tlv_buf_left
);
517 if (tlv_type
== TLV_TYPE_TX_PAUSE
) {
518 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_STA
)
519 mwifiex_process_sta_tx_pause(priv
, tlv
);
521 mwifiex_process_uap_tx_pause(priv
, tlv
);
524 tlv_buf_left
-= sizeof(struct mwifiex_ie_types_header
) +
526 tlv
= (void *)((u8
*)tlv
+ tlv_len
+
527 sizeof(struct mwifiex_ie_types_header
));
533 * This function handles coex events generated by firmware
535 void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private
*priv
,
536 struct sk_buff
*event_skb
)
538 struct mwifiex_adapter
*adapter
= priv
->adapter
;
539 struct mwifiex_ie_types_header
*tlv
;
540 struct mwifiex_ie_types_btcoex_aggr_win_size
*winsizetlv
;
541 struct mwifiex_ie_types_btcoex_scan_time
*scantlv
;
542 s32 len
= event_skb
->len
- sizeof(u32
);
543 u8
*cur_ptr
= event_skb
->data
+ sizeof(u32
);
544 u16 tlv_type
, tlv_len
;
546 while (len
>= sizeof(struct mwifiex_ie_types_header
)) {
547 tlv
= (struct mwifiex_ie_types_header
*)cur_ptr
;
548 tlv_len
= le16_to_cpu(tlv
->len
);
549 tlv_type
= le16_to_cpu(tlv
->type
);
551 if ((tlv_len
+ sizeof(struct mwifiex_ie_types_header
)) > len
)
554 case TLV_BTCOEX_WL_AGGR_WINSIZE
:
556 (struct mwifiex_ie_types_btcoex_aggr_win_size
*)tlv
;
557 adapter
->coex_win_size
= winsizetlv
->coex_win_size
;
558 adapter
->coex_tx_win_size
=
559 winsizetlv
->tx_win_size
;
560 adapter
->coex_rx_win_size
=
561 winsizetlv
->rx_win_size
;
562 mwifiex_coex_ampdu_rxwinsize(adapter
);
563 mwifiex_update_ampdu_txwinsize(adapter
);
566 case TLV_BTCOEX_WL_SCANTIME
:
568 (struct mwifiex_ie_types_btcoex_scan_time
*)tlv
;
569 adapter
->coex_scan
= scantlv
->coex_scan
;
570 adapter
->coex_min_scan_time
= le16_to_cpu(scantlv
->min_scan_time
);
571 adapter
->coex_max_scan_time
= le16_to_cpu(scantlv
->max_scan_time
);
578 len
-= tlv_len
+ sizeof(struct mwifiex_ie_types_header
);
580 sizeof(struct mwifiex_ie_types_header
);
583 dev_dbg(adapter
->dev
, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
584 adapter
->coex_scan
, adapter
->coex_min_scan_time
,
585 adapter
->coex_win_size
, adapter
->coex_tx_win_size
,
586 adapter
->coex_rx_win_size
);
590 * This function handles events generated by firmware.
592 * This is a generic function and handles all events.
594 * Event specific routines are called by this function based
595 * upon the generated event cause.
597 * For the following events, the function just forwards them to upper
598 * layers, optionally recording the change -
599 * - EVENT_LINK_SENSED
600 * - EVENT_MIC_ERR_UNICAST
601 * - EVENT_MIC_ERR_MULTICAST
602 * - EVENT_PORT_RELEASE
608 * - EVENT_DATA_RSSI_LOW
609 * - EVENT_DATA_SNR_LOW
610 * - EVENT_DATA_RSSI_HIGH
611 * - EVENT_DATA_SNR_HIGH
612 * - EVENT_LINK_QUALITY
613 * - EVENT_PRE_BEACON_LOST
614 * - EVENT_IBSS_COALESCED
615 * - EVENT_IBSS_STA_CONNECT
616 * - EVENT_IBSS_STA_DISCONNECT
617 * - EVENT_WEP_ICV_ERR
619 * - EVENT_HOSTWAKE_STAIE
621 * For the following events, no action is taken -
622 * - EVENT_MIB_CHANGED
624 * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL
626 * Rest of the supported events requires driver handling -
627 * - EVENT_DEAUTHENTICATED
628 * - EVENT_DISASSOCIATED
632 * - EVENT_DEEP_SLEEP_AWAKE
634 * - EVENT_ADHOC_BCN_LOST
635 * - EVENT_BG_SCAN_REPORT
636 * - EVENT_WMM_STATUS_CHANGE
639 * - EVENT_BA_STREAM_TIEMOUT
640 * - EVENT_AMSDU_AGGR_CTRL
642 int mwifiex_process_sta_event(struct mwifiex_private
*priv
)
644 struct mwifiex_adapter
*adapter
= priv
->adapter
;
646 u32 eventcause
= adapter
->event_cause
;
647 u16 ctrl
, reason_code
;
648 u8 ibss_sta_addr
[ETH_ALEN
];
649 struct mwifiex_sta_node
*sta_ptr
;
651 switch (eventcause
) {
652 case EVENT_DUMMY_HOST_WAKEUP_SIGNAL
:
653 mwifiex_dbg(adapter
, ERROR
,
654 "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
656 case EVENT_LINK_SENSED
:
657 mwifiex_dbg(adapter
, EVENT
, "event: LINK_SENSED\n");
658 if (!netif_carrier_ok(priv
->netdev
))
659 netif_carrier_on(priv
->netdev
);
660 mwifiex_wake_up_net_dev_queue(priv
->netdev
, adapter
);
663 case EVENT_DEAUTHENTICATED
:
664 mwifiex_dbg(adapter
, EVENT
, "event: Deauthenticated\n");
665 if (priv
->wps
.session_enable
) {
666 mwifiex_dbg(adapter
, INFO
,
667 "info: receive deauth event in wps session\n");
670 adapter
->dbg
.num_event_deauth
++;
671 if (priv
->media_connected
) {
673 le16_to_cpu(*(__le16
*)adapter
->event_body
);
674 mwifiex_reset_connect_state(priv
, reason_code
, true);
678 case EVENT_DISASSOCIATED
:
679 mwifiex_dbg(adapter
, EVENT
, "event: Disassociated\n");
680 if (priv
->wps
.session_enable
) {
681 mwifiex_dbg(adapter
, INFO
,
682 "info: receive disassoc event in wps session\n");
685 adapter
->dbg
.num_event_disassoc
++;
686 if (priv
->media_connected
) {
688 le16_to_cpu(*(__le16
*)adapter
->event_body
);
689 mwifiex_reset_connect_state(priv
, reason_code
, true);
693 case EVENT_LINK_LOST
:
694 mwifiex_dbg(adapter
, EVENT
, "event: Link lost\n");
695 adapter
->dbg
.num_event_link_lost
++;
696 if (priv
->media_connected
) {
698 le16_to_cpu(*(__le16
*)adapter
->event_body
);
699 mwifiex_reset_connect_state(priv
, reason_code
, true);
704 mwifiex_dbg(adapter
, EVENT
, "info: EVENT: SLEEP\n");
706 adapter
->ps_state
= PS_STATE_PRE_SLEEP
;
708 mwifiex_check_ps_cond(adapter
);
712 mwifiex_dbg(adapter
, EVENT
, "info: EVENT: AWAKE\n");
713 if (!adapter
->pps_uapsd_mode
&&
715 (priv
->bss_mode
== NL80211_IFTYPE_ADHOC
)) &&
716 priv
->media_connected
&& adapter
->sleep_period
.period
) {
717 adapter
->pps_uapsd_mode
= true;
718 mwifiex_dbg(adapter
, EVENT
,
719 "event: PPS/UAPSD mode activated\n");
721 adapter
->tx_lock_flag
= false;
722 if (adapter
->pps_uapsd_mode
&& adapter
->gen_null_pkt
) {
723 if (mwifiex_check_last_packet_indication(priv
)) {
724 if (adapter
->data_sent
||
725 (adapter
->if_ops
.is_port_ready
&&
726 !adapter
->if_ops
.is_port_ready(priv
))) {
727 adapter
->ps_state
= PS_STATE_AWAKE
;
728 adapter
->pm_wakeup_card_req
= false;
729 adapter
->pm_wakeup_fw_try
= false;
730 del_timer(&adapter
->wakeup_timer
);
733 if (!mwifiex_send_null_packet
735 MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET
|
736 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET
))
742 adapter
->ps_state
= PS_STATE_AWAKE
;
743 adapter
->pm_wakeup_card_req
= false;
744 adapter
->pm_wakeup_fw_try
= false;
745 del_timer(&adapter
->wakeup_timer
);
749 case EVENT_DEEP_SLEEP_AWAKE
:
750 adapter
->if_ops
.wakeup_complete(adapter
);
751 mwifiex_dbg(adapter
, EVENT
, "event: DS_AWAKE\n");
752 if (adapter
->is_deep_sleep
)
753 adapter
->is_deep_sleep
= false;
756 case EVENT_HS_ACT_REQ
:
757 mwifiex_dbg(adapter
, EVENT
, "event: HS_ACT_REQ\n");
758 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_HS_CFG_ENH
,
762 case EVENT_MIC_ERR_UNICAST
:
763 mwifiex_dbg(adapter
, EVENT
, "event: UNICAST MIC ERROR\n");
764 cfg80211_michael_mic_failure(priv
->netdev
, priv
->cfg_bssid
,
765 NL80211_KEYTYPE_PAIRWISE
,
766 -1, NULL
, GFP_KERNEL
);
769 case EVENT_MIC_ERR_MULTICAST
:
770 mwifiex_dbg(adapter
, EVENT
, "event: MULTICAST MIC ERROR\n");
771 cfg80211_michael_mic_failure(priv
->netdev
, priv
->cfg_bssid
,
772 NL80211_KEYTYPE_GROUP
,
773 -1, NULL
, GFP_KERNEL
);
775 case EVENT_MIB_CHANGED
:
776 case EVENT_INIT_DONE
:
779 case EVENT_ADHOC_BCN_LOST
:
780 mwifiex_dbg(adapter
, EVENT
, "event: ADHOC_BCN_LOST\n");
781 priv
->adhoc_is_link_sensed
= false;
782 mwifiex_clean_txrx(priv
);
783 mwifiex_stop_net_dev_queue(priv
->netdev
, adapter
);
784 if (netif_carrier_ok(priv
->netdev
))
785 netif_carrier_off(priv
->netdev
);
788 case EVENT_BG_SCAN_REPORT
:
789 mwifiex_dbg(adapter
, EVENT
, "event: BGS_REPORT\n");
790 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_BG_SCAN_QUERY
,
791 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
794 case EVENT_BG_SCAN_STOPPED
:
795 dev_dbg(adapter
->dev
, "event: BGS_STOPPED\n");
796 cfg80211_sched_scan_stopped(priv
->wdev
.wiphy
);
797 if (priv
->sched_scanning
)
798 priv
->sched_scanning
= false;
801 case EVENT_PORT_RELEASE
:
802 mwifiex_dbg(adapter
, EVENT
, "event: PORT RELEASE\n");
803 priv
->port_open
= true;
806 case EVENT_EXT_SCAN_REPORT
:
807 mwifiex_dbg(adapter
, EVENT
, "event: EXT_SCAN Report\n");
808 /* We intend to skip this event during suspend, but handle
809 * it in interface disabled case
811 if (adapter
->ext_scan
&& (!priv
->scan_aborting
||
812 !netif_running(priv
->netdev
)))
813 ret
= mwifiex_handle_event_ext_scan_report(priv
,
814 adapter
->event_skb
->data
);
818 case EVENT_WMM_STATUS_CHANGE
:
819 mwifiex_dbg(adapter
, EVENT
, "event: WMM status changed\n");
820 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_WMM_GET_STATUS
,
825 cfg80211_cqm_rssi_notify(priv
->netdev
,
826 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
,
828 mwifiex_send_cmd(priv
, HostCmd_CMD_RSSI_INFO
,
829 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
830 priv
->subsc_evt_rssi_state
= RSSI_LOW_RECVD
;
831 mwifiex_dbg(adapter
, EVENT
, "event: Beacon RSSI_LOW\n");
834 mwifiex_dbg(adapter
, EVENT
, "event: Beacon SNR_LOW\n");
837 mwifiex_dbg(adapter
, EVENT
, "event: MAX_FAIL\n");
839 case EVENT_RSSI_HIGH
:
840 cfg80211_cqm_rssi_notify(priv
->netdev
,
841 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
,
843 mwifiex_send_cmd(priv
, HostCmd_CMD_RSSI_INFO
,
844 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
845 priv
->subsc_evt_rssi_state
= RSSI_HIGH_RECVD
;
846 mwifiex_dbg(adapter
, EVENT
, "event: Beacon RSSI_HIGH\n");
849 mwifiex_dbg(adapter
, EVENT
, "event: Beacon SNR_HIGH\n");
851 case EVENT_DATA_RSSI_LOW
:
852 mwifiex_dbg(adapter
, EVENT
, "event: Data RSSI_LOW\n");
854 case EVENT_DATA_SNR_LOW
:
855 mwifiex_dbg(adapter
, EVENT
, "event: Data SNR_LOW\n");
857 case EVENT_DATA_RSSI_HIGH
:
858 mwifiex_dbg(adapter
, EVENT
, "event: Data RSSI_HIGH\n");
860 case EVENT_DATA_SNR_HIGH
:
861 mwifiex_dbg(adapter
, EVENT
, "event: Data SNR_HIGH\n");
863 case EVENT_LINK_QUALITY
:
864 mwifiex_dbg(adapter
, EVENT
, "event: Link Quality\n");
866 case EVENT_PRE_BEACON_LOST
:
867 mwifiex_dbg(adapter
, EVENT
, "event: Pre-Beacon Lost\n");
869 case EVENT_IBSS_COALESCED
:
870 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_COALESCED\n");
871 ret
= mwifiex_send_cmd(priv
,
872 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS
,
873 HostCmd_ACT_GEN_GET
, 0, NULL
, false);
875 case EVENT_IBSS_STA_CONNECT
:
876 ether_addr_copy(ibss_sta_addr
, adapter
->event_body
+ 2);
877 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_STA_CONNECT %pM\n",
879 sta_ptr
= mwifiex_add_sta_entry(priv
, ibss_sta_addr
);
880 if (sta_ptr
&& adapter
->adhoc_11n_enabled
) {
881 mwifiex_check_ibss_peer_capabilties(priv
, sta_ptr
,
883 if (sta_ptr
->is_11n_enabled
)
884 for (i
= 0; i
< MAX_NUM_TID
; i
++)
885 sta_ptr
->ampdu_sta
[i
] =
886 priv
->aggr_prio_tbl
[i
].ampdu_user
;
888 for (i
= 0; i
< MAX_NUM_TID
; i
++)
889 sta_ptr
->ampdu_sta
[i
] =
890 BA_STREAM_NOT_ALLOWED
;
891 memset(sta_ptr
->rx_seq
, 0xff, sizeof(sta_ptr
->rx_seq
));
895 case EVENT_IBSS_STA_DISCONNECT
:
896 ether_addr_copy(ibss_sta_addr
, adapter
->event_body
+ 2);
897 mwifiex_dbg(adapter
, EVENT
, "event: IBSS_STA_DISCONNECT %pM\n",
899 sta_ptr
= mwifiex_get_sta_entry(priv
, ibss_sta_addr
);
900 if (sta_ptr
&& sta_ptr
->is_11n_enabled
) {
901 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv
,
903 mwifiex_del_tx_ba_stream_tbl_by_ra(priv
, ibss_sta_addr
);
905 mwifiex_wmm_del_peer_ra_list(priv
, ibss_sta_addr
);
906 mwifiex_del_sta_entry(priv
, ibss_sta_addr
);
909 mwifiex_dbg(adapter
, EVENT
, "event: ADDBA Request\n");
910 mwifiex_send_cmd(priv
, HostCmd_CMD_11N_ADDBA_RSP
,
911 HostCmd_ACT_GEN_SET
, 0,
912 adapter
->event_body
, false);
915 mwifiex_dbg(adapter
, EVENT
, "event: DELBA Request\n");
916 mwifiex_11n_delete_ba_stream(priv
, adapter
->event_body
);
918 case EVENT_BA_STREAM_TIEMOUT
:
919 mwifiex_dbg(adapter
, EVENT
, "event: BA Stream timeout\n");
920 mwifiex_11n_ba_stream_timeout(priv
,
921 (struct host_cmd_ds_11n_batimeout
923 adapter
->event_body
);
925 case EVENT_AMSDU_AGGR_CTRL
:
926 ctrl
= le16_to_cpu(*(__le16
*)adapter
->event_body
);
927 mwifiex_dbg(adapter
, EVENT
,
928 "event: AMSDU_AGGR_CTRL %d\n", ctrl
);
930 adapter
->tx_buf_size
=
931 min_t(u16
, adapter
->curr_tx_buf_size
, ctrl
);
932 mwifiex_dbg(adapter
, EVENT
, "event: tx_buf_size %d\n",
933 adapter
->tx_buf_size
);
936 case EVENT_WEP_ICV_ERR
:
937 mwifiex_dbg(adapter
, EVENT
, "event: WEP ICV error\n");
940 case EVENT_BW_CHANGE
:
941 mwifiex_dbg(adapter
, EVENT
, "event: BW Change\n");
944 case EVENT_HOSTWAKE_STAIE
:
945 mwifiex_dbg(adapter
, EVENT
,
946 "event: HOSTWAKE_STAIE %d\n", eventcause
);
949 case EVENT_REMAIN_ON_CHAN_EXPIRED
:
950 mwifiex_dbg(adapter
, EVENT
,
951 "event: Remain on channel expired\n");
952 cfg80211_remain_on_channel_expired(&priv
->wdev
,
953 priv
->roc_cfg
.cookie
,
957 memset(&priv
->roc_cfg
, 0x00, sizeof(struct mwifiex_roc_cfg
));
961 case EVENT_CHANNEL_SWITCH_ANN
:
962 mwifiex_dbg(adapter
, EVENT
, "event: Channel Switch Announcement\n");
963 priv
->csa_expire_time
=
964 jiffies
+ msecs_to_jiffies(DFS_CHAN_MOVE_TIME
);
965 priv
->csa_chan
= priv
->curr_bss_params
.bss_descriptor
.channel
;
966 ret
= mwifiex_send_cmd(priv
, HostCmd_CMD_802_11_DEAUTHENTICATE
,
967 HostCmd_ACT_GEN_SET
, 0,
968 priv
->curr_bss_params
.bss_descriptor
.mac_address
,
972 case EVENT_TDLS_GENERIC_EVENT
:
973 ret
= mwifiex_parse_tdls_event(priv
, adapter
->event_skb
);
976 case EVENT_TX_DATA_PAUSE
:
977 mwifiex_dbg(adapter
, EVENT
, "event: TX DATA PAUSE\n");
978 mwifiex_process_tx_pause_event(priv
, adapter
->event_skb
);
981 case EVENT_MULTI_CHAN_INFO
:
982 mwifiex_dbg(adapter
, EVENT
, "event: multi-chan info\n");
983 mwifiex_process_multi_chan_event(priv
, adapter
->event_skb
);
986 case EVENT_TX_STATUS_REPORT
:
987 mwifiex_dbg(adapter
, EVENT
, "event: TX_STATUS Report\n");
988 mwifiex_parse_tx_status_event(priv
, adapter
->event_body
);
991 case EVENT_CHANNEL_REPORT_RDY
:
992 mwifiex_dbg(adapter
, EVENT
, "event: Channel Report\n");
993 ret
= mwifiex_11h_handle_chanrpt_ready(priv
,
996 case EVENT_RADAR_DETECTED
:
997 mwifiex_dbg(adapter
, EVENT
, "event: Radar detected\n");
998 ret
= mwifiex_11h_handle_radar_detected(priv
,
1001 case EVENT_BT_COEX_WLAN_PARA_CHANGE
:
1002 dev_dbg(adapter
->dev
, "EVENT: BT coex wlan param update\n");
1003 mwifiex_bt_coex_wlan_param_update_event(priv
,
1004 adapter
->event_skb
);
1006 case EVENT_RXBA_SYNC
:
1007 dev_dbg(adapter
->dev
, "EVENT: RXBA_SYNC\n");
1008 mwifiex_11n_rxba_sync_event(priv
, adapter
->event_body
,
1009 adapter
->event_skb
->len
-
1010 sizeof(eventcause
));
1013 mwifiex_dbg(adapter
, ERROR
, "event: unknown event id: %#x\n",