blob: 92033a9fb957fdcf2b7bea1a7deb409c74f91fcb [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**
23 * DOC : wlan_hdd_stats.c
24 *
25 * WLAN Host Device Driver statistics related implementation
26 *
27 */
28
29#include "wlan_hdd_stats.h"
30#include "sme_api.h"
31#include "cds_sched.h"
32#include "wlan_hdd_trace.h"
33
34#ifdef WLAN_FEATURE_LINK_LAYER_STATS
35
36/**
37 * struct hdd_ll_stats_context - hdd link layer stats context
38 *
39 * @request_id: userspace-assigned link layer stats request id
40 * @request_bitmap: userspace-assigned link layer stats request bitmap
41 * @response_event: LL stats request wait event
42 */
43struct hdd_ll_stats_context {
44 uint32_t request_id;
45 uint32_t request_bitmap;
46 struct completion response_event;
47 spinlock_t context_lock;
48};
49
50static struct hdd_ll_stats_context ll_stats_context;
51
52#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
53
54/* 11B, 11G Rate table include Basic rate and Extended rate
55 * The IDX field is the rate index
56 * The HI field is the rate when RSSI is strong or being ignored
57 * (in this case we report actual rate)
58 * The MID field is the rate when RSSI is moderate
59 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
60 * The LO field is the rate when RSSI is low
61 * (in this case we don't report rates, actual current rate used)
62 */
63static const struct {
64 uint8_t beacon_rate_index;
65 uint16_t supported_rate[4];
66} supported_data_rate[] = {
67/* IDX HI HM LM LO (RSSI-based index */
68 {
69 2, {
70 10, 10, 10, 0
71 }
72 }, {
73 4, {
74 20, 20, 10, 0
75 }
76 }, {
77 11, {
78 55, 20, 10, 0
79 }
80 }, {
81 12, {
82 60, 55, 20, 0
83 }
84 }, {
85 18, {
86 90, 55, 20, 0
87 }
88 }, {
89 22, {
90 110, 55, 20, 0
91 }
92 }, {
93 24, {
94 120, 90, 60, 0
95 }
96 }, {
97 36, {
98 180, 120, 60, 0
99 }
100 }, {
101 44, {
102 220, 180, 60, 0
103 }
104 }, {
105 48, {
106 240, 180, 90, 0
107 }
108 }, {
109 66, {
110 330, 180, 90, 0
111 }
112 }, {
113 72, {
114 360, 240, 90, 0
115 }
116 }, {
117 96, {
118 480, 240, 120, 0
119 }
120 }, {
121 108, {
122 540, 240, 120, 0
123 }
124 }
125};
126/* MCS Based rate table HT MCS parameters with Nss = 1 */
127static struct index_data_rate_type supported_mcs_rate_nss1[] = {
128/* MCS L20 L40 S20 S40 */
129 {0, {65, 135, 72, 150} },
130 {1, {130, 270, 144, 300} },
131 {2, {195, 405, 217, 450} },
132 {3, {260, 540, 289, 600} },
133 {4, {390, 810, 433, 900} },
134 {5, {520, 1080, 578, 1200} },
135 {6, {585, 1215, 650, 1350} },
136 {7, {650, 1350, 722, 1500} }
137};
138
139/* HT MCS parameters with Nss = 2 */
140static struct index_data_rate_type supported_mcs_rate_nss2[] = {
141/* MCS L20 L40 S20 S40 */
142 {0, {130, 270, 144, 300} },
143 {1, {260, 540, 289, 600} },
144 {2, {390, 810, 433, 900} },
145 {3, {520, 1080, 578, 1200} },
146 {4, {780, 1620, 867, 1800} },
147 {5, {1040, 2160, 1156, 2400} },
148 {6, {1170, 2430, 1300, 2700} },
149 {7, {1300, 2700, 1444, 3000} }
150};
151
152#ifdef WLAN_FEATURE_11AC
153/* MCS Based VHT rate table MCS parameters with Nss = 1*/
154static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
155/* MCS L80 S80 L40 S40 L20 S40*/
156 {0, {293, 325}, {135, 150}, {65, 72} },
157 {1, {585, 650}, {270, 300}, {130, 144} },
158 {2, {878, 975}, {405, 450}, {195, 217} },
159 {3, {1170, 1300}, {540, 600}, {260, 289} },
160 {4, {1755, 1950}, {810, 900}, {390, 433} },
161 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
162 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
163 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
164 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
165 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
166};
167
168/*MCS parameters with Nss = 2*/
169static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
170/* MCS L80 S80 L40 S40 L20 S40*/
171 {0, {585, 650}, {270, 300}, {130, 144} },
172 {1, {1170, 1300}, {540, 600}, {260, 289} },
173 {2, {1755, 1950}, {810, 900}, {390, 433} },
174 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
175 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
176 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
177 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
178 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
179 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
180 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
181};
182#endif /* End of WLAN_FEATURE_11AC */
183
184/*array index ponints to MCS and array value points respective rssi*/
185static int rssi_mcs_tbl[][10] = {
186/*MCS 0 1 2 3 4 5 6 7 8 9*/
187 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
188 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
189 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
190};
191
192
193#ifdef WLAN_FEATURE_LINK_LAYER_STATS
194
195/**
196 * put_wifi_rate_stat() - put wifi rate stats
197 * @stats: Pointer to stats context
198 * @vendor_event: Pointer to vendor event
199 *
200 * Return: bool
201 */
202static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
203 struct sk_buff *vendor_event)
204{
205 if (nla_put_u8(vendor_event,
206 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
207 stats->rate.preamble) ||
208 nla_put_u8(vendor_event,
209 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
210 stats->rate.nss) ||
211 nla_put_u8(vendor_event,
212 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
213 stats->rate.bw) ||
214 nla_put_u8(vendor_event,
215 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
216 stats->rate.rateMcsIdx) ||
217 nla_put_u32(vendor_event,
218 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
219 stats->rate.bitrate) ||
220 nla_put_u32(vendor_event,
221 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
222 stats->txMpdu) ||
223 nla_put_u32(vendor_event,
224 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
225 stats->rxMpdu) ||
226 nla_put_u32(vendor_event,
227 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
228 stats->mpduLost) ||
229 nla_put_u32(vendor_event,
230 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
231 stats->retries) ||
232 nla_put_u32(vendor_event,
233 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
234 stats->retriesShort) ||
235 nla_put_u32(vendor_event,
236 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
237 stats->retriesLong)) {
238 hddLog(CDF_TRACE_LEVEL_ERROR,
239 FL("QCA_WLAN_VENDOR_ATTR put fail"));
240 return false;
241 }
242
243 return true;
244}
245
246/**
247 * put_wifi_peer_info() - put wifi peer info
248 * @stats: Pointer to stats context
249 * @vendor_event: Pointer to vendor event
250 *
251 * Return: bool
252 */
253static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
254 struct sk_buff *vendor_event)
255{
256 u32 i = 0;
257 tpSirWifiRateStat pRateStats;
258
259 if (nla_put_u32
260 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
261 stats->type) ||
262 nla_put(vendor_event,
263 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
264 CDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
265 nla_put_u32(vendor_event,
266 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
267 stats->capabilities) ||
268 nla_put_u32(vendor_event,
269 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
270 stats->numRate)) {
271 hddLog(CDF_TRACE_LEVEL_ERROR,
272 FL("QCA_WLAN_VENDOR_ATTR put fail"));
273 goto error;
274 }
275
276 if (stats->numRate) {
277 struct nlattr *rateInfo;
278 struct nlattr *rates;
279
280 rateInfo = nla_nest_start(vendor_event,
281 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
282 if (rateInfo == NULL)
283 goto error;
284
285 for (i = 0; i < stats->numRate; i++) {
286 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
287 stats->rateStats +
288 (i *
289 sizeof
290 (tSirWifiRateStat)));
291 rates = nla_nest_start(vendor_event, i);
292 if (rates == NULL)
293 goto error;
294
295 if (false ==
296 put_wifi_rate_stat(pRateStats, vendor_event)) {
297 hddLog(CDF_TRACE_LEVEL_ERROR,
298 FL("QCA_WLAN_VENDOR_ATTR put fail"));
299 return false;
300 }
301 nla_nest_end(vendor_event, rates);
302 }
303 nla_nest_end(vendor_event, rateInfo);
304 }
305
306 return true;
307error:
308 return false;
309}
310
311/**
312 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
313 * @stats: Pointer to stats context
314 * @vendor_event: Pointer to vendor event
315 *
316 * Return: bool
317 */
318static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
319 struct sk_buff *vendor_event)
320{
321 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
322 stats->ac) ||
323 nla_put_u32(vendor_event,
324 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
325 stats->txMpdu) ||
326 nla_put_u32(vendor_event,
327 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
328 stats->rxMpdu) ||
329 nla_put_u32(vendor_event,
330 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
331 stats->txMcast) ||
332 nla_put_u32(vendor_event,
333 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
334 stats->rxMcast) ||
335 nla_put_u32(vendor_event,
336 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
337 stats->rxAmpdu) ||
338 nla_put_u32(vendor_event,
339 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
340 stats->txAmpdu) ||
341 nla_put_u32(vendor_event,
342 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
343 stats->mpduLost) ||
344 nla_put_u32(vendor_event,
345 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
346 stats->retries) ||
347 nla_put_u32(vendor_event,
348 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
349 stats->retriesShort) ||
350 nla_put_u32(vendor_event,
351 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
352 stats->retriesLong) ||
353 nla_put_u32(vendor_event,
354 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
355 stats->contentionTimeMin) ||
356 nla_put_u32(vendor_event,
357 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
358 stats->contentionTimeMax) ||
359 nla_put_u32(vendor_event,
360 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
361 stats->contentionTimeAvg) ||
362 nla_put_u32(vendor_event,
363 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
364 stats->contentionNumSamples)) {
365 hddLog(CDF_TRACE_LEVEL_ERROR,
366 FL("QCA_WLAN_VENDOR_ATTR put fail"));
367 return false;
368 }
369
370 return true;
371}
372
373/**
374 * put_wifi_interface_info() - put wifi interface info
375 * @stats: Pointer to stats context
376 * @vendor_event: Pointer to vendor event
377 *
378 * Return: bool
379 */
380static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
381 struct sk_buff *vendor_event)
382{
383 if (nla_put_u32(vendor_event,
384 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
385 stats->mode) ||
386 nla_put(vendor_event,
387 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
388 CDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
389 nla_put_u32(vendor_event,
390 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
391 stats->state) ||
392 nla_put_u32(vendor_event,
393 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
394 stats->roaming) ||
395 nla_put_u32(vendor_event,
396 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
397 stats->capabilities) ||
398 nla_put(vendor_event,
399 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
400 strlen(stats->ssid), stats->ssid) ||
401 nla_put(vendor_event,
402 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
403 CDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
404 nla_put(vendor_event,
405 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
406 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
407 nla_put(vendor_event,
408 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
409 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
410 hddLog(CDF_TRACE_LEVEL_ERROR,
411 FL("QCA_WLAN_VENDOR_ATTR put fail"));
412 return false;
413 }
414
415 return true;
416}
417
418/**
419 * put_wifi_iface_stats() - put wifi interface stats
420 * @pWifiIfaceStat: Pointer to interface stats context
421 * @num_peer: Number of peers
422 * @vendor_event: Pointer to vendor event
423 *
424 * Return: bool
425 */
426static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
427 u32 num_peers, struct sk_buff *vendor_event)
428{
429 int i = 0;
430 struct nlattr *wmmInfo;
431 struct nlattr *wmmStats;
432 u64 average_tsf_offset;
433
434 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
435 vendor_event)) {
436 hddLog(CDF_TRACE_LEVEL_ERROR,
437 FL("QCA_WLAN_VENDOR_ATTR put fail"));
438 return false;
439
440 }
441
442 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
443 average_tsf_offset = (average_tsf_offset << 32) |
444 pWifiIfaceStat->avg_bcn_spread_offset_low ;
445
446 if (nla_put_u32(vendor_event,
447 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
448 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
449 nla_put_u32(vendor_event,
450 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
451 num_peers) ||
452 nla_put_u32(vendor_event,
453 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
454 pWifiIfaceStat->beaconRx) ||
455 nla_put_u32(vendor_event,
456 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
457 pWifiIfaceStat->mgmtRx) ||
458 nla_put_u32(vendor_event,
459 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
460 pWifiIfaceStat->mgmtActionRx) ||
461 nla_put_u32(vendor_event,
462 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
463 pWifiIfaceStat->mgmtActionTx) ||
464 nla_put_u32(vendor_event,
465 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
466 pWifiIfaceStat->rssiMgmt) ||
467 nla_put_u32(vendor_event,
468 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
469 pWifiIfaceStat->rssiData) ||
470 nla_put_u32(vendor_event,
471 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
472 pWifiIfaceStat->rssiAck) ||
473 nla_put_u32(vendor_event,
474 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
475 pWifiIfaceStat->is_leaky_ap) ||
476 nla_put_u32(vendor_event,
477 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
478 pWifiIfaceStat->avg_rx_frms_leaked) ||
479 nla_put_u32(vendor_event,
480 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
481 pWifiIfaceStat->rx_leak_window) ||
482 nla_put_u64(vendor_event,
483 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
484 average_tsf_offset)) {
485 hddLog(CDF_TRACE_LEVEL_ERROR,
486 FL("QCA_WLAN_VENDOR_ATTR put fail"));
487 return false;
488 }
489
490 wmmInfo = nla_nest_start(vendor_event,
491 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
492 if (wmmInfo == NULL)
493 return false;
494
495 for (i = 0; i < WIFI_AC_MAX; i++) {
496 wmmStats = nla_nest_start(vendor_event, i);
497 if (wmmStats == NULL)
498 return false;
499
500 if (false ==
501 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
502 vendor_event)) {
503 hddLog(CDF_TRACE_LEVEL_ERROR,
504 FL("put_wifi_wmm_ac_stat Fail"));
505 return false;
506 }
507
508 nla_nest_end(vendor_event, wmmStats);
509 }
510 nla_nest_end(vendor_event, wmmInfo);
511 return true;
512}
513
514/**
515 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
516 * @deviceMode: Device mode
517 *
518 * Return: interface mode
519 */
520static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
521{
522 switch (deviceMode) {
523 case WLAN_HDD_INFRA_STATION:
524 return WIFI_INTERFACE_STA;
525 case WLAN_HDD_SOFTAP:
526 return WIFI_INTERFACE_SOFTAP;
527 case WLAN_HDD_P2P_CLIENT:
528 return WIFI_INTERFACE_P2P_CLIENT;
529 case WLAN_HDD_P2P_GO:
530 return WIFI_INTERFACE_P2P_GO;
531 case WLAN_HDD_IBSS:
532 return WIFI_INTERFACE_IBSS;
533 default:
534 /* Return Interface Mode as STA for all the unsupported modes */
535 return WIFI_INTERFACE_STA;
536 }
537}
538
539/**
540 * hdd_get_interface_info() - get interface info
541 * @pAdapter: Pointer to device adapter
542 * @pInfo: Pointer to interface info
543 *
544 * Return: bool
545 */
546static bool hdd_get_interface_info(hdd_adapter_t *pAdapter,
547 tpSirWifiInterfaceInfo pInfo)
548{
549 uint8_t *staMac = NULL;
550 hdd_station_ctx_t *pHddStaCtx;
551 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
552 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
553
554 pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode);
555
556 cdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent);
557
558 if (((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
559 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
560 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode))) {
561 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
562 if (eConnectionState_NotConnected ==
563 pHddStaCtx->conn_info.connState) {
564 pInfo->state = WIFI_DISCONNECTED;
565 }
566 if (eConnectionState_Connecting ==
567 pHddStaCtx->conn_info.connState) {
568 hddLog(CDF_TRACE_LEVEL_ERROR,
569 "%s: Session ID %d, Connection is in progress",
570 __func__, pAdapter->sessionId);
571 pInfo->state = WIFI_ASSOCIATING;
572 }
573 if ((eConnectionState_Associated ==
574 pHddStaCtx->conn_info.connState)
575 && (false == pHddStaCtx->conn_info.uIsAuthenticated)) {
576 staMac =
577 (uint8_t *) &(pAdapter->macAddressCurrent.
578 bytes[0]);
579 hddLog(CDF_TRACE_LEVEL_ERROR,
580 "%s: client " MAC_ADDRESS_STR
581 " is in the middle of WPS/EAPOL exchange.",
582 __func__, MAC_ADDR_ARRAY(staMac));
583 pInfo->state = WIFI_AUTHENTICATING;
584 }
585 if (eConnectionState_Associated ==
586 pHddStaCtx->conn_info.connState) {
587 pInfo->state = WIFI_ASSOCIATED;
588 cdf_copy_macaddr(&pInfo->bssid,
589 &pHddStaCtx->conn_info.bssId);
590 cdf_mem_copy(pInfo->ssid,
591 pHddStaCtx->conn_info.SSID.SSID.ssId,
592 pHddStaCtx->conn_info.SSID.SSID.length);
593 /*
594 * NULL Terminate the string
595 */
596 pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0;
597 }
598 }
599
600 cdf_mem_copy(pInfo->countryStr,
601 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
602
603 cdf_mem_copy(pInfo->apCountryStr,
604 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
605
606 return true;
607}
608
609/**
610 * hdd_link_layer_process_peer_stats() - This function is called after
611 * @pAdapter: Pointer to device adapter
612 * @more_data: More data
613 * @pData: Pointer to stats data
614 *
615 * Receiving Link Layer Peer statistics from FW.This function converts
616 * the firmware data to the NL data and sends the same to the kernel/upper
617 * layers.
618 *
619 * Return: None
620 */
621static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter,
622 u32 more_data,
623 tpSirWifiPeerStat pData)
624{
625 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
626 tpSirWifiRateStat pWifiRateStat;
627 tpSirWifiPeerStat pWifiPeerStat;
628 tpSirWifiPeerInfo pWifiPeerInfo;
629 struct sk_buff *vendor_event;
630 int status, i, j;
631 struct nlattr *peers;
632 int numRate;
633
634 pWifiPeerStat = pData;
635
636 status = wlan_hdd_validate_context(pHddCtx);
637 if (0 != status) {
638 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
639 return;
640 }
641
642 hddLog(CDF_TRACE_LEVEL_INFO,
643 "LL_STATS_PEER_ALL : numPeers %u, more data = %u",
644 pWifiPeerStat->numPeers, more_data);
645
646 for (i = 0; i < pWifiPeerStat->numPeers; i++) {
647 pWifiPeerInfo = (tpSirWifiPeerInfo)
648 ((uint8_t *) pWifiPeerStat->peerInfo +
649 (i * sizeof(tSirWifiPeerInfo)));
650
651 if (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)
652 pWifiPeerInfo->type = WIFI_PEER_AP;
653
654 if (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)
655 pWifiPeerInfo->type = WIFI_PEER_P2P_GO;
656
657 hddLog(CDF_TRACE_LEVEL_INFO,
658 " %d) LL_STATS Channel Stats "
659 " Peer Type %u "
660 " peerMacAddress %pM "
661 " capabilities 0x%x "
662 " numRate %u ",
663 i,
664 pWifiPeerInfo->type,
665 pWifiPeerInfo->peerMacAddress.bytes,
666 pWifiPeerInfo->capabilities, pWifiPeerInfo->numRate);
667 {
668 for (j = 0; j < pWifiPeerInfo->numRate; j++) {
669 pWifiRateStat = (tpSirWifiRateStat)
670 ((uint8_t *) pWifiPeerInfo->rateStats +
671 (j * sizeof(tSirWifiRateStat)));
672
673 hddLog(CDF_TRACE_LEVEL_INFO,
674 " peer Rate Stats "
675 " preamble %u "
676 " nss %u "
677 " bw %u "
678 " rateMcsIdx %u "
679 " reserved %u "
680 " bitrate %u "
681 " txMpdu %u "
682 " rxMpdu %u "
683 " mpduLost %u "
684 " retries %u "
685 " retriesShort %u "
686 " retriesLong %u",
687 pWifiRateStat->rate.preamble,
688 pWifiRateStat->rate.nss,
689 pWifiRateStat->rate.bw,
690 pWifiRateStat->rate.rateMcsIdx,
691 pWifiRateStat->rate.reserved,
692 pWifiRateStat->rate.bitrate,
693 pWifiRateStat->txMpdu,
694 pWifiRateStat->rxMpdu,
695 pWifiRateStat->mpduLost,
696 pWifiRateStat->retries,
697 pWifiRateStat->retriesShort,
698 pWifiRateStat->retriesLong);
699 }
700 }
701 }
702
703 /*
704 * Allocate a size of 4096 for the peer stats comprising
705 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
706 * sizeof (tSirWifiRateStat).Each field is put with an
707 * NL attribute.The size of 4096 is considered assuming
708 * that number of rates shall not exceed beyond 50 with
709 * the sizeof (tSirWifiRateStat) being 32.
710 */
711 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
712 LL_STATS_EVENT_BUF_SIZE);
713
714 if (!vendor_event) {
715 hddLog(LOGE,
716 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
717 return;
718 }
719
720 if (nla_put_u32(vendor_event,
721 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
722 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
723 nla_put_u32(vendor_event,
724 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
725 more_data) ||
726 nla_put_u32(vendor_event,
727 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
728 pWifiPeerStat->numPeers)) {
729 hddLog(CDF_TRACE_LEVEL_ERROR,
730 "%s: QCA_WLAN_VENDOR_ATTR put fail", __func__);
731
732 kfree_skb(vendor_event);
733 return;
734 }
735
736 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
737 pWifiPeerStat->peerInfo);
738
739 if (pWifiPeerStat->numPeers) {
740 struct nlattr *peerInfo;
741 peerInfo = nla_nest_start(vendor_event,
742 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
743 if (peerInfo == NULL) {
744 hddLog(LOGE, FL("nla_nest_start failed"));
745 kfree_skb(vendor_event);
746 return;
747 }
748
749 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
750 peers = nla_nest_start(vendor_event, i);
751 if (peers == NULL) {
752 hddLog(LOGE, FL("nla_nest_start failed"));
753 kfree_skb(vendor_event);
754 return;
755 }
756
757 numRate = pWifiPeerInfo->numRate;
758
759 if (false ==
760 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
761 hddLog(CDF_TRACE_LEVEL_ERROR,
762 FL("put_wifi_peer_info fail"));
763 kfree_skb(vendor_event);
764 return;
765 }
766
767 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
768 pWifiPeerStat->
769 peerInfo +
770 (i *
771 sizeof
772 (tSirWifiPeerInfo))
773 +
774 (numRate *
775 sizeof
776 (tSirWifiRateStat)));
777 nla_nest_end(vendor_event, peers);
778 }
779 nla_nest_end(vendor_event, peerInfo);
780 }
781 cfg80211_vendor_cmd_reply(vendor_event);
782 return;
783}
784
785/**
786 * hdd_link_layer_process_iface_stats() - This function is called after
787 * @pAdapter: Pointer to device adapter
788 * @pData: Pointer to stats data
789 * @num_peers: Number of peers
790 *
791 * Receiving Link Layer Interface statistics from FW.This function converts
792 * the firmware data to the NL data and sends the same to the kernel/upper
793 * layers.
794 *
795 * Return: None
796 */
797static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter,
798 tpSirWifiIfaceStat pData,
799 u32 num_peers)
800{
801 tpSirWifiIfaceStat pWifiIfaceStat;
802 struct sk_buff *vendor_event;
803 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
804 int status;
805 int i;
806
807 pWifiIfaceStat = pData;
808
809 status = wlan_hdd_validate_context(pHddCtx);
810 if (0 != status) {
811 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
812 return;
813 }
814
815 /*
816 * Allocate a size of 4096 for the interface stats comprising
817 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
818 * assuming that all these fit with in the limit.Please take
819 * a call on the limit based on the data requirements on
820 * interface statistics.
821 */
822 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
823 LL_STATS_EVENT_BUF_SIZE);
824
825 if (!vendor_event) {
826 hddLog(CDF_TRACE_LEVEL_ERROR,
827 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
828 return;
829 }
830
831 hddLog(CDF_TRACE_LEVEL_INFO, "WMI_LINK_STATS_IFACE Data");
832
833 if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
834 hddLog(CDF_TRACE_LEVEL_ERROR,
835 FL("hdd_get_interface_info get fail"));
836 kfree_skb(vendor_event);
837 return;
838 }
839
840 hddLog(CDF_TRACE_LEVEL_INFO,
841 " Num peers %u "
842 "LL_STATS_IFACE: "
843 " Mode %u "
844 " MAC %pM "
845 " State %u "
846 " Roaming %u "
847 " capabilities 0x%x "
848 " SSID %s "
849 " BSSID %pM",
850 num_peers,
851 pWifiIfaceStat->info.mode,
852 pWifiIfaceStat->info.macAddr.bytes,
853 pWifiIfaceStat->info.state,
854 pWifiIfaceStat->info.roaming,
855 pWifiIfaceStat->info.capabilities,
856 pWifiIfaceStat->info.ssid, pWifiIfaceStat->info.bssid.bytes);
857
858 hddLog(CDF_TRACE_LEVEL_INFO,
859 " AP country str: %c%c%c",
860 pWifiIfaceStat->info.apCountryStr[0],
861 pWifiIfaceStat->info.apCountryStr[1],
862 pWifiIfaceStat->info.apCountryStr[2]);
863
864 hddLog(CDF_TRACE_LEVEL_INFO,
865 " Country Str Association: %c%c%c",
866 pWifiIfaceStat->info.countryStr[0],
867 pWifiIfaceStat->info.countryStr[1],
868 pWifiIfaceStat->info.countryStr[2]);
869
870 hddLog(CDF_TRACE_LEVEL_INFO,
871 " beaconRx %u "
872 " mgmtRx %u "
873 " mgmtActionRx %u "
874 " mgmtActionTx %u "
875 " rssiMgmt %u "
876 " rssiData %u "
877 " rssiAck %u "
878 " avg_bcn_spread_offset_high %u"
879 " avg_bcn_spread_offset_low %u"
880 " is leaky_ap %u"
881 " avg_rx_frms_leaked %u"
882 " rx_leak_window %u",
883 pWifiIfaceStat->beaconRx,
884 pWifiIfaceStat->mgmtRx,
885 pWifiIfaceStat->mgmtActionRx,
886 pWifiIfaceStat->mgmtActionTx,
887 pWifiIfaceStat->rssiMgmt,
888 pWifiIfaceStat->rssiData,
889 pWifiIfaceStat->rssiAck,
890 pWifiIfaceStat->avg_bcn_spread_offset_high,
891 pWifiIfaceStat->avg_bcn_spread_offset_low,
892 pWifiIfaceStat->is_leaky_ap,
893 pWifiIfaceStat->avg_rx_frms_leaked,
894 pWifiIfaceStat->rx_leak_window);
895
896 for (i = 0; i < WIFI_AC_MAX; i++) {
897 hddLog(CDF_TRACE_LEVEL_INFO,
898 " %d) LL_STATS IFACE: "
899 " ac: %u txMpdu: %u "
900 " rxMpdu: %u txMcast: %u "
901 " rxMcast: %u rxAmpdu: %u "
902 " txAmpdu: %u mpduLost: %u "
903 " retries: %u retriesShort: %u "
904 " retriesLong: %u contentionTimeMin: %u "
905 " contentionTimeMax: %u contentionTimeAvg: %u "
906 " contentionNumSamples: %u",
907 i,
908 pWifiIfaceStat->AccessclassStats[i].ac,
909 pWifiIfaceStat->AccessclassStats[i].txMpdu,
910 pWifiIfaceStat->AccessclassStats[i].rxMpdu,
911 pWifiIfaceStat->AccessclassStats[i].txMcast,
912 pWifiIfaceStat->AccessclassStats[i].rxMcast,
913 pWifiIfaceStat->AccessclassStats[i].rxAmpdu,
914 pWifiIfaceStat->AccessclassStats[i].txAmpdu,
915 pWifiIfaceStat->AccessclassStats[i].mpduLost,
916 pWifiIfaceStat->AccessclassStats[i].retries,
917 pWifiIfaceStat->AccessclassStats[i].retriesShort,
918 pWifiIfaceStat->AccessclassStats[i].retriesLong,
919 pWifiIfaceStat->AccessclassStats[i].contentionTimeMin,
920 pWifiIfaceStat->AccessclassStats[i].contentionTimeMax,
921 pWifiIfaceStat->AccessclassStats[i].contentionTimeAvg,
922 pWifiIfaceStat->AccessclassStats[i].
923 contentionNumSamples);
924 }
925
926 if (false ==
927 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
928 hddLog(CDF_TRACE_LEVEL_ERROR, FL("put_wifi_iface_stats fail"));
929 kfree_skb(vendor_event);
930 return;
931 }
932
933 cfg80211_vendor_cmd_reply(vendor_event);
934 return;
935}
936
937/**
938 * hdd_link_layer_process_radio_stats() - This function is called after
939 * @pAdapter: Pointer to device adapter
940 * @more_data: More data
941 * @pData: Pointer to stats data
942 * @num_radios: Number of radios
943 *
944 * Receiving Link Layer Radio statistics from FW.This function converts
945 * the firmware data to the NL data and sends the same to the kernel/upper
946 * layers.
947 *
948 * Return: None
949 */
950static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter,
951 u32 more_data,
952 tpSirWifiRadioStat pData,
953 u32 num_radio)
954{
955 int status, i;
956 tpSirWifiRadioStat pWifiRadioStat;
957 tpSirWifiChannelStats pWifiChannelStats;
958 struct sk_buff *vendor_event;
959 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
960
961 pWifiRadioStat = pData;
962 status = wlan_hdd_validate_context(pHddCtx);
963 if (0 != status) {
964 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
965 return;
966 }
967
968 hddLog(CDF_TRACE_LEVEL_INFO,
969 "LL_STATS_RADIO"
970 " number of radios = %u"
971 " radio is %d onTime is %u"
972 " txTime is %u rxTime is %u"
973 " onTimeScan is %u onTimeNbd is %u"
974 " onTimeGscan is %u onTimeRoamScan is %u"
975 " onTimePnoScan is %u onTimeHs20 is %u"
976 " numChannels is %u",
977 num_radio,
978 pWifiRadioStat->radio,
979 pWifiRadioStat->onTime,
980 pWifiRadioStat->txTime,
981 pWifiRadioStat->rxTime,
982 pWifiRadioStat->onTimeScan,
983 pWifiRadioStat->onTimeNbd,
984 pWifiRadioStat->onTimeGscan,
985 pWifiRadioStat->onTimeRoamScan,
986 pWifiRadioStat->onTimePnoScan,
987 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels);
988
989 /*
990 * Allocate a size of 4096 for the Radio stats comprising
991 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
992 * (tSirWifiChannelStats).Each channel data is put with an
993 * NL attribute.The size of 4096 is considered assuming that
994 * number of channels shall not exceed beyond 60 with the
995 * sizeof (tSirWifiChannelStats) being 24 bytes.
996 */
997
998 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
999 LL_STATS_EVENT_BUF_SIZE);
1000
1001 if (!vendor_event) {
1002 hddLog(LOGE,
1003 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1004 return;
1005 }
1006
1007 if (nla_put_u32(vendor_event,
1008 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1009 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
1010 nla_put_u32(vendor_event,
1011 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
1012 more_data) ||
1013 nla_put_u32(vendor_event,
1014 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
1015 num_radio) ||
1016 nla_put_u32(vendor_event,
1017 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
1018 pWifiRadioStat->radio) ||
1019 nla_put_u32(vendor_event,
1020 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
1021 pWifiRadioStat->onTime) ||
1022 nla_put_u32(vendor_event,
1023 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
1024 pWifiRadioStat->txTime) ||
1025 nla_put_u32(vendor_event,
1026 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
1027 pWifiRadioStat->rxTime) ||
1028 nla_put_u32(vendor_event,
1029 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
1030 pWifiRadioStat->onTimeScan) ||
1031 nla_put_u32(vendor_event,
1032 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
1033 pWifiRadioStat->onTimeNbd) ||
1034 nla_put_u32(vendor_event,
1035 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
1036 pWifiRadioStat->onTimeGscan) ||
1037 nla_put_u32(vendor_event,
1038 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
1039 pWifiRadioStat->onTimeRoamScan) ||
1040 nla_put_u32(vendor_event,
1041 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
1042 pWifiRadioStat->onTimePnoScan) ||
1043 nla_put_u32(vendor_event,
1044 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
1045 pWifiRadioStat->onTimeHs20) ||
1046 nla_put_u32(vendor_event,
1047 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
1048 pWifiRadioStat->numChannels)) {
1049 hddLog(CDF_TRACE_LEVEL_ERROR,
1050 FL("QCA_WLAN_VENDOR_ATTR put fail"));
1051
1052 kfree_skb(vendor_event);
1053 return;
1054 }
1055
1056 if (pWifiRadioStat->numChannels) {
1057 struct nlattr *chList;
1058 struct nlattr *chInfo;
1059
1060 chList = nla_nest_start(vendor_event,
1061 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
1062 if (chList == NULL) {
1063 hddLog(LOGE, FL("nla_nest_start failed"));
1064 kfree_skb(vendor_event);
1065 return;
1066 }
1067
1068 for (i = 0; i < pWifiRadioStat->numChannels; i++) {
1069 pWifiChannelStats = (tpSirWifiChannelStats) ((uint8_t *)
1070 pWifiRadioStat->
1071 channels +
1072 (i *
1073 sizeof
1074 (tSirWifiChannelStats)));
1075
1076 hddLog(CDF_TRACE_LEVEL_INFO,
1077 " %d) Channel Info"
1078 " width is %u "
1079 " CenterFreq %u "
1080 " CenterFreq0 %u "
1081 " CenterFreq1 %u "
1082 " onTime %u "
1083 " ccaBusyTime %u",
1084 i,
1085 pWifiChannelStats->channel.width,
1086 pWifiChannelStats->channel.centerFreq,
1087 pWifiChannelStats->channel.centerFreq0,
1088 pWifiChannelStats->channel.centerFreq1,
1089 pWifiChannelStats->onTime,
1090 pWifiChannelStats->ccaBusyTime);
1091
1092 chInfo = nla_nest_start(vendor_event, i);
1093 if (chInfo == NULL) {
1094 hddLog(LOGE, FL("nla_nest_start failed"));
1095 kfree_skb(vendor_event);
1096 return;
1097 }
1098
1099 if (nla_put_u32(vendor_event,
1100 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
1101 pWifiChannelStats->channel.width) ||
1102 nla_put_u32(vendor_event,
1103 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
1104 pWifiChannelStats->channel.centerFreq) ||
1105 nla_put_u32(vendor_event,
1106 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
1107 pWifiChannelStats->channel.
1108 centerFreq0) ||
1109 nla_put_u32(vendor_event,
1110 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
1111 pWifiChannelStats->channel.
1112 centerFreq1) ||
1113 nla_put_u32(vendor_event,
1114 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
1115 pWifiChannelStats->onTime) ||
1116 nla_put_u32(vendor_event,
1117 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
1118 pWifiChannelStats->ccaBusyTime)) {
1119 hddLog(CDF_TRACE_LEVEL_ERROR,
1120 FL("nla_put failed"));
1121 kfree_skb(vendor_event);
1122 return;
1123 }
1124 nla_nest_end(vendor_event, chInfo);
1125 }
1126 nla_nest_end(vendor_event, chList);
1127 }
1128 cfg80211_vendor_cmd_reply(vendor_event);
1129 return;
1130}
1131
1132/**
1133 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1134 * @ctx: Pointer to hdd context
1135 * @indType: Indication type
1136 * @pRsp: Pointer to response
1137 *
1138 * After receiving Link Layer indications from FW.This callback converts the
1139 * firmware data to the NL data and send the same to the kernel/upper layers.
1140 *
1141 * Return: None
1142 */
1143static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
1144 int indType, void *pRsp)
1145{
1146 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1147 struct hdd_ll_stats_context *context;
1148 hdd_adapter_t *pAdapter = NULL;
1149 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1150 int status;
1151
1152 status = wlan_hdd_validate_context(pHddCtx);
1153
1154 if (0 != status) {
1155 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1156 return;
1157 }
1158
1159 pAdapter = hdd_get_adapter_by_vdev(pHddCtx,
1160 linkLayerStatsResults->ifaceId);
1161
1162 if (NULL == pAdapter) {
1163 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1164 "%s: vdev_id %d does not exist with host",
1165 __func__, linkLayerStatsResults->ifaceId);
1166 return;
1167 }
1168
1169 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1170 "%s: Link Layer Indication indType: %d", __func__, indType);
1171
1172 switch (indType) {
1173 case SIR_HAL_LL_STATS_RESULTS_RSP:
1174 {
1175 hddLog(CDF_TRACE_LEVEL_INFO,
1176 FL("RESPONSE SIR_HAL_LL_STATS_RESULTS_RSP"));
1177 hddLog(CDF_TRACE_LEVEL_INFO,
1178 "LL_STATS RESULTS RESPONSE paramID = 0x%x",
1179 linkLayerStatsResults->paramId);
1180 hddLog(CDF_TRACE_LEVEL_INFO,
1181 "LL_STATS RESULTS RESPONSE ifaceId = %u",
1182 linkLayerStatsResults->ifaceId);
1183 hddLog(CDF_TRACE_LEVEL_INFO,
1184 "LL_STATS RESULTS RESPONSE respId = %u",
1185 linkLayerStatsResults->rspId);
1186 hddLog(CDF_TRACE_LEVEL_INFO,
1187 "LL_STATS RESULTS RESPONSE more data = %u",
1188 linkLayerStatsResults->moreResultToFollow);
1189 hddLog(CDF_TRACE_LEVEL_INFO,
1190 "LL_STATS RESULTS RESPONSE num radio = %u",
1191 linkLayerStatsResults->num_radio);
1192 hddLog(CDF_TRACE_LEVEL_INFO,
1193 "LL_STATS RESULTS RESPONSE result = %p",
1194 linkLayerStatsResults->results);
1195
1196 context = &ll_stats_context;
1197 spin_lock(&context->context_lock);
1198 /* validate response received from target */
1199 if ((context->request_id != linkLayerStatsResults->rspId) ||
1200 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1201 spin_unlock(&context->context_lock);
1202 hddLog(LOGE,
1203 FL("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x"),
1204 context->request_id, linkLayerStatsResults->rspId,
1205 context->request_bitmap, linkLayerStatsResults->paramId);
1206 return;
1207 }
1208 spin_unlock(&context->context_lock);
1209
1210 if (linkLayerStatsResults->
1211 paramId & WMI_LINK_STATS_RADIO) {
1212 hdd_link_layer_process_radio_stats(pAdapter,
1213 linkLayerStatsResults->moreResultToFollow,
1214 (tpSirWifiRadioStat)linkLayerStatsResults->results,
1215 linkLayerStatsResults->num_radio);
1216
1217 spin_lock(&context->context_lock);
1218 if (!linkLayerStatsResults->moreResultToFollow)
1219 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1220 spin_unlock(&context->context_lock);
1221
1222 } else if (linkLayerStatsResults->
1223 paramId & WMI_LINK_STATS_IFACE) {
1224 hdd_link_layer_process_iface_stats(pAdapter,
1225 (tpSirWifiIfaceStat)linkLayerStatsResults->results,
1226 linkLayerStatsResults->num_peers);
1227
1228 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301229 /* Firmware doesn't send peerstats event if no peers are
1230 * connected. HDD should not wait for any peerstats in
1231 * this case and return the status to middleware after
1232 * receiving iface stats
1233 */
1234 if (!linkLayerStatsResults->num_peers)
1235 context->request_bitmap &=
1236 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001237 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1238 spin_unlock(&context->context_lock);
1239
1240 } else if (linkLayerStatsResults->
1241 paramId & WMI_LINK_STATS_ALL_PEER) {
1242 hdd_link_layer_process_peer_stats(pAdapter,
1243 linkLayerStatsResults->moreResultToFollow,
1244 (tpSirWifiPeerStat)linkLayerStatsResults->results);
1245
1246 spin_lock(&context->context_lock);
1247 if (!linkLayerStatsResults->moreResultToFollow)
1248 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1249 spin_unlock(&context->context_lock);
1250
1251 } else {
1252 hddLog(LOGE,
1253 FL("INVALID LL_STATS_NOTIFY RESPONSE"));
1254 }
1255
1256 spin_lock(&context->context_lock);
1257 /* complete response event if all requests are completed */
1258 if (0 == context->request_bitmap)
1259 complete(&context->response_event);
1260 spin_unlock(&context->context_lock);
1261
1262 break;
1263 }
1264 default:
1265 hddLog(CDF_TRACE_LEVEL_ERROR, "invalid event type %d", indType);
1266 break;
1267 }
1268
1269 return;
1270}
1271
1272/**
1273 * wlan_hdd_cfg80211_link_layer_stats_init() - initialize link layer stats
1274 * @pHddCtx: Pointer to hdd context
1275 *
1276 * Return: None
1277 */
1278void wlan_hdd_cfg80211_link_layer_stats_init(hdd_context_t *pHddCtx)
1279{
1280 sme_set_link_layer_stats_ind_cb(pHddCtx->hHal,
1281 wlan_hdd_cfg80211_link_layer_stats_callback);
1282}
1283
1284const struct
1285nla_policy
1286 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1287 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1288 .type = NLA_U32},
1289 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1290 .type = NLA_U32},
1291};
1292
1293/**
1294 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1295 * @wiphy: Pointer to wiphy
1296 * @wdev: Pointer to wdev
1297 * @data: Pointer to data
1298 * @data_len: Data length
1299 *
1300 * Return: int
1301 */
1302static int
1303__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1304 struct wireless_dev *wdev,
1305 const void *data,
1306 int data_len)
1307{
1308 int status;
1309 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1310 tSirLLStatsSetReq LinkLayerStatsSetReq;
1311 struct net_device *dev = wdev->netdev;
1312 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1313 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1314
1315 if (CDF_FTM_MODE == hdd_get_conparam()) {
1316 hdd_err("Command not allowed in FTM mode");
1317 return -EPERM;
1318 }
1319
1320 status = wlan_hdd_validate_context(pHddCtx);
1321 if (0 != status) {
1322 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1323 return -EINVAL;
1324 }
1325
1326 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1327 (struct nlattr *)data,
1328 data_len, qca_wlan_vendor_ll_set_policy)) {
1329 hddLog(CDF_TRACE_LEVEL_ERROR,
1330 FL("maximum attribute not present"));
1331 return -EINVAL;
1332 }
1333
1334 if (!tb_vendor
1335 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
1336 hddLog(CDF_TRACE_LEVEL_ERROR, FL("MPDU size Not present"));
1337 return -EINVAL;
1338 }
1339
1340 if (!tb_vendor
1341 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
1342 hddLog(CDF_TRACE_LEVEL_ERROR,
1343 FL("Stats Gathering Not Present"));
1344 return -EINVAL;
1345 }
1346
1347 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1348 LinkLayerStatsSetReq.reqId = 1;
1349
1350 LinkLayerStatsSetReq.mpduSizeThreshold =
1351 nla_get_u32(tb_vendor
1352 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1353
1354 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1355 nla_get_u32(tb_vendor
1356 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1357
1358 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1359
1360 hddLog(CDF_TRACE_LEVEL_INFO,
1361 "LL_STATS_SET reqId = %d", LinkLayerStatsSetReq.reqId);
1362 hddLog(CDF_TRACE_LEVEL_INFO,
1363 "LL_STATS_SET staId = %d", LinkLayerStatsSetReq.staId);
1364 hddLog(CDF_TRACE_LEVEL_INFO,
1365 "LL_STATS_SET mpduSizeThreshold = %d",
1366 LinkLayerStatsSetReq.mpduSizeThreshold);
1367 hddLog(CDF_TRACE_LEVEL_INFO,
1368 "LL_STATS_SET aggressive Statistics Gathering = %d",
1369 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
1370
1371 if (CDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
1372 &LinkLayerStatsSetReq)) {
1373 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1374 "sme_ll_stats_set_req Failed", __func__);
1375 return -EINVAL;
1376 }
1377
1378 pAdapter->isLinkLayerStatsSet = 1;
1379
1380 return 0;
1381}
1382
1383/**
1384 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1385 * @wiphy: Pointer to wiphy
1386 * @wdev: Pointer to wdev
1387 * @data: Pointer to data
1388 * @data_len: Data length
1389 *
1390 * Return: 0 if success, non-zero for failure
1391 */
1392int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1393 struct wireless_dev *wdev,
1394 const void *data,
1395 int data_len)
1396{
1397 int ret = 0;
1398
1399 cds_ssr_protect(__func__);
1400 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1401 cds_ssr_unprotect(__func__);
1402
1403 return ret;
1404}
1405
1406const struct
1407nla_policy
1408 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1409 /* Unsigned 32bit value provided by the caller issuing the GET stats
1410 * command. When reporting
1411 * the stats results, the driver uses the same value to indicate
1412 * which GET request the results
1413 * correspond to.
1414 */
1415 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1416
1417 /* Unsigned 32bit value . bit mask to identify what statistics are
1418 requested for retrieval */
1419 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1420};
1421
1422/**
1423 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1424 * @wiphy: Pointer to wiphy
1425 * @wdev: Pointer to wdev
1426 * @data: Pointer to data
1427 * @data_len: Data length
1428 *
1429 * Return: int
1430 */
1431static int
1432__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1433 struct wireless_dev *wdev,
1434 const void *data,
1435 int data_len)
1436{
1437 unsigned long rc;
1438 struct hdd_ll_stats_context *context;
1439 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1440 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1441 tSirLLStatsGetReq LinkLayerStatsGetReq;
1442 struct net_device *dev = wdev->netdev;
1443 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1444 int status;
1445
1446 if (CDF_FTM_MODE == hdd_get_conparam()) {
1447 hdd_err("Command not allowed in FTM mode");
1448 return -EPERM;
1449 }
1450
1451 status = wlan_hdd_validate_context(pHddCtx);
1452 if (0 != status) {
1453 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1454 return -EINVAL;
1455 }
1456
1457 if (!pAdapter->isLinkLayerStatsSet) {
1458 hddLog(CDF_TRACE_LEVEL_FATAL,
1459 "%s: isLinkLayerStatsSet : %d",
1460 __func__, pAdapter->isLinkLayerStatsSet);
1461 return -EINVAL;
1462 }
1463
1464 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1465 (struct nlattr *)data,
1466 data_len, qca_wlan_vendor_ll_get_policy)) {
1467 hddLog(CDF_TRACE_LEVEL_ERROR, FL("max attribute not present"));
1468 return -EINVAL;
1469 }
1470
1471 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
1472 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Request Id Not present"));
1473 return -EINVAL;
1474 }
1475
1476 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
1477 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Req Mask Not present"));
1478 return -EINVAL;
1479 }
1480
1481 LinkLayerStatsGetReq.reqId =
1482 nla_get_u32(tb_vendor
1483 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1484 LinkLayerStatsGetReq.paramIdMask =
1485 nla_get_u32(tb_vendor
1486 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1487
1488 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1489
1490 hddLog(LOG1,
1491 FL("LL_STATS_GET reqId = %d"), LinkLayerStatsGetReq.reqId);
1492 hddLog(LOG1,
1493 FL("LL_STATS_GET staId = %d"), LinkLayerStatsGetReq.staId);
1494 hddLog(LOG1,
1495 FL("LL_STATS_GET paramIdMask = %d"),
1496 LinkLayerStatsGetReq.paramIdMask);
1497
1498 context = &ll_stats_context;
1499 spin_lock(&context->context_lock);
1500 context->request_id = LinkLayerStatsGetReq.reqId;
1501 context->request_bitmap = LinkLayerStatsGetReq.paramIdMask;
1502 INIT_COMPLETION(context->response_event);
1503 spin_unlock(&context->context_lock);
1504
1505 if (CDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal,
1506 &LinkLayerStatsGetReq)) {
1507 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1508 "sme_ll_stats_get_req Failed", __func__);
1509 return -EINVAL;
1510 }
1511
1512 rc = wait_for_completion_timeout(&context->response_event,
1513 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1514 if (!rc) {
1515 hddLog(LOGE,
1516 FL("Target response timed out request id %d request bitmap 0x%x"),
1517 context->request_id, context->request_bitmap);
1518 return -ETIMEDOUT;
1519 }
1520
1521 return 0;
1522}
1523
1524/**
1525 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1526 * @wiphy: Pointer to wiphy
1527 * @wdev: Pointer to wdev
1528 * @data: Pointer to data
1529 * @data_len: Data length
1530 *
1531 * Return: 0 if success, non-zero for failure
1532 */
1533int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1534 struct wireless_dev *wdev,
1535 const void *data,
1536 int data_len)
1537{
1538 int ret = 0;
1539
1540 cds_ssr_protect(__func__);
1541 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1542 cds_ssr_unprotect(__func__);
1543
1544 return ret;
1545}
1546
1547const struct
1548nla_policy
1549 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1550 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1551 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1552 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1553 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1554};
1555
1556/**
1557 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1558 * @wiphy: Pointer to wiphy
1559 * @wdev: Pointer to wdev
1560 * @data: Pointer to data
1561 * @data_len: Data length
1562 *
1563 * Return: int
1564 */
1565static int
1566__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1567 struct wireless_dev *wdev,
1568 const void *data,
1569 int data_len)
1570{
1571 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1572 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1573 tSirLLStatsClearReq LinkLayerStatsClearReq;
1574 struct net_device *dev = wdev->netdev;
1575 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1576 u32 statsClearReqMask;
1577 u8 stopReq;
1578 int status;
1579 struct sk_buff *temp_skbuff;
1580
1581 if (CDF_FTM_MODE == hdd_get_conparam()) {
1582 hdd_err("Command not allowed in FTM mode");
1583 return -EPERM;
1584 }
1585
1586 status = wlan_hdd_validate_context(pHddCtx);
1587 if (0 != status) {
1588 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1589 return -EINVAL;
1590 }
1591
1592 if (!pAdapter->isLinkLayerStatsSet) {
1593 hddLog(CDF_TRACE_LEVEL_FATAL,
1594 "%s: isLinkLayerStatsSet : %d",
1595 __func__, pAdapter->isLinkLayerStatsSet);
1596 return -EINVAL;
1597 }
1598
1599 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1600 (struct nlattr *)data,
1601 data_len, qca_wlan_vendor_ll_clr_policy)) {
1602 hddLog(CDF_TRACE_LEVEL_ERROR,
1603 FL("STATS_CLR_MAX is not present"));
1604 return -EINVAL;
1605 }
1606
1607 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1608 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
1609 hddLog(CDF_TRACE_LEVEL_ERROR,
1610 FL("Error in LL_STATS CLR CONFIG PARA"));
1611 return -EINVAL;
1612 }
1613
1614 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1615 nla_get_u32(tb_vendor
1616 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1617
1618 stopReq = LinkLayerStatsClearReq.stopReq =
1619 nla_get_u8(tb_vendor
1620 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1621
1622 /*
1623 * Shall take the request Id if the Upper layers pass. 1 For now.
1624 */
1625 LinkLayerStatsClearReq.reqId = 1;
1626
1627 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1628
1629 hddLog(CDF_TRACE_LEVEL_INFO,
1630 "LL_STATS_CLEAR reqId = %d", LinkLayerStatsClearReq.reqId);
1631 hddLog(CDF_TRACE_LEVEL_INFO,
1632 "LL_STATS_CLEAR staId = %d", LinkLayerStatsClearReq.staId);
1633 hddLog(CDF_TRACE_LEVEL_INFO,
1634 "LL_STATS_CLEAR statsClearReqMask = 0x%X",
1635 LinkLayerStatsClearReq.statsClearReqMask);
1636 hddLog(CDF_TRACE_LEVEL_INFO,
1637 "LL_STATS_CLEAR stopReq = %d", LinkLayerStatsClearReq.stopReq);
1638
1639 if (CDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
1640 &LinkLayerStatsClearReq)) {
1641 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1642 2 *
1643 sizeof(u32) +
1644 2 *
1645 NLMSG_HDRLEN);
1646 if (temp_skbuff != NULL) {
1647 if (nla_put_u32(temp_skbuff,
1648 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1649 statsClearReqMask) ||
1650 nla_put_u32(temp_skbuff,
1651 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1652 stopReq)) {
1653 hddLog(CDF_TRACE_LEVEL_ERROR,
1654 FL("LL_STATS_CLR put fail"));
1655 kfree_skb(temp_skbuff);
1656 return -EINVAL;
1657 }
1658
1659 /* If the ask is to stop the stats collection as part of clear
1660 * (stopReq = 1) , ensure that no further requests of get
1661 * go to the firmware by having isLinkLayerStatsSet set to 0.
1662 * However it the stopReq as part of the clear request is 0 ,
1663 * the request to get the statistics are honoured as in this
1664 * case the firmware is just asked to clear the statistics.
1665 */
1666 if (stopReq == 1)
1667 pAdapter->isLinkLayerStatsSet = 0;
1668
1669 return cfg80211_vendor_cmd_reply(temp_skbuff);
1670 }
1671 return -ENOMEM;
1672 }
1673
1674 return -EINVAL;
1675}
1676
1677/**
1678 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1679 * @wiphy: Pointer to wiphy
1680 * @wdev: Pointer to wdev
1681 * @data: Pointer to data
1682 * @data_len: Data length
1683 *
1684 * Return: 0 if success, non-zero for failure
1685 */
1686int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1687 struct wireless_dev *wdev,
1688 const void *data,
1689 int data_len)
1690{
1691 int ret = 0;
1692
1693 cds_ssr_protect(__func__);
1694 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1695 cds_ssr_unprotect(__func__);
1696
1697 return ret;
1698}
1699
1700#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1701
1702#ifdef WLAN_FEATURE_STATS_EXT
1703/**
1704 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1705 * @wiphy: Pointer to wiphy
1706 * @wdev: Pointer to wdev
1707 * @data: Pointer to data
1708 * @data_len: Data length
1709 *
1710 * Return: int
1711 */
1712static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1713 struct wireless_dev *wdev,
1714 const void *data,
1715 int data_len)
1716{
1717 tStatsExtRequestReq stats_ext_req;
1718 struct net_device *dev = wdev->netdev;
1719 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1720 int ret_val;
1721 CDF_STATUS status;
1722 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1723
1724 ENTER();
1725
1726 ret_val = wlan_hdd_validate_context(hdd_ctx);
1727 if (ret_val)
1728 return ret_val;
1729
1730 if (CDF_FTM_MODE == hdd_get_conparam()) {
1731 hdd_err("Command not allowed in FTM mode");
1732 return -EPERM;
1733 }
1734
1735 stats_ext_req.request_data_len = data_len;
1736 stats_ext_req.request_data = (void *)data;
1737
1738 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
1739
1740 if (CDF_STATUS_SUCCESS != status)
1741 ret_val = -EINVAL;
1742
1743 return ret_val;
1744}
1745
1746/**
1747 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1748 * @wiphy: Pointer to wiphy
1749 * @wdev: Pointer to wdev
1750 * @data: Pointer to data
1751 * @data_len: Data length
1752 *
1753 * Return: int
1754 */
1755int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1756 struct wireless_dev *wdev,
1757 const void *data,
1758 int data_len)
1759{
1760 int ret;
1761
1762 cds_ssr_protect(__func__);
1763 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
1764 data, data_len);
1765 cds_ssr_unprotect(__func__);
1766
1767 return ret;
1768}
1769
1770/**
1771 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
1772 * @ctx: Pointer to HDD context
1773 * @msg: Message received
1774 *
1775 * Return: nothing
1776 */
1777static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
1778 tStatsExtEvent *msg)
1779{
1780
1781 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1782 struct sk_buff *vendor_event;
1783 int status;
1784 int ret_val;
1785 tStatsExtEvent *data = msg;
1786 hdd_adapter_t *pAdapter = NULL;
1787
1788 status = wlan_hdd_validate_context(pHddCtx);
1789
1790 if (0 != status) {
1791 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1792 "%s: HDD context is not valid", __func__);
1793 return;
1794 }
1795
1796 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
1797
1798 if (NULL == pAdapter) {
1799 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1800 "%s: vdev_id %d does not exist with host",
1801 __func__, data->vdev_id);
1802 return;
1803 }
1804
1805 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1806 NULL,
1807 data->event_data_len +
1808 sizeof(uint32_t) +
1809 NLMSG_HDRLEN + NLMSG_HDRLEN,
1810 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
1811 GFP_KERNEL);
1812
1813 if (!vendor_event) {
1814 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1815 "%s: cfg80211_vendor_event_alloc failed", __func__);
1816 return;
1817 }
1818
1819 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
1820 pAdapter->dev->ifindex);
1821 if (ret_val) {
1822 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1823 "%s: QCA_WLAN_VENDOR_ATTR_IFINDEX put fail",
1824 __func__);
1825 kfree_skb(vendor_event);
1826
1827 return;
1828 }
1829
1830 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
1831 data->event_data_len, data->event_data);
1832
1833 if (ret_val) {
1834 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1835 "%s: QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail",
1836 __func__);
1837 kfree_skb(vendor_event);
1838
1839 return;
1840 }
1841
1842 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1843
1844}
1845
1846/**
1847 * wlan_hdd_cfg80211_stats_ext_init() - ext stats init
1848 * @ctx: Pointer to HDD context
1849 *
1850 * Return: nothing
1851 */
1852void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx)
1853{
1854 sme_stats_ext_register_callback(pHddCtx->hHal,
1855 wlan_hdd_cfg80211_stats_ext_callback);
1856}
1857#endif /* End of WLAN_FEATURE_STATS_EXT */
1858
1859/**
1860 * __wlan_hdd_cfg80211_get_station() - get station statistics
1861 * @wiphy: Pointer to wiphy
1862 * @dev: Pointer to network device
1863 * @mac: Pointer to mac
1864 * @sinfo: Pointer to station info
1865 *
1866 * Return: 0 for success, non-zero for failure
1867 */
1868static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
1869 struct net_device *dev,
1870 const uint8_t *mac,
1871 struct station_info *sinfo)
1872{
1873 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1874 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1875 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
1876 uint8_t rate_flags;
1877
1878 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
1879 struct hdd_config *pCfg = pHddCtx->config;
1880
1881 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
1882 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
1883 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
1884 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
1885 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
1886 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
1887 uint16_t maxRate = 0;
1888 uint16_t myRate;
1889 uint16_t currentRate = 0;
1890 uint8_t maxSpeedMCS = 0;
1891 uint8_t maxMCSIdx = 0;
1892 uint8_t rateFlag = 1;
1893 uint8_t i, j, rssidx;
1894 uint8_t nss = 1;
1895 int status, mode = 0, maxHtIdx;
1896 struct index_vht_data_rate_type *supported_vht_mcs_rate;
1897 struct index_data_rate_type *supported_mcs_rate;
1898
1899#ifdef WLAN_FEATURE_11AC
1900 uint32_t vht_mcs_map;
1901 enum eDataRate11ACMaxMcs vhtMaxMcs;
1902#endif /* WLAN_FEATURE_11AC */
1903
1904
1905 ENTER();
1906
1907 if (CDF_FTM_MODE == hdd_get_conparam()) {
1908 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1909 return -EINVAL;
1910 }
1911
1912 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
1913 (0 == ssidlen)) {
1914 hddLog(LOG1, FL("Not associated or Invalid ssidlen, %d"),
1915 ssidlen);
1916 /*To keep GUI happy */
1917 return 0;
1918 }
1919
1920 if (true == pHddStaCtx->hdd_ReassocScenario) {
1921 hddLog(LOG1,
1922 FL("Roaming is in progress, cannot continue with this request"));
1923 return 0;
1924 }
1925
1926 status = wlan_hdd_validate_context(pHddCtx);
1927
1928 if (0 != status) {
1929 hddLog(LOGE, FL("HDD context is not valid"));
1930 return status;
1931 }
1932
1933 wlan_hdd_get_rssi(pAdapter, &sinfo->signal);
1934 sinfo->filled |= STATION_INFO_SIGNAL;
1935
1936#ifdef WLAN_FEATURE_LPSS
1937 if (!pAdapter->rssi_send) {
1938 pAdapter->rssi_send = true;
Yue Mae3eaebe2015-10-27 12:42:40 -07001939 if (pHddCtx->isUnloadInProgress != true)
1940 wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 }
1942#endif
1943
1944 wlan_hdd_get_station_stats(pAdapter);
1945 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
1946
1947 /* convert to the UI units of 100kbps */
1948 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
1949 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
1950 nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt;
1951
1952 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
1953 /* Get current rate flags if report actual */
1954 rate_flags =
1955 pAdapter->hdd_stats.ClassA_stat.
1956 promiscuous_rx_frag_cnt;
1957 }
1958
1959 if (pAdapter->hdd_stats.ClassA_stat.mcs_index ==
1960 INVALID_MCS_IDX) {
1961 rate_flags = eHAL_TX_RATE_LEGACY;
1962 pAdapter->hdd_stats.ClassA_stat.mcs_index = 0;
1963 }
1964 }
1965#ifdef LINKSPEED_DEBUG_ENABLED
1966 pr_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d\n",
1967 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
1968 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
1969 (int)pCfg->linkSpeedRssiLow, (int)rate_flags,
1970 (int)pAdapter->hdd_stats.ClassA_stat.mcs_index);
1971#endif /* LINKSPEED_DEBUG_ENABLED */
1972
1973 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
1974 /* we do not want to necessarily report the current speed */
1975 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
1976 /* report the max possible speed */
1977 rssidx = 0;
1978 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
1979 pCfg->reportMaxLinkSpeed) {
1980 /* report the max possible speed with RSSI scaling */
1981 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
1982 /* report the max possible speed */
1983 rssidx = 0;
1984 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
1985 /* report middle speed */
1986 rssidx = 1;
1987 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
1988 /* report middle speed */
1989 rssidx = 2;
1990 } else {
1991 /* report actual speed */
1992 rssidx = 3;
1993 }
1994 } else {
1995 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
1996 hddLog(LOGE,
1997 FL("Invalid value for reportMaxLinkSpeed: %u"),
1998 pCfg->reportMaxLinkSpeed);
1999 rssidx = 0;
2000 }
2001
2002 maxRate = 0;
2003
2004 /* Get Basic Rate Set */
2005 if (0 !=
2006 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
2007 WNI_CFG_OPERATIONAL_RATE_SET,
2008 OperationalRates,
2009 &ORLeng)) {
2010 hddLog(LOGE, FL("cfg get returned failure"));
2011 /*To keep GUI happy */
2012 return 0;
2013 }
2014
2015 for (i = 0; i < ORLeng; i++) {
2016 for (j = 0;
2017 j < ARRAY_SIZE(supported_data_rate); j++) {
2018 /* Validate Rate Set */
2019 if (supported_data_rate[j].beacon_rate_index ==
2020 (OperationalRates[i] & 0x7F)) {
2021 currentRate =
2022 supported_data_rate[j].
2023 supported_rate[rssidx];
2024 break;
2025 }
2026 }
2027 /* Update MAX rate */
2028 maxRate =
2029 (currentRate > maxRate) ? currentRate : maxRate;
2030 }
2031
2032 /* Get Extended Rate Set */
2033 if (0 !=
2034 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
2035 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
2036 ExtendedRates, &ERLeng)) {
2037 hddLog(LOGE, FL("cfg get returned failure"));
2038 /*To keep GUI happy */
2039 return 0;
2040 }
2041
2042 for (i = 0; i < ERLeng; i++) {
2043 for (j = 0;
2044 j < ARRAY_SIZE(supported_data_rate); j++) {
2045 if (supported_data_rate[j].beacon_rate_index ==
2046 (ExtendedRates[i] & 0x7F)) {
2047 currentRate =
2048 supported_data_rate[j].
2049 supported_rate[rssidx];
2050 break;
2051 }
2052 }
2053 /* Update MAX rate */
2054 maxRate =
2055 (currentRate > maxRate) ? currentRate : maxRate;
2056 }
2057 /* Get MCS Rate Set --
2058 Only if we are connected in non legacy mode and not reporting
2059 actual speed */
2060 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
2061 if (0 !=
2062 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
2063 WNI_CFG_CURRENT_MCS_SET, MCSRates,
2064 &MCSLeng)) {
2065 hddLog(LOGE, FL("cfg get returned failure"));
2066 /*To keep GUI happy */
2067 return 0;
2068 }
2069 rateFlag = 0;
2070#ifdef WLAN_FEATURE_11AC
2071 supported_vht_mcs_rate =
2072 (struct index_vht_data_rate_type *)
2073 ((nss ==
2074 1) ? &supported_vht_mcs_rate_nss1 :
2075 &supported_vht_mcs_rate_nss2);
2076
2077 if (rate_flags & eHAL_TX_RATE_VHT80)
2078 mode = 2;
2079 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
2080 (rate_flags & eHAL_TX_RATE_HT40))
2081 mode = 1;
2082 else
2083 mode = 0;
2084
2085 /* VHT80 rate has seperate rate table */
2086 if (rate_flags &
2087 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
2088 eHAL_TX_RATE_VHT80)) {
2089 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
2090 WNI_CFG_VHT_TX_MCS_MAP,
2091 &vht_mcs_map);
2092 vhtMaxMcs = (enum eDataRate11ACMaxMcs)
2093 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
2094 if (rate_flags & eHAL_TX_RATE_SGI)
2095 rateFlag |= 1;
2096 if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs)
2097 maxMCSIdx = 7;
2098 else if (DATA_RATE_11AC_MAX_MCS_8 ==
2099 vhtMaxMcs)
2100 maxMCSIdx = 8;
2101 else if (DATA_RATE_11AC_MAX_MCS_9 ==
2102 vhtMaxMcs) {
2103 /* VHT20 is supporting 0~8 */
2104 if (rate_flags & eHAL_TX_RATE_VHT20)
2105 maxMCSIdx = 8;
2106 else
2107 maxMCSIdx = 9;
2108 }
2109
2110 if (rssidx != 0) {
2111 for (i = 0; i <= maxMCSIdx; i++) {
2112 if (sinfo->signal <=
2113 rssi_mcs_tbl[mode][i]) {
2114 maxMCSIdx = i;
2115 break;
2116 }
2117 }
2118 }
2119
2120 if (rate_flags & eHAL_TX_RATE_VHT80) {
2121 currentRate =
2122 supported_vht_mcs_rate[pAdapter->
2123 hdd_stats.ClassA_stat.mcs_index].
2124 supported_VHT80_rate[rateFlag];
2125 maxRate =
2126 supported_vht_mcs_rate[maxMCSIdx].
2127 supported_VHT80_rate[rateFlag];
2128 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2129 currentRate =
2130 supported_vht_mcs_rate[pAdapter->
2131 hdd_stats.ClassA_stat.mcs_index].
2132 supported_VHT40_rate[rateFlag];
2133 maxRate =
2134 supported_vht_mcs_rate[maxMCSIdx].
2135 supported_VHT40_rate[rateFlag];
2136 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2137 currentRate =
2138 supported_vht_mcs_rate[pAdapter->
2139 hdd_stats.ClassA_stat.mcs_index].
2140 supported_VHT20_rate[rateFlag];
2141 maxRate =
2142 supported_vht_mcs_rate[maxMCSIdx].
2143 supported_VHT20_rate[rateFlag];
2144 }
2145
2146 maxSpeedMCS = 1;
2147 if (currentRate > maxRate)
2148 maxRate = currentRate;
2149
2150 } else
2151#endif /* WLAN_FEATURE_11AC */
2152 {
2153 if (rate_flags & eHAL_TX_RATE_HT40)
2154 rateFlag |= 1;
2155 if (rate_flags & eHAL_TX_RATE_SGI)
2156 rateFlag |= 2;
2157
2158 supported_mcs_rate =
2159 (struct index_data_rate_type *)
2160 ((nss ==
2161 1) ? &supported_mcs_rate_nss1 :
2162 &supported_mcs_rate_nss2);
2163
2164 maxHtIdx = MAX_HT_MCS_IDX;
2165 if (rssidx != 0) {
2166 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
2167 if (sinfo->signal <=
2168 rssi_mcs_tbl[mode][i]) {
2169 maxHtIdx = i + 1;
2170 break;
2171 }
2172 }
2173 }
2174
2175 for (i = 0; i < MCSLeng; i++) {
2176 for (j = 0; j < maxHtIdx; j++) {
2177 if (supported_mcs_rate[j].
2178 beacon_rate_index ==
2179 MCSRates[i]) {
2180 currentRate =
2181 supported_mcs_rate[j].
2182 supported_rate
2183 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302184 maxMCSIdx =
2185 supported_mcs_rate[j].
2186 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002187 break;
2188 }
2189 }
2190
2191 if ((j < MAX_HT_MCS_IDX)
2192 && (currentRate > maxRate)) {
2193 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302195 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002196 }
2197 }
2198 }
2199
2200 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
2201 maxRate = myRate;
2202 maxSpeedMCS = 1;
2203 maxMCSIdx = pAdapter->hdd_stats.ClassA_stat.mcs_index;
2204 }
2205 /* report a value at least as big as current rate */
2206 if ((maxRate < myRate) || (0 == maxRate)) {
2207 maxRate = myRate;
2208 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2209 maxSpeedMCS = 0;
2210 } else {
2211 maxSpeedMCS = 1;
2212 maxMCSIdx =
2213 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2214 }
2215 }
2216
2217 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2218 sinfo->txrate.legacy = maxRate;
2219#ifdef LINKSPEED_DEBUG_ENABLED
2220 pr_info("Reporting legacy rate %d\n",
2221 sinfo->txrate.legacy);
2222#endif /* LINKSPEED_DEBUG_ENABLED */
2223 } else {
2224 sinfo->txrate.mcs = maxMCSIdx;
2225#ifdef WLAN_FEATURE_11AC
2226 sinfo->txrate.nss = nss;
2227 if (rate_flags & eHAL_TX_RATE_VHT80) {
2228 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2229 sinfo->txrate.flags |=
2230 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2231 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2232 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2233 sinfo->txrate.flags |=
2234 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2235 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2236 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2237 } else
2238 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2239#endif /* WLAN_FEATURE_11AC */
2240 if (rate_flags &
2241 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2242 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2243 if (rate_flags & eHAL_TX_RATE_HT40) {
2244 sinfo->txrate.flags |=
2245 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2246 }
2247 }
2248 if (rate_flags & eHAL_TX_RATE_SGI) {
2249 if (!
2250 (sinfo->txrate.
2251 flags & RATE_INFO_FLAGS_VHT_MCS))
2252 sinfo->txrate.flags |=
2253 RATE_INFO_FLAGS_MCS;
2254 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2255 }
2256#ifdef LINKSPEED_DEBUG_ENABLED
2257 pr_info("Reporting MCS rate %d flags %x\n",
2258 sinfo->txrate.mcs, sinfo->txrate.flags);
2259#endif /* LINKSPEED_DEBUG_ENABLED */
2260 }
2261 } else {
2262 /* report current rate instead of max rate */
2263
2264 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2265 /* provide to the UI in units of 100kbps */
2266 sinfo->txrate.legacy = myRate;
2267#ifdef LINKSPEED_DEBUG_ENABLED
2268 pr_info("Reporting actual legacy rate %d\n",
2269 sinfo->txrate.legacy);
2270#endif /* LINKSPEED_DEBUG_ENABLED */
2271 } else {
2272 /* must be MCS */
2273 sinfo->txrate.mcs =
2274 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2275#ifdef WLAN_FEATURE_11AC
2276 sinfo->txrate.nss = nss;
2277 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2278 if (rate_flags & eHAL_TX_RATE_VHT80) {
2279 sinfo->txrate.flags |=
2280 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2281 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2282 sinfo->txrate.flags |=
2283 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2284 }
2285#endif /* WLAN_FEATURE_11AC */
2286 if (rate_flags &
2287 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2288 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2289 if (rate_flags & eHAL_TX_RATE_HT40) {
2290 sinfo->txrate.flags |=
2291 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2292 }
2293 }
2294 if (rate_flags & eHAL_TX_RATE_SGI) {
2295 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2296 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2297 }
2298#ifdef LINKSPEED_DEBUG_ENABLED
2299 pr_info("Reporting actual MCS rate %d flags %x\n",
2300 sinfo->txrate.mcs, sinfo->txrate.flags);
2301#endif /* LINKSPEED_DEBUG_ENABLED */
2302 }
2303 }
2304 sinfo->filled |= STATION_INFO_TX_BITRATE;
2305
2306 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
2307 sinfo->filled |= STATION_INFO_TX_BYTES;
2308
2309 sinfo->tx_packets =
2310 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] +
2311 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] +
2312 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] +
2313 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3];
2314
2315 sinfo->tx_retries =
2316 pAdapter->hdd_stats.summary_stat.retry_cnt[0] +
2317 pAdapter->hdd_stats.summary_stat.retry_cnt[1] +
2318 pAdapter->hdd_stats.summary_stat.retry_cnt[2] +
2319 pAdapter->hdd_stats.summary_stat.retry_cnt[3];
2320
2321 sinfo->tx_failed =
2322 pAdapter->hdd_stats.summary_stat.fail_cnt[0] +
2323 pAdapter->hdd_stats.summary_stat.fail_cnt[1] +
2324 pAdapter->hdd_stats.summary_stat.fail_cnt[2] +
2325 pAdapter->hdd_stats.summary_stat.fail_cnt[3];
2326
2327 sinfo->filled |=
2328 STATION_INFO_TX_PACKETS |
2329 STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED;
2330
2331 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
2332 sinfo->filled |= STATION_INFO_RX_BYTES;
2333
2334 sinfo->rx_packets = pAdapter->stats.rx_packets;
2335 sinfo->filled |= STATION_INFO_RX_PACKETS;
2336
2337 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2338 TRACE_CODE_HDD_CFG80211_GET_STA,
2339 pAdapter->sessionId, maxRate));
2340 EXIT();
2341 return 0;
2342}
2343
2344/**
2345 * wlan_hdd_cfg80211_get_station() - get station statistics
2346 * @wiphy: Pointer to wiphy
2347 * @dev: Pointer to network device
2348 * @mac: Pointer to mac
2349 * @sinfo: Pointer to station info
2350 *
2351 * Return: 0 for success, non-zero for failure
2352 */
2353#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2354int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2355 struct net_device *dev, const uint8_t *mac,
2356 struct station_info *sinfo)
2357#else
2358int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2359 struct net_device *dev, uint8_t *mac,
2360 struct station_info *sinfo)
2361#endif
2362{
2363 int ret;
2364
2365 cds_ssr_protect(__func__);
2366 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
2367 cds_ssr_unprotect(__func__);
2368
2369 return ret;
2370}
2371
2372/**
2373 * hdd_get_stats() - Function to retrieve interface statistics
2374 * @dev: pointer to network device
2375 *
2376 * This function is the ndo_get_stats method for all netdevs
2377 * registered with the kernel
2378 *
2379 * Return: pointer to net_device_stats structure
2380 */
2381struct net_device_stats *hdd_get_stats(struct net_device *dev)
2382{
2383 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2384
2385 return &adapter->stats;
2386}
2387/**
2388 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
2389 * @wiphy: Pointer to wiphy
2390 * @dev: Pointer to network device
2391 * @idx: Index
2392 * @survey: Pointer to survey info
2393 *
2394 * Return: 0 for success, non-zero for failure
2395 */
2396static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2397 struct net_device *dev,
2398 int idx, struct survey_info *survey)
2399{
2400 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2401 hdd_context_t *pHddCtx;
2402 hdd_station_ctx_t *pHddStaCtx;
2403 tHalHandle halHandle;
2404 uint32_t channel = 0, freq = 0; /* Initialization Required */
2405 int8_t snr, rssi;
2406 int status, i, j, filled = 0;
2407
2408 ENTER();
2409
2410 if (CDF_FTM_MODE == hdd_get_conparam()) {
2411 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2412 return -EINVAL;
2413 }
2414
2415 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2416 status = wlan_hdd_validate_context(pHddCtx);
2417
2418 if (0 != status) {
2419 hddLog(LOGE, FL("HDD context is not valid"));
2420 return status;
2421 }
2422
2423 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2424
2425 if (0 == pHddCtx->config->fEnableSNRMonitoring ||
2426 0 != pAdapter->survey_idx ||
2427 eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2428 /* The survey dump ops when implemented completely is expected
2429 * to return a survey of all channels and the ops is called by
2430 * the kernel with incremental values of the argument 'idx'
2431 * till it returns -ENONET. But we can only support the survey
2432 * for the operating channel for now. survey_idx is used to
2433 * track that the ops is called only once and then return
2434 * -ENONET for the next iteration
2435 */
2436 pAdapter->survey_idx = 0;
2437 return -ENONET;
2438 }
2439
2440 if (!pHddStaCtx->hdd_ReassocScenario) {
2441 hdd_err("Roaming in progress, hence return");
2442 return -ENONET;
2443 }
2444
2445 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
2446
2447 wlan_hdd_get_snr(pAdapter, &snr);
2448 wlan_hdd_get_rssi(pAdapter, &rssi);
2449
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302450 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2451 TRACE_CODE_HDD_CFG80211_DUMP_SURVEY,
2452 pAdapter->sessionId, pAdapter->device_mode));
2453
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId);
2455 hdd_wlan_get_freq(channel, &freq);
2456
2457 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
2458 if (NULL == wiphy->bands[i]) {
2459 hddLog(LOG1, FL("wiphy->bands[i] is NULL, i = %d"), i);
2460 continue;
2461 }
2462
2463 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
2464 struct ieee80211_supported_band *band = wiphy->bands[i];
2465
2466 if (band->channels[j].center_freq == (uint16_t) freq) {
2467 survey->channel = &band->channels[j];
2468 /* The Rx BDs contain SNR values in dB for the
2469 * received frames while the supplicant expects
2470 * noise. So we calculate and return the value
2471 * of noise (dBm)
2472 * SNR (dB) = RSSI (dBm) - NOISE (dBm)
2473 */
2474 survey->noise = rssi - snr;
2475 survey->filled = SURVEY_INFO_NOISE_DBM;
2476 filled = 1;
2477 }
2478 }
2479 }
2480
2481 if (filled)
2482 pAdapter->survey_idx = 1;
2483 else {
2484 pAdapter->survey_idx = 0;
2485 return -ENONET;
2486 }
2487
2488 return 0;
2489}
2490
2491/**
2492 * wlan_hdd_cfg80211_dump_survey() - get survey related info
2493 * @wiphy: Pointer to wiphy
2494 * @dev: Pointer to network device
2495 * @idx: Index
2496 * @survey: Pointer to survey info
2497 *
2498 * Return: 0 for success, non-zero for failure
2499 */
2500int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2501 struct net_device *dev,
2502 int idx, struct survey_info *survey)
2503{
2504 int ret;
2505
2506 cds_ssr_protect(__func__);
2507 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
2508 cds_ssr_unprotect(__func__);
2509
2510 return ret;
2511}
2512/**
2513 * hdd_init_ll_stats_ctx() - initialize link layer stats context
2514 *
2515 * Return: none
2516 */
2517inline void hdd_init_ll_stats_ctx(void)
2518{
2519 spin_lock_init(&ll_stats_context.context_lock);
2520 init_completion(&ll_stats_context.response_event);
2521 ll_stats_context.request_bitmap = 0;
2522
2523 return;
2524}