Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc2 436 lines 15 kB view raw
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