linux/drivers/staging/csr/mlme.c
<<
>>
Prefs
   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    if (sig->SignalPrimitiveHeader.SignalId == 0) {
 158        unifi_error(priv, "unifi_mlme_blocking_request: Invalid Signal Id (0x%x)\n",
 159                    sig->SignalPrimitiveHeader.SignalId);
 160        return -EINVAL;
 161    }
 162
 163    down(&priv->mlme_blocking_mutex);
 164
 165    sig->SignalPrimitiveHeader.ReceiverProcessId = 0;
 166    sig->SignalPrimitiveHeader.SenderProcessId = pcli->sender_id | pcli->seq_no;
 167
 168    unifi_trace(priv, UDBG2, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
 169                pcli->client_id,
 170                sig->SignalPrimitiveHeader.SenderProcessId,
 171                sig->SignalPrimitiveHeader.SignalId);
 172    /* Send the signal to UniFi */
 173    r = ul_send_signal_unpacked(priv, sig, data_ptrs);
 174    if (r) {
 175        up(&priv->mlme_blocking_mutex);
 176        unifi_error(priv, "Error queueing MLME REQUEST signal\n");
 177        return r;
 178    }
 179
 180    unifi_trace(priv, UDBG5, "Send 0x%.4X, seq = %d\n",
 181                sig->SignalPrimitiveHeader.SignalId, pcli->seq_no);
 182
 183    /*
 184     * Advance the sequence number of the last sent signal, only
 185     * if the signal has been successfully set.
 186     */
 187    pcli->seq_no++;
 188    if (pcli->seq_no > 0x0F) {
 189        pcli->seq_no = 0;
 190    }
 191
 192    r = unifi_mlme_wait_for_reply(priv, pcli, (sig->SignalPrimitiveHeader.SignalId + 1), timeout);
 193    up(&priv->mlme_blocking_mutex);
 194
 195    if (r) {
 196        unifi_error(priv, "Error waiting for MLME CONFIRM signal\n");
 197        return r;
 198    }
 199
 200    return 0;
 201} /* unifi_mlme_blocking_request() */
 202
 203
 204/*
 205 * ---------------------------------------------------------------------------
 206 *  unifi_mlme_copy_reply_and_wakeup_client
 207 *
 208 *      Copy the reply signal from UniFi to the client's structure
 209 *      and wake up the waiting client.
 210 *
 211 *  Arguments:
 212 *      None.
 213 *
 214 *  Returns:
 215 *      None.
 216 * ---------------------------------------------------------------------------
 217 */
 218void
 219unifi_mlme_copy_reply_and_wakeup_client(ul_client_t *pcli,
 220                                        CSR_SIGNAL *signal, int signal_len,
 221                                        const bulk_data_param_t *bulkdata)
 222{
 223    int i;
 224
 225    /* Copy the signal to the reply */
 226    memcpy(pcli->reply_signal, signal, signal_len);
 227
 228    /* Get the sequence number of the signal that woke us up. */
 229    pcli->wake_seq_no = pcli->reply_signal->SignalPrimitiveHeader.ReceiverProcessId & 0x0F;
 230
 231    /* Append any bulk data */
 232    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
 233        if (bulkdata->d[i].data_length > 0) {
 234            if (bulkdata->d[i].os_data_ptr) {
 235                memcpy(pcli->reply_bulkdata[i]->ptr, bulkdata->d[i].os_data_ptr, bulkdata->d[i].data_length);
 236                pcli->reply_bulkdata[i]->length = bulkdata->d[i].data_length;
 237            } else {
 238                pcli->reply_bulkdata[i]->length = 0;
 239            }
 240        }
 241    }
 242
 243    /* Wake the requesting MLME function. */
 244    pcli->wake_up_wq_id = pcli->reply_signal->SignalPrimitiveHeader.SignalId;
 245    wake_up_interruptible(&pcli->udi_wq);
 246
 247} /* unifi_mlme_copy_reply_and_wakeup_client() */
 248
 249
 250/*
 251 * ---------------------------------------------------------------------------
 252 *  uf_abort_mlme
 253 *
 254 *      Abort any MLME operation in progress.
 255 *      This is used in the error recovery mechanism.
 256 *
 257 *  Arguments:
 258 *      priv          Pointer to driver context.
 259 *
 260 *  Returns:
 261 *      0 on success.
 262 * ---------------------------------------------------------------------------
 263 */
 264int
 265uf_abort_mlme(unifi_priv_t *priv)
 266{
 267    ul_client_t *ul_cli;
 268
 269    /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
 270    priv->io_aborted = 1;
 271
 272    ul_cli = priv->netdev_client;
 273    if (ul_cli) {
 274        wake_up_interruptible(&ul_cli->udi_wq);
 275    }
 276
 277    ul_cli = priv->wext_client;
 278    if (ul_cli) {
 279        wake_up_interruptible(&ul_cli->udi_wq);
 280    }
 281
 282    return 0;
 283} /* uf_abort_mlme() */
 284
 285
 286
 287/*
 288 * ---------------------------------------------------------------------------
 289 *
 290 *      Human-readable decoding of Reason and Result codes.
 291 *
 292 * ---------------------------------------------------------------------------
 293 */
 294
 295struct mlme_code {
 296    const char *name;
 297    int id;
 298};
 299
 300static const struct mlme_code Result_codes[] = {
 301    { "Success",                             0x0000 },
 302    { "Unspecified Failure",                 0x0001 },
 303    /* (Reserved)                      0x0002 - 0x0009 */
 304    { "Refused Capabilities Mismatch",       0x000A },
 305    /* (Reserved)                          0x000B */
 306    { "Refused External Reason",             0x000C },
 307    /* (Reserved)                      0x000D - 0x0010 */
 308    { "Refused AP Out Of Memory",            0x0011 },
 309    { "Refused Basic Rates Mismatch",        0x0012 },
 310    /* (Reserved)                      0x0013 - 0x001F */
 311    { "Failure",                             0x0020 },
 312    /* (Reserved)                      0x0021 - 0x0024 */
 313    { "Refused Reason Unspecified",          0x0025 },
 314    { "Invalid Parameters",                  0x0026 },
 315    { "Rejected With Suggested Changes",     0x0027 },
 316    /* (Reserved)                      0x0028 - 0x002E */
 317    { "Rejected For Delay Period",           0x002F },
 318    { "Not Allowed",                         0x0030 },
 319    { "Not Present",                         0x0031 },
 320    { "Not QSTA",                            0x0032 },
 321    /* (Reserved)                      0x0033 - 0x7FFF */
 322    { "Timeout",                             0x8000 },
 323    { "Too Many Simultaneous Requests",      0x8001 },
 324    { "BSS Already Started Or Joined",       0x8002 },
 325    { "Not Supported",                       0x8003 },
 326    { "Transmission Failure",                0x8004 },
 327    { "Refused Not Authenticated",           0x8005 },
 328    { "Reset Required Before Start",         0x8006 },
 329    { "LM Info Unavailable",                 0x8007 },
 330    { NULL, -1 }
 331};
 332
 333static const struct mlme_code Reason_codes[] = {
 334    /* (Reserved)                      0x0000 */
 335    { "Unspecified Reason",              0x0001 },
 336    { "Authentication Not Valid",        0x0002 },
 337    { "Deauthenticated Leave BSS",       0x0003 },
 338    { "Disassociated Inactivity",        0x0004 },
 339    { "AP Overload",                     0x0005 },
 340    { "Class2 Frame Error",              0x0006 },
 341    { "Class3 Frame Error",              0x0007 },
 342    { "Disassociated Leave BSS",         0x0008 },
 343    { "Association Not Authenticated",   0x0009 },
 344    { "Disassociated Power Capability",  0x000A },
 345    { "Disassociated Supported Channels", 0x000B },
 346    /* (Reserved)                      0x000C */
 347    { "Invalid Information Element",     0x000D },
 348    { "Michael MIC Failure",             0x000E },
 349    { "Fourway Handshake Timeout",       0x000F },
 350    { "Group Key Update Timeout",        0x0010 },
 351    { "Handshake Element Different",     0x0011 },
 352    { "Invalid Group Cipher",            0x0012 },
 353    { "Invalid Pairwise Cipher",         0x0013 },
 354    { "Invalid AKMP",                    0x0014 },
 355    { "Unsupported RSN IE Version",      0x0015 },
 356    { "Invalid RSN IE Capabilities",     0x0016 },
 357    { "Dot1X Auth Failed",               0x0017 },
 358    { "Cipher Rejected By Policy",       0x0018 },
 359    /* (Reserved)                  0x0019 - 0x001F */
 360    { "QoS Unspecified Reason",          0x0020 },
 361    { "QoS Insufficient Bandwidth",      0x0021 },
 362    { "QoS Excessive Not Ack",           0x0022 },
 363    { "QoS TXOP Limit Exceeded",         0x0023 },
 364    { "QSTA Leaving",                    0x0024 },
 365    { "End TS, End DLS, End BA",         0x0025 },
 366    { "Unknown TS, Unknown DLS, Unknown BA", 0x0026 },
 367    { "Timeout",                         0x0027 },
 368    /* (Reserved)                  0x0028 - 0x002C */
 369    { "STAKey Mismatch",                 0x002D },
 370    { NULL, -1 }
 371};
 372
 373
 374static const char *
 375lookup_something(const struct mlme_code *n, int id)
 376{
 377    for (; n->name; n++) {
 378        if (n->id == id) {
 379            return n->name;
 380        }
 381    }
 382
 383    /* not found */
 384    return NULL;
 385} /* lookup_something() */
 386
 387
 388const char *
 389lookup_result_code(int result)
 390{
 391    static char fallback[16];
 392    const char *str;
 393
 394    str = lookup_something(Result_codes, result);
 395
 396    if (str == NULL) {
 397        snprintf(fallback, 16, "%d", result);
 398        str = fallback;
 399    }
 400
 401    return str;
 402} /* lookup_result_code() */
 403
 404
 405/*
 406 * ---------------------------------------------------------------------------
 407 *  lookup_reason
 408 *
 409 *      Return a description string for a WiFi MLME ReasonCode.
 410 *
 411 *  Arguments:
 412 *      reason          The ReasonCode to interpret.
 413 *
 414 *  Returns:
 415 *      Pointer to description string.
 416 * ---------------------------------------------------------------------------
 417 */
 418const char *
 419lookup_reason_code(int reason)
 420{
 421    static char fallback[16];
 422    const char *str;
 423
 424    str = lookup_something(Reason_codes, reason);
 425
 426    if (str == NULL) {
 427        snprintf(fallback, 16, "%d", reason);
 428        str = fallback;
 429    }
 430
 431    return str;
 432} /* lookup_reason_code() */
 433
 434