2 * ---------------------------------------------------------------------------
6 * This file provides functions to send MLME requests to the UniFi.
8 * Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
10 * Refer to LICENSE.txt included with this source code for details on
13 * ---------------------------------------------------------------------------
15 #include "csr_wifi_hip_unifi.h"
16 #include "unifi_priv.h"
19 * ---------------------------------------------------------------------------
20 * unifi_mlme_wait_for_reply
22 * Wait for a reply after sending a signal.
25 * priv Pointer to device private context struct
26 * ul_client Pointer to linux client
27 * sig_reply_id ID of the expected reply (defined in sigs.h).
28 * timeout timeout in ms
31 * 0 on success, -ve POSIX code on error.
34 * This function waits for a specific (sig_reply_id) signal from UniFi.
35 * It also match the sequence number of the received (cfm) signal, with
36 * the latest sequence number of the signal (req) we have sent.
37 * These two number match be equal.
38 * Should only be used for waiting xxx.cfm signals and only after
39 * we have sent the matching xxx.req signal to UniFi.
40 * If no response is received within the expected time (timeout), we assume
41 * that the UniFi is busy and return an error.
42 * If the wait is aborted by a kernel signal arriving, we stop waiting.
43 * If a response from UniFi is not what we expected, we discard it and
44 * wait again. This could be a response from an aborted request. If we
45 * see several bad responses we assume we have lost synchronisation with
47 * ---------------------------------------------------------------------------
50 unifi_mlme_wait_for_reply(unifi_priv_t
*priv
, ul_client_t
*pcli
, int sig_reply_id
, int timeout
)
55 unsigned int sent_seq_no
;
57 /* Convert t in ms to jiffies */
58 t
= msecs_to_jiffies(t
);
61 /* Wait for the confirm or timeout. */
62 r
= wait_event_interruptible_timeout(pcli
->udi_wq
,
63 (pcli
->wake_up_wq_id
) || (priv
->io_aborted
== 1),
65 /* Check for general i/o error */
66 if (priv
->io_aborted
) {
67 unifi_error(priv
, "MLME operation aborted\n");
72 * If r=0 the request has timed-out.
73 * If r>0 the request has completed successfully.
74 * If r=-ERESTARTSYS an event (kill signal) has interrupted the wait_event.
76 if ((r
== 0) && (pcli
->wake_up_wq_id
== 0)) {
77 unifi_error(priv
, "mlme_wait: timed-out waiting for 0x%.4X, after %lu msec.\n",
78 sig_reply_id
, jiffies_to_msecs(t
));
79 pcli
->wake_up_wq_id
= 0;
81 } else if (r
== -ERESTARTSYS
) {
82 unifi_error(priv
, "mlme_wait: waiting for 0x%.4X was aborted.\n", sig_reply_id
);
83 pcli
->wake_up_wq_id
= 0;
86 /* Get the sequence number of the signal that we previously set. */
87 if (pcli
->seq_no
!= 0) {
88 sent_seq_no
= pcli
->seq_no
- 1;
93 unifi_trace(priv
, UDBG5
, "Received 0x%.4X, seq: (r:%d, s:%d)\n",
95 pcli
->wake_seq_no
, sent_seq_no
);
97 /* The two sequence ids must match. */
98 if (pcli
->wake_seq_no
== sent_seq_no
) {
99 /* and the signal ids must match. */
100 if (sig_reply_id
== pcli
->wake_up_wq_id
) {
101 /* Found the expected signal */
104 /* This should never happen ... */
105 unifi_error(priv
, "mlme_wait: mismatching signal id (0x%.4X - exp 0x%.4X) (seq %d)\n",
109 pcli
->wake_up_wq_id
= 0;
113 /* Wait for the next signal. */
114 pcli
->wake_up_wq_id
= 0;
118 unifi_error(priv
, "mlme_wait: confirm wait retries exhausted (0x%.4X - exp 0x%.4X)\n",
121 pcli
->wake_up_wq_id
= 0;
127 pcli
->wake_up_wq_id
= 0;
130 } /* unifi_mlme_wait_for_reply() */
134 * ---------------------------------------------------------------------------
135 * unifi_mlme_blocking_request
137 * Send a MLME request signal to UniFi.
140 * priv Pointer to device private context struct
141 * pcli Pointer to context of calling process
142 * sig Pointer to the signal to send
143 * data_ptrs Pointer to the bulk data of the signal
144 * timeout The request's timeout.
147 * 0 on success, 802.11 result code on error.
148 * ---------------------------------------------------------------------------
151 unifi_mlme_blocking_request(unifi_priv_t
*priv
, ul_client_t
*pcli
,
152 CSR_SIGNAL
*sig
, bulk_data_param_t
*data_ptrs
,
159 if (sig
->SignalPrimitiveHeader
.SignalId
== 0) {
160 unifi_error(priv
, "unifi_mlme_blocking_request: Invalid Signal Id (0x%x)\n",
161 sig
->SignalPrimitiveHeader
.SignalId
);
165 down(&priv
->mlme_blocking_mutex
);
167 sig
->SignalPrimitiveHeader
.ReceiverProcessId
= 0;
168 sig
->SignalPrimitiveHeader
.SenderProcessId
= pcli
->sender_id
| pcli
->seq_no
;
170 unifi_trace(priv
, UDBG2
, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
172 sig
->SignalPrimitiveHeader
.SenderProcessId
,
173 sig
->SignalPrimitiveHeader
.SignalId
);
174 /* Send the signal to UniFi */
175 r
= ul_send_signal_unpacked(priv
, sig
, data_ptrs
);
177 up(&priv
->mlme_blocking_mutex
);
178 unifi_error(priv
, "Error queueing MLME REQUEST signal\n");
182 unifi_trace(priv
, UDBG5
, "Send 0x%.4X, seq = %d\n",
183 sig
->SignalPrimitiveHeader
.SignalId
, pcli
->seq_no
);
186 * Advance the sequence number of the last sent signal, only
187 * if the signal has been successfully set.
190 if (pcli
->seq_no
> 0x0F) {
194 r
= unifi_mlme_wait_for_reply(priv
, pcli
, (sig
->SignalPrimitiveHeader
.SignalId
+ 1), timeout
);
195 up(&priv
->mlme_blocking_mutex
);
198 unifi_error(priv
, "Error waiting for MLME CONFIRM signal\n");
204 } /* unifi_mlme_blocking_request() */
208 * ---------------------------------------------------------------------------
209 * unifi_mlme_copy_reply_and_wakeup_client
211 * Copy the reply signal from UniFi to the client's structure
212 * and wake up the waiting client.
219 * ---------------------------------------------------------------------------
222 unifi_mlme_copy_reply_and_wakeup_client(ul_client_t
*pcli
,
223 CSR_SIGNAL
*signal
, int signal_len
,
224 const bulk_data_param_t
*bulkdata
)
228 /* Copy the signal to the reply */
229 memcpy(pcli
->reply_signal
, signal
, signal_len
);
231 /* Get the sequence number of the signal that woke us up. */
232 pcli
->wake_seq_no
= pcli
->reply_signal
->SignalPrimitiveHeader
.ReceiverProcessId
& 0x0F;
234 /* Append any bulk data */
235 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; i
++) {
236 if (bulkdata
->d
[i
].data_length
> 0) {
237 if (bulkdata
->d
[i
].os_data_ptr
) {
238 memcpy(pcli
->reply_bulkdata
[i
]->ptr
, bulkdata
->d
[i
].os_data_ptr
, bulkdata
->d
[i
].data_length
);
239 pcli
->reply_bulkdata
[i
]->length
= bulkdata
->d
[i
].data_length
;
241 pcli
->reply_bulkdata
[i
]->length
= 0;
246 /* Wake the requesting MLME function. */
247 pcli
->wake_up_wq_id
= pcli
->reply_signal
->SignalPrimitiveHeader
.SignalId
;
248 wake_up_interruptible(&pcli
->udi_wq
);
250 } /* unifi_mlme_copy_reply_and_wakeup_client() */
254 * ---------------------------------------------------------------------------
257 * Abort any MLME operation in progress.
258 * This is used in the error recovery mechanism.
261 * priv Pointer to driver context.
265 * ---------------------------------------------------------------------------
268 uf_abort_mlme(unifi_priv_t
*priv
)
272 /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
273 priv
->io_aborted
= 1;
275 ul_cli
= priv
->netdev_client
;
277 wake_up_interruptible(&ul_cli
->udi_wq
);
280 ul_cli
= priv
->wext_client
;
282 wake_up_interruptible(&ul_cli
->udi_wq
);
286 } /* uf_abort_mlme() */
291 * ---------------------------------------------------------------------------
293 * Human-readable decoding of Reason and Result codes.
295 * ---------------------------------------------------------------------------
303 static const struct mlme_code Result_codes
[] = {
304 { "Success", 0x0000 },
305 { "Unspecified Failure", 0x0001 },
306 /* (Reserved) 0x0002 - 0x0009 */
307 { "Refused Capabilities Mismatch", 0x000A },
308 /* (Reserved) 0x000B */
309 { "Refused External Reason", 0x000C },
310 /* (Reserved) 0x000D - 0x0010 */
311 { "Refused AP Out Of Memory", 0x0011 },
312 { "Refused Basic Rates Mismatch", 0x0012 },
313 /* (Reserved) 0x0013 - 0x001F */
314 { "Failure", 0x0020 },
315 /* (Reserved) 0x0021 - 0x0024 */
316 { "Refused Reason Unspecified", 0x0025 },
317 { "Invalid Parameters", 0x0026 },
318 { "Rejected With Suggested Changes", 0x0027 },
319 /* (Reserved) 0x0028 - 0x002E */
320 { "Rejected For Delay Period", 0x002F },
321 { "Not Allowed", 0x0030 },
322 { "Not Present", 0x0031 },
323 { "Not QSTA", 0x0032 },
324 /* (Reserved) 0x0033 - 0x7FFF */
325 { "Timeout", 0x8000 },
326 { "Too Many Simultaneous Requests", 0x8001 },
327 { "BSS Already Started Or Joined", 0x8002 },
328 { "Not Supported", 0x8003 },
329 { "Transmission Failure", 0x8004 },
330 { "Refused Not Authenticated", 0x8005 },
331 { "Reset Required Before Start", 0x8006 },
332 { "LM Info Unavailable", 0x8007 },
336 static const struct mlme_code Reason_codes
[] = {
337 /* (Reserved) 0x0000 */
338 { "Unspecified Reason", 0x0001 },
339 { "Authentication Not Valid", 0x0002 },
340 { "Deauthenticated Leave BSS", 0x0003 },
341 { "Disassociated Inactivity", 0x0004 },
342 { "AP Overload", 0x0005 },
343 { "Class2 Frame Error", 0x0006 },
344 { "Class3 Frame Error", 0x0007 },
345 { "Disassociated Leave BSS", 0x0008 },
346 { "Association Not Authenticated", 0x0009 },
347 { "Disassociated Power Capability", 0x000A },
348 { "Disassociated Supported Channels", 0x000B },
349 /* (Reserved) 0x000C */
350 { "Invalid Information Element", 0x000D },
351 { "Michael MIC Failure", 0x000E },
352 { "Fourway Handshake Timeout", 0x000F },
353 { "Group Key Update Timeout", 0x0010 },
354 { "Handshake Element Different", 0x0011 },
355 { "Invalid Group Cipher", 0x0012 },
356 { "Invalid Pairwise Cipher", 0x0013 },
357 { "Invalid AKMP", 0x0014 },
358 { "Unsupported RSN IE Version", 0x0015 },
359 { "Invalid RSN IE Capabilities", 0x0016 },
360 { "Dot1X Auth Failed", 0x0017 },
361 { "Cipher Rejected By Policy", 0x0018 },
362 /* (Reserved) 0x0019 - 0x001F */
363 { "QoS Unspecified Reason", 0x0020 },
364 { "QoS Insufficient Bandwidth", 0x0021 },
365 { "QoS Excessive Not Ack", 0x0022 },
366 { "QoS TXOP Limit Exceeded", 0x0023 },
367 { "QSTA Leaving", 0x0024 },
368 { "End TS, End DLS, End BA", 0x0025 },
369 { "Unknown TS, Unknown DLS, Unknown BA", 0x0026 },
370 { "Timeout", 0x0027 },
371 /* (Reserved) 0x0028 - 0x002C */
372 { "STAKey Mismatch", 0x002D },
378 lookup_something(const struct mlme_code
*n
, int id
)
380 for (; n
->name
; n
++) {
388 } /* lookup_something() */
392 lookup_result_code(int result
)
394 static char fallback
[16];
397 str
= lookup_something(Result_codes
, result
);
400 snprintf(fallback
, 16, "%d", result
);
405 } /* lookup_result_code() */
409 * ---------------------------------------------------------------------------
412 * Return a description string for a WiFi MLME ReasonCode.
415 * reason The ReasonCode to interpret.
418 * Pointer to description string.
419 * ---------------------------------------------------------------------------
422 lookup_reason_code(int reason
)
424 static char fallback
[16];
427 str
= lookup_something(Reason_codes
, reason
);
430 snprintf(fallback
, 16, "%d", reason
);
435 } /* lookup_reason_code() */