Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mlme.c
Go to the documentation of this file.
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. */
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
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",
162  return -EINVAL;
163  }
164 
165  down(&priv->mlme_blocking_mutex);
166 
169 
170  unifi_trace(priv, UDBG2, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
171  pcli->client_id,
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",
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
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. */
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. */
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
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 *
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 *
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