2 * This file contains the handling of command
3 * responses as well as events generated by firmware.
6 #include <linux/hardirq.h>
7 #include <linux/slab.h>
8 #include <linux/delay.h>
9 #include <linux/sched.h>
10 #include <asm/unaligned.h>
11 #include <net/cfg80211.h>
17 * lbs_mac_event_disconnected - handles disconnect event. It
18 * reports disconnect to upper layer, clean tx/rx packets,
19 * reset link state etc.
21 * @priv: A pointer to struct lbs_private structure
25 void lbs_mac_event_disconnected(struct lbs_private
*priv
)
27 if (priv
->connect_status
!= LBS_CONNECTED
)
30 lbs_deb_enter(LBS_DEB_ASSOC
);
33 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
34 * It causes problem in the Supplicant
36 msleep_interruptible(1000);
38 if (priv
->wdev
->iftype
== NL80211_IFTYPE_STATION
)
39 lbs_send_disconnect_notification(priv
);
41 /* report disconnect to upper layer */
42 netif_stop_queue(priv
->dev
);
43 netif_carrier_off(priv
->dev
);
45 /* Free Tx and Rx packets */
46 kfree_skb(priv
->currenttxskb
);
47 priv
->currenttxskb
= NULL
;
48 priv
->tx_pending_len
= 0;
50 priv
->connect_status
= LBS_DISCONNECTED
;
52 if (priv
->psstate
!= PS_STATE_FULL_POWER
) {
53 /* make firmware to exit PS mode */
54 lbs_deb_cmd("disconnected, so exit PS mode\n");
55 lbs_set_ps_mode(priv
, PS_MODE_ACTION_EXIT_PS
, false);
57 lbs_deb_leave(LBS_DEB_ASSOC
);
60 int lbs_process_command_response(struct lbs_private
*priv
, u8
*data
, u32 len
)
62 uint16_t respcmd
, curcmd
;
63 struct cmd_header
*resp
;
68 lbs_deb_enter(LBS_DEB_HOST
);
70 mutex_lock(&priv
->lock
);
71 spin_lock_irqsave(&priv
->driver_lock
, flags
);
74 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
76 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
81 curcmd
= le16_to_cpu(priv
->cur_cmd
->cmdbuf
->command
);
82 respcmd
= le16_to_cpu(resp
->command
);
83 result
= le16_to_cpu(resp
->result
);
85 lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
86 respcmd
, le16_to_cpu(resp
->seqnum
), len
);
87 lbs_deb_hex(LBS_DEB_CMD
, "CMD_RESP", (void *) resp
, len
);
89 if (resp
->seqnum
!= priv
->cur_cmd
->cmdbuf
->seqnum
) {
90 netdev_info(priv
->dev
,
91 "Received CMD_RESP with invalid sequence %d (expected %d)\n",
92 le16_to_cpu(resp
->seqnum
),
93 le16_to_cpu(priv
->cur_cmd
->cmdbuf
->seqnum
));
94 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
98 if (respcmd
!= CMD_RET(curcmd
) &&
99 respcmd
!= CMD_RET_802_11_ASSOCIATE
&& curcmd
!= CMD_802_11_ASSOCIATE
) {
100 netdev_info(priv
->dev
, "Invalid CMD_RESP %x to command %x!\n",
102 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
107 if (resp
->result
== cpu_to_le16(0x0004)) {
108 /* 0x0004 means -EAGAIN. Drop the response, let it time out
109 and be resubmitted */
110 netdev_info(priv
->dev
,
111 "Firmware returns DEFER to command %x. Will let it time out...\n",
112 le16_to_cpu(resp
->command
));
113 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
118 /* Now we got response from FW, cancel the command timer */
119 del_timer(&priv
->command_timer
);
120 priv
->cmd_timed_out
= 0;
122 if (respcmd
== CMD_RET(CMD_802_11_PS_MODE
)) {
123 struct cmd_ds_802_11_ps_mode
*psmode
= (void *) &resp
[1];
124 u16 action
= le16_to_cpu(psmode
->action
);
127 "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
131 lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
134 * We should not re-try enter-ps command in
135 * ad-hoc mode. It takes place in
136 * lbs_execute_next_command().
138 if (priv
->wdev
->iftype
== NL80211_IFTYPE_MONITOR
&&
139 action
== PS_MODE_ACTION_ENTER_PS
)
140 priv
->psmode
= LBS802_11POWERMODECAM
;
141 } else if (action
== PS_MODE_ACTION_ENTER_PS
) {
142 priv
->needtowakeup
= 0;
143 priv
->psstate
= PS_STATE_AWAKE
;
145 lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
146 if (priv
->connect_status
!= LBS_CONNECTED
) {
148 * When Deauth Event received before Enter_PS command
149 * response, We need to wake up the firmware.
152 "disconnected, invoking lbs_ps_wakeup\n");
154 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
155 mutex_unlock(&priv
->lock
);
156 lbs_set_ps_mode(priv
, PS_MODE_ACTION_EXIT_PS
,
158 mutex_lock(&priv
->lock
);
159 spin_lock_irqsave(&priv
->driver_lock
, flags
);
161 } else if (action
== PS_MODE_ACTION_EXIT_PS
) {
162 priv
->needtowakeup
= 0;
163 priv
->psstate
= PS_STATE_FULL_POWER
;
164 lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
166 lbs_deb_host("CMD_RESP: PS action 0x%X\n", action
);
169 __lbs_complete_command(priv
, priv
->cur_cmd
, result
);
170 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
176 /* If the command is not successful, cleanup and return failure */
177 if ((result
!= 0 || !(respcmd
& 0x8000))) {
178 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
181 * Handling errors here
184 case CMD_RET(CMD_GET_HW_SPEC
):
185 case CMD_RET(CMD_802_11_RESET
):
186 lbs_deb_host("CMD_RESP: reset failed\n");
190 __lbs_complete_command(priv
, priv
->cur_cmd
, result
);
191 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
197 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
199 if (priv
->cur_cmd
&& priv
->cur_cmd
->callback
) {
200 ret
= priv
->cur_cmd
->callback(priv
, priv
->cur_cmd
->callback_arg
,
204 spin_lock_irqsave(&priv
->driver_lock
, flags
);
207 /* Clean up and Put current command back to cmdfreeq */
208 __lbs_complete_command(priv
, priv
->cur_cmd
, result
);
210 spin_unlock_irqrestore(&priv
->driver_lock
, flags
);
213 mutex_unlock(&priv
->lock
);
214 lbs_deb_leave_args(LBS_DEB_HOST
, "ret %d", ret
);
218 int lbs_process_event(struct lbs_private
*priv
, u32 event
)
221 struct cmd_header cmd
;
223 lbs_deb_enter(LBS_DEB_CMD
);
226 case MACREG_INT_CODE_LINK_SENSED
:
227 lbs_deb_cmd("EVENT: link sensed\n");
230 case MACREG_INT_CODE_DEAUTHENTICATED
:
231 lbs_deb_cmd("EVENT: deauthenticated\n");
232 lbs_mac_event_disconnected(priv
);
235 case MACREG_INT_CODE_DISASSOCIATED
:
236 lbs_deb_cmd("EVENT: disassociated\n");
237 lbs_mac_event_disconnected(priv
);
240 case MACREG_INT_CODE_LINK_LOST_NO_SCAN
:
241 lbs_deb_cmd("EVENT: link lost\n");
242 lbs_mac_event_disconnected(priv
);
245 case MACREG_INT_CODE_PS_SLEEP
:
246 lbs_deb_cmd("EVENT: ps sleep\n");
248 /* handle unexpected PS SLEEP event */
249 if (priv
->psstate
== PS_STATE_FULL_POWER
) {
251 "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
254 priv
->psstate
= PS_STATE_PRE_SLEEP
;
256 lbs_ps_confirm_sleep(priv
);
260 case MACREG_INT_CODE_HOST_AWAKE
:
261 lbs_deb_cmd("EVENT: host awake\n");
262 if (priv
->reset_deep_sleep_wakeup
)
263 priv
->reset_deep_sleep_wakeup(priv
);
264 priv
->is_deep_sleep
= 0;
265 lbs_cmd_async(priv
, CMD_802_11_WAKEUP_CONFIRM
, &cmd
,
267 priv
->is_host_sleep_activated
= 0;
268 wake_up_interruptible(&priv
->host_sleep_q
);
271 case MACREG_INT_CODE_DEEP_SLEEP_AWAKE
:
272 if (priv
->reset_deep_sleep_wakeup
)
273 priv
->reset_deep_sleep_wakeup(priv
);
274 lbs_deb_cmd("EVENT: ds awake\n");
275 priv
->is_deep_sleep
= 0;
276 priv
->wakeup_dev_required
= 0;
277 wake_up_interruptible(&priv
->ds_awake_q
);
280 case MACREG_INT_CODE_PS_AWAKE
:
281 lbs_deb_cmd("EVENT: ps awake\n");
282 /* handle unexpected PS AWAKE event */
283 if (priv
->psstate
== PS_STATE_FULL_POWER
) {
285 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
289 priv
->psstate
= PS_STATE_AWAKE
;
291 if (priv
->needtowakeup
) {
293 * wait for the command processing to finish
294 * before resuming sending
295 * priv->needtowakeup will be set to FALSE
298 lbs_deb_cmd("waking up ...\n");
299 lbs_set_ps_mode(priv
, PS_MODE_ACTION_EXIT_PS
, false);
303 case MACREG_INT_CODE_MIC_ERR_UNICAST
:
304 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
305 lbs_send_mic_failureevent(priv
, event
);
308 case MACREG_INT_CODE_MIC_ERR_MULTICAST
:
309 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
310 lbs_send_mic_failureevent(priv
, event
);
313 case MACREG_INT_CODE_MIB_CHANGED
:
314 lbs_deb_cmd("EVENT: MIB CHANGED\n");
316 case MACREG_INT_CODE_INIT_DONE
:
317 lbs_deb_cmd("EVENT: INIT DONE\n");
319 case MACREG_INT_CODE_ADHOC_BCN_LOST
:
320 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
322 case MACREG_INT_CODE_RSSI_LOW
:
323 netdev_alert(priv
->dev
, "EVENT: rssi low\n");
325 case MACREG_INT_CODE_SNR_LOW
:
326 netdev_alert(priv
->dev
, "EVENT: snr low\n");
328 case MACREG_INT_CODE_MAX_FAIL
:
329 netdev_alert(priv
->dev
, "EVENT: max fail\n");
331 case MACREG_INT_CODE_RSSI_HIGH
:
332 netdev_alert(priv
->dev
, "EVENT: rssi high\n");
334 case MACREG_INT_CODE_SNR_HIGH
:
335 netdev_alert(priv
->dev
, "EVENT: snr high\n");
338 case MACREG_INT_CODE_MESH_AUTO_STARTED
:
339 /* Ignore spurious autostart events */
340 netdev_info(priv
->dev
, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
344 netdev_alert(priv
->dev
, "EVENT: unknown event id %d\n", event
);
348 lbs_deb_leave_args(LBS_DEB_CMD
, "ret %d", ret
);