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 <linux/version.h>
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
18 #include "unifi_priv.h"
22 static void free_bulkdata_buffers(unifi_priv_t
*priv
, bulk_data_param_t
*bulkdata
);
23 static void reset_driver_status(unifi_priv_t
*priv
);
26 * ---------------------------------------------------------------------------
29 * Initialise the clients array to empty.
32 * priv Pointer to device private context struct
38 * This function needs to be called before priv is stored in
40 * ---------------------------------------------------------------------------
43 ul_init_clients(unifi_priv_t
*priv
)
46 ul_client_t
*ul_clients
;
48 sema_init(&priv
->udi_logging_mutex
, 1);
49 priv
->logging_client
= NULL
;
51 ul_clients
= priv
->ul_clients
;
53 for (id
= 0; id
< MAX_UDI_CLIENTS
; id
++) {
54 memset(&ul_clients
[id
], 0, sizeof(ul_client_t
));
56 ul_clients
[id
].client_id
= id
;
57 ul_clients
[id
].sender_id
= UDI_SENDER_ID_BASE
+ (id
<< UDI_SENDER_ID_SHIFT
);
58 ul_clients
[id
].instance
= -1;
59 ul_clients
[id
].event_hook
= NULL
;
61 INIT_LIST_HEAD(&ul_clients
[id
].udi_log
);
62 init_waitqueue_head(&ul_clients
[id
].udi_wq
);
63 sema_init(&ul_clients
[id
].udi_sem
, 1);
65 ul_clients
[id
].wake_up_wq_id
= 0;
66 ul_clients
[id
].seq_no
= 0;
67 ul_clients
[id
].wake_seq_no
= 0;
68 ul_clients
[id
].snap_filter
.count
= 0;
70 } /* ul_init_clients() */
74 * ---------------------------------------------------------------------------
77 * This function registers a new ul client.
80 * priv Pointer to device private context struct
81 * configuration Special configuration for the client.
82 * udi_event_clbk Callback for receiving event from unifi.
85 * 0 if a new clients is registered, -1 otherwise.
86 * ---------------------------------------------------------------------------
89 ul_register_client(unifi_priv_t
*priv
, unsigned int configuration
,
90 udi_event_t udi_event_clbk
)
92 unsigned char id
, ref
;
93 ul_client_t
*ul_clients
;
95 ul_clients
= priv
->ul_clients
;
97 /* check for an unused entry */
98 for (id
= 0; id
< MAX_UDI_CLIENTS
; id
++) {
99 if (ul_clients
[id
].udi_enabled
== 0) {
100 ul_clients
[id
].instance
= priv
->instance
;
101 ul_clients
[id
].udi_enabled
= 1;
102 ul_clients
[id
].configuration
= configuration
;
104 /* Allocate memory for the reply signal.. */
105 ul_clients
[id
].reply_signal
= kmalloc(sizeof(CSR_SIGNAL
), GFP_KERNEL
);
106 if (ul_clients
[id
].reply_signal
== NULL
) {
107 unifi_error(priv
, "Failed to allocate reply signal for client.\n");
110 /* .. and the bulk data of the reply signal. */
111 for (ref
= 0; ref
< UNIFI_MAX_DATA_REFERENCES
; ref
++) {
112 ul_clients
[id
].reply_bulkdata
[ref
] = kmalloc(sizeof(bulk_data_t
), GFP_KERNEL
);
113 /* If allocation fails, free allocated memory. */
114 if (ul_clients
[id
].reply_bulkdata
[ref
] == NULL
) {
115 for (; ref
> 0; ref
--) {
116 kfree(ul_clients
[id
].reply_bulkdata
[ref
- 1]);
118 kfree(ul_clients
[id
].reply_signal
);
119 unifi_error(priv
, "Failed to allocate bulk data buffers for client.\n");
124 /* Set the event callback. */
125 ul_clients
[id
].event_hook
= udi_event_clbk
;
127 unifi_trace(priv
, UDBG2
, "UDI %d (0x%x) registered. configuration = 0x%x\n",
128 id
, &ul_clients
[id
], configuration
);
129 return &ul_clients
[id
];
133 } /* ul_register_client() */
137 * ---------------------------------------------------------------------------
138 * ul_deregister_client
140 * This function deregisters a blocking UDI client.
143 * client Pointer to the client we deregister.
146 * 0 if a new clients is deregistered.
147 * ---------------------------------------------------------------------------
150 ul_deregister_client(ul_client_t
*ul_client
)
152 struct list_head
*pos
, *n
;
154 unifi_priv_t
*priv
= uf_find_instance(ul_client
->instance
);
157 ul_client
->instance
= -1;
158 ul_client
->event_hook
= NULL
;
159 ul_client
->udi_enabled
= 0;
160 unifi_trace(priv
, UDBG5
, "UDI (0x%x) deregistered.\n", ul_client
);
162 /* Free memory allocated for the reply signal and its bulk data. */
163 kfree(ul_client
->reply_signal
);
164 for (ref
= 0; ref
< UNIFI_MAX_DATA_REFERENCES
; ref
++) {
165 kfree(ul_client
->reply_bulkdata
[ref
]);
168 if (ul_client
->snap_filter
.count
) {
169 ul_client
->snap_filter
.count
= 0;
170 kfree(ul_client
->snap_filter
.protocols
);
173 /* Free anything pending on the udi_log list */
174 down(&ul_client
->udi_sem
);
175 list_for_each_safe(pos
, n
, &ul_client
->udi_log
)
177 logptr
= list_entry(pos
, udi_log_t
, q
);
181 up(&ul_client
->udi_sem
);
184 } /* ul_deregister_client() */
189 * ---------------------------------------------------------------------------
192 * This function is registered with the driver core.
193 * It is called every time a UniFi HIP Signal is sent. It iterates over
194 * the list of processes interested in receiving log events and
195 * delivers the events to them.
198 * ospriv Pointer to driver's private data.
199 * sigdata Pointer to the packed signal buffer.
200 * signal_len Length of the packed signal.
201 * bulkdata Pointer to the signal's bulk data.
202 * dir Direction of the signal
208 * ---------------------------------------------------------------------------
211 logging_handler(void *ospriv
,
212 u8
*sigdata
, u32 signal_len
,
213 const bulk_data_param_t
*bulkdata
,
214 enum udi_log_direction direction
)
216 unifi_priv_t
*priv
= (unifi_priv_t
*)ospriv
;
220 dir
= (direction
== UDI_LOG_FROM_HOST
) ? UDI_FROM_HOST
: UDI_TO_HOST
;
222 down(&priv
->udi_logging_mutex
);
223 client
= priv
->logging_client
;
224 if (client
!= NULL
) {
225 client
->event_hook(client
, sigdata
, signal_len
,
228 up(&priv
->udi_logging_mutex
);
230 } /* logging_handler() */
235 * ---------------------------------------------------------------------------
238 * This function uses the client's register callback
239 * to indicate configuration information e.g core errors.
242 * priv Pointer to driver's private data.
243 * conf_param Pointer to the configuration data.
244 * len Length of the configuration data.
248 * ---------------------------------------------------------------------------
251 ul_log_config_ind(unifi_priv_t
*priv
, u8
*conf_param
, int len
)
253 #ifdef CSR_SUPPORT_SME
254 if (priv
->smepriv
== NULL
)
258 if ((CONFIG_IND_ERROR
== (*conf_param
)) && (priv
->wifi_on_state
== wifi_on_in_progress
)) {
259 unifi_notice(priv
, "ul_log_config_ind: wifi on in progress, suppress error\n");
261 /* wifi_off_ind (error or exit) */
262 CsrWifiRouterCtrlWifiOffIndSend(priv
->CSR_WIFI_SME_IFACEQUEUE
,0, (CsrWifiRouterCtrlControlIndication
)(*conf_param
));
264 #ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
265 unifi_debug_buf_dump();
268 bulk_data_param_t bulkdata
;
271 * If someone killed unifi_managed before the driver was unloaded
272 * the g_drvpriv pointer is going to be NULL. In this case it is
273 * safe to assume that there is no client to get the indication.
276 unifi_notice(NULL
, "uf_sme_event_ind: NULL priv\n");
280 /* Create a null bulkdata structure. */
281 bulkdata
.d
[0].data_length
= 0;
282 bulkdata
.d
[1].data_length
= 0;
284 sme_native_log_event(priv
->sme_cli
, conf_param
, sizeof(u8
),
285 &bulkdata
, UDI_CONFIG_IND
);
287 #endif /* CSR_SUPPORT_SME */
289 } /* ul_log_config_ind */
293 * ---------------------------------------------------------------------------
294 * free_bulkdata_buffers
296 * Free the bulkdata buffers e.g. after a failed unifi_send_signal().
299 * priv Pointer to device private struct
300 * bulkdata Pointer to bulkdata parameter table
304 * ---------------------------------------------------------------------------
307 free_bulkdata_buffers(unifi_priv_t
*priv
, bulk_data_param_t
*bulkdata
)
312 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; ++i
) {
313 if (bulkdata
->d
[i
].data_length
!= 0) {
314 unifi_net_data_free(priv
, (bulk_data_desc_t
*)(&bulkdata
->d
[i
]));
315 /* data_length is now 0 */
320 } /* free_bulkdata_buffers */
323 _align_bulk_data_buffers(unifi_priv_t
*priv
, u8
*signal
,
324 bulk_data_param_t
*bulkdata
)
328 if ((bulkdata
== NULL
) || (CSR_WIFI_ALIGN_BYTES
== 0)) {
332 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; i
++)
336 * The following complex casting is in place in order to eliminate 64-bit compilation warning
337 * "cast to/from pointer from/to integer of different size"
339 u32 align_offset
= (u32
)(long)(bulkdata
->d
[i
].os_data_ptr
) & (CSR_WIFI_ALIGN_BYTES
-1);
342 skb
= (struct sk_buff
*)bulkdata
->d
[i
].os_net_buf_ptr
;
345 "_align_bulk_data_buffers: Align offset found (%d) but skb is NULL!\n",
349 if (bulkdata
->d
[i
].data_length
== 0) {
351 "_align_bulk_data_buffers: Align offset found (%d) but length is zero\n",
353 return CSR_RESULT_SUCCESS
;
355 unifi_trace(priv
, UDBG5
,
356 "Align f-h buffer (0x%p) by %d bytes (skb->data: 0x%p)\n",
357 bulkdata
->d
[i
].os_data_ptr
, align_offset
, skb
->data
);
360 /* Check if there is enough headroom... */
361 if (unlikely(skb_headroom(skb
) < align_offset
))
363 struct sk_buff
*tmp
= skb
;
365 unifi_trace(priv
, UDBG5
, "Headroom not enough - realloc it\n");
366 skb
= skb_realloc_headroom(skb
, align_offset
);
369 "_align_bulk_data_buffers: skb_realloc_headroom failed - signal is dropped\n");
372 /* Free the old bulk data only if allocation succeeds */
374 /* Bulkdata needs to point to the new skb */
375 bulkdata
->d
[i
].os_net_buf_ptr
= (const unsigned char*)skb
;
376 bulkdata
->d
[i
].os_data_ptr
= (const void*)skb
->data
;
378 /* ... before pushing the data to the right alignment offset */
379 skb_push(skb
, align_offset
);
382 /* The direction bit is zero for the from-host */
383 signal
[SIZEOF_SIGNAL_HEADER
+ (i
* SIZEOF_DATAREF
) + 1] = align_offset
;
387 } /* _align_bulk_data_buffers() */
391 * ---------------------------------------------------------------------------
392 * ul_send_signal_unpacked
394 * This function sends a host formatted signal to unifi.
397 * priv Pointer to driver's private data.
398 * sigptr Pointer to the signal.
399 * bulkdata Pointer to the signal's bulk data.
402 * O on success, error code otherwise.
405 * The signals have to be sent in the format described in the host interface
406 * specification, i.e wire formatted. Certain clients use the host formatted
407 * structures. The write_pack() transforms the host formatted signal
408 * into the wired formatted signal. The code is in the core, since the signals
409 * are defined therefore binded to the host interface specification.
410 * ---------------------------------------------------------------------------
413 ul_send_signal_unpacked(unifi_priv_t
*priv
, CSR_SIGNAL
*sigptr
,
414 bulk_data_param_t
*bulkdata
)
416 u8 sigbuf
[UNIFI_PACKED_SIGBUF_SIZE
];
419 unsigned long lock_flags
;
423 csrResult
= write_pack(sigptr
, sigbuf
, &packed_siglen
);
424 if (csrResult
!= CSR_RESULT_SUCCESS
) {
425 unifi_error(priv
, "Malformed HIP signal in ul_send_signal_unpacked()\n");
426 return CsrHipResultToStatus(csrResult
);
428 r
= _align_bulk_data_buffers(priv
, sigbuf
, (bulk_data_param_t
*)bulkdata
);
433 spin_lock_irqsave(&priv
->send_signal_lock
, lock_flags
);
434 csrResult
= unifi_send_signal(priv
->card
, sigbuf
, packed_siglen
, bulkdata
);
435 if (csrResult
!= CSR_RESULT_SUCCESS
) {
436 /* free_bulkdata_buffers(priv, (bulk_data_param_t *)bulkdata); */
437 spin_unlock_irqrestore(&priv
->send_signal_lock
, lock_flags
);
438 return CsrHipResultToStatus(csrResult
);
440 spin_unlock_irqrestore(&priv
->send_signal_lock
, lock_flags
);
443 } /* ul_send_signal_unpacked() */
447 * ---------------------------------------------------------------------------
448 * reset_driver_status
450 * This function is called from ul_send_signal_raw() when it detects
451 * that the SME has sent a MLME-RESET request.
454 * priv Pointer to device private struct
458 * ---------------------------------------------------------------------------
461 reset_driver_status(unifi_priv_t
*priv
)
463 priv
->sta_wmm_capabilities
= 0;
464 #ifdef CSR_NATIVE_LINUX
465 #ifdef CSR_SUPPORT_WEXT
466 priv
->wext_conf
.flag_associated
= 0;
467 priv
->wext_conf
.block_controlled_port
= CSR_WIFI_ROUTER_PORT_ACTION_8021X_PORT_OPEN
;
468 priv
->wext_conf
.bss_wmm_capabilities
= 0;
469 priv
->wext_conf
.disable_join_on_ssid_set
= 0;
472 } /* reset_driver_status() */
476 * ---------------------------------------------------------------------------
479 * This function sends a wire formatted data signal to unifi.
482 * priv Pointer to driver's private data.
483 * sigptr Pointer to the signal.
484 * siglen Length of the signal.
485 * bulkdata Pointer to the signal's bulk data.
488 * O on success, error code otherwise.
489 * ---------------------------------------------------------------------------
492 ul_send_signal_raw(unifi_priv_t
*priv
, unsigned char *sigptr
, int siglen
,
493 bulk_data_param_t
*bulkdata
)
496 unsigned long lock_flags
;
500 * Make sure that the signal is updated with the bulk data
503 r
= _align_bulk_data_buffers(priv
, (u8
*)sigptr
, bulkdata
);
508 spin_lock_irqsave(&priv
->send_signal_lock
, lock_flags
);
509 csrResult
= unifi_send_signal(priv
->card
, sigptr
, siglen
, bulkdata
);
510 if (csrResult
!= CSR_RESULT_SUCCESS
) {
511 free_bulkdata_buffers(priv
, bulkdata
);
512 spin_unlock_irqrestore(&priv
->send_signal_lock
, lock_flags
);
513 return CsrHipResultToStatus(csrResult
);
515 spin_unlock_irqrestore(&priv
->send_signal_lock
, lock_flags
);
518 * Since this is use by unicli, if we get an MLME reset request
519 * we need to initialize a few status parameters
520 * that the driver uses to make decisions.
522 if (GET_SIGNAL_ID(sigptr
) == CSR_MLME_RESET_REQUEST_ID
) {
523 reset_driver_status(priv
);
527 } /* ul_send_signal_raw() */