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 /* The additional time taken by the UniFi to do a scan per channel */
20 #define SCAN_STARTUP_TIME 300 /* in millisecs */
24 * ---------------------------------------------------------------------------
25 * unifi_mlme_wait_for_reply
27 * Wait for a reply after sending a signal.
30 * priv Pointer to device private context struct
31 * ul_client Pointer to linux client
32 * sig_reply_id ID of the expected reply (defined in sigs.h).
33 * timeout timeout in ms
36 * 0 on success, -ve POSIX code on error.
39 * This function waits for a specific (sig_reply_id) signal from UniFi.
40 * It also match the sequence number of the received (cfm) signal, with
41 * the latest sequence number of the signal (req) we have sent.
42 * These two number match be equal.
43 * Should only be used for waiting xxx.cfm signals and only after
44 * we have sent the matching xxx.req signal to UniFi.
45 * If no response is received within the expected time (timeout), we assume
46 * that the UniFi is busy and return an error.
47 * If the wait is aborted by a kernel signal arriving, we stop waiting.
48 * If a response from UniFi is not what we expected, we discard it and
49 * wait again. This could be a response from an aborted request. If we
50 * see several bad responses we assume we have lost synchronisation with
52 * ---------------------------------------------------------------------------
55 unifi_mlme_wait_for_reply(unifi_priv_t *priv, ul_client_t *pcli, int sig_reply_id, int timeout)
60 unsigned int sent_seq_no;
62 /* Convert t in ms to jiffies */
63 t = msecs_to_jiffies(t);
66 /* Wait for the confirm or timeout. */
67 r = wait_event_interruptible_timeout(pcli->udi_wq,
68 (pcli->wake_up_wq_id) || (priv->io_aborted == 1),
70 /* Check for general i/o error */
71 if (priv->io_aborted) {
72 unifi_error(priv, "MLME operation aborted\n");
77 * If r=0 the request has timed-out.
78 * If r>0 the request has completed successfully.
79 * If r=-ERESTARTSYS an event (kill signal) has interrupted the wait_event.
81 if ((r == 0) && (pcli->wake_up_wq_id == 0)) {
82 unifi_error(priv, "mlme_wait: timed-out waiting for 0x%.4X, after %lu msec.\n",
83 sig_reply_id, jiffies_to_msecs(t));
84 pcli->wake_up_wq_id = 0;
86 } else if (r == -ERESTARTSYS) {
87 unifi_error(priv, "mlme_wait: waiting for 0x%.4X was aborted.\n", sig_reply_id);
88 pcli->wake_up_wq_id = 0;
91 /* Get the sequence number of the signal that we previously set. */
92 if (pcli->seq_no != 0) {
93 sent_seq_no = pcli->seq_no - 1;
98 unifi_trace(priv, UDBG5, "Received 0x%.4X, seq: (r:%d, s:%d)\n",
100 pcli->wake_seq_no, sent_seq_no);
102 /* The two sequence ids must match. */
103 if (pcli->wake_seq_no == sent_seq_no) {
104 /* and the signal ids must match. */
105 if (sig_reply_id == pcli->wake_up_wq_id) {
106 /* Found the expected signal */
109 /* This should never happen ... */
110 unifi_error(priv, "mlme_wait: mismatching signal id (0x%.4X - exp 0x%.4X) (seq %d)\n",
114 pcli->wake_up_wq_id = 0;
118 /* Wait for the next signal. */
119 pcli->wake_up_wq_id = 0;
123 unifi_error(priv, "mlme_wait: confirm wait retries exhausted (0x%.4X - exp 0x%.4X)\n",
126 pcli->wake_up_wq_id = 0;
132 pcli->wake_up_wq_id = 0;
135 } /* unifi_mlme_wait_for_reply() */
139 * ---------------------------------------------------------------------------
140 * unifi_mlme_blocking_request
142 * Send a MLME request signal to UniFi.
145 * priv Pointer to device private context struct
146 * pcli Pointer to context of calling process
147 * sig Pointer to the signal to send
148 * data_ptrs Pointer to the bulk data of the signal
149 * timeout The request's timeout.
152 * 0 on success, 802.11 result code on error.
153 * ---------------------------------------------------------------------------
156 unifi_mlme_blocking_request(unifi_priv_t *priv, ul_client_t *pcli,
157 CSR_SIGNAL *sig, bulk_data_param_t *data_ptrs,
164 if (sig->SignalPrimitiveHeader.SignalId == 0) {
165 unifi_error(priv, "unifi_mlme_blocking_request: Invalid Signal Id (0x%x)\n",
166 sig->SignalPrimitiveHeader.SignalId);
170 down(&priv->mlme_blocking_mutex);
172 sig->SignalPrimitiveHeader.ReceiverProcessId = 0;
173 sig->SignalPrimitiveHeader.SenderProcessId = pcli->sender_id | pcli->seq_no;
175 unifi_trace(priv, UDBG2, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
177 sig->SignalPrimitiveHeader.SenderProcessId,
178 sig->SignalPrimitiveHeader.SignalId);
179 /* Send the signal to UniFi */
180 r = ul_send_signal_unpacked(priv, sig, data_ptrs);
182 up(&priv->mlme_blocking_mutex);
183 unifi_error(priv, "Error queueing MLME REQUEST signal\n");
187 unifi_trace(priv, UDBG5, "Send 0x%.4X, seq = %d\n",
188 sig->SignalPrimitiveHeader.SignalId, pcli->seq_no);
191 * Advance the sequence number of the last sent signal, only
192 * if the signal has been successfully set.
195 if (pcli->seq_no > 0x0F) {
199 r = unifi_mlme_wait_for_reply(priv, pcli, (sig->SignalPrimitiveHeader.SignalId + 1), timeout);
200 up(&priv->mlme_blocking_mutex);
203 unifi_error(priv, "Error waiting for MLME CONFIRM signal\n");
209 } /* unifi_mlme_blocking_request() */
213 * ---------------------------------------------------------------------------
214 * unifi_mlme_copy_reply_and_wakeup_client
216 * Copy the reply signal from UniFi to the client's structure
217 * and wake up the waiting client.
224 * ---------------------------------------------------------------------------
227 unifi_mlme_copy_reply_and_wakeup_client(ul_client_t *pcli,
228 CSR_SIGNAL *signal, int signal_len,
229 const bulk_data_param_t *bulkdata)
233 /* Copy the signal to the reply */
234 memcpy(pcli->reply_signal, signal, signal_len);
236 /* Get the sequence number of the signal that woke us up. */
237 pcli->wake_seq_no = pcli->reply_signal->SignalPrimitiveHeader.ReceiverProcessId & 0x0F;
239 /* Append any bulk data */
240 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
241 if (bulkdata->d[i].data_length > 0) {
242 if (bulkdata->d[i].os_data_ptr) {
243 memcpy(pcli->reply_bulkdata[i]->ptr, bulkdata->d[i].os_data_ptr, bulkdata->d[i].data_length);
244 pcli->reply_bulkdata[i]->length = bulkdata->d[i].data_length;
246 pcli->reply_bulkdata[i]->length = 0;
251 /* Wake the requesting MLME function. */
252 pcli->wake_up_wq_id = pcli->reply_signal->SignalPrimitiveHeader.SignalId;
253 wake_up_interruptible(&pcli->udi_wq);
255 } /* unifi_mlme_copy_reply_and_wakeup_client() */
259 * ---------------------------------------------------------------------------
262 * Abort any MLME operation in progress.
263 * This is used in the error recovery mechanism.
266 * priv Pointer to driver context.
270 * ---------------------------------------------------------------------------
273 uf_abort_mlme(unifi_priv_t *priv)
277 /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
278 priv->io_aborted = 1;
280 ul_cli = priv->netdev_client;
282 wake_up_interruptible(&ul_cli->udi_wq);
285 ul_cli = priv->wext_client;
287 wake_up_interruptible(&ul_cli->udi_wq);
291 } /* uf_abort_mlme() */
296 * ---------------------------------------------------------------------------
298 * Human-readable decoding of Reason and Result codes.
300 * ---------------------------------------------------------------------------
308 static const struct mlme_code Result_codes[] = {
309 { "Success", 0x0000 },
310 { "Unspecified Failure", 0x0001 },
311 /* (Reserved) 0x0002 - 0x0009 */
312 { "Refused Capabilities Mismatch", 0x000A },
313 /* (Reserved) 0x000B */
314 { "Refused External Reason", 0x000C },
315 /* (Reserved) 0x000D - 0x0010 */
316 { "Refused AP Out Of Memory", 0x0011 },
317 { "Refused Basic Rates Mismatch", 0x0012 },
318 /* (Reserved) 0x0013 - 0x001F */
319 { "Failure", 0x0020 },
320 /* (Reserved) 0x0021 - 0x0024 */
321 { "Refused Reason Unspecified", 0x0025 },
322 { "Invalid Parameters", 0x0026 },
323 { "Rejected With Suggested Changes", 0x0027 },
324 /* (Reserved) 0x0028 - 0x002E */
325 { "Rejected For Delay Period", 0x002F },
326 { "Not Allowed", 0x0030 },
327 { "Not Present", 0x0031 },
328 { "Not QSTA", 0x0032 },
329 /* (Reserved) 0x0033 - 0x7FFF */
330 { "Timeout", 0x8000 },
331 { "Too Many Simultaneous Requests", 0x8001 },
332 { "BSS Already Started Or Joined", 0x8002 },
333 { "Not Supported", 0x8003 },
334 { "Transmission Failure", 0x8004 },
335 { "Refused Not Authenticated", 0x8005 },
336 { "Reset Required Before Start", 0x8006 },
337 { "LM Info Unavailable", 0x8007 },
341 static const struct mlme_code Reason_codes[] = {
342 /* (Reserved) 0x0000 */
343 { "Unspecified Reason", 0x0001 },
344 { "Authentication Not Valid", 0x0002 },
345 { "Deauthenticated Leave BSS", 0x0003 },
346 { "Disassociated Inactivity", 0x0004 },
347 { "AP Overload", 0x0005 },
348 { "Class2 Frame Error", 0x0006 },
349 { "Class3 Frame Error", 0x0007 },
350 { "Disassociated Leave BSS", 0x0008 },
351 { "Association Not Authenticated", 0x0009 },
352 { "Disassociated Power Capability", 0x000A },
353 { "Disassociated Supported Channels", 0x000B },
354 /* (Reserved) 0x000C */
355 { "Invalid Information Element", 0x000D },
356 { "Michael MIC Failure", 0x000E },
357 { "Fourway Handshake Timeout", 0x000F },
358 { "Group Key Update Timeout", 0x0010 },
359 { "Handshake Element Different", 0x0011 },
360 { "Invalid Group Cipher", 0x0012 },
361 { "Invalid Pairwise Cipher", 0x0013 },
362 { "Invalid AKMP", 0x0014 },
363 { "Unsupported RSN IE Version", 0x0015 },
364 { "Invalid RSN IE Capabilities", 0x0016 },
365 { "Dot1X Auth Failed", 0x0017 },
366 { "Cipher Rejected By Policy", 0x0018 },
367 /* (Reserved) 0x0019 - 0x001F */
368 { "QoS Unspecified Reason", 0x0020 },
369 { "QoS Insufficient Bandwidth", 0x0021 },
370 { "QoS Excessive Not Ack", 0x0022 },
371 { "QoS TXOP Limit Exceeded", 0x0023 },
372 { "QSTA Leaving", 0x0024 },
373 { "End TS, End DLS, End BA", 0x0025 },
374 { "Unknown TS, Unknown DLS, Unknown BA", 0x0026 },
375 { "Timeout", 0x0027 },
376 /* (Reserved) 0x0028 - 0x002C */
377 { "STAKey Mismatch", 0x002D },
383 lookup_something(const struct mlme_code *n, int id)
385 for (; n->name; n++) {
393 } /* lookup_something() */
397 lookup_result_code(int result)
399 static char fallback[16];
402 str = lookup_something(Result_codes, result);
405 snprintf(fallback, 16, "%d", result);
410 } /* lookup_result_code() */
414 * ---------------------------------------------------------------------------
417 * Return a description string for a WiFi MLME ReasonCode.
420 * reason The ReasonCode to interpret.
423 * Pointer to description string.
424 * ---------------------------------------------------------------------------
427 lookup_reason_code(int reason)
429 static char fallback[16];
432 str = lookup_something(Reason_codes, reason);
435 snprintf(fallback, 16, "%d", reason);
440 } /* lookup_reason_code() */