blob: 4d3b35c3fb21f98eea1e8abc3a5577222b8ee2ad [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);
1229 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1230 spin_unlock(&context->context_lock);
1231
1232 } else if (linkLayerStatsResults->
1233 paramId & WMI_LINK_STATS_ALL_PEER) {
1234 hdd_link_layer_process_peer_stats(pAdapter,
1235 linkLayerStatsResults->moreResultToFollow,
1236 (tpSirWifiPeerStat)linkLayerStatsResults->results);
1237
1238 spin_lock(&context->context_lock);
1239 if (!linkLayerStatsResults->moreResultToFollow)
1240 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1241 spin_unlock(&context->context_lock);
1242
1243 } else {
1244 hddLog(LOGE,
1245 FL("INVALID LL_STATS_NOTIFY RESPONSE"));
1246 }
1247
1248 spin_lock(&context->context_lock);
1249 /* complete response event if all requests are completed */
1250 if (0 == context->request_bitmap)
1251 complete(&context->response_event);
1252 spin_unlock(&context->context_lock);
1253
1254 break;
1255 }
1256 default:
1257 hddLog(CDF_TRACE_LEVEL_ERROR, "invalid event type %d", indType);
1258 break;
1259 }
1260
1261 return;
1262}
1263
1264/**
1265 * wlan_hdd_cfg80211_link_layer_stats_init() - initialize link layer stats
1266 * @pHddCtx: Pointer to hdd context
1267 *
1268 * Return: None
1269 */
1270void wlan_hdd_cfg80211_link_layer_stats_init(hdd_context_t *pHddCtx)
1271{
1272 sme_set_link_layer_stats_ind_cb(pHddCtx->hHal,
1273 wlan_hdd_cfg80211_link_layer_stats_callback);
1274}
1275
1276const struct
1277nla_policy
1278 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1279 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1280 .type = NLA_U32},
1281 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1282 .type = NLA_U32},
1283};
1284
1285/**
1286 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1287 * @wiphy: Pointer to wiphy
1288 * @wdev: Pointer to wdev
1289 * @data: Pointer to data
1290 * @data_len: Data length
1291 *
1292 * Return: int
1293 */
1294static int
1295__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1296 struct wireless_dev *wdev,
1297 const void *data,
1298 int data_len)
1299{
1300 int status;
1301 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1302 tSirLLStatsSetReq LinkLayerStatsSetReq;
1303 struct net_device *dev = wdev->netdev;
1304 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1305 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1306
1307 if (CDF_FTM_MODE == hdd_get_conparam()) {
1308 hdd_err("Command not allowed in FTM mode");
1309 return -EPERM;
1310 }
1311
1312 status = wlan_hdd_validate_context(pHddCtx);
1313 if (0 != status) {
1314 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1315 return -EINVAL;
1316 }
1317
1318 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1319 (struct nlattr *)data,
1320 data_len, qca_wlan_vendor_ll_set_policy)) {
1321 hddLog(CDF_TRACE_LEVEL_ERROR,
1322 FL("maximum attribute not present"));
1323 return -EINVAL;
1324 }
1325
1326 if (!tb_vendor
1327 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
1328 hddLog(CDF_TRACE_LEVEL_ERROR, FL("MPDU size Not present"));
1329 return -EINVAL;
1330 }
1331
1332 if (!tb_vendor
1333 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
1334 hddLog(CDF_TRACE_LEVEL_ERROR,
1335 FL("Stats Gathering Not Present"));
1336 return -EINVAL;
1337 }
1338
1339 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1340 LinkLayerStatsSetReq.reqId = 1;
1341
1342 LinkLayerStatsSetReq.mpduSizeThreshold =
1343 nla_get_u32(tb_vendor
1344 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1345
1346 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1347 nla_get_u32(tb_vendor
1348 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1349
1350 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1351
1352 hddLog(CDF_TRACE_LEVEL_INFO,
1353 "LL_STATS_SET reqId = %d", LinkLayerStatsSetReq.reqId);
1354 hddLog(CDF_TRACE_LEVEL_INFO,
1355 "LL_STATS_SET staId = %d", LinkLayerStatsSetReq.staId);
1356 hddLog(CDF_TRACE_LEVEL_INFO,
1357 "LL_STATS_SET mpduSizeThreshold = %d",
1358 LinkLayerStatsSetReq.mpduSizeThreshold);
1359 hddLog(CDF_TRACE_LEVEL_INFO,
1360 "LL_STATS_SET aggressive Statistics Gathering = %d",
1361 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
1362
1363 if (CDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
1364 &LinkLayerStatsSetReq)) {
1365 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1366 "sme_ll_stats_set_req Failed", __func__);
1367 return -EINVAL;
1368 }
1369
1370 pAdapter->isLinkLayerStatsSet = 1;
1371
1372 return 0;
1373}
1374
1375/**
1376 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1377 * @wiphy: Pointer to wiphy
1378 * @wdev: Pointer to wdev
1379 * @data: Pointer to data
1380 * @data_len: Data length
1381 *
1382 * Return: 0 if success, non-zero for failure
1383 */
1384int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1385 struct wireless_dev *wdev,
1386 const void *data,
1387 int data_len)
1388{
1389 int ret = 0;
1390
1391 cds_ssr_protect(__func__);
1392 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1393 cds_ssr_unprotect(__func__);
1394
1395 return ret;
1396}
1397
1398const struct
1399nla_policy
1400 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1401 /* Unsigned 32bit value provided by the caller issuing the GET stats
1402 * command. When reporting
1403 * the stats results, the driver uses the same value to indicate
1404 * which GET request the results
1405 * correspond to.
1406 */
1407 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1408
1409 /* Unsigned 32bit value . bit mask to identify what statistics are
1410 requested for retrieval */
1411 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1412};
1413
1414/**
1415 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1416 * @wiphy: Pointer to wiphy
1417 * @wdev: Pointer to wdev
1418 * @data: Pointer to data
1419 * @data_len: Data length
1420 *
1421 * Return: int
1422 */
1423static int
1424__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1425 struct wireless_dev *wdev,
1426 const void *data,
1427 int data_len)
1428{
1429 unsigned long rc;
1430 struct hdd_ll_stats_context *context;
1431 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1432 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1433 tSirLLStatsGetReq LinkLayerStatsGetReq;
1434 struct net_device *dev = wdev->netdev;
1435 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1436 int status;
1437
1438 if (CDF_FTM_MODE == hdd_get_conparam()) {
1439 hdd_err("Command not allowed in FTM mode");
1440 return -EPERM;
1441 }
1442
1443 status = wlan_hdd_validate_context(pHddCtx);
1444 if (0 != status) {
1445 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1446 return -EINVAL;
1447 }
1448
1449 if (!pAdapter->isLinkLayerStatsSet) {
1450 hddLog(CDF_TRACE_LEVEL_FATAL,
1451 "%s: isLinkLayerStatsSet : %d",
1452 __func__, pAdapter->isLinkLayerStatsSet);
1453 return -EINVAL;
1454 }
1455
1456 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1457 (struct nlattr *)data,
1458 data_len, qca_wlan_vendor_ll_get_policy)) {
1459 hddLog(CDF_TRACE_LEVEL_ERROR, FL("max attribute not present"));
1460 return -EINVAL;
1461 }
1462
1463 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
1464 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Request Id Not present"));
1465 return -EINVAL;
1466 }
1467
1468 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
1469 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Req Mask Not present"));
1470 return -EINVAL;
1471 }
1472
1473 LinkLayerStatsGetReq.reqId =
1474 nla_get_u32(tb_vendor
1475 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1476 LinkLayerStatsGetReq.paramIdMask =
1477 nla_get_u32(tb_vendor
1478 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1479
1480 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1481
1482 hddLog(LOG1,
1483 FL("LL_STATS_GET reqId = %d"), LinkLayerStatsGetReq.reqId);
1484 hddLog(LOG1,
1485 FL("LL_STATS_GET staId = %d"), LinkLayerStatsGetReq.staId);
1486 hddLog(LOG1,
1487 FL("LL_STATS_GET paramIdMask = %d"),
1488 LinkLayerStatsGetReq.paramIdMask);
1489
1490 context = &ll_stats_context;
1491 spin_lock(&context->context_lock);
1492 context->request_id = LinkLayerStatsGetReq.reqId;
1493 context->request_bitmap = LinkLayerStatsGetReq.paramIdMask;
1494 INIT_COMPLETION(context->response_event);
1495 spin_unlock(&context->context_lock);
1496
1497 if (CDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal,
1498 &LinkLayerStatsGetReq)) {
1499 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1500 "sme_ll_stats_get_req Failed", __func__);
1501 return -EINVAL;
1502 }
1503
1504 rc = wait_for_completion_timeout(&context->response_event,
1505 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1506 if (!rc) {
1507 hddLog(LOGE,
1508 FL("Target response timed out request id %d request bitmap 0x%x"),
1509 context->request_id, context->request_bitmap);
1510 return -ETIMEDOUT;
1511 }
1512
1513 return 0;
1514}
1515
1516/**
1517 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1518 * @wiphy: Pointer to wiphy
1519 * @wdev: Pointer to wdev
1520 * @data: Pointer to data
1521 * @data_len: Data length
1522 *
1523 * Return: 0 if success, non-zero for failure
1524 */
1525int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1526 struct wireless_dev *wdev,
1527 const void *data,
1528 int data_len)
1529{
1530 int ret = 0;
1531
1532 cds_ssr_protect(__func__);
1533 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1534 cds_ssr_unprotect(__func__);
1535
1536 return ret;
1537}
1538
1539const struct
1540nla_policy
1541 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1542 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1543 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1544 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1545 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1546};
1547
1548/**
1549 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1550 * @wiphy: Pointer to wiphy
1551 * @wdev: Pointer to wdev
1552 * @data: Pointer to data
1553 * @data_len: Data length
1554 *
1555 * Return: int
1556 */
1557static int
1558__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1559 struct wireless_dev *wdev,
1560 const void *data,
1561 int data_len)
1562{
1563 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1564 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1565 tSirLLStatsClearReq LinkLayerStatsClearReq;
1566 struct net_device *dev = wdev->netdev;
1567 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1568 u32 statsClearReqMask;
1569 u8 stopReq;
1570 int status;
1571 struct sk_buff *temp_skbuff;
1572
1573 if (CDF_FTM_MODE == hdd_get_conparam()) {
1574 hdd_err("Command not allowed in FTM mode");
1575 return -EPERM;
1576 }
1577
1578 status = wlan_hdd_validate_context(pHddCtx);
1579 if (0 != status) {
1580 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
1581 return -EINVAL;
1582 }
1583
1584 if (!pAdapter->isLinkLayerStatsSet) {
1585 hddLog(CDF_TRACE_LEVEL_FATAL,
1586 "%s: isLinkLayerStatsSet : %d",
1587 __func__, pAdapter->isLinkLayerStatsSet);
1588 return -EINVAL;
1589 }
1590
1591 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1592 (struct nlattr *)data,
1593 data_len, qca_wlan_vendor_ll_clr_policy)) {
1594 hddLog(CDF_TRACE_LEVEL_ERROR,
1595 FL("STATS_CLR_MAX is not present"));
1596 return -EINVAL;
1597 }
1598
1599 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1600 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
1601 hddLog(CDF_TRACE_LEVEL_ERROR,
1602 FL("Error in LL_STATS CLR CONFIG PARA"));
1603 return -EINVAL;
1604 }
1605
1606 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1607 nla_get_u32(tb_vendor
1608 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1609
1610 stopReq = LinkLayerStatsClearReq.stopReq =
1611 nla_get_u8(tb_vendor
1612 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1613
1614 /*
1615 * Shall take the request Id if the Upper layers pass. 1 For now.
1616 */
1617 LinkLayerStatsClearReq.reqId = 1;
1618
1619 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1620
1621 hddLog(CDF_TRACE_LEVEL_INFO,
1622 "LL_STATS_CLEAR reqId = %d", LinkLayerStatsClearReq.reqId);
1623 hddLog(CDF_TRACE_LEVEL_INFO,
1624 "LL_STATS_CLEAR staId = %d", LinkLayerStatsClearReq.staId);
1625 hddLog(CDF_TRACE_LEVEL_INFO,
1626 "LL_STATS_CLEAR statsClearReqMask = 0x%X",
1627 LinkLayerStatsClearReq.statsClearReqMask);
1628 hddLog(CDF_TRACE_LEVEL_INFO,
1629 "LL_STATS_CLEAR stopReq = %d", LinkLayerStatsClearReq.stopReq);
1630
1631 if (CDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
1632 &LinkLayerStatsClearReq)) {
1633 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1634 2 *
1635 sizeof(u32) +
1636 2 *
1637 NLMSG_HDRLEN);
1638 if (temp_skbuff != NULL) {
1639 if (nla_put_u32(temp_skbuff,
1640 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1641 statsClearReqMask) ||
1642 nla_put_u32(temp_skbuff,
1643 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1644 stopReq)) {
1645 hddLog(CDF_TRACE_LEVEL_ERROR,
1646 FL("LL_STATS_CLR put fail"));
1647 kfree_skb(temp_skbuff);
1648 return -EINVAL;
1649 }
1650
1651 /* If the ask is to stop the stats collection as part of clear
1652 * (stopReq = 1) , ensure that no further requests of get
1653 * go to the firmware by having isLinkLayerStatsSet set to 0.
1654 * However it the stopReq as part of the clear request is 0 ,
1655 * the request to get the statistics are honoured as in this
1656 * case the firmware is just asked to clear the statistics.
1657 */
1658 if (stopReq == 1)
1659 pAdapter->isLinkLayerStatsSet = 0;
1660
1661 return cfg80211_vendor_cmd_reply(temp_skbuff);
1662 }
1663 return -ENOMEM;
1664 }
1665
1666 return -EINVAL;
1667}
1668
1669/**
1670 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1671 * @wiphy: Pointer to wiphy
1672 * @wdev: Pointer to wdev
1673 * @data: Pointer to data
1674 * @data_len: Data length
1675 *
1676 * Return: 0 if success, non-zero for failure
1677 */
1678int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1679 struct wireless_dev *wdev,
1680 const void *data,
1681 int data_len)
1682{
1683 int ret = 0;
1684
1685 cds_ssr_protect(__func__);
1686 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1687 cds_ssr_unprotect(__func__);
1688
1689 return ret;
1690}
1691
1692#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1693
1694#ifdef WLAN_FEATURE_STATS_EXT
1695/**
1696 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1697 * @wiphy: Pointer to wiphy
1698 * @wdev: Pointer to wdev
1699 * @data: Pointer to data
1700 * @data_len: Data length
1701 *
1702 * Return: int
1703 */
1704static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1705 struct wireless_dev *wdev,
1706 const void *data,
1707 int data_len)
1708{
1709 tStatsExtRequestReq stats_ext_req;
1710 struct net_device *dev = wdev->netdev;
1711 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1712 int ret_val;
1713 CDF_STATUS status;
1714 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1715
1716 ENTER();
1717
1718 ret_val = wlan_hdd_validate_context(hdd_ctx);
1719 if (ret_val)
1720 return ret_val;
1721
1722 if (CDF_FTM_MODE == hdd_get_conparam()) {
1723 hdd_err("Command not allowed in FTM mode");
1724 return -EPERM;
1725 }
1726
1727 stats_ext_req.request_data_len = data_len;
1728 stats_ext_req.request_data = (void *)data;
1729
1730 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
1731
1732 if (CDF_STATUS_SUCCESS != status)
1733 ret_val = -EINVAL;
1734
1735 return ret_val;
1736}
1737
1738/**
1739 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1740 * @wiphy: Pointer to wiphy
1741 * @wdev: Pointer to wdev
1742 * @data: Pointer to data
1743 * @data_len: Data length
1744 *
1745 * Return: int
1746 */
1747int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1748 struct wireless_dev *wdev,
1749 const void *data,
1750 int data_len)
1751{
1752 int ret;
1753
1754 cds_ssr_protect(__func__);
1755 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
1756 data, data_len);
1757 cds_ssr_unprotect(__func__);
1758
1759 return ret;
1760}
1761
1762/**
1763 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
1764 * @ctx: Pointer to HDD context
1765 * @msg: Message received
1766 *
1767 * Return: nothing
1768 */
1769static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
1770 tStatsExtEvent *msg)
1771{
1772
1773 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1774 struct sk_buff *vendor_event;
1775 int status;
1776 int ret_val;
1777 tStatsExtEvent *data = msg;
1778 hdd_adapter_t *pAdapter = NULL;
1779
1780 status = wlan_hdd_validate_context(pHddCtx);
1781
1782 if (0 != status) {
1783 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1784 "%s: HDD context is not valid", __func__);
1785 return;
1786 }
1787
1788 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
1789
1790 if (NULL == pAdapter) {
1791 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1792 "%s: vdev_id %d does not exist with host",
1793 __func__, data->vdev_id);
1794 return;
1795 }
1796
1797 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1798 NULL,
1799 data->event_data_len +
1800 sizeof(uint32_t) +
1801 NLMSG_HDRLEN + NLMSG_HDRLEN,
1802 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
1803 GFP_KERNEL);
1804
1805 if (!vendor_event) {
1806 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1807 "%s: cfg80211_vendor_event_alloc failed", __func__);
1808 return;
1809 }
1810
1811 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
1812 pAdapter->dev->ifindex);
1813 if (ret_val) {
1814 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1815 "%s: QCA_WLAN_VENDOR_ATTR_IFINDEX put fail",
1816 __func__);
1817 kfree_skb(vendor_event);
1818
1819 return;
1820 }
1821
1822 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
1823 data->event_data_len, data->event_data);
1824
1825 if (ret_val) {
1826 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1827 "%s: QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail",
1828 __func__);
1829 kfree_skb(vendor_event);
1830
1831 return;
1832 }
1833
1834 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1835
1836}
1837
1838/**
1839 * wlan_hdd_cfg80211_stats_ext_init() - ext stats init
1840 * @ctx: Pointer to HDD context
1841 *
1842 * Return: nothing
1843 */
1844void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx)
1845{
1846 sme_stats_ext_register_callback(pHddCtx->hHal,
1847 wlan_hdd_cfg80211_stats_ext_callback);
1848}
1849#endif /* End of WLAN_FEATURE_STATS_EXT */
1850
1851/**
1852 * __wlan_hdd_cfg80211_get_station() - get station statistics
1853 * @wiphy: Pointer to wiphy
1854 * @dev: Pointer to network device
1855 * @mac: Pointer to mac
1856 * @sinfo: Pointer to station info
1857 *
1858 * Return: 0 for success, non-zero for failure
1859 */
1860static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
1861 struct net_device *dev,
1862 const uint8_t *mac,
1863 struct station_info *sinfo)
1864{
1865 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1866 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1867 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
1868 uint8_t rate_flags;
1869
1870 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
1871 struct hdd_config *pCfg = pHddCtx->config;
1872
1873 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
1874 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
1875 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
1876 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
1877 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
1878 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
1879 uint16_t maxRate = 0;
1880 uint16_t myRate;
1881 uint16_t currentRate = 0;
1882 uint8_t maxSpeedMCS = 0;
1883 uint8_t maxMCSIdx = 0;
1884 uint8_t rateFlag = 1;
1885 uint8_t i, j, rssidx;
1886 uint8_t nss = 1;
1887 int status, mode = 0, maxHtIdx;
1888 struct index_vht_data_rate_type *supported_vht_mcs_rate;
1889 struct index_data_rate_type *supported_mcs_rate;
1890
1891#ifdef WLAN_FEATURE_11AC
1892 uint32_t vht_mcs_map;
1893 enum eDataRate11ACMaxMcs vhtMaxMcs;
1894#endif /* WLAN_FEATURE_11AC */
1895
1896
1897 ENTER();
1898
1899 if (CDF_FTM_MODE == hdd_get_conparam()) {
1900 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1901 return -EINVAL;
1902 }
1903
1904 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
1905 (0 == ssidlen)) {
1906 hddLog(LOG1, FL("Not associated or Invalid ssidlen, %d"),
1907 ssidlen);
1908 /*To keep GUI happy */
1909 return 0;
1910 }
1911
1912 if (true == pHddStaCtx->hdd_ReassocScenario) {
1913 hddLog(LOG1,
1914 FL("Roaming is in progress, cannot continue with this request"));
1915 return 0;
1916 }
1917
1918 status = wlan_hdd_validate_context(pHddCtx);
1919
1920 if (0 != status) {
1921 hddLog(LOGE, FL("HDD context is not valid"));
1922 return status;
1923 }
1924
1925 wlan_hdd_get_rssi(pAdapter, &sinfo->signal);
1926 sinfo->filled |= STATION_INFO_SIGNAL;
1927
1928#ifdef WLAN_FEATURE_LPSS
1929 if (!pAdapter->rssi_send) {
1930 pAdapter->rssi_send = true;
Yue Mae3eaebe2015-10-27 12:42:40 -07001931 if (pHddCtx->isUnloadInProgress != true)
1932 wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 }
1934#endif
1935
1936 wlan_hdd_get_station_stats(pAdapter);
1937 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
1938
1939 /* convert to the UI units of 100kbps */
1940 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
1941 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
1942 nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt;
1943
1944 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
1945 /* Get current rate flags if report actual */
1946 rate_flags =
1947 pAdapter->hdd_stats.ClassA_stat.
1948 promiscuous_rx_frag_cnt;
1949 }
1950
1951 if (pAdapter->hdd_stats.ClassA_stat.mcs_index ==
1952 INVALID_MCS_IDX) {
1953 rate_flags = eHAL_TX_RATE_LEGACY;
1954 pAdapter->hdd_stats.ClassA_stat.mcs_index = 0;
1955 }
1956 }
1957#ifdef LINKSPEED_DEBUG_ENABLED
1958 pr_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d\n",
1959 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
1960 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
1961 (int)pCfg->linkSpeedRssiLow, (int)rate_flags,
1962 (int)pAdapter->hdd_stats.ClassA_stat.mcs_index);
1963#endif /* LINKSPEED_DEBUG_ENABLED */
1964
1965 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
1966 /* we do not want to necessarily report the current speed */
1967 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
1968 /* report the max possible speed */
1969 rssidx = 0;
1970 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
1971 pCfg->reportMaxLinkSpeed) {
1972 /* report the max possible speed with RSSI scaling */
1973 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
1974 /* report the max possible speed */
1975 rssidx = 0;
1976 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
1977 /* report middle speed */
1978 rssidx = 1;
1979 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
1980 /* report middle speed */
1981 rssidx = 2;
1982 } else {
1983 /* report actual speed */
1984 rssidx = 3;
1985 }
1986 } else {
1987 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
1988 hddLog(LOGE,
1989 FL("Invalid value for reportMaxLinkSpeed: %u"),
1990 pCfg->reportMaxLinkSpeed);
1991 rssidx = 0;
1992 }
1993
1994 maxRate = 0;
1995
1996 /* Get Basic Rate Set */
1997 if (0 !=
1998 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1999 WNI_CFG_OPERATIONAL_RATE_SET,
2000 OperationalRates,
2001 &ORLeng)) {
2002 hddLog(LOGE, FL("cfg get returned failure"));
2003 /*To keep GUI happy */
2004 return 0;
2005 }
2006
2007 for (i = 0; i < ORLeng; i++) {
2008 for (j = 0;
2009 j < ARRAY_SIZE(supported_data_rate); j++) {
2010 /* Validate Rate Set */
2011 if (supported_data_rate[j].beacon_rate_index ==
2012 (OperationalRates[i] & 0x7F)) {
2013 currentRate =
2014 supported_data_rate[j].
2015 supported_rate[rssidx];
2016 break;
2017 }
2018 }
2019 /* Update MAX rate */
2020 maxRate =
2021 (currentRate > maxRate) ? currentRate : maxRate;
2022 }
2023
2024 /* Get Extended Rate Set */
2025 if (0 !=
2026 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
2027 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
2028 ExtendedRates, &ERLeng)) {
2029 hddLog(LOGE, FL("cfg get returned failure"));
2030 /*To keep GUI happy */
2031 return 0;
2032 }
2033
2034 for (i = 0; i < ERLeng; i++) {
2035 for (j = 0;
2036 j < ARRAY_SIZE(supported_data_rate); j++) {
2037 if (supported_data_rate[j].beacon_rate_index ==
2038 (ExtendedRates[i] & 0x7F)) {
2039 currentRate =
2040 supported_data_rate[j].
2041 supported_rate[rssidx];
2042 break;
2043 }
2044 }
2045 /* Update MAX rate */
2046 maxRate =
2047 (currentRate > maxRate) ? currentRate : maxRate;
2048 }
2049 /* Get MCS Rate Set --
2050 Only if we are connected in non legacy mode and not reporting
2051 actual speed */
2052 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
2053 if (0 !=
2054 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
2055 WNI_CFG_CURRENT_MCS_SET, MCSRates,
2056 &MCSLeng)) {
2057 hddLog(LOGE, FL("cfg get returned failure"));
2058 /*To keep GUI happy */
2059 return 0;
2060 }
2061 rateFlag = 0;
2062#ifdef WLAN_FEATURE_11AC
2063 supported_vht_mcs_rate =
2064 (struct index_vht_data_rate_type *)
2065 ((nss ==
2066 1) ? &supported_vht_mcs_rate_nss1 :
2067 &supported_vht_mcs_rate_nss2);
2068
2069 if (rate_flags & eHAL_TX_RATE_VHT80)
2070 mode = 2;
2071 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
2072 (rate_flags & eHAL_TX_RATE_HT40))
2073 mode = 1;
2074 else
2075 mode = 0;
2076
2077 /* VHT80 rate has seperate rate table */
2078 if (rate_flags &
2079 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
2080 eHAL_TX_RATE_VHT80)) {
2081 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
2082 WNI_CFG_VHT_TX_MCS_MAP,
2083 &vht_mcs_map);
2084 vhtMaxMcs = (enum eDataRate11ACMaxMcs)
2085 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
2086 if (rate_flags & eHAL_TX_RATE_SGI)
2087 rateFlag |= 1;
2088 if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs)
2089 maxMCSIdx = 7;
2090 else if (DATA_RATE_11AC_MAX_MCS_8 ==
2091 vhtMaxMcs)
2092 maxMCSIdx = 8;
2093 else if (DATA_RATE_11AC_MAX_MCS_9 ==
2094 vhtMaxMcs) {
2095 /* VHT20 is supporting 0~8 */
2096 if (rate_flags & eHAL_TX_RATE_VHT20)
2097 maxMCSIdx = 8;
2098 else
2099 maxMCSIdx = 9;
2100 }
2101
2102 if (rssidx != 0) {
2103 for (i = 0; i <= maxMCSIdx; i++) {
2104 if (sinfo->signal <=
2105 rssi_mcs_tbl[mode][i]) {
2106 maxMCSIdx = i;
2107 break;
2108 }
2109 }
2110 }
2111
2112 if (rate_flags & eHAL_TX_RATE_VHT80) {
2113 currentRate =
2114 supported_vht_mcs_rate[pAdapter->
2115 hdd_stats.ClassA_stat.mcs_index].
2116 supported_VHT80_rate[rateFlag];
2117 maxRate =
2118 supported_vht_mcs_rate[maxMCSIdx].
2119 supported_VHT80_rate[rateFlag];
2120 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2121 currentRate =
2122 supported_vht_mcs_rate[pAdapter->
2123 hdd_stats.ClassA_stat.mcs_index].
2124 supported_VHT40_rate[rateFlag];
2125 maxRate =
2126 supported_vht_mcs_rate[maxMCSIdx].
2127 supported_VHT40_rate[rateFlag];
2128 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2129 currentRate =
2130 supported_vht_mcs_rate[pAdapter->
2131 hdd_stats.ClassA_stat.mcs_index].
2132 supported_VHT20_rate[rateFlag];
2133 maxRate =
2134 supported_vht_mcs_rate[maxMCSIdx].
2135 supported_VHT20_rate[rateFlag];
2136 }
2137
2138 maxSpeedMCS = 1;
2139 if (currentRate > maxRate)
2140 maxRate = currentRate;
2141
2142 } else
2143#endif /* WLAN_FEATURE_11AC */
2144 {
2145 if (rate_flags & eHAL_TX_RATE_HT40)
2146 rateFlag |= 1;
2147 if (rate_flags & eHAL_TX_RATE_SGI)
2148 rateFlag |= 2;
2149
2150 supported_mcs_rate =
2151 (struct index_data_rate_type *)
2152 ((nss ==
2153 1) ? &supported_mcs_rate_nss1 :
2154 &supported_mcs_rate_nss2);
2155
2156 maxHtIdx = MAX_HT_MCS_IDX;
2157 if (rssidx != 0) {
2158 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
2159 if (sinfo->signal <=
2160 rssi_mcs_tbl[mode][i]) {
2161 maxHtIdx = i + 1;
2162 break;
2163 }
2164 }
2165 }
2166
2167 for (i = 0; i < MCSLeng; i++) {
2168 for (j = 0; j < maxHtIdx; j++) {
2169 if (supported_mcs_rate[j].
2170 beacon_rate_index ==
2171 MCSRates[i]) {
2172 currentRate =
2173 supported_mcs_rate[j].
2174 supported_rate
2175 [rateFlag];
2176 break;
2177 }
2178 }
2179
2180 if ((j < MAX_HT_MCS_IDX)
2181 && (currentRate > maxRate)) {
2182 maxRate = currentRate;
2183 maxSpeedMCS = 1;
2184 maxMCSIdx =
2185 supported_mcs_rate[j].
2186 beacon_rate_index;
2187 }
2188 }
2189 }
2190 }
2191
2192 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
2193 maxRate = myRate;
2194 maxSpeedMCS = 1;
2195 maxMCSIdx = pAdapter->hdd_stats.ClassA_stat.mcs_index;
2196 }
2197 /* report a value at least as big as current rate */
2198 if ((maxRate < myRate) || (0 == maxRate)) {
2199 maxRate = myRate;
2200 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2201 maxSpeedMCS = 0;
2202 } else {
2203 maxSpeedMCS = 1;
2204 maxMCSIdx =
2205 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2206 }
2207 }
2208
2209 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2210 sinfo->txrate.legacy = maxRate;
2211#ifdef LINKSPEED_DEBUG_ENABLED
2212 pr_info("Reporting legacy rate %d\n",
2213 sinfo->txrate.legacy);
2214#endif /* LINKSPEED_DEBUG_ENABLED */
2215 } else {
2216 sinfo->txrate.mcs = maxMCSIdx;
2217#ifdef WLAN_FEATURE_11AC
2218 sinfo->txrate.nss = nss;
2219 if (rate_flags & eHAL_TX_RATE_VHT80) {
2220 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2221 sinfo->txrate.flags |=
2222 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2223 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2224 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2225 sinfo->txrate.flags |=
2226 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2227 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2228 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2229 } else
2230 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2231#endif /* WLAN_FEATURE_11AC */
2232 if (rate_flags &
2233 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2234 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2235 if (rate_flags & eHAL_TX_RATE_HT40) {
2236 sinfo->txrate.flags |=
2237 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2238 }
2239 }
2240 if (rate_flags & eHAL_TX_RATE_SGI) {
2241 if (!
2242 (sinfo->txrate.
2243 flags & RATE_INFO_FLAGS_VHT_MCS))
2244 sinfo->txrate.flags |=
2245 RATE_INFO_FLAGS_MCS;
2246 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2247 }
2248#ifdef LINKSPEED_DEBUG_ENABLED
2249 pr_info("Reporting MCS rate %d flags %x\n",
2250 sinfo->txrate.mcs, sinfo->txrate.flags);
2251#endif /* LINKSPEED_DEBUG_ENABLED */
2252 }
2253 } else {
2254 /* report current rate instead of max rate */
2255
2256 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2257 /* provide to the UI in units of 100kbps */
2258 sinfo->txrate.legacy = myRate;
2259#ifdef LINKSPEED_DEBUG_ENABLED
2260 pr_info("Reporting actual legacy rate %d\n",
2261 sinfo->txrate.legacy);
2262#endif /* LINKSPEED_DEBUG_ENABLED */
2263 } else {
2264 /* must be MCS */
2265 sinfo->txrate.mcs =
2266 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2267#ifdef WLAN_FEATURE_11AC
2268 sinfo->txrate.nss = nss;
2269 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2270 if (rate_flags & eHAL_TX_RATE_VHT80) {
2271 sinfo->txrate.flags |=
2272 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2273 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2274 sinfo->txrate.flags |=
2275 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2276 }
2277#endif /* WLAN_FEATURE_11AC */
2278 if (rate_flags &
2279 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2280 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2281 if (rate_flags & eHAL_TX_RATE_HT40) {
2282 sinfo->txrate.flags |=
2283 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2284 }
2285 }
2286 if (rate_flags & eHAL_TX_RATE_SGI) {
2287 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2288 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2289 }
2290#ifdef LINKSPEED_DEBUG_ENABLED
2291 pr_info("Reporting actual MCS rate %d flags %x\n",
2292 sinfo->txrate.mcs, sinfo->txrate.flags);
2293#endif /* LINKSPEED_DEBUG_ENABLED */
2294 }
2295 }
2296 sinfo->filled |= STATION_INFO_TX_BITRATE;
2297
2298 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
2299 sinfo->filled |= STATION_INFO_TX_BYTES;
2300
2301 sinfo->tx_packets =
2302 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] +
2303 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] +
2304 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] +
2305 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3];
2306
2307 sinfo->tx_retries =
2308 pAdapter->hdd_stats.summary_stat.retry_cnt[0] +
2309 pAdapter->hdd_stats.summary_stat.retry_cnt[1] +
2310 pAdapter->hdd_stats.summary_stat.retry_cnt[2] +
2311 pAdapter->hdd_stats.summary_stat.retry_cnt[3];
2312
2313 sinfo->tx_failed =
2314 pAdapter->hdd_stats.summary_stat.fail_cnt[0] +
2315 pAdapter->hdd_stats.summary_stat.fail_cnt[1] +
2316 pAdapter->hdd_stats.summary_stat.fail_cnt[2] +
2317 pAdapter->hdd_stats.summary_stat.fail_cnt[3];
2318
2319 sinfo->filled |=
2320 STATION_INFO_TX_PACKETS |
2321 STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED;
2322
2323 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
2324 sinfo->filled |= STATION_INFO_RX_BYTES;
2325
2326 sinfo->rx_packets = pAdapter->stats.rx_packets;
2327 sinfo->filled |= STATION_INFO_RX_PACKETS;
2328
2329 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2330 TRACE_CODE_HDD_CFG80211_GET_STA,
2331 pAdapter->sessionId, maxRate));
2332 EXIT();
2333 return 0;
2334}
2335
2336/**
2337 * wlan_hdd_cfg80211_get_station() - get station statistics
2338 * @wiphy: Pointer to wiphy
2339 * @dev: Pointer to network device
2340 * @mac: Pointer to mac
2341 * @sinfo: Pointer to station info
2342 *
2343 * Return: 0 for success, non-zero for failure
2344 */
2345#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2346int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2347 struct net_device *dev, const uint8_t *mac,
2348 struct station_info *sinfo)
2349#else
2350int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2351 struct net_device *dev, uint8_t *mac,
2352 struct station_info *sinfo)
2353#endif
2354{
2355 int ret;
2356
2357 cds_ssr_protect(__func__);
2358 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
2359 cds_ssr_unprotect(__func__);
2360
2361 return ret;
2362}
2363
2364/**
2365 * hdd_get_stats() - Function to retrieve interface statistics
2366 * @dev: pointer to network device
2367 *
2368 * This function is the ndo_get_stats method for all netdevs
2369 * registered with the kernel
2370 *
2371 * Return: pointer to net_device_stats structure
2372 */
2373struct net_device_stats *hdd_get_stats(struct net_device *dev)
2374{
2375 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2376
2377 return &adapter->stats;
2378}
2379/**
2380 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
2381 * @wiphy: Pointer to wiphy
2382 * @dev: Pointer to network device
2383 * @idx: Index
2384 * @survey: Pointer to survey info
2385 *
2386 * Return: 0 for success, non-zero for failure
2387 */
2388static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2389 struct net_device *dev,
2390 int idx, struct survey_info *survey)
2391{
2392 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2393 hdd_context_t *pHddCtx;
2394 hdd_station_ctx_t *pHddStaCtx;
2395 tHalHandle halHandle;
2396 uint32_t channel = 0, freq = 0; /* Initialization Required */
2397 int8_t snr, rssi;
2398 int status, i, j, filled = 0;
2399
2400 ENTER();
2401
2402 if (CDF_FTM_MODE == hdd_get_conparam()) {
2403 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2404 return -EINVAL;
2405 }
2406
2407 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2408 status = wlan_hdd_validate_context(pHddCtx);
2409
2410 if (0 != status) {
2411 hddLog(LOGE, FL("HDD context is not valid"));
2412 return status;
2413 }
2414
2415 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2416
2417 if (0 == pHddCtx->config->fEnableSNRMonitoring ||
2418 0 != pAdapter->survey_idx ||
2419 eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2420 /* The survey dump ops when implemented completely is expected
2421 * to return a survey of all channels and the ops is called by
2422 * the kernel with incremental values of the argument 'idx'
2423 * till it returns -ENONET. But we can only support the survey
2424 * for the operating channel for now. survey_idx is used to
2425 * track that the ops is called only once and then return
2426 * -ENONET for the next iteration
2427 */
2428 pAdapter->survey_idx = 0;
2429 return -ENONET;
2430 }
2431
2432 if (!pHddStaCtx->hdd_ReassocScenario) {
2433 hdd_err("Roaming in progress, hence return");
2434 return -ENONET;
2435 }
2436
2437 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
2438
2439 wlan_hdd_get_snr(pAdapter, &snr);
2440 wlan_hdd_get_rssi(pAdapter, &rssi);
2441
2442 sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId);
2443 hdd_wlan_get_freq(channel, &freq);
2444
2445 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
2446 if (NULL == wiphy->bands[i]) {
2447 hddLog(LOG1, FL("wiphy->bands[i] is NULL, i = %d"), i);
2448 continue;
2449 }
2450
2451 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
2452 struct ieee80211_supported_band *band = wiphy->bands[i];
2453
2454 if (band->channels[j].center_freq == (uint16_t) freq) {
2455 survey->channel = &band->channels[j];
2456 /* The Rx BDs contain SNR values in dB for the
2457 * received frames while the supplicant expects
2458 * noise. So we calculate and return the value
2459 * of noise (dBm)
2460 * SNR (dB) = RSSI (dBm) - NOISE (dBm)
2461 */
2462 survey->noise = rssi - snr;
2463 survey->filled = SURVEY_INFO_NOISE_DBM;
2464 filled = 1;
2465 }
2466 }
2467 }
2468
2469 if (filled)
2470 pAdapter->survey_idx = 1;
2471 else {
2472 pAdapter->survey_idx = 0;
2473 return -ENONET;
2474 }
2475
2476 return 0;
2477}
2478
2479/**
2480 * wlan_hdd_cfg80211_dump_survey() - get survey related info
2481 * @wiphy: Pointer to wiphy
2482 * @dev: Pointer to network device
2483 * @idx: Index
2484 * @survey: Pointer to survey info
2485 *
2486 * Return: 0 for success, non-zero for failure
2487 */
2488int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2489 struct net_device *dev,
2490 int idx, struct survey_info *survey)
2491{
2492 int ret;
2493
2494 cds_ssr_protect(__func__);
2495 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
2496 cds_ssr_unprotect(__func__);
2497
2498 return ret;
2499}
2500/**
2501 * hdd_init_ll_stats_ctx() - initialize link layer stats context
2502 *
2503 * Return: none
2504 */
2505inline void hdd_init_ll_stats_ctx(void)
2506{
2507 spin_lock_init(&ll_stats_context.context_lock);
2508 init_completion(&ll_stats_context.response_event);
2509 ll_stats_context.request_bitmap = 0;
2510
2511 return;
2512}