]> Pileus Git - ~andy/linux/blob - drivers/staging/csr/sme_userspace.c
Merge tag 'mfd-3.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
[~andy/linux] / drivers / staging / csr / sme_userspace.c
1 /*
2  *****************************************************************************
3  *
4  * FILE : sme_userspace.c
5  *
6  * PURPOSE : Support functions for userspace SME helper application.
7  *
8  *
9  * Copyright (C) 2008-2011 by Cambridge Silicon Radio Ltd.
10  *
11  * Refer to LICENSE.txt included with this source code for details on
12  * the license terms.
13  *
14  *****************************************************************************
15  */
16
17 #include "unifi_priv.h"
18
19 /*
20  * Fix Me..... These need to be the correct values...
21  * Dynamic from the user space.
22  */
23 CsrSchedQid CSR_WIFI_ROUTER_IFACEQUEUE   = 0xFFFF;
24 CsrSchedQid CSR_WIFI_SME_IFACEQUEUE      = 0xFFFF;
25 #ifdef CSR_SUPPORT_WEXT_AP
26 CsrSchedQid CSR_WIFI_NME_IFACEQUEUE      = 0xFFFF;
27 #endif
28 int
29 uf_sme_init(unifi_priv_t *priv)
30 {
31     int i, j;
32
33     CsrWifiRouterTransportInit(priv);
34
35     priv->smepriv = priv;
36
37     init_waitqueue_head(&priv->sme_request_wq);
38
39     priv->filter_tclas_ies = NULL;
40     memset(&priv->packet_filters, 0, sizeof(uf_cfg_bcast_packet_filter_t));
41
42 #ifdef CSR_SUPPORT_WEXT
43     priv->ignore_bssid_join = FALSE;
44     priv->mib_data.length = 0;
45
46     uf_sme_wext_set_defaults(priv);
47 #endif /* CSR_SUPPORT_WEXT*/
48
49     priv->sta_ip_address = 0xFFFFFFFF;
50
51     priv->wifi_on_state = wifi_on_unspecified;
52
53     sema_init(&priv->sme_sem, 1);
54     memset(&priv->sme_reply, 0, sizeof(sme_reply_t));
55
56     priv->ta_ind_work.in_use = 0;
57     priv->ta_sample_ind_work.in_use = 0;
58
59     priv->CSR_WIFI_SME_IFACEQUEUE = 0xFFFF;
60
61     for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
62         priv->sme_unidata_ind_filters[i].in_use = 0;
63     }
64
65     /* Create a work queue item for Traffic Analysis indications to SME */
66     INIT_WORK(&priv->ta_ind_work.task, uf_ta_ind_wq);
67     INIT_WORK(&priv->ta_sample_ind_work.task, uf_ta_sample_ind_wq);
68 #ifdef CSR_SUPPORT_WEXT
69     INIT_WORK(&priv->sme_config_task, uf_sme_config_wq);
70 #endif
71
72     for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
73         netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
74         interfacePriv->m4_sent = FALSE;
75         interfacePriv->m4_bulk_data.net_buf_length = 0;
76         interfacePriv->m4_bulk_data.data_length = 0;
77         interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL;
78
79         memset(&interfacePriv->controlled_data_port, 0, sizeof(unifi_port_config_t));
80         interfacePriv->controlled_data_port.entries_in_use = 1;
81         interfacePriv->controlled_data_port.port_cfg[0].in_use = TRUE;
82         interfacePriv->controlled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
83         interfacePriv->controlled_data_port.overide_action = UF_DATA_PORT_OVERIDE;
84
85         memset(&interfacePriv->uncontrolled_data_port, 0, sizeof(unifi_port_config_t));
86         interfacePriv->uncontrolled_data_port.entries_in_use = 1;
87         interfacePriv->uncontrolled_data_port.port_cfg[0].in_use = TRUE;
88         interfacePriv->uncontrolled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
89         interfacePriv->uncontrolled_data_port.overide_action = UF_DATA_PORT_OVERIDE;
90
91         /* Mark the remainder of the port config table as unallocated */
92         for(j = 1; j < UNIFI_MAX_CONNECTIONS; j++) {
93             interfacePriv->controlled_data_port.port_cfg[j].in_use = FALSE;
94             interfacePriv->controlled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
95
96             interfacePriv->uncontrolled_data_port.port_cfg[j].in_use = FALSE;
97             interfacePriv->uncontrolled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
98         }
99
100         /* intializing the lists */
101         INIT_LIST_HEAD(&interfacePriv->genericMgtFrames);
102         INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastMgtFrames);
103         INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastFrames);
104
105         for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
106             interfacePriv->staInfo[j] = NULL;
107         }
108
109         interfacePriv->num_stations_joined = 0;
110         interfacePriv->sta_activity_check_enabled = FALSE;
111     }
112
113
114     return 0;
115 } /* uf_sme_init() */
116
117
118 void
119 uf_sme_deinit(unifi_priv_t *priv)
120 {
121     int i,j;
122     u8 ba_session_idx;
123     ba_session_rx_struct *ba_session_rx = NULL;
124     ba_session_tx_struct *ba_session_tx = NULL;
125     CsrWifiRouterCtrlStaInfo_t *staInfo = NULL;
126     netInterface_priv_t *interfacePriv = NULL;
127
128     /* Free any TCLASs previously allocated */
129     if (priv->packet_filters.tclas_ies_length) {
130         priv->packet_filters.tclas_ies_length = 0;
131         kfree(priv->filter_tclas_ies);
132         priv->filter_tclas_ies = NULL;
133     }
134
135     for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
136         priv->sme_unidata_ind_filters[i].in_use = 0;
137     }
138
139     /* Remove all the Peer database, before going down */
140     for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
141         down(&priv->ba_mutex);
142         for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
143             ba_session_rx = priv->interfacePriv[i]->ba_session_rx[ba_session_idx];
144             if(ba_session_rx) {
145                 blockack_session_stop(priv,
146                                     i,
147                                     CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT,
148                                     ba_session_rx->tID,
149                                     ba_session_rx->macAddress);
150             }
151         }
152         for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
153             ba_session_tx = priv->interfacePriv[i]->ba_session_tx[ba_session_idx];
154             if(ba_session_tx) {
155                 blockack_session_stop(priv,
156                                     i,
157                                     CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR,
158                                     ba_session_tx->tID,
159                                     ba_session_tx->macAddress);
160             }
161         }
162
163         up(&priv->ba_mutex);
164         interfacePriv = priv->interfacePriv[i];
165         if(interfacePriv){
166             for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
167                 if ((staInfo=interfacePriv->staInfo[j]) != NULL) {
168                     /* Clear the STA activity parameters before freeing station Record */
169                     unifi_trace(priv, UDBG1, "uf_sme_deinit: Canceling work queue for STA with AID: %d\n", staInfo->aid);
170                     cancel_work_sync(&staInfo->send_disconnected_ind_task);
171                     staInfo->nullDataHostTag = INVALID_HOST_TAG;
172                 }
173             }
174             if (interfacePriv->sta_activity_check_enabled){
175                 interfacePriv->sta_activity_check_enabled = FALSE;
176                 del_timer_sync(&interfacePriv->sta_activity_check_timer);
177             }
178         }
179         CsrWifiRouterCtrlInterfaceReset(priv, i);
180         priv->interfacePriv[i]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_NONE;
181     }
182
183
184 } /* uf_sme_deinit() */
185
186
187
188
189
190 /*
191  * ---------------------------------------------------------------------------
192  *  unifi_ta_indicate_protocol
193  *
194  *      Report that a packet of a particular type has been seen
195  *
196  *  Arguments:
197  *      drv_priv        The device context pointer passed to ta_init.
198  *      protocol        The protocol type enum value.
199  *      direction       Whether the packet was a tx or rx.
200  *      src_addr        The source MAC address from the data packet.
201  *
202  *  Returns:
203  *      None.
204  *
205  *  Notes:
206  *      We defer the actual sending to a background workqueue,
207  *      see uf_ta_ind_wq().
208  * ---------------------------------------------------------------------------
209  */
210 void
211 unifi_ta_indicate_protocol(void *ospriv,
212                            CsrWifiRouterCtrlTrafficPacketType packet_type,
213                            CsrWifiRouterCtrlProtocolDirection direction,
214                            const CsrWifiMacAddress *src_addr)
215 {
216     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
217
218     if (priv->ta_ind_work.in_use) {
219         unifi_warning(priv,
220                 "unifi_ta_indicate_protocol: workqueue item still in use, not sending\n");
221         return;
222     }
223
224     if (CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX == direction)
225     {
226         u16 interfaceTag = 0;
227         CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
228                 interfaceTag,
229                 packet_type,
230                 direction,
231                 *src_addr);
232     }
233     else
234     {
235         priv->ta_ind_work.packet_type = packet_type;
236         priv->ta_ind_work.direction = direction;
237         priv->ta_ind_work.src_addr = *src_addr;
238
239         queue_work(priv->unifi_workqueue, &priv->ta_ind_work.task);
240     }
241
242 } /* unifi_ta_indicate_protocol() */
243
244
245 /*
246  * ---------------------------------------------------------------------------
247  * unifi_ta_indicate_sampling
248  *
249  *      Send the TA sampling information to the SME.
250  *
251  *  Arguments:
252  *      drv_priv        The device context pointer passed to ta_init.
253  *      stats   The TA sampling data to send.
254  *
255  *  Returns:
256  *      None.
257  * ---------------------------------------------------------------------------
258  */
259 void
260 unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
261 {
262     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
263
264     if (!priv) {
265         return;
266     }
267
268     if (priv->ta_sample_ind_work.in_use) {
269         unifi_warning(priv,
270                      "unifi_ta_indicate_sampling: workqueue item still in use, not sending\n");
271         return;
272     }
273
274     priv->ta_sample_ind_work.stats = *stats;
275
276     queue_work(priv->unifi_workqueue, &priv->ta_sample_ind_work.task);
277
278 } /* unifi_ta_indicate_sampling() */
279
280
281 /*
282  * ---------------------------------------------------------------------------
283  * unifi_ta_indicate_l4stats
284  *
285  *      Send the TA TCP/UDP throughput information to the driver.
286  *
287  *  Arguments:
288  *    drv_priv        The device context pointer passed to ta_init.
289  *    rxTcpThroughput TCP RX throughput in KiloBytes
290  *    txTcpThroughput TCP TX throughput in KiloBytes
291  *    rxUdpThroughput UDP RX throughput in KiloBytes
292  *    txUdpThroughput UDP TX throughput in KiloBytes
293  *
294  *  Returns:
295  *      None.
296  * ---------------------------------------------------------------------------
297  */
298 void
299 unifi_ta_indicate_l4stats(void *ospriv,
300                           u32 rxTcpThroughput,
301                           u32 txTcpThroughput,
302                           u32 rxUdpThroughput,
303                           u32 txUdpThroughput)
304 {
305     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
306
307     if (!priv) {
308         return;
309     }
310     /* Save the info. The actual action will be taken in unifi_ta_indicate_sampling() */
311     priv->rxTcpThroughput = rxTcpThroughput;
312     priv->txTcpThroughput = txTcpThroughput;
313     priv->rxUdpThroughput = rxUdpThroughput;
314     priv->txUdpThroughput = txUdpThroughput;
315 } /* unifi_ta_indicate_l4stats() */