Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
csr_wifi_hip_ta_sampling.c
Go to the documentation of this file.
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 
46 {
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
75 static 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  */
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;
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 
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) +
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  {
139  {
141  u8 l4proto = data->os_data_ptr[TA_IP_TYPE_OFFSET];
142 
143  if (l4proto == TA_IP_TYPE_TCP)
144  {
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  {
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 */
169  {
170  /* DHCP frames are UDP frames with BOOTP ports */
172  {
174  {
175  source_port = (data->os_data_ptr[TA_UDP_SOURCE_PORT_OFFSET] * 256) +
177  dest_port = (data->os_data_ptr[TA_UDP_DEST_PORT_OFFSET] * 256) +
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) */
185  {
186  UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
187 
189  {
190  unifi_ta_indicate_protocol(card->ospriv,
192  direction,
193  &srcAddress);
195  }
196 
197  /* DHCPACK is a special indication */
199  {
201  {
202  unifi_ta_indicate_protocol(card->ospriv,
204  direction,
205  &srcAddress);
206  }
207  else
208  {
209  unifi_ta_indicate_protocol(card->ospriv,
211  direction,
212  &srcAddress);
213  }
214  }
215  }
216  }
217  }
218  }
219  }
220  }
221 
223  }
224 
225  /* detect protocol type EAPOL or WAI (treated as equivalent here) */
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) ||
232  {
233  UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
234  unifi_ta_indicate_protocol(card->ospriv,
236  direction, &srcAddress);
237  }
239  }
240  }
241 
242  /* detect protocol type 0x0806 (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,
250  direction, &srcAddress);
252  }
253  }
254 
256  }
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);
264  direction, &srcAddress);
265  }
266  }
267 
269 } /* ta_detect_protocol() */
270 
271 
272 static 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  */
315 {
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  */
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 */
360  {
361  identity = ta_detect_protocol(card, direction, data, saddr, sta_macaddr);
362  }
363  else
364  {
366  }
367 
368 
369  /* Step2: Update the information in the current record */
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  */
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  */
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);
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  */
483 {
484  ta_data_t *tad = &card->ta_sampling;
485 
486  /* Reinitialise our data when we are 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 
500  {
501  tad->packet_filter = config->packetFilter;
502 
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  */
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