Root/drivers/staging/csr/csr_wifi_hip_ta_sampling.c

1/*****************************************************************************
2
3            (c) Cambridge Silicon Radio Limited 2012
4            All rights reserved and confidential information of CSR
5
6            Refer to LICENSE.txt included with this source for details
7            on the license terms.
8
9*****************************************************************************/
10
11/*
12 * ---------------------------------------------------------------------------
13 * FILE: csr_wifi_hip_ta_sampling.c
14 *
15 * PURPOSE:
16 * The traffic analysis sampling module.
17 * This gathers data which is sent to the SME and used to analyse
18 * the traffic behaviour.
19 *
20 * Provides:
21 * unifi_ta_sampling_init - Initialise the internal state
22 * unifi_ta_sample - Sampling function, call this for every data packet
23 *
24 * Calls these external functions which must be provided:
25 * unifi_ta_indicate_sampling - Pass sample data to the SME.
26 * unifi_ta_indicate_protocol - Report certain data packet types to the SME.
27 * ---------------------------------------------------------------------------
28 */
29
30#include "csr_wifi_hip_card_sdio.h"
31
32/* Maximum number of Tx frames we store each CYCLE_1, for detecting period */
33#define TA_MAX_INTERVALS_IN_C1 100
34
35/* Number of intervals in CYCLE_1 (one second), for detecting periodic */
36/* Must match size of unifi_TrafficStats.intervals - 1 */
37#define TA_INTERVALS_NUM 10
38
39/* Step (in msecs) between intervals, for detecting periodic */
40/* We are only interested in periods up to 100ms, i.e. between beacons */
41/* This is correct for TA_INTERVALS_NUM=10 */
42#define TA_INTERVALS_STEP 10
43
44
45enum ta_frame_identity
46{
47    TA_FRAME_UNKNOWN,
48    TA_FRAME_ETHERNET_UNINTERESTING,
49    TA_FRAME_ETHERNET_INTERESTING
50};
51
52
53#define TA_ETHERNET_TYPE_OFFSET 6
54#define TA_LLC_HEADER_SIZE 8
55#define TA_IP_TYPE_OFFSET 17
56#define TA_UDP_SOURCE_PORT_OFFSET 28
57#define TA_UDP_DEST_PORT_OFFSET (TA_UDP_SOURCE_PORT_OFFSET + 2)
58#define TA_BOOTP_CLIENT_MAC_ADDR_OFFSET 64
59#define TA_DHCP_MESSAGE_TYPE_OFFSET 278
60#define TA_DHCP_MESSAGE_TYPE_ACK 0x05
61#define TA_PROTO_TYPE_IP 0x0800
62#define TA_PROTO_TYPE_EAP 0x888E
63#define TA_PROTO_TYPE_WAI 0x8864
64#define TA_PROTO_TYPE_ARP 0x0806
65#define TA_IP_TYPE_TCP 0x06
66#define TA_IP_TYPE_UDP 0x11
67#define TA_UDP_PORT_BOOTPC 0x0044
68#define TA_UDP_PORT_BOOTPS 0x0043
69#define TA_EAPOL_TYPE_OFFSET 9
70#define TA_EAPOL_TYPE_START 0x01
71
72#define snap_802_2 0xAAAA0300
73#define oui_rfc1042 0x00000000
74#define oui_8021h 0x0000f800
75static const u8 aironet_snap[5] = { 0x00, 0x40, 0x96, 0x00, 0x00 };
76
77
78/*
79 * ---------------------------------------------------------------------------
80 * ta_detect_protocol
81 *
82 * Internal only.
83 * Detects a specific protocol in a frame and indicates a TA event.
84 *
85 * Arguments:
86 * ta The pointer to the TA module.
87 * direction The direction of the frame (tx or rx).
88 * data Pointer to the structure that contains the data.
89 *
90 * Returns:
91 * None
92 * ---------------------------------------------------------------------------
93 */
94static enum ta_frame_identity ta_detect_protocol(card_t *card, CsrWifiRouterCtrlProtocolDirection direction,
95                                                 const bulk_data_desc_t *data,
96                                                 const u8 *saddr,
97                                                 const u8 *sta_macaddr)
98{
99    ta_data_t *tad = &card->ta_sampling;
100    u16 proto;
101    u16 source_port, dest_port;
102    CsrWifiMacAddress srcAddress;
103    u32 snap_hdr, oui_hdr;
104
105    if (data->data_length < TA_LLC_HEADER_SIZE)
106    {
107        return TA_FRAME_UNKNOWN;
108    }
109
110    snap_hdr = (((u32)data->os_data_ptr[0]) << 24) |
111               (((u32)data->os_data_ptr[1]) << 16) |
112               (((u32)data->os_data_ptr[2]) << 8);
113    if (snap_hdr != snap_802_2)
114    {
115        return TA_FRAME_UNKNOWN;
116    }
117
118    if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
119    {
120        /*
121         * Here we would use the custom filter to detect interesting frames.
122         */
123    }
124
125    oui_hdr = (((u32)data->os_data_ptr[3]) << 24) |
126              (((u32)data->os_data_ptr[4]) << 16) |
127              (((u32)data->os_data_ptr[5]) << 8);
128    if ((oui_hdr == oui_rfc1042) || (oui_hdr == oui_8021h))
129    {
130        proto = (data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET] * 256) +
131                data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET + 1];
132
133        /* The only interesting IP frames are the DHCP */
134        if (proto == TA_PROTO_TYPE_IP)
135        {
136            if (data->data_length > TA_IP_TYPE_OFFSET)
137            {
138                if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
139                {
140                    ta_l4stats_t *ta_l4stats = &tad->ta_l4stats;
141                    u8 l4proto = data->os_data_ptr[TA_IP_TYPE_OFFSET];
142
143                    if (l4proto == TA_IP_TYPE_TCP)
144                    {
145                        if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
146                        {
147                            ta_l4stats->txTcpBytesCount += data->data_length;
148                        }
149                        else
150                        {
151                            ta_l4stats->rxTcpBytesCount += data->data_length;
152                        }
153                    }
154                    else if (l4proto == TA_IP_TYPE_UDP)
155                    {
156                        if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
157                        {
158                            ta_l4stats->txUdpBytesCount += data->data_length;
159                        }
160                        else
161                        {
162                            ta_l4stats->rxUdpBytesCount += data->data_length;
163                        }
164                    }
165                }
166
167                /* detect DHCP frames */
168                if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP)
169                {
170                    /* DHCP frames are UDP frames with BOOTP ports */
171                    if (data->os_data_ptr[TA_IP_TYPE_OFFSET] == TA_IP_TYPE_UDP)
172                    {
173                        if (data->data_length > TA_UDP_DEST_PORT_OFFSET)
174                        {
175                            source_port = (data->os_data_ptr[TA_UDP_SOURCE_PORT_OFFSET] * 256) +
176                                          data->os_data_ptr[TA_UDP_SOURCE_PORT_OFFSET + 1];
177                            dest_port = (data->os_data_ptr[TA_UDP_DEST_PORT_OFFSET] * 256) +
178                                        data->os_data_ptr[TA_UDP_DEST_PORT_OFFSET + 1];
179
180                            if (((source_port == TA_UDP_PORT_BOOTPC) && (dest_port == TA_UDP_PORT_BOOTPS)) ||
181                                ((source_port == TA_UDP_PORT_BOOTPS) && (dest_port == TA_UDP_PORT_BOOTPC)))
182                            {
183                                /* The DHCP should have at least a message type (request, ack, nack, etc) */
184                                if (data->data_length > TA_DHCP_MESSAGE_TYPE_OFFSET + 6)
185                                {
186                                    UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
187
188                                    if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
189                                    {
190                                        unifi_ta_indicate_protocol(card->ospriv,
191                                                                   CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
192                                                                   direction,
193                                                                   &srcAddress);
194                                        return TA_FRAME_ETHERNET_UNINTERESTING;
195                                    }
196
197                                    /* DHCPACK is a special indication */
198                                    if (UNIFI_MAC_ADDRESS_CMP(data->os_data_ptr + TA_BOOTP_CLIENT_MAC_ADDR_OFFSET, sta_macaddr) == TRUE)
199                                    {
200                                        if (data->os_data_ptr[TA_DHCP_MESSAGE_TYPE_OFFSET] == TA_DHCP_MESSAGE_TYPE_ACK)
201                                        {
202                                            unifi_ta_indicate_protocol(card->ospriv,
203                                                                       CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP_ACK,
204                                                                       direction,
205                                                                       &srcAddress);
206                                        }
207                                        else
208                                        {
209                                            unifi_ta_indicate_protocol(card->ospriv,
210                                                                       CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
211                                                                       direction,
212                                                                       &srcAddress);
213                                        }
214                                    }
215                                }
216                            }
217                        }
218                    }
219                }
220            }
221
222            return TA_FRAME_ETHERNET_INTERESTING;
223        }
224
225        /* detect protocol type EAPOL or WAI (treated as equivalent here) */
226        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL)
227        {
228            if (TA_PROTO_TYPE_EAP == proto || TA_PROTO_TYPE_WAI == proto)
229            {
230                if ((TA_PROTO_TYPE_WAI == proto) || (direction != CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX) ||
231                    (data->os_data_ptr[TA_EAPOL_TYPE_OFFSET] == TA_EAPOL_TYPE_START))
232                {
233                    UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
234                    unifi_ta_indicate_protocol(card->ospriv,
235                                               CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL,
236                                               direction, &srcAddress);
237                }
238                return TA_FRAME_ETHERNET_UNINTERESTING;
239            }
240        }
241
242        /* detect protocol type 0x0806 (ARP) */
243        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP)
244        {
245            if (proto == TA_PROTO_TYPE_ARP)
246            {
247                UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
248                unifi_ta_indicate_protocol(card->ospriv,
249                                           CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP,
250                                           direction, &srcAddress);
251                return TA_FRAME_ETHERNET_UNINTERESTING;
252            }
253        }
254
255        return TA_FRAME_ETHERNET_INTERESTING;
256    }
257    else if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET)
258    {
259        /* detect Aironet frames */
260        if (!memcmp(data->os_data_ptr + 3, aironet_snap, 5))
261        {
262            UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
263            unifi_ta_indicate_protocol(card->ospriv, CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET,
264                                       direction, &srcAddress);
265        }
266    }
267
268    return TA_FRAME_ETHERNET_UNINTERESTING;
269} /* ta_detect_protocol() */
270
271
272static void tas_reset_data(ta_data_t *tad)
273{
274    s16 i;
275
276    for (i = 0; i < (TA_INTERVALS_NUM + 1); i++)
277    {
278        tad->stats.intervals[i] = 0;
279    }
280
281    tad->stats.rxFramesNum = 0;
282    tad->stats.txFramesNum = 0;
283    tad->stats.rxBytesCount = 0;
284    tad->stats.txBytesCount = 0;
285    tad->stats.rxMeanRate = 0;
286
287    tad->rx_sum_rate = 0;
288
289    tad->ta_l4stats.rxTcpBytesCount = 0;
290    tad->ta_l4stats.txTcpBytesCount = 0;
291    tad->ta_l4stats.rxUdpBytesCount = 0;
292    tad->ta_l4stats.txUdpBytesCount = 0;
293} /* tas_reset_data() */
294
295
296/*
297 * ---------------------------------------------------------------------------
298 * API.
299 * unifi_ta_sampling_init
300 *
301 * (Re)Initialise the Traffic Analysis sampling module.
302 * Resets the counters and timestamps.
303 *
304 * Arguments:
305 * tad Pointer to a ta_data_t structure containing the
306 * context for this device instance.
307 * drv_priv An opaque pointer that the TA sampling module will
308 * pass in call-outs.
309 *
310 * Returns:
311 * None.
312 * ---------------------------------------------------------------------------
313 */
314void unifi_ta_sampling_init(card_t *card)
315{
316    (void)unifi_ta_configure(card, CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET, NULL);
317
318    card->ta_sampling.packet_filter = CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE;
319    card->ta_sampling.traffic_type = CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_OCCASIONAL;
320} /* unifi_ta_sampling_init() */
321
322
323/*
324 * ---------------------------------------------------------------------------
325 * API.
326 * unifi_ta_sample
327 *
328 * Sample a data frame for the TA module.
329 * This function stores all the useful information it can extract from
330 * the frame and detects any specific protocols.
331 *
332 * Arguments:
333 * tad The pointer to the TA sampling context struct.
334 * direction The direction of the frame (rx, tx)
335 * data Pointer to the frame data
336 * saddr Source MAC address of frame.
337 * timestamp Time (in msecs) that the frame was received.
338 * rate Reported data rate for the rx frame (0 for tx frames)
339 *
340 * Returns:
341 * None
342 * ---------------------------------------------------------------------------
343 */
344void unifi_ta_sample(card_t *card,
345                     CsrWifiRouterCtrlProtocolDirection direction,
346                     const bulk_data_desc_t *data,
347                     const u8 *saddr,
348                     const u8 *sta_macaddr,
349                     u32 timestamp,
350                     u16 rate)
351{
352    ta_data_t *tad = &card->ta_sampling;
353    enum ta_frame_identity identity;
354    u32 time_delta;
355
356
357
358    /* Step1: Check for specific frames */
359    if (tad->packet_filter != CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE)
360    {
361        identity = ta_detect_protocol(card, direction, data, saddr, sta_macaddr);
362    }
363    else
364    {
365        identity = TA_FRAME_ETHERNET_INTERESTING;
366    }
367
368
369    /* Step2: Update the information in the current record */
370    if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX)
371    {
372        /* Update the Rx packet count and the throughput count */
373        tad->stats.rxFramesNum++;
374        tad->stats.rxBytesCount += data->data_length;
375
376        /* Accumulate packet Rx rates for later averaging */
377        tad->rx_sum_rate += rate;
378    }
379    else
380    {
381        if (identity == TA_FRAME_ETHERNET_INTERESTING)
382        {
383            /*
384             * Store the period between the last and the current frame.
385             * There is not point storing more than TA_MAX_INTERVALS_IN_C1 periods,
386             * the traffic will be bursty or continuous.
387             */
388            if (tad->stats.txFramesNum < TA_MAX_INTERVALS_IN_C1)
389            {
390                u32 interval;
391                u32 index_in_intervals;
392
393                interval = timestamp - tad->tx_last_ts;
394                tad->tx_last_ts = timestamp;
395                index_in_intervals = (interval + TA_INTERVALS_STEP / 2 - 1) / TA_INTERVALS_STEP;
396
397                /* If the interval is interesting, update the t1_intervals count */
398                if (index_in_intervals <= TA_INTERVALS_NUM)
399                {
400                    unifi_trace(card->ospriv, UDBG5,
401                                "unifi_ta_sample: TX interval=%d index=%d\n",
402                                interval, index_in_intervals);
403                    tad->stats.intervals[index_in_intervals]++;
404                }
405            }
406        }
407
408        /* Update the Tx packet count... */
409        tad->stats.txFramesNum++;
410        /* ... and the number of bytes for throughput. */
411        tad->stats.txBytesCount += data->data_length;
412    }
413
414    /*
415     * If more than one second has elapsed since the last report, send
416     * another one.
417     */
418    /* Unsigned subtraction handles wrap-around from 0xFFFFFFFF to 0 */
419    time_delta = timestamp - tad->last_indication_time;
420    if (time_delta >= 1000)
421    {
422        /*
423         * rxFramesNum can be flashed in tas_reset_data() by another thread.
424         * Use a temp to avoid division by zero.
425         */
426        u32 temp_rxFramesNum;
427        temp_rxFramesNum = tad->stats.rxFramesNum;
428
429        /* Calculate this interval's mean frame Rx rate from the sum */
430        if (temp_rxFramesNum)
431        {
432            tad->stats.rxMeanRate = tad->rx_sum_rate / temp_rxFramesNum;
433        }
434        unifi_trace(card->ospriv, UDBG5,
435                    "unifi_ta_sample: RX fr=%lu, r=%u, sum=%lu, av=%lu\n",
436                    tad->stats.rxFramesNum, rate,
437                    tad->rx_sum_rate, tad->stats.rxMeanRate);
438
439        /*
440         * Send the information collected in the stats struct
441         * to the SME and reset the counters.
442         */
443        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
444        {
445            u32 rxTcpThroughput = tad->ta_l4stats.rxTcpBytesCount / time_delta;
446            u32 txTcpThroughput = tad->ta_l4stats.txTcpBytesCount / time_delta;
447            u32 rxUdpThroughput = tad->ta_l4stats.rxUdpBytesCount / time_delta;
448            u32 txUdpThroughput = tad->ta_l4stats.txUdpBytesCount / time_delta;
449
450            unifi_ta_indicate_l4stats(card->ospriv,
451                                      rxTcpThroughput,
452                                      txTcpThroughput,
453                                      rxUdpThroughput,
454                                      txUdpThroughput
455                                      );
456        }
457        unifi_ta_indicate_sampling(card->ospriv, &tad->stats);
458        tas_reset_data(tad);
459        tad->last_indication_time = timestamp;
460    }
461} /* unifi_ta_sample() */
462
463
464/*
465 * ---------------------------------------------------------------------------
466 * External API.
467 * unifi_ta_configure
468 *
469 * Configures the TA module parameters.
470 *
471 * Arguments:
472 * ta The pointer to the TA module.
473 * config_type The type of the configuration request
474 * config Pointer to the configuration parameters.
475 *
476 * Returns:
477 * CSR_RESULT_SUCCESS on success, CSR error code otherwise
478 * ---------------------------------------------------------------------------
479 */
480CsrResult unifi_ta_configure(card_t *card,
481                             CsrWifiRouterCtrlTrafficConfigType config_type,
482                             const CsrWifiRouterCtrlTrafficConfig *config)
483{
484    ta_data_t *tad = &card->ta_sampling;
485
486    /* Reinitialise our data when we are reset */
487    if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET)
488    {
489        /* Reset the stats to zero */
490        tas_reset_data(tad);
491
492        /* Reset the timer variables */
493        tad->tx_last_ts = 0;
494        tad->last_indication_time = 0;
495
496        return CSR_RESULT_SUCCESS;
497    }
498
499    if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER)
500    {
501        tad->packet_filter = config->packetFilter;
502
503        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
504        {
505            tad->custom_filter = config->customFilter;
506        }
507
508        return CSR_RESULT_SUCCESS;
509    }
510
511    return CSR_RESULT_SUCCESS;
512} /* unifi_ta_configure() */
513
514
515/*
516 * ---------------------------------------------------------------------------
517 * External API.
518 * unifi_ta_classification
519 *
520 * Configures the current TA classification.
521 *
522 * Arguments:
523 * ta The pointer to the TA module.
524 * traffic_type The classification type
525 * period The traffic period if the type is periodic
526 *
527 * Returns:
528 * None
529 * ---------------------------------------------------------------------------
530 */
531void unifi_ta_classification(card_t *card,
532                             CsrWifiRouterCtrlTrafficType traffic_type,
533                             u16 period)
534{
535    unifi_trace(card->ospriv, UDBG3,
536                "Changed current ta classification to: %d\n", traffic_type);
537
538    card->ta_sampling.traffic_type = traffic_type;
539}
540
541
542

Archive Download this file



interactive