Merge branch 'tip/perf/core-2' of git://git.kernel.org/pub/scm/linux/kernel/git/roste...
[firefly-linux-kernel-4.4.55.git] / 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  */
49 static int
50 unifi_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  */
150 int
151 unifi_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  */
221 void
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)
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  */
267 int
268 uf_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
298 struct mlme_code {
299     const char *name;
300     int id;
301 };
302
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 },
333     { NULL, -1 }
334 };
335
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 },
373     { NULL, -1 }
374 };
375
376
377 static const char *
378 lookup_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
391 const char *
392 lookup_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  */
421 const char *
422 lookup_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