1 /*****************************************************************************
3 (c) Cambridge Silicon Radio Limited 2012
4 All rights reserved and confidential information of CSR
6 Refer to LICENSE.txt included with this source for details
9 *****************************************************************************/
12 * ---------------------------------------------------------------------------
13 * FILE: csr_wifi_hip_ta_sampling.c
16 * The traffic analysis sampling module.
17 * This gathers data which is sent to the SME and used to analyse
18 * the traffic behaviour.
21 * unifi_ta_sampling_init - Initialise the internal state
22 * unifi_ta_sample - Sampling function, call this for every data packet
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 * ---------------------------------------------------------------------------
30 #include "csr_wifi_hip_card_sdio.h"
32 /* Maximum number of Tx frames we store each CYCLE_1, for detecting period */
33 #define TA_MAX_INTERVALS_IN_C1 100
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
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
45 enum ta_frame_identity
48 TA_FRAME_ETHERNET_UNINTERESTING,
49 TA_FRAME_ETHERNET_INTERESTING
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
72 #define snap_802_2 0xAAAA0300
73 #define oui_rfc1042 0x00000000
74 #define oui_8021h 0x0000f800
75 static const u8 aironet_snap[5] = { 0x00, 0x40, 0x96, 0x00, 0x00 };
79 * ---------------------------------------------------------------------------
83 * Detects a specific protocol in a frame and indicates a TA event.
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.
92 * ---------------------------------------------------------------------------
94 static enum ta_frame_identity ta_detect_protocol(card_t *card, CsrWifiRouterCtrlProtocolDirection direction,
95 const bulk_data_desc_t *data,
97 const u8 *sta_macaddr)
99 ta_data_t *tad = &card->ta_sampling;
101 u16 source_port, dest_port;
102 CsrWifiMacAddress srcAddress;
103 u32 snap_hdr, oui_hdr;
105 if (data->data_length < TA_LLC_HEADER_SIZE)
107 return TA_FRAME_UNKNOWN;
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)
115 return TA_FRAME_UNKNOWN;
118 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
121 * Here we would use the custom filter to detect interesting frames.
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))
130 proto = (data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET] * 256) +
131 data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET + 1];
133 /* The only interesting IP frames are the DHCP */
134 if (proto == TA_PROTO_TYPE_IP)
136 if (data->data_length > TA_IP_TYPE_OFFSET)
138 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
140 ta_l4stats_t *ta_l4stats = &tad->ta_l4stats;
141 u8 l4proto = data->os_data_ptr[TA_IP_TYPE_OFFSET];
143 if (l4proto == TA_IP_TYPE_TCP)
145 if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
147 ta_l4stats->txTcpBytesCount += data->data_length;
151 ta_l4stats->rxTcpBytesCount += data->data_length;
154 else if (l4proto == TA_IP_TYPE_UDP)
156 if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
158 ta_l4stats->txUdpBytesCount += data->data_length;
162 ta_l4stats->rxUdpBytesCount += data->data_length;
167 /* detect DHCP frames */
168 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP)
170 /* DHCP frames are UDP frames with BOOTP ports */
171 if (data->os_data_ptr[TA_IP_TYPE_OFFSET] == TA_IP_TYPE_UDP)
173 if (data->data_length > TA_UDP_DEST_PORT_OFFSET)
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];
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)))
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)
186 UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
188 if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
190 unifi_ta_indicate_protocol(card->ospriv,
191 CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
194 return TA_FRAME_ETHERNET_UNINTERESTING;
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)
200 if (data->os_data_ptr[TA_DHCP_MESSAGE_TYPE_OFFSET] == TA_DHCP_MESSAGE_TYPE_ACK)
202 unifi_ta_indicate_protocol(card->ospriv,
203 CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP_ACK,
209 unifi_ta_indicate_protocol(card->ospriv,
210 CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
222 return TA_FRAME_ETHERNET_INTERESTING;
225 /* detect protocol type EAPOL or WAI (treated as equivalent here) */
226 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL)
228 if (TA_PROTO_TYPE_EAP == proto || TA_PROTO_TYPE_WAI == proto)
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))
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);
238 return TA_FRAME_ETHERNET_UNINTERESTING;
242 /* detect protocol type 0x0806 (ARP) */
243 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP)
245 if (proto == TA_PROTO_TYPE_ARP)
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;
255 return TA_FRAME_ETHERNET_INTERESTING;
257 else if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET)
259 /* detect Aironet frames */
260 if (!memcmp(data->os_data_ptr + 3, aironet_snap, 5))
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);
268 return TA_FRAME_ETHERNET_UNINTERESTING;
269 } /* ta_detect_protocol() */
272 static void tas_reset_data(ta_data_t *tad)
276 for (i = 0; i < (TA_INTERVALS_NUM + 1); i++)
278 tad->stats.intervals[i] = 0;
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;
287 tad->rx_sum_rate = 0;
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() */
297 * ---------------------------------------------------------------------------
299 * unifi_ta_sampling_init
301 * (Re)Initialise the Traffic Analysis sampling module.
302 * Resets the counters and timestamps.
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
312 * ---------------------------------------------------------------------------
314 void unifi_ta_sampling_init(card_t *card)
316 (void)unifi_ta_configure(card, CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET, NULL);
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() */
324 * ---------------------------------------------------------------------------
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.
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)
342 * ---------------------------------------------------------------------------
344 void unifi_ta_sample(card_t *card,
345 CsrWifiRouterCtrlProtocolDirection direction,
346 const bulk_data_desc_t *data,
348 const u8 *sta_macaddr,
352 ta_data_t *tad = &card->ta_sampling;
353 enum ta_frame_identity identity;
358 /* Step1: Check for specific frames */
359 if (tad->packet_filter != CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE)
361 identity = ta_detect_protocol(card, direction, data, saddr, sta_macaddr);
365 identity = TA_FRAME_ETHERNET_INTERESTING;
369 /* Step2: Update the information in the current record */
370 if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX)
372 /* Update the Rx packet count and the throughput count */
373 tad->stats.rxFramesNum++;
374 tad->stats.rxBytesCount += data->data_length;
376 /* Accumulate packet Rx rates for later averaging */
377 tad->rx_sum_rate += rate;
381 if (identity == TA_FRAME_ETHERNET_INTERESTING)
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.
388 if (tad->stats.txFramesNum < TA_MAX_INTERVALS_IN_C1)
391 u32 index_in_intervals;
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;
397 /* If the interval is interesting, update the t1_intervals count */
398 if (index_in_intervals <= TA_INTERVALS_NUM)
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]++;
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;
415 * If more than one second has elapsed since the last report, send
418 /* Unsigned subtraction handles wrap-around from 0xFFFFFFFF to 0 */
419 time_delta = timestamp - tad->last_indication_time;
420 if (time_delta >= 1000)
423 * rxFramesNum can be flashed in tas_reset_data() by another thread.
424 * Use a temp to avoid division by zero.
426 u32 temp_rxFramesNum;
427 temp_rxFramesNum = tad->stats.rxFramesNum;
429 /* Calculate this interval's mean frame Rx rate from the sum */
430 if (temp_rxFramesNum)
432 tad->stats.rxMeanRate = tad->rx_sum_rate / temp_rxFramesNum;
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);
440 * Send the information collected in the stats struct
441 * to the SME and reset the counters.
443 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
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;
450 unifi_ta_indicate_l4stats(card->ospriv,
457 unifi_ta_indicate_sampling(card->ospriv, &tad->stats);
459 tad->last_indication_time = timestamp;
461 } /* unifi_ta_sample() */
465 * ---------------------------------------------------------------------------
469 * Configures the TA module parameters.
472 * ta The pointer to the TA module.
473 * config_type The type of the configuration request
474 * config Pointer to the configuration parameters.
477 * CSR_RESULT_SUCCESS on success, CSR error code otherwise
478 * ---------------------------------------------------------------------------
480 CsrResult unifi_ta_configure(card_t *card,
481 CsrWifiRouterCtrlTrafficConfigType config_type,
482 const CsrWifiRouterCtrlTrafficConfig *config)
484 ta_data_t *tad = &card->ta_sampling;
486 /* Reinitialise our data when we are reset */
487 if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET)
489 /* Reset the stats to zero */
492 /* Reset the timer variables */
494 tad->last_indication_time = 0;
496 return CSR_RESULT_SUCCESS;
499 if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER)
501 tad->packet_filter = config->packetFilter;
503 if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
505 tad->custom_filter = config->customFilter;
508 return CSR_RESULT_SUCCESS;
511 return CSR_RESULT_SUCCESS;
512 } /* unifi_ta_configure() */
516 * ---------------------------------------------------------------------------
518 * unifi_ta_classification
520 * Configures the current TA classification.
523 * ta The pointer to the TA module.
524 * traffic_type The classification type
525 * period The traffic period if the type is periodic
529 * ---------------------------------------------------------------------------
531 void unifi_ta_classification(card_t *card,
532 CsrWifiRouterCtrlTrafficType traffic_type,
535 unifi_trace(card->ospriv, UDBG3,
536 "Changed current ta classification to: %d\n", traffic_type);
538 card->ta_sampling.traffic_type = traffic_type;