blob: 660ec09266b9f108ee28464a2329a59d430798c9 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
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);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800626 tpSirWifiPeerStat pWifiPeerStat;
627 tpSirWifiPeerInfo pWifiPeerInfo;
628 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530629 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800630 struct nlattr *peers;
631 int numRate;
632
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530633 ENTER();
634
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635 pWifiPeerStat = pData;
636
637 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530638 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800640
641 hddLog(CDF_TRACE_LEVEL_INFO,
642 "LL_STATS_PEER_ALL : numPeers %u, more data = %u",
643 pWifiPeerStat->numPeers, more_data);
644
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800645 /*
646 * Allocate a size of 4096 for the peer stats comprising
647 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
648 * sizeof (tSirWifiRateStat).Each field is put with an
649 * NL attribute.The size of 4096 is considered assuming
650 * that number of rates shall not exceed beyond 50 with
651 * the sizeof (tSirWifiRateStat) being 32.
652 */
653 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
654 LL_STATS_EVENT_BUF_SIZE);
655
656 if (!vendor_event) {
657 hddLog(LOGE,
658 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
659 return;
660 }
661
662 if (nla_put_u32(vendor_event,
663 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
664 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
665 nla_put_u32(vendor_event,
666 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
667 more_data) ||
668 nla_put_u32(vendor_event,
669 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
670 pWifiPeerStat->numPeers)) {
671 hddLog(CDF_TRACE_LEVEL_ERROR,
672 "%s: QCA_WLAN_VENDOR_ATTR put fail", __func__);
673
674 kfree_skb(vendor_event);
675 return;
676 }
677
678 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
679 pWifiPeerStat->peerInfo);
680
681 if (pWifiPeerStat->numPeers) {
682 struct nlattr *peerInfo;
683 peerInfo = nla_nest_start(vendor_event,
684 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
685 if (peerInfo == NULL) {
686 hddLog(LOGE, FL("nla_nest_start failed"));
687 kfree_skb(vendor_event);
688 return;
689 }
690
691 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
692 peers = nla_nest_start(vendor_event, i);
693 if (peers == NULL) {
694 hddLog(LOGE, FL("nla_nest_start failed"));
695 kfree_skb(vendor_event);
696 return;
697 }
698
699 numRate = pWifiPeerInfo->numRate;
700
701 if (false ==
702 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
703 hddLog(CDF_TRACE_LEVEL_ERROR,
704 FL("put_wifi_peer_info fail"));
705 kfree_skb(vendor_event);
706 return;
707 }
708
709 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
710 pWifiPeerStat->
711 peerInfo +
712 (i *
713 sizeof
714 (tSirWifiPeerInfo))
715 +
716 (numRate *
717 sizeof
718 (tSirWifiRateStat)));
719 nla_nest_end(vendor_event, peers);
720 }
721 nla_nest_end(vendor_event, peerInfo);
722 }
723 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530724 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725 return;
726}
727
728/**
729 * hdd_link_layer_process_iface_stats() - This function is called after
730 * @pAdapter: Pointer to device adapter
731 * @pData: Pointer to stats data
732 * @num_peers: Number of peers
733 *
734 * Receiving Link Layer Interface statistics from FW.This function converts
735 * the firmware data to the NL data and sends the same to the kernel/upper
736 * layers.
737 *
738 * Return: None
739 */
740static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter,
741 tpSirWifiIfaceStat pData,
742 u32 num_peers)
743{
744 tpSirWifiIfaceStat pWifiIfaceStat;
745 struct sk_buff *vendor_event;
746 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
747 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530749 ENTER();
750
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751 pWifiIfaceStat = pData;
752
753 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530754 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756
757 /*
758 * Allocate a size of 4096 for the interface stats comprising
759 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
760 * assuming that all these fit with in the limit.Please take
761 * a call on the limit based on the data requirements on
762 * interface statistics.
763 */
764 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
765 LL_STATS_EVENT_BUF_SIZE);
766
767 if (!vendor_event) {
768 hddLog(CDF_TRACE_LEVEL_ERROR,
769 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
770 return;
771 }
772
773 hddLog(CDF_TRACE_LEVEL_INFO, "WMI_LINK_STATS_IFACE Data");
774
775 if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
776 hddLog(CDF_TRACE_LEVEL_ERROR,
777 FL("hdd_get_interface_info get fail"));
778 kfree_skb(vendor_event);
779 return;
780 }
781
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782 if (false ==
783 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
784 hddLog(CDF_TRACE_LEVEL_ERROR, FL("put_wifi_iface_stats fail"));
785 kfree_skb(vendor_event);
786 return;
787 }
788
789 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530790 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800791 return;
792}
793
794/**
795 * hdd_link_layer_process_radio_stats() - This function is called after
796 * @pAdapter: Pointer to device adapter
797 * @more_data: More data
798 * @pData: Pointer to stats data
799 * @num_radios: Number of radios
800 *
801 * Receiving Link Layer Radio statistics from FW.This function converts
802 * the firmware data to the NL data and sends the same to the kernel/upper
803 * layers.
804 *
805 * Return: None
806 */
807static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter,
808 u32 more_data,
809 tpSirWifiRadioStat pData,
810 u32 num_radio)
811{
812 int status, i;
813 tpSirWifiRadioStat pWifiRadioStat;
814 tpSirWifiChannelStats pWifiChannelStats;
815 struct sk_buff *vendor_event;
816 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
817
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530818 ENTER();
819
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 pWifiRadioStat = pData;
821 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530822 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800824
825 hddLog(CDF_TRACE_LEVEL_INFO,
826 "LL_STATS_RADIO"
827 " number of radios = %u"
828 " radio is %d onTime is %u"
829 " txTime is %u rxTime is %u"
830 " onTimeScan is %u onTimeNbd is %u"
831 " onTimeGscan is %u onTimeRoamScan is %u"
832 " onTimePnoScan is %u onTimeHs20 is %u"
833 " numChannels is %u",
834 num_radio,
835 pWifiRadioStat->radio,
836 pWifiRadioStat->onTime,
837 pWifiRadioStat->txTime,
838 pWifiRadioStat->rxTime,
839 pWifiRadioStat->onTimeScan,
840 pWifiRadioStat->onTimeNbd,
841 pWifiRadioStat->onTimeGscan,
842 pWifiRadioStat->onTimeRoamScan,
843 pWifiRadioStat->onTimePnoScan,
844 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels);
845
846 /*
847 * Allocate a size of 4096 for the Radio stats comprising
848 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
849 * (tSirWifiChannelStats).Each channel data is put with an
850 * NL attribute.The size of 4096 is considered assuming that
851 * number of channels shall not exceed beyond 60 with the
852 * sizeof (tSirWifiChannelStats) being 24 bytes.
853 */
854
855 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
856 LL_STATS_EVENT_BUF_SIZE);
857
858 if (!vendor_event) {
859 hddLog(LOGE,
860 FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
861 return;
862 }
863
864 if (nla_put_u32(vendor_event,
865 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
866 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
867 nla_put_u32(vendor_event,
868 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
869 more_data) ||
870 nla_put_u32(vendor_event,
871 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
872 num_radio) ||
873 nla_put_u32(vendor_event,
874 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
875 pWifiRadioStat->radio) ||
876 nla_put_u32(vendor_event,
877 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
878 pWifiRadioStat->onTime) ||
879 nla_put_u32(vendor_event,
880 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
881 pWifiRadioStat->txTime) ||
882 nla_put_u32(vendor_event,
883 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
884 pWifiRadioStat->rxTime) ||
885 nla_put_u32(vendor_event,
886 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
887 pWifiRadioStat->onTimeScan) ||
888 nla_put_u32(vendor_event,
889 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
890 pWifiRadioStat->onTimeNbd) ||
891 nla_put_u32(vendor_event,
892 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
893 pWifiRadioStat->onTimeGscan) ||
894 nla_put_u32(vendor_event,
895 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
896 pWifiRadioStat->onTimeRoamScan) ||
897 nla_put_u32(vendor_event,
898 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
899 pWifiRadioStat->onTimePnoScan) ||
900 nla_put_u32(vendor_event,
901 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
902 pWifiRadioStat->onTimeHs20) ||
903 nla_put_u32(vendor_event,
904 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
905 pWifiRadioStat->numChannels)) {
906 hddLog(CDF_TRACE_LEVEL_ERROR,
907 FL("QCA_WLAN_VENDOR_ATTR put fail"));
908
909 kfree_skb(vendor_event);
910 return;
911 }
912
913 if (pWifiRadioStat->numChannels) {
914 struct nlattr *chList;
915 struct nlattr *chInfo;
916
917 chList = nla_nest_start(vendor_event,
918 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
919 if (chList == NULL) {
920 hddLog(LOGE, FL("nla_nest_start failed"));
921 kfree_skb(vendor_event);
922 return;
923 }
924
925 for (i = 0; i < pWifiRadioStat->numChannels; i++) {
926 pWifiChannelStats = (tpSirWifiChannelStats) ((uint8_t *)
927 pWifiRadioStat->
928 channels +
929 (i *
930 sizeof
931 (tSirWifiChannelStats)));
932
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 chInfo = nla_nest_start(vendor_event, i);
934 if (chInfo == NULL) {
935 hddLog(LOGE, FL("nla_nest_start failed"));
936 kfree_skb(vendor_event);
937 return;
938 }
939
940 if (nla_put_u32(vendor_event,
941 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
942 pWifiChannelStats->channel.width) ||
943 nla_put_u32(vendor_event,
944 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
945 pWifiChannelStats->channel.centerFreq) ||
946 nla_put_u32(vendor_event,
947 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
948 pWifiChannelStats->channel.
949 centerFreq0) ||
950 nla_put_u32(vendor_event,
951 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
952 pWifiChannelStats->channel.
953 centerFreq1) ||
954 nla_put_u32(vendor_event,
955 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
956 pWifiChannelStats->onTime) ||
957 nla_put_u32(vendor_event,
958 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
959 pWifiChannelStats->ccaBusyTime)) {
960 hddLog(CDF_TRACE_LEVEL_ERROR,
961 FL("nla_put failed"));
962 kfree_skb(vendor_event);
963 return;
964 }
965 nla_nest_end(vendor_event, chInfo);
966 }
967 nla_nest_end(vendor_event, chList);
968 }
969 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530970 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971 return;
972}
973
974/**
975 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
976 * @ctx: Pointer to hdd context
977 * @indType: Indication type
978 * @pRsp: Pointer to response
979 *
980 * After receiving Link Layer indications from FW.This callback converts the
981 * firmware data to the NL data and send the same to the kernel/upper layers.
982 *
983 * Return: None
984 */
985static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
986 int indType, void *pRsp)
987{
988 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
989 struct hdd_ll_stats_context *context;
990 hdd_adapter_t *pAdapter = NULL;
991 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
992 int status;
993
994 status = wlan_hdd_validate_context(pHddCtx);
995
996 if (0 != status) {
997 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
998 return;
999 }
1000
1001 pAdapter = hdd_get_adapter_by_vdev(pHddCtx,
1002 linkLayerStatsResults->ifaceId);
1003
1004 if (NULL == pAdapter) {
1005 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1006 "%s: vdev_id %d does not exist with host",
1007 __func__, linkLayerStatsResults->ifaceId);
1008 return;
1009 }
1010
1011 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1012 "%s: Link Layer Indication indType: %d", __func__, indType);
1013
1014 switch (indType) {
1015 case SIR_HAL_LL_STATS_RESULTS_RSP:
1016 {
1017 hddLog(CDF_TRACE_LEVEL_INFO,
Sushant Kaushik7a535882015-11-02 13:31:21 +05301018 "LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p",
1019 linkLayerStatsResults->paramId,
1020 linkLayerStatsResults->ifaceId,
1021 linkLayerStatsResults->rspId,
1022 linkLayerStatsResults->moreResultToFollow,
1023 linkLayerStatsResults->num_radio,
1024 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025
1026 context = &ll_stats_context;
1027 spin_lock(&context->context_lock);
1028 /* validate response received from target */
1029 if ((context->request_id != linkLayerStatsResults->rspId) ||
1030 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1031 spin_unlock(&context->context_lock);
1032 hddLog(LOGE,
1033 FL("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x"),
1034 context->request_id, linkLayerStatsResults->rspId,
1035 context->request_bitmap, linkLayerStatsResults->paramId);
1036 return;
1037 }
1038 spin_unlock(&context->context_lock);
1039
1040 if (linkLayerStatsResults->
1041 paramId & WMI_LINK_STATS_RADIO) {
1042 hdd_link_layer_process_radio_stats(pAdapter,
1043 linkLayerStatsResults->moreResultToFollow,
1044 (tpSirWifiRadioStat)linkLayerStatsResults->results,
1045 linkLayerStatsResults->num_radio);
1046
1047 spin_lock(&context->context_lock);
1048 if (!linkLayerStatsResults->moreResultToFollow)
1049 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1050 spin_unlock(&context->context_lock);
1051
1052 } else if (linkLayerStatsResults->
1053 paramId & WMI_LINK_STATS_IFACE) {
1054 hdd_link_layer_process_iface_stats(pAdapter,
1055 (tpSirWifiIfaceStat)linkLayerStatsResults->results,
1056 linkLayerStatsResults->num_peers);
1057
1058 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301059 /* Firmware doesn't send peerstats event if no peers are
1060 * connected. HDD should not wait for any peerstats in
1061 * this case and return the status to middleware after
1062 * receiving iface stats
1063 */
1064 if (!linkLayerStatsResults->num_peers)
1065 context->request_bitmap &=
1066 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1068 spin_unlock(&context->context_lock);
1069
1070 } else if (linkLayerStatsResults->
1071 paramId & WMI_LINK_STATS_ALL_PEER) {
1072 hdd_link_layer_process_peer_stats(pAdapter,
1073 linkLayerStatsResults->moreResultToFollow,
1074 (tpSirWifiPeerStat)linkLayerStatsResults->results);
1075
1076 spin_lock(&context->context_lock);
1077 if (!linkLayerStatsResults->moreResultToFollow)
1078 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1079 spin_unlock(&context->context_lock);
1080
1081 } else {
1082 hddLog(LOGE,
1083 FL("INVALID LL_STATS_NOTIFY RESPONSE"));
1084 }
1085
1086 spin_lock(&context->context_lock);
1087 /* complete response event if all requests are completed */
1088 if (0 == context->request_bitmap)
1089 complete(&context->response_event);
1090 spin_unlock(&context->context_lock);
1091
1092 break;
1093 }
1094 default:
1095 hddLog(CDF_TRACE_LEVEL_ERROR, "invalid event type %d", indType);
1096 break;
1097 }
1098
1099 return;
1100}
1101
1102/**
1103 * wlan_hdd_cfg80211_link_layer_stats_init() - initialize link layer stats
1104 * @pHddCtx: Pointer to hdd context
1105 *
1106 * Return: None
1107 */
1108void wlan_hdd_cfg80211_link_layer_stats_init(hdd_context_t *pHddCtx)
1109{
1110 sme_set_link_layer_stats_ind_cb(pHddCtx->hHal,
1111 wlan_hdd_cfg80211_link_layer_stats_callback);
1112}
1113
1114const struct
1115nla_policy
1116 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1117 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1118 .type = NLA_U32},
1119 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1120 .type = NLA_U32},
1121};
1122
1123/**
1124 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1125 * @wiphy: Pointer to wiphy
1126 * @wdev: Pointer to wdev
1127 * @data: Pointer to data
1128 * @data_len: Data length
1129 *
1130 * Return: int
1131 */
1132static int
1133__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1134 struct wireless_dev *wdev,
1135 const void *data,
1136 int data_len)
1137{
1138 int status;
1139 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1140 tSirLLStatsSetReq LinkLayerStatsSetReq;
1141 struct net_device *dev = wdev->netdev;
1142 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1143 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1144
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301145 ENTER();
1146
Peng Xuf5d60c82015-10-02 17:17:03 -07001147 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 hdd_err("Command not allowed in FTM mode");
1149 return -EPERM;
1150 }
1151
1152 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301153 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155
1156 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1157 (struct nlattr *)data,
1158 data_len, qca_wlan_vendor_ll_set_policy)) {
1159 hddLog(CDF_TRACE_LEVEL_ERROR,
1160 FL("maximum attribute not present"));
1161 return -EINVAL;
1162 }
1163
1164 if (!tb_vendor
1165 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
1166 hddLog(CDF_TRACE_LEVEL_ERROR, FL("MPDU size Not present"));
1167 return -EINVAL;
1168 }
1169
1170 if (!tb_vendor
1171 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
1172 hddLog(CDF_TRACE_LEVEL_ERROR,
1173 FL("Stats Gathering Not Present"));
1174 return -EINVAL;
1175 }
1176
1177 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1178 LinkLayerStatsSetReq.reqId = 1;
1179
1180 LinkLayerStatsSetReq.mpduSizeThreshold =
1181 nla_get_u32(tb_vendor
1182 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1183
1184 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1185 nla_get_u32(tb_vendor
1186 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1187
1188 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1189
1190 hddLog(CDF_TRACE_LEVEL_INFO,
Sushant Kaushik7a535882015-11-02 13:31:21 +05301191 "LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
1192 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1193 LinkLayerStatsSetReq.mpduSizeThreshold,
1194 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001195
1196 if (CDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
1197 &LinkLayerStatsSetReq)) {
1198 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1199 "sme_ll_stats_set_req Failed", __func__);
1200 return -EINVAL;
1201 }
1202
1203 pAdapter->isLinkLayerStatsSet = 1;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301204 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 return 0;
1206}
1207
1208/**
1209 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1210 * @wiphy: Pointer to wiphy
1211 * @wdev: Pointer to wdev
1212 * @data: Pointer to data
1213 * @data_len: Data length
1214 *
1215 * Return: 0 if success, non-zero for failure
1216 */
1217int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1218 struct wireless_dev *wdev,
1219 const void *data,
1220 int data_len)
1221{
1222 int ret = 0;
1223
1224 cds_ssr_protect(__func__);
1225 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1226 cds_ssr_unprotect(__func__);
1227
1228 return ret;
1229}
1230
1231const struct
1232nla_policy
1233 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1234 /* Unsigned 32bit value provided by the caller issuing the GET stats
1235 * command. When reporting
1236 * the stats results, the driver uses the same value to indicate
1237 * which GET request the results
1238 * correspond to.
1239 */
1240 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1241
1242 /* Unsigned 32bit value . bit mask to identify what statistics are
1243 requested for retrieval */
1244 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1245};
1246
1247/**
1248 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1249 * @wiphy: Pointer to wiphy
1250 * @wdev: Pointer to wdev
1251 * @data: Pointer to data
1252 * @data_len: Data length
1253 *
1254 * Return: int
1255 */
1256static int
1257__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1258 struct wireless_dev *wdev,
1259 const void *data,
1260 int data_len)
1261{
1262 unsigned long rc;
1263 struct hdd_ll_stats_context *context;
1264 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1265 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1266 tSirLLStatsGetReq LinkLayerStatsGetReq;
1267 struct net_device *dev = wdev->netdev;
1268 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1269 int status;
1270
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301271 ENTER();
1272
Peng Xuf5d60c82015-10-02 17:17:03 -07001273 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274 hdd_err("Command not allowed in FTM mode");
1275 return -EPERM;
1276 }
1277
1278 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301279 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001280 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001281
1282 if (!pAdapter->isLinkLayerStatsSet) {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08001283 hdd_warn("isLinkLayerStatsSet : %d", pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001284 return -EINVAL;
1285 }
1286
1287 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1288 (struct nlattr *)data,
1289 data_len, qca_wlan_vendor_ll_get_policy)) {
1290 hddLog(CDF_TRACE_LEVEL_ERROR, FL("max attribute not present"));
1291 return -EINVAL;
1292 }
1293
1294 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
1295 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Request Id Not present"));
1296 return -EINVAL;
1297 }
1298
1299 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
1300 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Req Mask Not present"));
1301 return -EINVAL;
1302 }
1303
1304 LinkLayerStatsGetReq.reqId =
1305 nla_get_u32(tb_vendor
1306 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1307 LinkLayerStatsGetReq.paramIdMask =
1308 nla_get_u32(tb_vendor
1309 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1310
1311 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1312
Sushant Kaushik7a535882015-11-02 13:31:21 +05301313 hddLog(CDF_TRACE_LEVEL_INFO,
1314 "LL_STATS_GET reqId = %d, staId = %d, paramIdMask = %d",
1315 LinkLayerStatsGetReq.reqId,
1316 LinkLayerStatsGetReq.staId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 LinkLayerStatsGetReq.paramIdMask);
1318
1319 context = &ll_stats_context;
1320 spin_lock(&context->context_lock);
1321 context->request_id = LinkLayerStatsGetReq.reqId;
1322 context->request_bitmap = LinkLayerStatsGetReq.paramIdMask;
1323 INIT_COMPLETION(context->response_event);
1324 spin_unlock(&context->context_lock);
1325
1326 if (CDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal,
1327 &LinkLayerStatsGetReq)) {
1328 hddLog(CDF_TRACE_LEVEL_ERROR, "%s:"
1329 "sme_ll_stats_get_req Failed", __func__);
1330 return -EINVAL;
1331 }
1332
1333 rc = wait_for_completion_timeout(&context->response_event,
1334 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1335 if (!rc) {
1336 hddLog(LOGE,
1337 FL("Target response timed out request id %d request bitmap 0x%x"),
1338 context->request_id, context->request_bitmap);
1339 return -ETIMEDOUT;
1340 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301341 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 return 0;
1343}
1344
1345/**
1346 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1347 * @wiphy: Pointer to wiphy
1348 * @wdev: Pointer to wdev
1349 * @data: Pointer to data
1350 * @data_len: Data length
1351 *
1352 * Return: 0 if success, non-zero for failure
1353 */
1354int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1355 struct wireless_dev *wdev,
1356 const void *data,
1357 int data_len)
1358{
1359 int ret = 0;
1360
1361 cds_ssr_protect(__func__);
1362 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1363 cds_ssr_unprotect(__func__);
1364
1365 return ret;
1366}
1367
1368const struct
1369nla_policy
1370 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1371 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1372 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1373 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1374 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1375};
1376
1377/**
1378 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1379 * @wiphy: Pointer to wiphy
1380 * @wdev: Pointer to wdev
1381 * @data: Pointer to data
1382 * @data_len: Data length
1383 *
1384 * Return: int
1385 */
1386static int
1387__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1388 struct wireless_dev *wdev,
1389 const void *data,
1390 int data_len)
1391{
1392 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1393 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1394 tSirLLStatsClearReq LinkLayerStatsClearReq;
1395 struct net_device *dev = wdev->netdev;
1396 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1397 u32 statsClearReqMask;
1398 u8 stopReq;
1399 int status;
1400 struct sk_buff *temp_skbuff;
1401
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301402 ENTER();
1403
Peng Xuf5d60c82015-10-02 17:17:03 -07001404 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 hdd_err("Command not allowed in FTM mode");
1406 return -EPERM;
1407 }
1408
1409 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301410 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001412
1413 if (!pAdapter->isLinkLayerStatsSet) {
1414 hddLog(CDF_TRACE_LEVEL_FATAL,
1415 "%s: isLinkLayerStatsSet : %d",
1416 __func__, pAdapter->isLinkLayerStatsSet);
1417 return -EINVAL;
1418 }
1419
1420 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1421 (struct nlattr *)data,
1422 data_len, qca_wlan_vendor_ll_clr_policy)) {
1423 hddLog(CDF_TRACE_LEVEL_ERROR,
1424 FL("STATS_CLR_MAX is not present"));
1425 return -EINVAL;
1426 }
1427
1428 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1429 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
1430 hddLog(CDF_TRACE_LEVEL_ERROR,
1431 FL("Error in LL_STATS CLR CONFIG PARA"));
1432 return -EINVAL;
1433 }
1434
1435 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1436 nla_get_u32(tb_vendor
1437 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1438
1439 stopReq = LinkLayerStatsClearReq.stopReq =
1440 nla_get_u8(tb_vendor
1441 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1442
1443 /*
1444 * Shall take the request Id if the Upper layers pass. 1 For now.
1445 */
1446 LinkLayerStatsClearReq.reqId = 1;
1447
1448 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1449
1450 hddLog(CDF_TRACE_LEVEL_INFO,
Sushant Kaushik7a535882015-11-02 13:31:21 +05301451 "LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
1452 LinkLayerStatsClearReq.reqId,
1453 LinkLayerStatsClearReq.staId,
1454 LinkLayerStatsClearReq.statsClearReqMask,
1455 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456
1457 if (CDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
1458 &LinkLayerStatsClearReq)) {
1459 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1460 2 *
1461 sizeof(u32) +
1462 2 *
1463 NLMSG_HDRLEN);
1464 if (temp_skbuff != NULL) {
1465 if (nla_put_u32(temp_skbuff,
1466 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1467 statsClearReqMask) ||
1468 nla_put_u32(temp_skbuff,
1469 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1470 stopReq)) {
1471 hddLog(CDF_TRACE_LEVEL_ERROR,
1472 FL("LL_STATS_CLR put fail"));
1473 kfree_skb(temp_skbuff);
1474 return -EINVAL;
1475 }
1476
1477 /* If the ask is to stop the stats collection as part of clear
1478 * (stopReq = 1) , ensure that no further requests of get
1479 * go to the firmware by having isLinkLayerStatsSet set to 0.
1480 * However it the stopReq as part of the clear request is 0 ,
1481 * the request to get the statistics are honoured as in this
1482 * case the firmware is just asked to clear the statistics.
1483 */
1484 if (stopReq == 1)
1485 pAdapter->isLinkLayerStatsSet = 0;
1486
1487 return cfg80211_vendor_cmd_reply(temp_skbuff);
1488 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301489 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001490 return -ENOMEM;
1491 }
1492
1493 return -EINVAL;
1494}
1495
1496/**
1497 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1498 * @wiphy: Pointer to wiphy
1499 * @wdev: Pointer to wdev
1500 * @data: Pointer to data
1501 * @data_len: Data length
1502 *
1503 * Return: 0 if success, non-zero for failure
1504 */
1505int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1506 struct wireless_dev *wdev,
1507 const void *data,
1508 int data_len)
1509{
1510 int ret = 0;
1511
1512 cds_ssr_protect(__func__);
1513 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1514 cds_ssr_unprotect(__func__);
1515
1516 return ret;
1517}
1518
1519#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1520
1521#ifdef WLAN_FEATURE_STATS_EXT
1522/**
1523 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1524 * @wiphy: Pointer to wiphy
1525 * @wdev: Pointer to wdev
1526 * @data: Pointer to data
1527 * @data_len: Data length
1528 *
1529 * Return: int
1530 */
1531static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1532 struct wireless_dev *wdev,
1533 const void *data,
1534 int data_len)
1535{
1536 tStatsExtRequestReq stats_ext_req;
1537 struct net_device *dev = wdev->netdev;
1538 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1539 int ret_val;
1540 CDF_STATUS status;
1541 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1542
1543 ENTER();
1544
1545 ret_val = wlan_hdd_validate_context(hdd_ctx);
1546 if (ret_val)
1547 return ret_val;
1548
Peng Xuf5d60c82015-10-02 17:17:03 -07001549 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 hdd_err("Command not allowed in FTM mode");
1551 return -EPERM;
1552 }
1553
1554 stats_ext_req.request_data_len = data_len;
1555 stats_ext_req.request_data = (void *)data;
1556
1557 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
1558
1559 if (CDF_STATUS_SUCCESS != status)
1560 ret_val = -EINVAL;
1561
1562 return ret_val;
1563}
1564
1565/**
1566 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1567 * @wiphy: Pointer to wiphy
1568 * @wdev: Pointer to wdev
1569 * @data: Pointer to data
1570 * @data_len: Data length
1571 *
1572 * Return: int
1573 */
1574int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1575 struct wireless_dev *wdev,
1576 const void *data,
1577 int data_len)
1578{
1579 int ret;
1580
1581 cds_ssr_protect(__func__);
1582 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
1583 data, data_len);
1584 cds_ssr_unprotect(__func__);
1585
1586 return ret;
1587}
1588
1589/**
1590 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
1591 * @ctx: Pointer to HDD context
1592 * @msg: Message received
1593 *
1594 * Return: nothing
1595 */
1596static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
1597 tStatsExtEvent *msg)
1598{
1599
1600 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1601 struct sk_buff *vendor_event;
1602 int status;
1603 int ret_val;
1604 tStatsExtEvent *data = msg;
1605 hdd_adapter_t *pAdapter = NULL;
1606
1607 status = wlan_hdd_validate_context(pHddCtx);
1608
1609 if (0 != status) {
1610 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1611 "%s: HDD context is not valid", __func__);
1612 return;
1613 }
1614
1615 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
1616
1617 if (NULL == pAdapter) {
1618 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1619 "%s: vdev_id %d does not exist with host",
1620 __func__, data->vdev_id);
1621 return;
1622 }
1623
1624 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1625 NULL,
1626 data->event_data_len +
1627 sizeof(uint32_t) +
1628 NLMSG_HDRLEN + NLMSG_HDRLEN,
1629 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
1630 GFP_KERNEL);
1631
1632 if (!vendor_event) {
1633 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1634 "%s: cfg80211_vendor_event_alloc failed", __func__);
1635 return;
1636 }
1637
1638 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
1639 pAdapter->dev->ifindex);
1640 if (ret_val) {
1641 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1642 "%s: QCA_WLAN_VENDOR_ATTR_IFINDEX put fail",
1643 __func__);
1644 kfree_skb(vendor_event);
1645
1646 return;
1647 }
1648
1649 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
1650 data->event_data_len, data->event_data);
1651
1652 if (ret_val) {
1653 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1654 "%s: QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail",
1655 __func__);
1656 kfree_skb(vendor_event);
1657
1658 return;
1659 }
1660
1661 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1662
1663}
1664
1665/**
1666 * wlan_hdd_cfg80211_stats_ext_init() - ext stats init
1667 * @ctx: Pointer to HDD context
1668 *
1669 * Return: nothing
1670 */
1671void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx)
1672{
1673 sme_stats_ext_register_callback(pHddCtx->hHal,
1674 wlan_hdd_cfg80211_stats_ext_callback);
1675}
1676#endif /* End of WLAN_FEATURE_STATS_EXT */
1677
1678/**
1679 * __wlan_hdd_cfg80211_get_station() - get station statistics
1680 * @wiphy: Pointer to wiphy
1681 * @dev: Pointer to network device
1682 * @mac: Pointer to mac
1683 * @sinfo: Pointer to station info
1684 *
1685 * Return: 0 for success, non-zero for failure
1686 */
1687static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
1688 struct net_device *dev,
1689 const uint8_t *mac,
1690 struct station_info *sinfo)
1691{
1692 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1693 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1694 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
1695 uint8_t rate_flags;
1696
1697 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
1698 struct hdd_config *pCfg = pHddCtx->config;
1699
1700 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
1701 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
1702 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
1703 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
1704 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
1705 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
1706 uint16_t maxRate = 0;
1707 uint16_t myRate;
1708 uint16_t currentRate = 0;
1709 uint8_t maxSpeedMCS = 0;
1710 uint8_t maxMCSIdx = 0;
1711 uint8_t rateFlag = 1;
1712 uint8_t i, j, rssidx;
1713 uint8_t nss = 1;
1714 int status, mode = 0, maxHtIdx;
1715 struct index_vht_data_rate_type *supported_vht_mcs_rate;
1716 struct index_data_rate_type *supported_mcs_rate;
1717
1718#ifdef WLAN_FEATURE_11AC
1719 uint32_t vht_mcs_map;
1720 enum eDataRate11ACMaxMcs vhtMaxMcs;
1721#endif /* WLAN_FEATURE_11AC */
1722
1723
1724 ENTER();
1725
Peng Xuf5d60c82015-10-02 17:17:03 -07001726 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1728 return -EINVAL;
1729 }
1730
1731 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
1732 (0 == ssidlen)) {
1733 hddLog(LOG1, FL("Not associated or Invalid ssidlen, %d"),
1734 ssidlen);
1735 /*To keep GUI happy */
1736 return 0;
1737 }
1738
1739 if (true == pHddStaCtx->hdd_ReassocScenario) {
1740 hddLog(LOG1,
1741 FL("Roaming is in progress, cannot continue with this request"));
1742 return 0;
1743 }
1744
1745 status = wlan_hdd_validate_context(pHddCtx);
1746
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301747 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
1750 wlan_hdd_get_rssi(pAdapter, &sinfo->signal);
1751 sinfo->filled |= STATION_INFO_SIGNAL;
1752
1753#ifdef WLAN_FEATURE_LPSS
1754 if (!pAdapter->rssi_send) {
1755 pAdapter->rssi_send = true;
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001756 if (cds_is_driver_unloading())
Yue Mae3eaebe2015-10-27 12:42:40 -07001757 wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 }
1759#endif
1760
1761 wlan_hdd_get_station_stats(pAdapter);
1762 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
1763
1764 /* convert to the UI units of 100kbps */
1765 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
1766 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
1767 nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt;
1768
1769 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
1770 /* Get current rate flags if report actual */
1771 rate_flags =
1772 pAdapter->hdd_stats.ClassA_stat.
1773 promiscuous_rx_frag_cnt;
1774 }
1775
1776 if (pAdapter->hdd_stats.ClassA_stat.mcs_index ==
1777 INVALID_MCS_IDX) {
1778 rate_flags = eHAL_TX_RATE_LEGACY;
1779 pAdapter->hdd_stats.ClassA_stat.mcs_index = 0;
1780 }
1781 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08001782
1783 hdd_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
1784 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
1785 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
1786 (int)pCfg->linkSpeedRssiLow, (int)rate_flags,
1787 (int)pAdapter->hdd_stats.ClassA_stat.mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001788
1789 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
1790 /* we do not want to necessarily report the current speed */
1791 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
1792 /* report the max possible speed */
1793 rssidx = 0;
1794 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
1795 pCfg->reportMaxLinkSpeed) {
1796 /* report the max possible speed with RSSI scaling */
1797 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
1798 /* report the max possible speed */
1799 rssidx = 0;
1800 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
1801 /* report middle speed */
1802 rssidx = 1;
1803 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
1804 /* report middle speed */
1805 rssidx = 2;
1806 } else {
1807 /* report actual speed */
1808 rssidx = 3;
1809 }
1810 } else {
1811 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
1812 hddLog(LOGE,
1813 FL("Invalid value for reportMaxLinkSpeed: %u"),
1814 pCfg->reportMaxLinkSpeed);
1815 rssidx = 0;
1816 }
1817
1818 maxRate = 0;
1819
1820 /* Get Basic Rate Set */
1821 if (0 !=
1822 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1823 WNI_CFG_OPERATIONAL_RATE_SET,
1824 OperationalRates,
1825 &ORLeng)) {
1826 hddLog(LOGE, FL("cfg get returned failure"));
1827 /*To keep GUI happy */
1828 return 0;
1829 }
1830
1831 for (i = 0; i < ORLeng; i++) {
1832 for (j = 0;
1833 j < ARRAY_SIZE(supported_data_rate); j++) {
1834 /* Validate Rate Set */
1835 if (supported_data_rate[j].beacon_rate_index ==
1836 (OperationalRates[i] & 0x7F)) {
1837 currentRate =
1838 supported_data_rate[j].
1839 supported_rate[rssidx];
1840 break;
1841 }
1842 }
1843 /* Update MAX rate */
1844 maxRate =
1845 (currentRate > maxRate) ? currentRate : maxRate;
1846 }
1847
1848 /* Get Extended Rate Set */
1849 if (0 !=
1850 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1851 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
1852 ExtendedRates, &ERLeng)) {
1853 hddLog(LOGE, FL("cfg get returned failure"));
1854 /*To keep GUI happy */
1855 return 0;
1856 }
1857
1858 for (i = 0; i < ERLeng; i++) {
1859 for (j = 0;
1860 j < ARRAY_SIZE(supported_data_rate); j++) {
1861 if (supported_data_rate[j].beacon_rate_index ==
1862 (ExtendedRates[i] & 0x7F)) {
1863 currentRate =
1864 supported_data_rate[j].
1865 supported_rate[rssidx];
1866 break;
1867 }
1868 }
1869 /* Update MAX rate */
1870 maxRate =
1871 (currentRate > maxRate) ? currentRate : maxRate;
1872 }
1873 /* Get MCS Rate Set --
1874 Only if we are connected in non legacy mode and not reporting
1875 actual speed */
1876 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
1877 if (0 !=
1878 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1879 WNI_CFG_CURRENT_MCS_SET, MCSRates,
1880 &MCSLeng)) {
1881 hddLog(LOGE, FL("cfg get returned failure"));
1882 /*To keep GUI happy */
1883 return 0;
1884 }
1885 rateFlag = 0;
1886#ifdef WLAN_FEATURE_11AC
1887 supported_vht_mcs_rate =
1888 (struct index_vht_data_rate_type *)
1889 ((nss ==
1890 1) ? &supported_vht_mcs_rate_nss1 :
1891 &supported_vht_mcs_rate_nss2);
1892
1893 if (rate_flags & eHAL_TX_RATE_VHT80)
1894 mode = 2;
1895 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
1896 (rate_flags & eHAL_TX_RATE_HT40))
1897 mode = 1;
1898 else
1899 mode = 0;
1900
1901 /* VHT80 rate has seperate rate table */
1902 if (rate_flags &
1903 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
1904 eHAL_TX_RATE_VHT80)) {
1905 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
1906 WNI_CFG_VHT_TX_MCS_MAP,
1907 &vht_mcs_map);
1908 vhtMaxMcs = (enum eDataRate11ACMaxMcs)
1909 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
1910 if (rate_flags & eHAL_TX_RATE_SGI)
1911 rateFlag |= 1;
1912 if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs)
1913 maxMCSIdx = 7;
1914 else if (DATA_RATE_11AC_MAX_MCS_8 ==
1915 vhtMaxMcs)
1916 maxMCSIdx = 8;
1917 else if (DATA_RATE_11AC_MAX_MCS_9 ==
1918 vhtMaxMcs) {
1919 /* VHT20 is supporting 0~8 */
1920 if (rate_flags & eHAL_TX_RATE_VHT20)
1921 maxMCSIdx = 8;
1922 else
1923 maxMCSIdx = 9;
1924 }
1925
1926 if (rssidx != 0) {
1927 for (i = 0; i <= maxMCSIdx; i++) {
1928 if (sinfo->signal <=
1929 rssi_mcs_tbl[mode][i]) {
1930 maxMCSIdx = i;
1931 break;
1932 }
1933 }
1934 }
1935
1936 if (rate_flags & eHAL_TX_RATE_VHT80) {
1937 currentRate =
1938 supported_vht_mcs_rate[pAdapter->
1939 hdd_stats.ClassA_stat.mcs_index].
1940 supported_VHT80_rate[rateFlag];
1941 maxRate =
1942 supported_vht_mcs_rate[maxMCSIdx].
1943 supported_VHT80_rate[rateFlag];
1944 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
1945 currentRate =
1946 supported_vht_mcs_rate[pAdapter->
1947 hdd_stats.ClassA_stat.mcs_index].
1948 supported_VHT40_rate[rateFlag];
1949 maxRate =
1950 supported_vht_mcs_rate[maxMCSIdx].
1951 supported_VHT40_rate[rateFlag];
1952 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
1953 currentRate =
1954 supported_vht_mcs_rate[pAdapter->
1955 hdd_stats.ClassA_stat.mcs_index].
1956 supported_VHT20_rate[rateFlag];
1957 maxRate =
1958 supported_vht_mcs_rate[maxMCSIdx].
1959 supported_VHT20_rate[rateFlag];
1960 }
1961
1962 maxSpeedMCS = 1;
1963 if (currentRate > maxRate)
1964 maxRate = currentRate;
1965
1966 } else
1967#endif /* WLAN_FEATURE_11AC */
1968 {
1969 if (rate_flags & eHAL_TX_RATE_HT40)
1970 rateFlag |= 1;
1971 if (rate_flags & eHAL_TX_RATE_SGI)
1972 rateFlag |= 2;
1973
1974 supported_mcs_rate =
1975 (struct index_data_rate_type *)
1976 ((nss ==
1977 1) ? &supported_mcs_rate_nss1 :
1978 &supported_mcs_rate_nss2);
1979
1980 maxHtIdx = MAX_HT_MCS_IDX;
1981 if (rssidx != 0) {
1982 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
1983 if (sinfo->signal <=
1984 rssi_mcs_tbl[mode][i]) {
1985 maxHtIdx = i + 1;
1986 break;
1987 }
1988 }
1989 }
1990
1991 for (i = 0; i < MCSLeng; i++) {
1992 for (j = 0; j < maxHtIdx; j++) {
1993 if (supported_mcs_rate[j].
1994 beacon_rate_index ==
1995 MCSRates[i]) {
1996 currentRate =
1997 supported_mcs_rate[j].
1998 supported_rate
1999 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302000 maxMCSIdx =
2001 supported_mcs_rate[j].
2002 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003 break;
2004 }
2005 }
2006
2007 if ((j < MAX_HT_MCS_IDX)
2008 && (currentRate > maxRate)) {
2009 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302011 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 }
2013 }
2014 }
2015
2016 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
2017 maxRate = myRate;
2018 maxSpeedMCS = 1;
2019 maxMCSIdx = pAdapter->hdd_stats.ClassA_stat.mcs_index;
2020 }
2021 /* report a value at least as big as current rate */
2022 if ((maxRate < myRate) || (0 == maxRate)) {
2023 maxRate = myRate;
2024 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2025 maxSpeedMCS = 0;
2026 } else {
2027 maxSpeedMCS = 1;
2028 maxMCSIdx =
2029 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2030 }
2031 }
2032
2033 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2034 sinfo->txrate.legacy = maxRate;
2035#ifdef LINKSPEED_DEBUG_ENABLED
2036 pr_info("Reporting legacy rate %d\n",
2037 sinfo->txrate.legacy);
2038#endif /* LINKSPEED_DEBUG_ENABLED */
2039 } else {
2040 sinfo->txrate.mcs = maxMCSIdx;
2041#ifdef WLAN_FEATURE_11AC
2042 sinfo->txrate.nss = nss;
2043 if (rate_flags & eHAL_TX_RATE_VHT80) {
2044 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2045 sinfo->txrate.flags |=
2046 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2047 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2048 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2049 sinfo->txrate.flags |=
2050 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2051 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2052 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2053 } else
2054 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2055#endif /* WLAN_FEATURE_11AC */
2056 if (rate_flags &
2057 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2058 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2059 if (rate_flags & eHAL_TX_RATE_HT40) {
2060 sinfo->txrate.flags |=
2061 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2062 }
2063 }
2064 if (rate_flags & eHAL_TX_RATE_SGI) {
2065 if (!
2066 (sinfo->txrate.
2067 flags & RATE_INFO_FLAGS_VHT_MCS))
2068 sinfo->txrate.flags |=
2069 RATE_INFO_FLAGS_MCS;
2070 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2071 }
2072#ifdef LINKSPEED_DEBUG_ENABLED
2073 pr_info("Reporting MCS rate %d flags %x\n",
2074 sinfo->txrate.mcs, sinfo->txrate.flags);
2075#endif /* LINKSPEED_DEBUG_ENABLED */
2076 }
2077 } else {
2078 /* report current rate instead of max rate */
2079
2080 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2081 /* provide to the UI in units of 100kbps */
2082 sinfo->txrate.legacy = myRate;
2083#ifdef LINKSPEED_DEBUG_ENABLED
2084 pr_info("Reporting actual legacy rate %d\n",
2085 sinfo->txrate.legacy);
2086#endif /* LINKSPEED_DEBUG_ENABLED */
2087 } else {
2088 /* must be MCS */
2089 sinfo->txrate.mcs =
2090 pAdapter->hdd_stats.ClassA_stat.mcs_index;
2091#ifdef WLAN_FEATURE_11AC
2092 sinfo->txrate.nss = nss;
2093 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2094 if (rate_flags & eHAL_TX_RATE_VHT80) {
2095 sinfo->txrate.flags |=
2096 RATE_INFO_FLAGS_80_MHZ_WIDTH;
2097 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2098 sinfo->txrate.flags |=
2099 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2100 }
2101#endif /* WLAN_FEATURE_11AC */
2102 if (rate_flags &
2103 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2104 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2105 if (rate_flags & eHAL_TX_RATE_HT40) {
2106 sinfo->txrate.flags |=
2107 RATE_INFO_FLAGS_40_MHZ_WIDTH;
2108 }
2109 }
2110 if (rate_flags & eHAL_TX_RATE_SGI) {
2111 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2112 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2113 }
2114#ifdef LINKSPEED_DEBUG_ENABLED
2115 pr_info("Reporting actual MCS rate %d flags %x\n",
2116 sinfo->txrate.mcs, sinfo->txrate.flags);
2117#endif /* LINKSPEED_DEBUG_ENABLED */
2118 }
2119 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08002120
2121 if (rate_flags & eHAL_TX_RATE_LEGACY)
2122 hdd_info("Reporting legacy rate %d", sinfo->txrate.legacy);
2123 else
2124 hdd_info("Reporting MCS rate %d flags 0x%x",
2125 sinfo->txrate.mcs, sinfo->txrate.flags);
2126
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127 sinfo->filled |= STATION_INFO_TX_BITRATE;
2128
2129 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
2130 sinfo->filled |= STATION_INFO_TX_BYTES;
2131
2132 sinfo->tx_packets =
2133 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] +
2134 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] +
2135 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] +
2136 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3];
2137
2138 sinfo->tx_retries =
2139 pAdapter->hdd_stats.summary_stat.retry_cnt[0] +
2140 pAdapter->hdd_stats.summary_stat.retry_cnt[1] +
2141 pAdapter->hdd_stats.summary_stat.retry_cnt[2] +
2142 pAdapter->hdd_stats.summary_stat.retry_cnt[3];
2143
2144 sinfo->tx_failed =
2145 pAdapter->hdd_stats.summary_stat.fail_cnt[0] +
2146 pAdapter->hdd_stats.summary_stat.fail_cnt[1] +
2147 pAdapter->hdd_stats.summary_stat.fail_cnt[2] +
2148 pAdapter->hdd_stats.summary_stat.fail_cnt[3];
2149
2150 sinfo->filled |=
2151 STATION_INFO_TX_PACKETS |
2152 STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED;
2153
2154 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
2155 sinfo->filled |= STATION_INFO_RX_BYTES;
2156
2157 sinfo->rx_packets = pAdapter->stats.rx_packets;
2158 sinfo->filled |= STATION_INFO_RX_PACKETS;
2159
2160 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2161 TRACE_CODE_HDD_CFG80211_GET_STA,
2162 pAdapter->sessionId, maxRate));
2163 EXIT();
2164 return 0;
2165}
2166
2167/**
2168 * wlan_hdd_cfg80211_get_station() - get station statistics
2169 * @wiphy: Pointer to wiphy
2170 * @dev: Pointer to network device
2171 * @mac: Pointer to mac
2172 * @sinfo: Pointer to station info
2173 *
2174 * Return: 0 for success, non-zero for failure
2175 */
2176#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2177int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2178 struct net_device *dev, const uint8_t *mac,
2179 struct station_info *sinfo)
2180#else
2181int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2182 struct net_device *dev, uint8_t *mac,
2183 struct station_info *sinfo)
2184#endif
2185{
2186 int ret;
2187
2188 cds_ssr_protect(__func__);
2189 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
2190 cds_ssr_unprotect(__func__);
2191
2192 return ret;
2193}
2194
2195/**
2196 * hdd_get_stats() - Function to retrieve interface statistics
2197 * @dev: pointer to network device
2198 *
2199 * This function is the ndo_get_stats method for all netdevs
2200 * registered with the kernel
2201 *
2202 * Return: pointer to net_device_stats structure
2203 */
2204struct net_device_stats *hdd_get_stats(struct net_device *dev)
2205{
2206 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2207
2208 return &adapter->stats;
2209}
2210/**
2211 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
2212 * @wiphy: Pointer to wiphy
2213 * @dev: Pointer to network device
2214 * @idx: Index
2215 * @survey: Pointer to survey info
2216 *
2217 * Return: 0 for success, non-zero for failure
2218 */
2219static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2220 struct net_device *dev,
2221 int idx, struct survey_info *survey)
2222{
2223 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2224 hdd_context_t *pHddCtx;
2225 hdd_station_ctx_t *pHddStaCtx;
2226 tHalHandle halHandle;
2227 uint32_t channel = 0, freq = 0; /* Initialization Required */
2228 int8_t snr, rssi;
2229 int status, i, j, filled = 0;
2230
2231 ENTER();
2232
Peng Xuf5d60c82015-10-02 17:17:03 -07002233 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2235 return -EINVAL;
2236 }
2237
2238 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2239 status = wlan_hdd_validate_context(pHddCtx);
2240
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302241 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002243
2244 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2245
2246 if (0 == pHddCtx->config->fEnableSNRMonitoring ||
2247 0 != pAdapter->survey_idx ||
2248 eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2249 /* The survey dump ops when implemented completely is expected
2250 * to return a survey of all channels and the ops is called by
2251 * the kernel with incremental values of the argument 'idx'
2252 * till it returns -ENONET. But we can only support the survey
2253 * for the operating channel for now. survey_idx is used to
2254 * track that the ops is called only once and then return
2255 * -ENONET for the next iteration
2256 */
2257 pAdapter->survey_idx = 0;
2258 return -ENONET;
2259 }
2260
2261 if (!pHddStaCtx->hdd_ReassocScenario) {
2262 hdd_err("Roaming in progress, hence return");
2263 return -ENONET;
2264 }
2265
2266 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
2267
2268 wlan_hdd_get_snr(pAdapter, &snr);
2269 wlan_hdd_get_rssi(pAdapter, &rssi);
2270
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302271 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2272 TRACE_CODE_HDD_CFG80211_DUMP_SURVEY,
2273 pAdapter->sessionId, pAdapter->device_mode));
2274
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275 sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId);
2276 hdd_wlan_get_freq(channel, &freq);
2277
2278 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08002279 if (NULL == wiphy->bands[i])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 continue;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002281
2282 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
2283 struct ieee80211_supported_band *band = wiphy->bands[i];
2284
2285 if (band->channels[j].center_freq == (uint16_t) freq) {
2286 survey->channel = &band->channels[j];
2287 /* The Rx BDs contain SNR values in dB for the
2288 * received frames while the supplicant expects
2289 * noise. So we calculate and return the value
2290 * of noise (dBm)
2291 * SNR (dB) = RSSI (dBm) - NOISE (dBm)
2292 */
2293 survey->noise = rssi - snr;
2294 survey->filled = SURVEY_INFO_NOISE_DBM;
2295 filled = 1;
2296 }
2297 }
2298 }
2299
2300 if (filled)
2301 pAdapter->survey_idx = 1;
2302 else {
2303 pAdapter->survey_idx = 0;
2304 return -ENONET;
2305 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302306 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 return 0;
2308}
2309
2310/**
2311 * wlan_hdd_cfg80211_dump_survey() - get survey related info
2312 * @wiphy: Pointer to wiphy
2313 * @dev: Pointer to network device
2314 * @idx: Index
2315 * @survey: Pointer to survey info
2316 *
2317 * Return: 0 for success, non-zero for failure
2318 */
2319int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2320 struct net_device *dev,
2321 int idx, struct survey_info *survey)
2322{
2323 int ret;
2324
2325 cds_ssr_protect(__func__);
2326 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
2327 cds_ssr_unprotect(__func__);
2328
2329 return ret;
2330}
2331/**
2332 * hdd_init_ll_stats_ctx() - initialize link layer stats context
2333 *
2334 * Return: none
2335 */
2336inline void hdd_init_ll_stats_ctx(void)
2337{
2338 spin_lock_init(&ll_stats_context.context_lock);
2339 init_completion(&ll_stats_context.response_event);
2340 ll_stats_context.request_bitmap = 0;
2341
2342 return;
2343}