Root/drivers/staging/csr/mlme.c

1/*
2 * ---------------------------------------------------------------------------
3 * FILE: mlme.c
4 *
5 * PURPOSE:
6 * This file provides functions to send MLME requests to the UniFi.
7 *
8 * Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
9 *
10 * Refer to LICENSE.txt included with this source code for details on
11 * the license terms.
12 *
13 * ---------------------------------------------------------------------------
14 */
15#include "csr_wifi_hip_unifi.h"
16#include "unifi_priv.h"
17
18/*
19 * ---------------------------------------------------------------------------
20 * unifi_mlme_wait_for_reply
21 *
22 * Wait for a reply after sending a signal.
23 *
24 * Arguments:
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
29 *
30 * Returns:
31 * 0 on success, -ve POSIX code on error.
32 *
33 * Notes:
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
46 * UniFi.
47 * ---------------------------------------------------------------------------
48 */
49static int
50unifi_mlme_wait_for_reply(unifi_priv_t *priv, ul_client_t *pcli, int sig_reply_id, int timeout)
51{
52    int retries = 0;
53    long r;
54    long t = timeout;
55    unsigned int sent_seq_no;
56
57    /* Convert t in ms to jiffies */
58    t = msecs_to_jiffies(t);
59
60    do {
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),
64                                             t);
65        /* Check for general i/o error */
66        if (priv->io_aborted) {
67            unifi_error(priv, "MLME operation aborted\n");
68            return -EIO;
69        }
70
71        /*
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.
75         */
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;
80            return -ETIMEDOUT;
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;
84            return -EINTR;
85        } else {
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;
89            } else {
90                sent_seq_no = 0x0F;
91            }
92
93            unifi_trace(priv, UDBG5, "Received 0x%.4X, seq: (r:%d, s:%d)\n",
94                        pcli->wake_up_wq_id,
95                        pcli->wake_seq_no, sent_seq_no);
96
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 */
102                    break;
103                } else {
104                    /* This should never happen ... */
105                    unifi_error(priv, "mlme_wait: mismatching signal id (0x%.4X - exp 0x%.4X) (seq %d)\n",
106                                pcli->wake_up_wq_id,
107                                sig_reply_id,
108                                pcli->wake_seq_no);
109                    pcli->wake_up_wq_id = 0;
110                    return -EIO;
111                }
112            }
113            /* Wait for the next signal. */
114            pcli->wake_up_wq_id = 0;
115
116            retries ++;
117            if (retries >= 3) {
118                unifi_error(priv, "mlme_wait: confirm wait retries exhausted (0x%.4X - exp 0x%.4X)\n",
119                            pcli->wake_up_wq_id,
120                            sig_reply_id);
121                pcli->wake_up_wq_id = 0;
122                return -EIO;
123            }
124        }
125    } while (1);
126
127    pcli->wake_up_wq_id = 0;
128
129    return 0;
130} /* unifi_mlme_wait_for_reply() */
131
132
133/*
134 * ---------------------------------------------------------------------------
135 * unifi_mlme_blocking_request
136 *
137 * Send a MLME request signal to UniFi.
138 *
139 * Arguments:
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.
145 *
146 * Returns:
147 * 0 on success, 802.11 result code on error.
148 * ---------------------------------------------------------------------------
149 */
150int
151unifi_mlme_blocking_request(unifi_priv_t *priv, ul_client_t *pcli,
152                            CSR_SIGNAL *sig, bulk_data_param_t *data_ptrs,
153                            int timeout)
154{
155    int r;
156
157    func_enter();
158
159    if (sig->SignalPrimitiveHeader.SignalId == 0) {
160        unifi_error(priv, "unifi_mlme_blocking_request: Invalid Signal Id (0x%x)\n",
161                    sig->SignalPrimitiveHeader.SignalId);
162        return -EINVAL;
163    }
164
165    down(&priv->mlme_blocking_mutex);
166
167    sig->SignalPrimitiveHeader.ReceiverProcessId = 0;
168    sig->SignalPrimitiveHeader.SenderProcessId = pcli->sender_id | pcli->seq_no;
169
170    unifi_trace(priv, UDBG2, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
171                pcli->client_id,
172                sig->SignalPrimitiveHeader.SenderProcessId,
173                sig->SignalPrimitiveHeader.SignalId);
174    /* Send the signal to UniFi */
175    r = ul_send_signal_unpacked(priv, sig, data_ptrs);
176    if (r) {
177        up(&priv->mlme_blocking_mutex);
178        unifi_error(priv, "Error queueing MLME REQUEST signal\n");
179        return r;
180    }
181
182    unifi_trace(priv, UDBG5, "Send 0x%.4X, seq = %d\n",
183                sig->SignalPrimitiveHeader.SignalId, pcli->seq_no);
184
185    /*
186     * Advance the sequence number of the last sent signal, only
187     * if the signal has been successfully set.
188     */
189    pcli->seq_no++;
190    if (pcli->seq_no > 0x0F) {
191        pcli->seq_no = 0;
192    }
193
194    r = unifi_mlme_wait_for_reply(priv, pcli, (sig->SignalPrimitiveHeader.SignalId + 1), timeout);
195    up(&priv->mlme_blocking_mutex);
196
197    if (r) {
198        unifi_error(priv, "Error waiting for MLME CONFIRM signal\n");
199        return r;
200    }
201
202    func_exit();
203    return 0;
204} /* unifi_mlme_blocking_request() */
205
206
207/*
208 * ---------------------------------------------------------------------------
209 * unifi_mlme_copy_reply_and_wakeup_client
210 *
211 * Copy the reply signal from UniFi to the client's structure
212 * and wake up the waiting client.
213 *
214 * Arguments:
215 * None.
216 *
217 * Returns:
218 * None.
219 * ---------------------------------------------------------------------------
220 */
221void
222unifi_mlme_copy_reply_and_wakeup_client(ul_client_t *pcli,
223                                        CSR_SIGNAL *signal, int signal_len,
224                                        const bulk_data_param_t *bulkdata)
225{
226    int i;
227
228    /* Copy the signal to the reply */
229    memcpy(pcli->reply_signal, signal, signal_len);
230
231    /* Get the sequence number of the signal that woke us up. */
232    pcli->wake_seq_no = pcli->reply_signal->SignalPrimitiveHeader.ReceiverProcessId & 0x0F;
233
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;
240            } else {
241                pcli->reply_bulkdata[i]->length = 0;
242            }
243        }
244    }
245
246    /* Wake the requesting MLME function. */
247    pcli->wake_up_wq_id = pcli->reply_signal->SignalPrimitiveHeader.SignalId;
248    wake_up_interruptible(&pcli->udi_wq);
249
250} /* unifi_mlme_copy_reply_and_wakeup_client() */
251
252
253/*
254 * ---------------------------------------------------------------------------
255 * uf_abort_mlme
256 *
257 * Abort any MLME operation in progress.
258 * This is used in the error recovery mechanism.
259 *
260 * Arguments:
261 * priv Pointer to driver context.
262 *
263 * Returns:
264 * 0 on success.
265 * ---------------------------------------------------------------------------
266 */
267int
268uf_abort_mlme(unifi_priv_t *priv)
269{
270    ul_client_t *ul_cli;
271
272    /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
273    priv->io_aborted = 1;
274
275    ul_cli = priv->netdev_client;
276    if (ul_cli) {
277        wake_up_interruptible(&ul_cli->udi_wq);
278    }
279
280    ul_cli = priv->wext_client;
281    if (ul_cli) {
282        wake_up_interruptible(&ul_cli->udi_wq);
283    }
284
285    return 0;
286} /* uf_abort_mlme() */
287
288
289
290/*
291 * ---------------------------------------------------------------------------
292 *
293 * Human-readable decoding of Reason and Result codes.
294 *
295 * ---------------------------------------------------------------------------
296 */
297
298struct mlme_code {
299    const char *name;
300    int id;
301};
302
303static 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 },
333    { NULL, -1 }
334};
335
336static 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 },
373    { NULL, -1 }
374};
375
376
377static const char *
378lookup_something(const struct mlme_code *n, int id)
379{
380    for (; n->name; n++) {
381        if (n->id == id) {
382            return n->name;
383        }
384    }
385
386    /* not found */
387    return NULL;
388} /* lookup_something() */
389
390
391const char *
392lookup_result_code(int result)
393{
394    static char fallback[16];
395    const char *str;
396
397    str = lookup_something(Result_codes, result);
398
399    if (str == NULL) {
400        snprintf(fallback, 16, "%d", result);
401        str = fallback;
402    }
403
404    return str;
405} /* lookup_result_code() */
406
407
408/*
409 * ---------------------------------------------------------------------------
410 * lookup_reason
411 *
412 * Return a description string for a WiFi MLME ReasonCode.
413 *
414 * Arguments:
415 * reason The ReasonCode to interpret.
416 *
417 * Returns:
418 * Pointer to description string.
419 * ---------------------------------------------------------------------------
420 */
421const char *
422lookup_reason_code(int reason)
423{
424    static char fallback[16];
425    const char *str;
426
427    str = lookup_something(Reason_codes, reason);
428
429    if (str == NULL) {
430        snprintf(fallback, 16, "%d", reason);
431        str = fallback;
432    }
433
434    return str;
435} /* lookup_reason_code() */
436
437

Archive Download this file



interactive