]> Pileus Git - ~andy/linux/blob - drivers/staging/csr/sme_native.c
mwifiex: don't try to associate when bss_mode is not STA
[~andy/linux] / drivers / staging / csr / sme_native.c
1 /*
2  * ***************************************************************************
3  *
4  *  FILE:     sme_native.c
5  *
6  * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
7  *
8  * Refer to LICENSE.txt included with this source code for details on
9  * the license terms.
10  *
11  * ***************************************************************************
12  */
13
14 #include <linux/netdevice.h>
15 #include "unifi_priv.h"
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
18
19 static const unsigned char wildcard_address[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
20
21 int
22 uf_sme_init(unifi_priv_t *priv)
23 {
24     sema_init(&priv->mlme_blocking_mutex, 1);
25
26 #ifdef CSR_SUPPORT_WEXT
27     {
28         int r = uf_init_wext_interface(priv);
29         if (r != 0) {
30             return r;
31         }
32     }
33 #endif
34
35     return 0;
36 } /* uf_sme_init() */
37
38
39 void
40 uf_sme_deinit(unifi_priv_t *priv)
41 {
42
43     /* Free memory allocated for the scan table */
44 /*    unifi_clear_scan_table(priv); */
45
46     /* Cancel any pending workqueue tasks */
47     flush_workqueue(priv->unifi_workqueue);
48
49 #ifdef CSR_SUPPORT_WEXT
50     uf_deinit_wext_interface(priv);
51 #endif
52
53 } /* uf_sme_deinit() */
54
55
56 int sme_mgt_wifi_on(unifi_priv_t *priv)
57 {
58     int r,i;
59     s32 csrResult;
60
61     if (priv == NULL) {
62         return -EINVAL;
63     }
64     /* Initialize the interface mode to None */
65     for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
66         priv->interfacePriv[i]->interfaceMode = 0;
67     }
68
69     /* Set up interface mode so that get_packet_priority() can
70      * select the right QOS priority when WMM is enabled.
71      */
72     priv->interfacePriv[0]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_STA;
73
74     r = uf_request_firmware_files(priv, UNIFI_FW_STA);
75     if (r) {
76         unifi_error(priv, "sme_mgt_wifi_on: Failed to get f/w\n");
77         return r;
78     }
79
80     /*
81      * The request to initialise UniFi might come while UniFi is running.
82      * We need to block all I/O activity until the reset completes, otherwise
83      * an SDIO error might occur resulting an indication to the SME which
84      * makes it think that the initialisation has failed.
85      */
86     priv->bh_thread.block_thread = 1;
87
88     /* Power on UniFi */
89     CsrSdioClaim(priv->sdio);
90     csrResult = CsrSdioPowerOn(priv->sdio);
91     CsrSdioRelease(priv->sdio);
92     if(csrResult != CSR_RESULT_SUCCESS && csrResult != CSR_SDIO_RESULT_NOT_RESET) {
93         return -EIO;
94     }
95
96     if (csrResult == CSR_RESULT_SUCCESS) {
97         /* Initialise UniFi hardware */
98         r = uf_init_hw(priv);
99         if (r) {
100             return r;
101         }
102     }
103
104     /* Re-enable the I/O thread */
105     priv->bh_thread.block_thread = 0;
106
107     /* Disable deep sleep signalling during the firmware initialisation, to
108      * prevent the wakeup mechanism raising the SDIO clock beyond INIT before
109      * the first MLME-RESET.ind. It gets re-enabled at the CONNECTED.ind,
110      * immediately after the MLME-RESET.ind
111      */
112     csrResult = unifi_configure_low_power_mode(priv->card,
113                                            UNIFI_LOW_POWER_DISABLED,
114                                            UNIFI_PERIODIC_WAKE_HOST_DISABLED);
115     if (csrResult != CSR_RESULT_SUCCESS) {
116         unifi_warning(priv,
117                       "sme_mgt_wifi_on: unifi_configure_low_power_mode() returned an error\n");
118     }
119
120
121     /* Start the I/O thread */
122     CsrSdioClaim(priv->sdio);
123     r = uf_init_bh(priv);
124     if (r) {
125         CsrSdioPowerOff(priv->sdio);
126         CsrSdioRelease(priv->sdio);
127         return r;
128     }
129     CsrSdioRelease(priv->sdio);
130
131     priv->init_progress = UNIFI_INIT_FW_DOWNLOADED;
132
133     return 0;
134 }
135
136 int
137 sme_sys_suspend(unifi_priv_t *priv)
138 {
139     const int interfaceNum = 0;     /* FIXME */
140     CsrResult csrResult;
141
142     /* Abort any pending requests. */
143     uf_abort_mlme(priv);
144
145     /* Allow our mlme request to go through. */
146     priv->io_aborted = 0;
147
148     /* Send MLME-RESET.req to UniFi. */
149     unifi_reset_state(priv, priv->netdev[interfaceNum]->dev_addr, 0);
150
151     /* Stop the network traffic */
152     netif_carrier_off(priv->netdev[interfaceNum]);
153
154     /* Put UniFi to deep sleep */
155     CsrSdioClaim(priv->sdio);
156     csrResult = unifi_force_low_power_mode(priv->card);
157     CsrSdioRelease(priv->sdio);
158
159     return 0;
160 } /* sme_sys_suspend() */
161
162
163 int
164 sme_sys_resume(unifi_priv_t *priv)
165 {
166 #ifdef CSR_SUPPORT_WEXT
167     /* Send disconnect event so clients will re-initialise connection. */
168     memset(priv->wext_conf.current_ssid, 0, UNIFI_MAX_SSID_LEN);
169     memset((void*)priv->wext_conf.current_bssid, 0, ETH_ALEN);
170     priv->wext_conf.capability = 0;
171     wext_send_disassoc_event(priv);
172 #endif
173     return 0;
174 } /* sme_sys_resume() */
175
176
177 /*
178  * ---------------------------------------------------------------------------
179  *  sme_native_log_event
180  *
181  *      Callback function to be registered as the SME event callback.
182  *      Copies the signal content into a new udi_log_t struct and adds
183  *      it to the read queue for the SME client.
184  *
185  *  Arguments:
186  *      arg             This is the value given to unifi_add_udi_hook, in
187  *                      this case a pointer to the client instance.
188  *      signal          Pointer to the received signal.
189  *      signal_len      Size of the signal structure in bytes.
190  *      bulkdata        Pointers to any associated bulk data.
191  *      dir             Direction of the signal. Zero means from host,
192  *                      non-zero means to host.
193  *
194  *  Returns:
195  *      None.
196  * ---------------------------------------------------------------------------
197  */
198 void
199 sme_native_log_event(ul_client_t *pcli,
200                      const u8 *sig_packed, int sig_len,
201                      const bulk_data_param_t *bulkdata,
202                      int dir)
203 {
204     unifi_priv_t *priv;
205     udi_log_t *logptr;
206     u8 *p;
207     int i, r;
208     int signal_len;
209     int total_len;
210     udi_msg_t *msgptr;
211     CSR_SIGNAL signal;
212     ul_client_t *client = pcli;
213
214     if (client == NULL) {
215         unifi_error(NULL, "sme_native_log_event: client has exited\n");
216         return;
217     }
218
219     priv = uf_find_instance(client->instance);
220     if (!priv) {
221         unifi_error(priv, "invalid priv\n");
222         return;
223     }
224
225     /* Just a sanity check */
226     if ((sig_packed == NULL) || (sig_len <= 0)) {
227         return;
228     }
229
230     /* Get the unpacked signal */
231     r = read_unpack_signal(sig_packed, &signal);
232     if (r == 0) {
233         signal_len = SigGetSize(&signal);
234     } else {
235         u16 receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sig_packed) + sizeof(u16)) & 0xFF00;
236
237         /* The control indications are 1 byte, pass them to client. */
238         if (sig_len == 1) {
239             unifi_trace(priv, UDBG5,
240                         "Control indication (0x%x) for native SME.\n",
241                         *sig_packed);
242
243             *(u8*)&signal = *sig_packed;
244             signal_len = sig_len;
245         } else if (receiver_id == 0) {
246             /*
247              * Also "unknown" signals with a ReceiverId of 0 are passed to the client
248              * without unpacking. (This is a code size optimisation to allow signals
249              * that the driver not interested in to be dropped from the unpack code).
250              */
251             unifi_trace(priv, UDBG5,
252                         "Signal 0x%.4X with ReceiverId 0 for native SME.\n",
253                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
254
255             *(u8*)&signal = *sig_packed;
256             signal_len = sig_len;
257         } else {
258             unifi_error(priv,
259                         "sme_native_log_event - Received unknown signal 0x%.4X.\n",
260                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
261             return;
262         }
263     }
264
265     unifi_trace(priv, UDBG3, "sme_native_log_event: signal 0x%.4X for %d\n",
266                 signal.SignalPrimitiveHeader.SignalId,
267                 client->client_id);
268
269     total_len = signal_len;
270     /* Calculate the buffer we need to store signal plus bulk data */
271     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
272         total_len += bulkdata->d[i].data_length;
273     }
274
275     /* Allocate log structure plus actual signal. */
276     logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
277
278     if (logptr == NULL) {
279         unifi_error(priv,
280                     "Failed to allocate %d bytes for a UDI log record\n",
281                     sizeof(udi_log_t) + total_len);
282         return;
283     }
284
285     /* Fill in udi_log struct */
286     INIT_LIST_HEAD(&logptr->q);
287     msgptr = &logptr->msg;
288     msgptr->length = sizeof(udi_msg_t) + total_len;
289     msgptr->timestamp = jiffies_to_msecs(jiffies);
290     msgptr->direction = dir;
291     msgptr->signal_length = signal_len;
292
293     /* Copy signal and bulk data to the log */
294     p = (u8 *)(msgptr + 1);
295     memcpy(p, &signal, signal_len);
296     p += signal_len;
297
298     /* Append any bulk data */
299     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
300         int len = bulkdata->d[i].data_length;
301
302         /*
303          * Len here might not be the same as the length in the bulk data slot.
304          * The slot length will always be even, but len could be odd.
305          */
306         if (len > 0) {
307             if (bulkdata->d[i].os_data_ptr) {
308                 memcpy(p, bulkdata->d[i].os_data_ptr, len);
309             } else {
310                 memset(p, 0, len);
311             }
312             p += len;
313         }
314     }
315
316     /* Add to tail of log queue */
317     down(&client->udi_sem);
318     list_add_tail(&logptr->q, &client->udi_log);
319     up(&client->udi_sem);
320
321     /* Wake any waiting user process */
322     wake_up_interruptible(&client->udi_wq);
323
324 } /* sme_native_log_event() */
325
326
327 /*
328  * ---------------------------------------------------------------------------
329  *  unifi_ta_indicate_protocol
330  *
331  *      Report that a packet of a particular type has been seen
332  *
333  *  Arguments:
334  *      drv_priv        The device context pointer passed to ta_init.
335  *      protocol        The protocol type enum value.
336  *      direction       Whether the packet was a tx or rx.
337  *      src_addr        The source MAC address from the data packet.
338  *
339  *  Returns:
340  *      None.
341  *
342  *  Notes:
343  *      We defer the actual sending to a background workqueue,
344  *      see uf_ta_ind_wq().
345  * ---------------------------------------------------------------------------
346  */
347 void
348 unifi_ta_indicate_protocol(void *ospriv,
349                            CsrWifiRouterCtrlTrafficPacketType packet_type,
350                            CsrWifiRouterCtrlProtocolDirection direction,
351                            const CsrWifiMacAddress *src_addr)
352 {
353
354 } /* unifi_ta_indicate_protocol */
355
356 /*
357  * ---------------------------------------------------------------------------
358  * unifi_ta_indicate_sampling
359  *
360  *      Send the TA sampling information to the SME.
361  *
362  *  Arguments:
363  *      drv_priv        The device context pointer passed to ta_init.
364  *      stats           The TA sampling data to send.
365  *
366  *  Returns:
367  *      None.
368  * ---------------------------------------------------------------------------
369  */
370 void
371 unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
372 {
373
374 } /* unifi_ta_indicate_sampling() */
375
376
377 void
378 unifi_ta_indicate_l4stats(void *ospriv,
379                             u32 rxTcpThroughput,
380                             u32 txTcpThroughput,
381                             u32 rxUdpThroughput,
382                             u32 txUdpThroughput)
383 {
384
385 } /* unifi_ta_indicate_l4stats() */
386
387 /*
388  * ---------------------------------------------------------------------------
389  * uf_native_process_udi_signal
390  *
391  *      Process interesting signals from the UDI interface.
392  *
393  *  Arguments:
394  *      pcli            A pointer to the client instance.
395  *      signal          Pointer to the received signal.
396  *      signal_len      Size of the signal structure in bytes.
397  *      bulkdata        Pointers to any associated bulk data.
398  *      dir             Direction of the signal. Zero means from host,
399  *                      non-zero means to host.
400  *
401  *
402  *  Returns:
403  *      None.
404  * ---------------------------------------------------------------------------
405  */
406 void
407 uf_native_process_udi_signal(ul_client_t *pcli,
408                              const u8 *packed_signal, int packed_signal_len,
409                              const bulk_data_param_t *bulkdata, int dir)
410 {
411
412 } /* uf_native_process_udi_signal() */
413
414
415 /*
416  * ---------------------------------------------------------------------------
417  *  sme_native_mlme_event_handler
418  *
419  *      Callback function to be used as the udi_event_callback when registering
420  *      as a client.
421  *      This function implements a blocking request-reply interface for WEXT.
422  *      To use it, a client specifies this function as the udi_event_callback
423  *      to ul_register_client(). The signal dispatcher in
424  *      unifi_receive_event() will call this function to deliver a signal.
425  *
426  *  Arguments:
427  *      pcli            Pointer to the client instance.
428  *      signal          Pointer to the received signal.
429  *      signal_len      Size of the signal structure in bytes.
430  *      bulkdata        Pointer to structure containing any associated bulk data.
431  *      dir             Direction of the signal. Zero means from host,
432  *                      non-zero means to host.
433  *
434  *  Returns:
435  *      None.
436  * ---------------------------------------------------------------------------
437  */
438 void
439 sme_native_mlme_event_handler(ul_client_t *pcli,
440                               const u8 *sig_packed, int sig_len,
441                               const bulk_data_param_t *bulkdata,
442                               int dir)
443 {
444     CSR_SIGNAL signal;
445     int signal_len;
446     unifi_priv_t *priv = uf_find_instance(pcli->instance);
447     int id, r;
448
449     /* Just a sanity check */
450     if ((sig_packed == NULL) || (sig_len <= 0)) {
451         return;
452     }
453
454     /* Get the unpacked signal */
455     r = read_unpack_signal(sig_packed, &signal);
456     if (r == 0) {
457         signal_len = SigGetSize(&signal);
458     } else {
459         unifi_error(priv,
460                     "sme_native_mlme_event_handler - Received unknown signal 0x%.4X.\n",
461                     CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
462         return;
463     }
464
465     id = signal.SignalPrimitiveHeader.SignalId;
466     unifi_trace(priv, UDBG4, "wext - Process signal 0x%.4X\n", id);
467
468     /*
469      * Take the appropriate action for the signal.
470      */
471     switch (id) {
472         /*
473          * Confirm replies from UniFi.
474          * These all have zero or one CSR_DATAREF member. (FIXME: check this is still true for softmac)
475          */
476         case CSR_MA_PACKET_CONFIRM_ID:
477         case CSR_MLME_RESET_CONFIRM_ID:
478         case CSR_MLME_GET_CONFIRM_ID:
479         case CSR_MLME_SET_CONFIRM_ID:
480         case CSR_MLME_GET_NEXT_CONFIRM_ID:
481         case CSR_MLME_POWERMGT_CONFIRM_ID:
482         case CSR_MLME_SCAN_CONFIRM_ID:
483         case CSR_MLME_HL_SYNC_CONFIRM_ID:
484         case CSR_MLME_MEASURE_CONFIRM_ID:
485         case CSR_MLME_SETKEYS_CONFIRM_ID:
486         case CSR_MLME_DELETEKEYS_CONFIRM_ID:
487         case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
488         case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
489         case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
490         case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
491         case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
492         case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
493         case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
494         case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
495         case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
496         case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
497         case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
498         case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
499         case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
500         case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
501         case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
502         case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
503         case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
504         case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
505         case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
506         case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
507         case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
508         case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
509         case CSR_MLME_SM_START_CONFIRM_ID:
510         case CSR_MLME_LEAVE_CONFIRM_ID:
511         case CSR_MLME_SET_TIM_CONFIRM_ID:
512         case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
513         case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
514         case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
515         case CSR_DEBUG_GENERIC_CONFIRM_ID:
516             unifi_mlme_copy_reply_and_wakeup_client(pcli, &signal, signal_len, bulkdata);
517             break;
518
519         case CSR_MLME_CONNECTED_INDICATION_ID:
520             /* We currently ignore the connected-ind for softmac f/w development */
521             unifi_info(priv, "CSR_MLME_CONNECTED_INDICATION_ID ignored\n");
522             break;
523
524         default:
525             break;
526     }
527
528 } /* sme_native_mlme_event_handler() */
529
530
531
532 /*
533  * -------------------------------------------------------------------------
534  *  unifi_reset_state
535  *
536  *      Ensure that a MAC address has been set.
537  *      Send the MLME-RESET signal.
538  *      This must be called at least once before starting to do any
539  *      network activities (e.g. scan, join etc).
540  *
541  * Arguments:
542  *      priv            Pointer to device private context struct
543  *      macaddr         Pointer to chip MAC address.
544  *                      If this is FF:FF:FF:FF:FF:FF it will be replaced
545  *                      with the MAC address from the chip.
546  *      set_default_mib 1 if the f/w must reset the MIB to the default values
547  *                      0 otherwise
548  *
549  * Returns:
550  *      0 on success, an error code otherwise.
551  * -------------------------------------------------------------------------
552  */
553 int
554 unifi_reset_state(unifi_priv_t *priv, unsigned char *macaddr,
555                   unsigned char set_default_mib)
556 {
557     int r = 0;
558
559 #ifdef CSR_SUPPORT_WEXT
560     /* The reset clears any 802.11 association. */
561     priv->wext_conf.flag_associated = 0;
562 #endif
563
564     return r;
565 } /* unifi_reset_state() */
566