aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/csr/sme_userspace.c
blob: abcb446fb8c00f7c5a3f354236de3a51ff091b5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/*
 *****************************************************************************
 *
 * FILE : sme_userspace.c
 *
 * PURPOSE : Support functions for userspace SME helper application.
 *
 *
 * Copyright (C) 2008-2011 by Cambridge Silicon Radio Ltd.
 *
 * Refer to LICENSE.txt included with this source code for details on
 * the license terms.
 *
 *****************************************************************************
 */

#include "unifi_priv.h"

/*
 * Fix Me..... These need to be the correct values...
 * Dynamic from the user space.
 */
CsrSchedQid CSR_WIFI_ROUTER_IFACEQUEUE   = 0xFFFF;
CsrSchedQid CSR_WIFI_SME_IFACEQUEUE      = 0xFFFF;
#ifdef CSR_SUPPORT_WEXT_AP
CsrSchedQid CSR_WIFI_NME_IFACEQUEUE      = 0xFFFF;
#endif
int
uf_sme_init(unifi_priv_t *priv)
{
    int i, j;

    CsrWifiRouterTransportInit(priv);

    priv->smepriv = priv;

    init_waitqueue_head(&priv->sme_request_wq);

    priv->filter_tclas_ies = NULL;
    memset(&priv->packet_filters, 0, sizeof(uf_cfg_bcast_packet_filter_t));

#ifdef CSR_SUPPORT_WEXT
    priv->ignore_bssid_join = FALSE;
    priv->mib_data.length = 0;

    uf_sme_wext_set_defaults(priv);
#endif /* CSR_SUPPORT_WEXT*/

    priv->sta_ip_address = 0xFFFFFFFF;

    priv->wifi_on_state = wifi_on_unspecified;

    sema_init(&priv->sme_sem, 1);
    memset(&priv->sme_reply, 0, sizeof(sme_reply_t));

    priv->ta_ind_work.in_use = 0;
    priv->ta_sample_ind_work.in_use = 0;

    priv->CSR_WIFI_SME_IFACEQUEUE = 0xFFFF;

    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
        priv->sme_unidata_ind_filters[i].in_use = 0;
    }

    /* Create a work queue item for Traffic Analysis indications to SME */
    INIT_WORK(&priv->ta_ind_work.task, uf_ta_ind_wq);
    INIT_WORK(&priv->ta_sample_ind_work.task, uf_ta_sample_ind_wq);
#ifdef CSR_SUPPORT_WEXT
    INIT_WORK(&priv->sme_config_task, uf_sme_config_wq);
#endif

    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
        interfacePriv->m4_sent = FALSE;
        interfacePriv->m4_bulk_data.net_buf_length = 0;
        interfacePriv->m4_bulk_data.data_length = 0;
        interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL;

        memset(&interfacePriv->controlled_data_port, 0, sizeof(unifi_port_config_t));
        interfacePriv->controlled_data_port.entries_in_use = 1;
        interfacePriv->controlled_data_port.port_cfg[0].in_use = TRUE;
        interfacePriv->controlled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
        interfacePriv->controlled_data_port.overide_action = UF_DATA_PORT_OVERIDE;

        memset(&interfacePriv->uncontrolled_data_port, 0, sizeof(unifi_port_config_t));
        interfacePriv->uncontrolled_data_port.entries_in_use = 1;
        interfacePriv->uncontrolled_data_port.port_cfg[0].in_use = TRUE;
        interfacePriv->uncontrolled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
        interfacePriv->uncontrolled_data_port.overide_action = UF_DATA_PORT_OVERIDE;

        /* Mark the remainder of the port config table as unallocated */
        for(j = 1; j < UNIFI_MAX_CONNECTIONS; j++) {
            interfacePriv->controlled_data_port.port_cfg[j].in_use = FALSE;
            interfacePriv->controlled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;

            interfacePriv->uncontrolled_data_port.port_cfg[j].in_use = FALSE;
            interfacePriv->uncontrolled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
        }

        /* intializing the lists */
        INIT_LIST_HEAD(&interfacePriv->genericMgtFrames);
        INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastMgtFrames);
        INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastFrames);

        for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
            interfacePriv->staInfo[j] = NULL;
        }

        interfacePriv->num_stations_joined = 0;
        interfacePriv->sta_activity_check_enabled = FALSE;
    }


    return 0;
} /* uf_sme_init() */


void
uf_sme_deinit(unifi_priv_t *priv)
{
    int i,j;
    u8 ba_session_idx;
    ba_session_rx_struct *ba_session_rx = NULL;
    ba_session_tx_struct *ba_session_tx = NULL;
    CsrWifiRouterCtrlStaInfo_t *staInfo = NULL;
    netInterface_priv_t *interfacePriv = NULL;

    /* Free any TCLASs previously allocated */
    if (priv->packet_filters.tclas_ies_length) {
        priv->packet_filters.tclas_ies_length = 0;
        kfree(priv->filter_tclas_ies);
        priv->filter_tclas_ies = NULL;
    }

    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
        priv->sme_unidata_ind_filters[i].in_use = 0;
    }

    /* Remove all the Peer database, before going down */
    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
        down(&priv->ba_mutex);
        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
            ba_session_rx = priv->interfacePriv[i]->ba_session_rx[ba_session_idx];
            if(ba_session_rx) {
                blockack_session_stop(priv,
                                    i,
                                    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT,
                                    ba_session_rx->tID,
                                    ba_session_rx->macAddress);
            }
        }
        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
            ba_session_tx = priv->interfacePriv[i]->ba_session_tx[ba_session_idx];
            if(ba_session_tx) {
                blockack_session_stop(priv,
                                    i,
                                    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR,
                                    ba_session_tx->tID,
                                    ba_session_tx->macAddress);
            }
        }

        up(&priv->ba_mutex);
        interfacePriv = priv->interfacePriv[i];
        if(interfacePriv){
            for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
                if ((staInfo=interfacePriv->staInfo[j]) != NULL) {
                    /* Clear the STA activity parameters before freeing station Record */
                    unifi_trace(priv, UDBG1, "uf_sme_deinit: Canceling work queue for STA with AID: %d\n", staInfo->aid);
                    cancel_work_sync(&staInfo->send_disconnected_ind_task);
                    staInfo->nullDataHostTag = INVALID_HOST_TAG;
                }
            }
            if (interfacePriv->sta_activity_check_enabled){
                interfacePriv->sta_activity_check_enabled = FALSE;
                del_timer_sync(&interfacePriv->sta_activity_check_timer);
            }
        }
        CsrWifiRouterCtrlInterfaceReset(priv, i);
        priv->interfacePriv[i]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_NONE;
    }


} /* uf_sme_deinit() */





/*
 * ---------------------------------------------------------------------------
 *  unifi_ta_indicate_protocol
 *
 *      Report that a packet of a particular type has been seen
 *
 *  Arguments:
 *      drv_priv        The device context pointer passed to ta_init.
 *      protocol        The protocol type enum value.
 *      direction       Whether the packet was a tx or rx.
 *      src_addr        The source MAC address from the data packet.
 *
 *  Returns:
 *      None.
 *
 *  Notes:
 *      We defer the actual sending to a background workqueue,
 *      see uf_ta_ind_wq().
 * ---------------------------------------------------------------------------
 */
void
unifi_ta_indicate_protocol(void *ospriv,
                           CsrWifiRouterCtrlTrafficPacketType packet_type,
                           CsrWifiRouterCtrlProtocolDirection direction,
                           const CsrWifiMacAddress *src_addr)
{
    unifi_priv_t *priv = (unifi_priv_t*)ospriv;

    if (priv->ta_ind_work.in_use) {
        unifi_warning(priv,
                "unifi_ta_indicate_protocol: workqueue item still in use, not sending\n");
        return;
    }

    if (CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX == direction)
    {
        u16 interfaceTag = 0;
        CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
                interfaceTag,
                packet_type,
                direction,
                *src_addr);
    }
    else
    {
        priv->ta_ind_work.packet_type = packet_type;
        priv->ta_ind_work.direction = direction;
        priv->ta_ind_work.src_addr = *src_addr;

        queue_work(priv->unifi_workqueue, &priv->ta_ind_work.task);
    }

} /* unifi_ta_indicate_protocol() */


/*
 * ---------------------------------------------------------------------------
 * unifi_ta_indicate_sampling
 *
 *      Send the TA sampling information to the SME.
 *
 *  Arguments:
 *      drv_priv        The device context pointer passed to ta_init.
 *      stats   The TA sampling data to send.
 *
 *  Returns:
 *      None.
 * ---------------------------------------------------------------------------
 */
void
unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
{
    unifi_priv_t *priv = (unifi_priv_t*)ospriv;

    if (!priv) {
        return;
    }

    if (priv->ta_sample_ind_work.in_use) {
        unifi_warning(priv,
                     "unifi_ta_indicate_sampling: workqueue item still in use, not sending\n");
        return;
    }

    priv->ta_sample_ind_work.stats = *stats;

    queue_work(priv->unifi_workqueue, &priv->ta_sample_ind_work.task);

} /* unifi_ta_indicate_sampling() */


/*
 * ---------------------------------------------------------------------------
 * unifi_ta_indicate_l4stats
 *
 *      Send the TA TCP/UDP throughput information to the driver.
 *
 *  Arguments:
 *    drv_priv        The device context pointer passed to ta_init.
 *    rxTcpThroughput TCP RX throughput in KiloBytes
 *    txTcpThroughput TCP TX throughput in KiloBytes
 *    rxUdpThroughput UDP RX throughput in KiloBytes
 *    txUdpThroughput UDP TX throughput in KiloBytes
 *
 *  Returns:
 *      None.
 * ---------------------------------------------------------------------------
 */
void
unifi_ta_indicate_l4stats(void *ospriv,
                          u32 rxTcpThroughput,
                          u32 txTcpThroughput,
                          u32 rxUdpThroughput,
                          u32 txUdpThroughput)
{
    unifi_priv_t *priv = (unifi_priv_t*)ospriv;

    if (!priv) {
        return;
    }
    /* Save the info. The actual action will be taken in unifi_ta_indicate_sampling() */
    priv->rxTcpThroughput = rxTcpThroughput;
    priv->txTcpThroughput = txTcpThroughput;
    priv->rxUdpThroughput = rxUdpThroughput;
    priv->txUdpThroughput = txUdpThroughput;
} /* unifi_ta_indicate_l4stats() */