2 * ***************************************************************************
6 * Manage list of client applications using UniFi.
8 * Copyright (C) 2006-2009 by Cambridge Silicon Radio Ltd.
10 * Refer to LICENSE.txt included with this source code for details on
13 * ***************************************************************************
15 #include "csr_wifi_hip_unifi.h"
16 #include "csr_wifi_hip_conversions.h"
17 #include "unifi_priv.h"
21 static void free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata);
22 static void reset_driver_status(unifi_priv_t *priv);
25 * ---------------------------------------------------------------------------
28 * Initialise the clients array to empty.
31 * priv Pointer to device private context struct
37 * This function needs to be called before priv is stored in
39 * ---------------------------------------------------------------------------
42 ul_init_clients(unifi_priv_t *priv)
45 ul_client_t *ul_clients;
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
48 sema_init(&priv->udi_logging_mutex, 1);
50 init_MUTEX(&priv->udi_logging_mutex);
52 priv->logging_client = NULL;
54 ul_clients = priv->ul_clients;
56 for (id = 0; id < MAX_UDI_CLIENTS; id++) {
57 memset(&ul_clients[id], 0, sizeof(ul_client_t));
59 ul_clients[id].client_id = id;
60 ul_clients[id].sender_id = UDI_SENDER_ID_BASE + (id << UDI_SENDER_ID_SHIFT);
61 ul_clients[id].instance = -1;
62 ul_clients[id].event_hook = NULL;
64 INIT_LIST_HEAD(&ul_clients[id].udi_log);
65 init_waitqueue_head(&ul_clients[id].udi_wq);
66 sema_init(&ul_clients[id].udi_sem, 1);
68 ul_clients[id].wake_up_wq_id = 0;
69 ul_clients[id].seq_no = 0;
70 ul_clients[id].wake_seq_no = 0;
71 ul_clients[id].snap_filter.count = 0;
73 } /* ul_init_clients() */
77 * ---------------------------------------------------------------------------
80 * This function registers a new ul client.
83 * priv Pointer to device private context struct
84 * configuration Special configuration for the client.
85 * udi_event_clbk Callback for receiving event from unifi.
88 * 0 if a new clients is registered, -1 otherwise.
89 * ---------------------------------------------------------------------------
92 ul_register_client(unifi_priv_t *priv, unsigned int configuration,
93 udi_event_t udi_event_clbk)
95 unsigned char id, ref;
96 ul_client_t *ul_clients;
98 ul_clients = priv->ul_clients;
100 /* check for an unused entry */
101 for (id = 0; id < MAX_UDI_CLIENTS; id++) {
102 if (ul_clients[id].udi_enabled == 0) {
103 ul_clients[id].instance = priv->instance;
104 ul_clients[id].udi_enabled = 1;
105 ul_clients[id].configuration = configuration;
107 /* Allocate memory for the reply signal.. */
108 ul_clients[id].reply_signal = kmalloc(sizeof(CSR_SIGNAL), GFP_KERNEL);
109 if (ul_clients[id].reply_signal == NULL) {
110 unifi_error(priv, "Failed to allocate reply signal for client.\n");
113 /* .. and the bulk data of the reply signal. */
114 for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
115 ul_clients[id].reply_bulkdata[ref] = kmalloc(sizeof(bulk_data_t), GFP_KERNEL);
116 /* If allocation fails, free allocated memory. */
117 if (ul_clients[id].reply_bulkdata[ref] == NULL) {
118 for (; ref > 0; ref --) {
119 kfree(ul_clients[id].reply_bulkdata[ref - 1]);
121 kfree(ul_clients[id].reply_signal);
122 unifi_error(priv, "Failed to allocate bulk data buffers for client.\n");
127 /* Set the event callback. */
128 ul_clients[id].event_hook = udi_event_clbk;
130 unifi_trace(priv, UDBG2, "UDI %d (0x%x) registered. configuration = 0x%x\n",
131 id, &ul_clients[id], configuration);
132 return &ul_clients[id];
136 } /* ul_register_client() */
140 * ---------------------------------------------------------------------------
141 * ul_deregister_client
143 * This function deregisters a blocking UDI client.
146 * client Pointer to the client we deregister.
149 * 0 if a new clients is deregistered.
150 * ---------------------------------------------------------------------------
153 ul_deregister_client(ul_client_t *ul_client)
155 struct list_head *pos, *n;
157 unifi_priv_t *priv = uf_find_instance(ul_client->instance);
160 ul_client->instance = -1;
161 ul_client->event_hook = NULL;
162 ul_client->udi_enabled = 0;
163 unifi_trace(priv, UDBG5, "UDI (0x%x) deregistered.\n", ul_client);
165 /* Free memory allocated for the reply signal and its bulk data. */
166 kfree(ul_client->reply_signal);
167 for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
168 kfree(ul_client->reply_bulkdata[ref]);
171 if (ul_client->snap_filter.count) {
172 ul_client->snap_filter.count = 0;
173 kfree(ul_client->snap_filter.protocols);
176 /* Free anything pending on the udi_log list */
177 down(&ul_client->udi_sem);
178 list_for_each_safe(pos, n, &ul_client->udi_log)
180 logptr = list_entry(pos, udi_log_t, q);
184 up(&ul_client->udi_sem);
187 } /* ul_deregister_client() */
192 * ---------------------------------------------------------------------------
195 * This function is registered with the driver core.
196 * It is called every time a UniFi HIP Signal is sent. It iterates over
197 * the list of processes interested in receiving log events and
198 * delivers the events to them.
201 * ospriv Pointer to driver's private data.
202 * sigdata Pointer to the packed signal buffer.
203 * signal_len Length of the packed signal.
204 * bulkdata Pointer to the signal's bulk data.
205 * dir Direction of the signal
211 * ---------------------------------------------------------------------------
214 logging_handler(void *ospriv,
215 u8 *sigdata, u32 signal_len,
216 const bulk_data_param_t *bulkdata,
217 enum udi_log_direction direction)
219 unifi_priv_t *priv = (unifi_priv_t*)ospriv;
223 dir = (direction == UDI_LOG_FROM_HOST) ? UDI_FROM_HOST : UDI_TO_HOST;
225 down(&priv->udi_logging_mutex);
226 client = priv->logging_client;
227 if (client != NULL) {
228 client->event_hook(client, sigdata, signal_len,
231 up(&priv->udi_logging_mutex);
233 } /* logging_handler() */
238 * ---------------------------------------------------------------------------
241 * This function uses the client's register callback
242 * to indicate configuration information e.g core errors.
245 * priv Pointer to driver's private data.
246 * conf_param Pointer to the configuration data.
247 * len Length of the configuration data.
251 * ---------------------------------------------------------------------------
254 ul_log_config_ind(unifi_priv_t *priv, u8 *conf_param, int len)
256 #ifdef CSR_SUPPORT_SME
257 if (priv->smepriv == NULL)
261 if ((CONFIG_IND_ERROR == (*conf_param)) && (priv->wifi_on_state == wifi_on_in_progress)) {
262 unifi_notice(priv, "ul_log_config_ind: wifi on in progress, suppress error\n");
264 /* wifi_off_ind (error or exit) */
265 CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, (CsrWifiRouterCtrlControlIndication)(*conf_param));
267 #ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
268 unifi_debug_buf_dump();
271 bulk_data_param_t bulkdata;
274 * If someone killed unifi_managed before the driver was unloaded
275 * the g_drvpriv pointer is going to be NULL. In this case it is
276 * safe to assume that there is no client to get the indication.
279 unifi_notice(NULL, "uf_sme_event_ind: NULL priv\n");
283 /* Create a null bulkdata structure. */
284 bulkdata.d[0].data_length = 0;
285 bulkdata.d[1].data_length = 0;
287 sme_native_log_event(priv->sme_cli, conf_param, sizeof(u8),
288 &bulkdata, UDI_CONFIG_IND);
290 #endif /* CSR_SUPPORT_SME */
292 } /* ul_log_config_ind */
296 * ---------------------------------------------------------------------------
297 * free_bulkdata_buffers
299 * Free the bulkdata buffers e.g. after a failed unifi_send_signal().
302 * priv Pointer to device private struct
303 * bulkdata Pointer to bulkdata parameter table
307 * ---------------------------------------------------------------------------
310 free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata)
315 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i) {
316 if (bulkdata->d[i].data_length != 0) {
317 unifi_net_data_free(priv, (bulk_data_desc_t *)(&bulkdata->d[i]));
318 /* data_length is now 0 */
323 } /* free_bulkdata_buffers */
326 _align_bulk_data_buffers(unifi_priv_t *priv, u8 *signal,
327 bulk_data_param_t *bulkdata)
331 if ((bulkdata == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
335 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
339 * The following complex casting is in place in order to eliminate 64-bit compilation warning
340 * "cast to/from pointer from/to integer of different size"
342 u32 align_offset = (u32)(long)(bulkdata->d[i].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1);
345 skb = (struct sk_buff*)bulkdata->d[i].os_net_buf_ptr;
348 "_align_bulk_data_buffers: Align offset found (%d) but skb is NULL!\n",
352 if (bulkdata->d[i].data_length == 0) {
354 "_align_bulk_data_buffers: Align offset found (%d) but length is zero\n",
356 return CSR_RESULT_SUCCESS;
358 unifi_trace(priv, UDBG5,
359 "Align f-h buffer (0x%p) by %d bytes (skb->data: 0x%p)\n",
360 bulkdata->d[i].os_data_ptr, align_offset, skb->data);
363 /* Check if there is enough headroom... */
364 if (unlikely(skb_headroom(skb) < align_offset))
366 struct sk_buff *tmp = skb;
368 unifi_trace(priv, UDBG5, "Headroom not enough - realloc it\n");
369 skb = skb_realloc_headroom(skb, align_offset);
372 "_align_bulk_data_buffers: skb_realloc_headroom failed - signal is dropped\n");
375 /* Free the old bulk data only if allocation succeeds */
377 /* Bulkdata needs to point to the new skb */
378 bulkdata->d[i].os_net_buf_ptr = (const unsigned char*)skb;
379 bulkdata->d[i].os_data_ptr = (const void*)skb->data;
381 /* ... before pushing the data to the right alignment offset */
382 skb_push(skb, align_offset);
385 /* The direction bit is zero for the from-host */
386 signal[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1] = align_offset;
390 } /* _align_bulk_data_buffers() */
394 * ---------------------------------------------------------------------------
395 * ul_send_signal_unpacked
397 * This function sends a host formatted signal to unifi.
400 * priv Pointer to driver's private data.
401 * sigptr Pointer to the signal.
402 * bulkdata Pointer to the signal's bulk data.
405 * O on success, error code otherwise.
408 * The signals have to be sent in the format described in the host interface
409 * specification, i.e wire formatted. Certain clients use the host formatted
410 * structures. The write_pack() transforms the host formatted signal
411 * into the wired formatted signal. The code is in the core, since the signals
412 * are defined therefore binded to the host interface specification.
413 * ---------------------------------------------------------------------------
416 ul_send_signal_unpacked(unifi_priv_t *priv, CSR_SIGNAL *sigptr,
417 bulk_data_param_t *bulkdata)
419 u8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
422 unsigned long lock_flags;
426 csrResult = write_pack(sigptr, sigbuf, &packed_siglen);
427 if (csrResult != CSR_RESULT_SUCCESS) {
428 unifi_error(priv, "Malformed HIP signal in ul_send_signal_unpacked()\n");
429 return CsrHipResultToStatus(csrResult);
431 r = _align_bulk_data_buffers(priv, sigbuf, (bulk_data_param_t*)bulkdata);
436 spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
437 csrResult = unifi_send_signal(priv->card, sigbuf, packed_siglen, bulkdata);
438 if (csrResult != CSR_RESULT_SUCCESS) {
439 /* free_bulkdata_buffers(priv, (bulk_data_param_t *)bulkdata); */
440 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
441 return CsrHipResultToStatus(csrResult);
443 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
446 } /* ul_send_signal_unpacked() */
450 * ---------------------------------------------------------------------------
451 * reset_driver_status
453 * This function is called from ul_send_signal_raw() when it detects
454 * that the SME has sent a MLME-RESET request.
457 * priv Pointer to device private struct
461 * ---------------------------------------------------------------------------
464 reset_driver_status(unifi_priv_t *priv)
466 priv->sta_wmm_capabilities = 0;
467 #ifdef CSR_NATIVE_LINUX
468 #ifdef CSR_SUPPORT_WEXT
469 priv->wext_conf.flag_associated = 0;
470 priv->wext_conf.block_controlled_port = CSR_WIFI_ROUTER_PORT_ACTION_8021X_PORT_OPEN;
471 priv->wext_conf.bss_wmm_capabilities = 0;
472 priv->wext_conf.disable_join_on_ssid_set = 0;
475 } /* reset_driver_status() */
479 * ---------------------------------------------------------------------------
482 * This function sends a wire formatted data signal to unifi.
485 * priv Pointer to driver's private data.
486 * sigptr Pointer to the signal.
487 * siglen Length of the signal.
488 * bulkdata Pointer to the signal's bulk data.
491 * O on success, error code otherwise.
492 * ---------------------------------------------------------------------------
495 ul_send_signal_raw(unifi_priv_t *priv, unsigned char *sigptr, int siglen,
496 bulk_data_param_t *bulkdata)
499 unsigned long lock_flags;
503 * Make sure that the signal is updated with the bulk data
506 r = _align_bulk_data_buffers(priv, (u8*)sigptr, bulkdata);
511 spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
512 csrResult = unifi_send_signal(priv->card, sigptr, siglen, bulkdata);
513 if (csrResult != CSR_RESULT_SUCCESS) {
514 free_bulkdata_buffers(priv, bulkdata);
515 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
516 return CsrHipResultToStatus(csrResult);
518 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
521 * Since this is use by unicli, if we get an MLME reset request
522 * we need to initialize a few status parameters
523 * that the driver uses to make decisions.
525 if (GET_SIGNAL_ID(sigptr) == CSR_MLME_RESET_REQUEST_ID) {
526 reset_driver_status(priv);
530 } /* ul_send_signal_raw() */