1 /*
2  * Copyright 2023, Cypress Semiconductor Corporation (an Infineon company)
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /** @file
19  *  Implements user functions for controlling the Wi-Fi system
20  *
21  *  This file provides end-user functions which allow actions such as scanning for
22  *  Wi-Fi networks, joining Wi-Fi networks, getting the MAC address, etc
23  *
24  */
25 
26 #include "whd_version.h"
27 #include "whd_chip_constants.h"
28 #include "whd_cdc_bdc.h"
29 #include "whd_thread_internal.h"
30 #include "whd_debug.h"
31 #include "whd_utils.h"
32 #include "whd_wifi_api.h"
33 #include "whd_buffer_api.h"
34 #include "whd_wlioctl.h"
35 #include "whd_types.h"
36 #include "whd_types_int.h"
37 
38 /******************************************************
39 *                   Constants
40 ******************************************************/
41 #define WL_CHANSPEC_CHAN_MASK             (0x00ff)
42 #define CHSPEC_CHANNEL(chspec)            ( (uint8_t)( (chspec) & WL_CHANSPEC_CHAN_MASK ) )
43 #define CH20MHZ_CHSPEC(channel)           (chanspec_t)( (chanspec_t)(channel) | GET_C_VAR(whd_driver, CHANSPEC_BW_20) |                                                           \
44                                                         GET_C_VAR(whd_driver, CHANSPEC_CTL_SB_NONE) | \
45                                                         ( ( (channel) <= CH_MAX_2G_CHANNEL ) ? GET_C_VAR(whd_driver, \
46                                                                                                          CHANSPEC_BAND_2G) \
47                                                           : GET_C_VAR(whd_driver, CHANSPEC_BAND_5G) ) )
48 
49 #define MAX_SUPPORTED_MCAST_ENTRIES   (10)
50 #define WLC_EVENT_MSG_LINK      (0x01)
51 
52 #define JOIN_ASSOCIATED             (uint32_t)(1 << 0)
53 #define JOIN_AUTHENTICATED          (uint32_t)(1 << 1)
54 #define JOIN_LINK_READY             (uint32_t)(1 << 2)
55 #define JOIN_SECURITY_COMPLETE      (uint32_t)(1 << 3)
56 #define JOIN_SSID_SET               (uint32_t)(1 << 4)
57 #define JOIN_NO_NETWORKS            (uint32_t)(1 << 5)
58 #define JOIN_EAPOL_KEY_M1_TIMEOUT   (uint32_t)(1 << 6)
59 #define JOIN_EAPOL_KEY_M3_TIMEOUT   (uint32_t)(1 << 7)
60 #define JOIN_EAPOL_KEY_G1_TIMEOUT   (uint32_t)(1 << 8)
61 #define JOIN_EAPOL_KEY_FAILURE      (uint32_t)(1 << 9)
62 
63 #define JOIN_SECURITY_FLAGS_MASK    (JOIN_SECURITY_COMPLETE | JOIN_EAPOL_KEY_M1_TIMEOUT | JOIN_EAPOL_KEY_M3_TIMEOUT | \
64                                      JOIN_EAPOL_KEY_G1_TIMEOUT | JOIN_EAPOL_KEY_FAILURE)
65 
66 #define DEFAULT_JOIN_ATTEMPT_TIMEOUT     (9000)   /* Overall join attempt timeout in milliseconds.(FW will do "full scan"[~2.8 seconds] + "psk-to-pmk"[2.x seconds] + "join"[5 seconds timer in FW]) */
67 #define DEFAULT_EAPOL_KEY_PACKET_TIMEOUT (2500)   /* Timeout when waiting for EAPOL key packet M1 or M3 in milliseconds.*/
68                                                   /* Some APs may be slow to provide M1 and 1000 ms is not long enough for edge of cell. */
69 #ifndef DEFAULT_PM2_SLEEP_RET_TIME
70 #define DEFAULT_PM2_SLEEP_RET_TIME   (200)
71 #endif
72 
73 #define PM2_SLEEP_RET_TIME_MIN       (10)     /* Minimum return-to-sleep in milliseconds */
74 #define PM2_SLEEP_RET_TIME_MAX       (2000)   /* Maximum return-to-sleep in milliseconds */
75 #define NULL_FRAMES_WITH_PM_SET_LIMIT (100)   /* NULL_FRAMES_WITH_PM_SET_LIMIT */
76 #define RSPEC_KBPS_MASK (0x7f)
77 #define RSPEC_500KBPS(rate) ( (rate) &  RSPEC_KBPS_MASK )
78 #define RSPEC_TO_KBPS(rate) (RSPEC_500KBPS( (rate) ) * (uint32_t)500)
79 #define UNSIGNED_CHAR_TO_CHAR(uch) ( (uch) & 0x7f )
80 #define ETHER_ISMULTI(ea) ( ( (const uint8_t *)(ea) )[0] & 1 )
81 
82 #define KEY_MAX_LEN                   (64)  /* Maximum key length */
83 #define KEY_MIN_LEN                   (8)   /* Minimum key length */
84 #define BT_CTRL_REG_ADDR              (0x18000c7c)
85 #define HOST_CTRL_REG_ADDR            (0x18000d6c)
86 #define BT_BUF_REG_ADDR               (0x18000c78)
87 /******************************************************
88 *             Local Structures
89 ******************************************************/
90 
91 #pragma pack(1)
92 
93 typedef struct
94 {
95     uint32_t entry_count;
96     whd_mac_t macs[1];
97 } mcast_list_t;
98 
99 typedef struct
100 {
101     int32_t rssi;
102     whd_mac_t macs;
103 } client_rssi_t;
104 
105 typedef struct
106 {
107     whd_sync_scan_result_t *aps;
108     uint32_t count;
109     uint32_t offset;
110     cy_semaphore_t scan_semaphore;
111 } whd_scan_userdata_t;
112 
113 #pragma pack()
114 
115 /******************************************************
116 *             Static Variables
117 ******************************************************/
118 
119 /* LOOK: !!!When adding events below, please modify whd_event_to_string!!! */
120 const whd_event_num_t join_events[]  =
121 {
122     WLC_E_SET_SSID, WLC_E_LINK, WLC_E_AUTH, WLC_E_DEAUTH_IND, WLC_E_DISASSOC_IND, WLC_E_PSK_SUP, WLC_E_CSA_COMPLETE_IND,
123     WLC_E_NONE
124 };
125 static const whd_event_num_t scan_events[] = { WLC_E_ESCAN_RESULT, WLC_E_NONE };
126 static const whd_event_num_t auth_events[] =
127 { WLC_E_EXT_AUTH_REQ, WLC_E_EXT_AUTH_FRAME_RX, WLC_E_NONE };
128 
129 /* Values are in 100's of Kbit/sec (1 = 100Kbit/s). Arranged as:
130  * [Bit index]
131  *    [0] = 20Mhz only
132  *       [0] = Long GI
133  *       [1] = Short GI
134  *    [1] = 40MHz support
135  *       [0] = Long GI
136  *       [1] = Short GI
137  */
138 static const uint16_t mcs_data_rate_lookup_table[32][2][2] =
139 {
140     [0] =
141     {
142         {   65, 72},
143         {   135, 150}
144     },
145     [1] =
146     {
147         {   130, 144},
148         {   270, 300}
149     },
150     [2] =
151     {
152         {   195, 217},
153         {   405, 450}
154     },
155     [3] =
156     {
157         {   260, 289},
158         {   540, 600}
159     },
160     [4] =
161     {
162         {   390, 433},
163         {   810, 900}
164     },
165     [5] =
166     {
167         {   520, 578},
168         {   1080, 1200}
169     },
170     [6] =
171     {
172         {   585, 650},
173         {   1215, 1350}
174     },
175     [7] =
176     {
177         {   650, 722},
178         {   1350, 1500}
179     },
180     [8] =
181     {
182         {   130, 144},
183         {   270, 300}
184     },
185     [9] =
186     {
187         {   260, 289},
188         {   540, 600}
189     },
190     [10] =
191     {
192         {   390, 433},
193         {   810, 900}
194     },
195     [11] =
196     {
197         {   520, 578},
198         {   1080, 1200}
199     },
200     [12] =
201     {
202         {   780, 867},
203         {   1620, 1800}
204     },
205     [13] =
206     {
207         {   1040, 1156},
208         {   2160, 2400}
209     },
210     [14] =
211     {
212         {   1170, 1300},
213         {   2430, 2700}
214     },
215     [15] =
216     {
217         {   1300, 1444},
218         {   2700, 3000}
219     },
220     [16] =
221     {
222         {   195, 217},
223         {   405, 450}
224     },
225     [17] =
226     {
227         {   390, 433},
228         {   810, 900}
229     },
230     [18] =
231     {
232         {   585, 650},
233         {   1215, 1350}
234     },
235     [19] =
236     {
237         {   780, 867},
238         {   1620, 1800}
239     },
240     [20] =
241     {
242         {   1170, 1300},
243         {   2430, 2700}
244     },
245     [21] =
246     {
247         {   1560, 1733},
248         {   3240, 3600}
249     },
250     [22] =
251     {
252         {   1755, 1950},
253         {   3645, 4050}
254     },
255     [23] =
256     {
257         {   1950, 2167},
258         {   4050, 4500}
259     },
260     [24] =
261     {
262         {   260, 288},
263         {   540, 600}
264     },
265     [25] =
266     {
267         {   520, 576},
268         {   1080, 1200}
269     },
270     [26] =
271     {
272         {   780, 868},
273         {   1620, 1800}
274     },
275     [27] =
276     {
277         {   1040, 1156},
278         {   2160, 2400}
279     },
280     [28] =
281     {
282         {   1560, 1732},
283         {   3240, 3600}
284     },
285     [29] =
286     {
287         {   2080, 2312},
288         {   4320, 4800}
289     },
290     [30] =
291     {
292         {   2340, 2600},
293         {   4860, 5400}
294     },
295     [31] =
296     {
297         {   2600, 2888},
298         {   5400, 6000}
299     },
300 };
301 
302 
303 /******************************************************
304 *             Static Function prototypes
305 ******************************************************/
306 static void *whd_wifi_join_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
307                                           const uint8_t *event_data, void *handler_user_data);
308 static void *whd_wifi_scan_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
309                                           const uint8_t *event_data,
310                                           void *handler_user_data);
311 static uint32_t whd_wifi_prepare_join(whd_interface_t ifp,
312                                       whd_security_t security,
313                                       const uint8_t *security_key,
314                                       uint8_t key_length,
315                                       cy_semaphore_t *semaphore);
316 static uint32_t whd_wifi_check_join_status(whd_interface_t ifp);
317 static void     whd_wifi_active_join_deinit(whd_interface_t ifp, cy_semaphore_t *stack_semaphore,
318                                             whd_result_t result);
319 static uint32_t whd_wifi_active_join_init(whd_interface_t ifp, whd_security_t auth_type,
320                                           const uint8_t *security_key, uint8_t key_length,
321                                           cy_semaphore_t *semaphore);
322 
323 /** Sets the current EAPOL key timeout for the given interface
324  *
325  * @param interface         : the interface for which we want to set the EAPOL key timeout
326  *        eapol_key_timeout : EAPOL key timeout value
327  *
328  * @return  WHD_SUCCESS : if success
329  *          Error code    : error code to indicate the type of error
330  */
331 static uint32_t whd_wifi_set_supplicant_key_timeout(whd_interface_t ifp, int32_t eapol_key_timeout);
332 
333 /******************************************************
334 *             Function definitions
335 ******************************************************/
336 uint32_t whd_get_bt_info(whd_driver_t whd_driver, whd_bt_info_t bt_info);
337 
whd_channel_to_wl_band(whd_driver_t whd_driver,uint32_t channel)338 inline wl_chanspec_t whd_channel_to_wl_band(whd_driver_t whd_driver, uint32_t channel)
339 {
340     return ( ( (channel) <= CH_MAX_2G_CHANNEL ) ? (uint16_t)GET_C_VAR(whd_driver, CHANSPEC_BAND_2G) :
341              (uint16_t)GET_C_VAR(whd_driver, CHANSPEC_BAND_5G) );
342 }
343 
whd_wifi_set_up(whd_interface_t ifp)344 uint32_t whd_wifi_set_up(whd_interface_t ifp)
345 {
346     whd_mac_t mac;
347     char version[200];
348     whd_driver_t whd_driver;
349 
350     CHECK_IFP_NULL(ifp);
351 
352     whd_driver = ifp->whd_driver;
353     if (whd_driver->internal_info.whd_wlan_status.state == WLAN_UP)
354     {
355         WPRINT_WHD_INFO( ("whd_wifi_set_up: already up.\n") );
356         return WHD_SUCCESS;
357     }
358 
359     /* Send UP command */
360     CHECK_RETURN(whd_wifi_set_ioctl_buffer(ifp, WLC_UP, NULL, 0) );
361 
362     if (whd_wifi_get_mac_address(ifp, &mac) == WHD_SUCCESS)
363     {
364         WPRINT_MACRO( ("WLAN MAC Address : %02X:%02X:%02X:%02X:%02X:%02X\n", mac.octet[0], mac.octet[1], mac.octet[2],
365                        mac.octet[3], mac.octet[4], mac.octet[5]) );
366     }
367 
368     if (whd_wifi_get_wifi_version(ifp, version, sizeof(version) ) == WHD_SUCCESS)
369     {
370         WPRINT_MACRO( ("WLAN Firmware    : %s", version) );
371     }
372 
373     /* minimize bootloader usage and start time from UART output */
374     if (whd_wifi_get_clm_version(ifp, version, sizeof(version) ) == WHD_SUCCESS)
375     {
376         WPRINT_MACRO( ("WLAN CLM         : %s\n", version) );
377     }
378 
379     WPRINT_MACRO( ("WHD VERSION      : " WHD_VERSION) );
380     WPRINT_MACRO( (" : " WHD_BRANCH) );
381 #if defined(__ARMCC_VERSION)
382     WPRINT_MACRO( (" : ARM CLANG %u", __ARMCC_VERSION) );
383 #elif defined(__ICCARM__)
384     WPRINT_MACRO( (" : IAR %u", __VER__) );
385 #elif defined(__GNUC__)
386     WPRINT_MACRO( (" : GCC %u.%u", __GNUC__, __GNUC_MINOR__) );
387 #else
388     WPRINT_MACRO( (" : UNKNOWN CC") );
389 #endif
390     WPRINT_MACRO( (" : " WHD_DATE "\n") );
391 
392     /* Update wlan status */
393     whd_driver->internal_info.whd_wlan_status.state = WLAN_UP;
394 
395     return WHD_SUCCESS;
396 }
397 
whd_wifi_set_down(whd_interface_t ifp)398 uint32_t whd_wifi_set_down(whd_interface_t ifp)
399 {
400     whd_driver_t whd_driver = ifp->whd_driver;
401 
402     if (whd_driver->internal_info.whd_wlan_status.state != WLAN_UP)
403     {
404         WPRINT_WHD_INFO( ("whd_wifi_set_down: already down.\n") );
405         return WHD_INTERFACE_NOT_UP;
406     }
407 
408     /* Send DOWN command */
409     CHECK_RETURN(whd_wifi_set_ioctl_buffer(ifp, WLC_DOWN, NULL, 0) );
410 
411     /* Update wlan status */
412     whd_driver->internal_info.whd_wlan_status.state = WLAN_DOWN;
413 
414     return WHD_SUCCESS;
415 }
416 
whd_get_bt_info(whd_driver_t whd_driver,whd_bt_info_t bt_info)417 uint32_t whd_get_bt_info(whd_driver_t whd_driver, whd_bt_info_t bt_info)
418 {
419     whd_result_t result;
420     whd_interface_t ifp;
421     uint32_t addr = 0;
422 
423     ifp = whd_get_primary_interface(whd_driver);
424 
425     CHECK_IFP_NULL(ifp);
426 
427     memset(bt_info, 0, sizeof(struct whd_bt_info) );
428     bt_info->bt_ctrl_reg_addr = BT_CTRL_REG_ADDR;
429     bt_info->host_ctrl_reg_addr = HOST_CTRL_REG_ADDR;
430     bt_info->bt_buf_reg_addr = BT_BUF_REG_ADDR;
431     result = whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_BTADDR, (uint8_t *)&addr, sizeof(uint32_t) );
432     if (result == WHD_SUCCESS)
433     {
434         bt_info->wlan_buf_addr = addr;
435     }
436     return WHD_SUCCESS;
437 }
438 
whd_wifi_set_channel(whd_interface_t ifp,uint32_t channel)439 uint32_t whd_wifi_set_channel(whd_interface_t ifp, uint32_t channel)
440 {
441     whd_buffer_t buffer;
442     uint32_t *data;
443     wl_chan_switch_t *chan_switch;
444     whd_driver_t whd_driver;
445 
446     CHECK_IFP_NULL(ifp);
447 
448     whd_driver = ifp->whd_driver;
449 
450     CHECK_DRIVER_NULL(whd_driver);
451 
452     /* Map P2P interface to either STA or AP interface depending if it's running as group owner or client */
453     if (ifp->role == WHD_P2P_ROLE)
454     {
455         if (whd_driver->internal_info.whd_wifi_p2p_go_is_up == WHD_TRUE)
456         {
457             ifp->role = WHD_AP_ROLE;
458         }
459         else
460         {
461             ifp->role = WHD_STA_ROLE;
462         }
463     }
464 
465     switch (ifp->role)
466     {
467         case WHD_STA_ROLE:
468             data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(uint32_t) );
469             CHECK_IOCTL_BUFFER(data);
470             *data = htod32(channel);
471             CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_GET, WLC_SET_CHANNEL, buffer, NULL) );
472             break;
473 
474         case WHD_AP_ROLE:
475             chan_switch = (wl_chan_switch_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(wl_chan_switch_t),
476                                                                        IOVAR_STR_CSA);
477             CHECK_IOCTL_BUFFER(chan_switch);
478             chan_switch->chspec =
479                 ( wl_chanspec_t )(GET_C_VAR(whd_driver,
480                                             CHANSPEC_BW_20) | GET_C_VAR(whd_driver, CHANSPEC_CTL_SB_NONE) | channel);
481             chan_switch->chspec |= whd_channel_to_wl_band(whd_driver, channel);
482             chan_switch->chspec = htod16(chan_switch->chspec);
483             chan_switch->count = 1;
484             chan_switch->mode = 1;
485             chan_switch->reg = 0;
486             CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
487             break;
488         case WHD_P2P_ROLE:
489         case WHD_INVALID_ROLE:
490         default:
491             whd_assert("Bad interface", 0 != 0);
492             return WHD_UNKNOWN_INTERFACE;
493     }
494 
495     return WHD_SUCCESS;
496 }
497 
whd_wifi_get_channel(whd_interface_t ifp,uint32_t * channel)498 uint32_t whd_wifi_get_channel(whd_interface_t ifp, uint32_t *channel)
499 {
500     whd_buffer_t buffer;
501     whd_buffer_t response;
502     channel_info_t *channel_info;
503     whd_driver_t whd_driver;
504 
505     CHECK_IFP_NULL(ifp);
506 
507     if (channel == NULL)
508         return WHD_BADARG;
509 
510     whd_driver = ifp->whd_driver;
511 
512     CHECK_DRIVER_NULL(whd_driver);
513 
514     CHECK_IOCTL_BUFFER(whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(channel_info_t) ) );
515 
516     CHECK_RETURN(whd_cdc_send_ioctl(ifp,  CDC_GET, WLC_GET_CHANNEL, buffer, &response) );
517 
518     channel_info = (channel_info_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
519     CHECK_PACKET_NULL(channel_info, WHD_NO_REGISTER_FUNCTION_POINTER);
520     *channel = (uint32_t)channel_info->hw_channel;
521     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
522     return WHD_SUCCESS;
523 }
524 
whd_wifi_enable_supplicant(whd_interface_t ifp,whd_security_t auth_type)525 uint32_t whd_wifi_enable_supplicant(whd_interface_t ifp, whd_security_t auth_type)
526 {
527     whd_buffer_t buffer;
528     uint32_t *data;
529     uint32_t bss_index = 0;
530     whd_driver_t whd_driver;
531 
532     CHECK_IFP_NULL(ifp);
533 
534     whd_driver = ifp->whd_driver;
535 
536     CHECK_DRIVER_NULL(whd_driver);
537 
538     /* Map the interface to a BSS index */
539     bss_index = ifp->bsscfgidx;
540 
541     /* Set supplicant variable - mfg app doesn't support these iovars, so don't care if return fails */
542     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)8, "bsscfg:" IOVAR_STR_SUP_WPA);
543     CHECK_IOCTL_BUFFER(data);
544     data[0] = bss_index;
545     data[1] = (uint32_t)( ( ( (auth_type & WPA_SECURITY)  != 0 ) ||
546                             ( (auth_type & WPA2_SECURITY) != 0 ) ||
547                             (auth_type & WPA3_SECURITY) != 0 ) ? 1 : 0 );
548     (void)whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0);
549 
550     return WHD_SUCCESS;
551 }
552 
whd_wifi_set_supplicant_key_timeout(whd_interface_t ifp,int32_t eapol_key_timeout)553 uint32_t whd_wifi_set_supplicant_key_timeout(whd_interface_t ifp, int32_t eapol_key_timeout)
554 {
555     whd_buffer_t buffer;
556     int32_t *data;
557     uint32_t bss_index = 0;
558     whd_driver_t whd_driver = (whd_driver_t)ifp->whd_driver;
559 
560     /* Map the interface to a BSS index */
561     bss_index = ifp->bsscfgidx;
562 
563     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)8, "bsscfg:" IOVAR_STR_SUP_WPA_TMO);
564     CHECK_IOCTL_BUFFER(data);
565     data[0] = (int32_t)bss_index;
566     data[1] = eapol_key_timeout;
567     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
568 
569     return WHD_SUCCESS;
570 }
571 
whd_wifi_set_passphrase(whd_interface_t ifp,const uint8_t * security_key,uint8_t key_length)572 uint32_t whd_wifi_set_passphrase(whd_interface_t ifp, const uint8_t *security_key, uint8_t key_length)
573 {
574     whd_buffer_t buffer;
575     whd_driver_t whd_driver;
576     wsec_pmk_t *psk;
577 
578     if (!ifp || !security_key || (key_length < KEY_MIN_LEN) || (key_length > KEY_MAX_LEN) )
579     {
580         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
581                            __func__, __LINE__) );
582         return WHD_WLAN_BADARG;
583     }
584 
585     whd_driver = ifp->whd_driver;
586     CHECK_DRIVER_NULL(whd_driver);
587 
588     psk = (wsec_pmk_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(wsec_pmk_t) );
589     CHECK_IOCTL_BUFFER(psk);
590 
591     memset(psk, 0, sizeof(wsec_pmk_t) );
592     memcpy(psk->key, security_key, key_length);
593     psk->key_len = htod16(key_length);
594     psk->flags = htod16( (uint16_t)WSEC_PASSPHRASE );
595 
596     /* Delay required to allow radio firmware to be ready to receive PMK and avoid intermittent failure */
597     CHECK_RETURN(cy_rtos_delay_milliseconds(1) );
598 
599     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_WSEC_PMK, buffer, 0) );
600 
601     return WHD_SUCCESS;
602 }
603 
whd_wifi_sae_password(whd_interface_t ifp,const uint8_t * security_key,uint8_t key_length)604 uint32_t whd_wifi_sae_password(whd_interface_t ifp, const uint8_t *security_key, uint8_t key_length)
605 {
606     whd_buffer_t buffer;
607     whd_driver_t whd_driver;
608     wsec_sae_password_t *sae_password;
609 
610     if (!ifp || !security_key || (key_length == 0) || (key_length > WSEC_MAX_SAE_PASSWORD_LEN) )
611     {
612         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
613                            __func__, __LINE__) );
614         return WHD_WLAN_BADARG;
615     }
616 
617     whd_driver = ifp->whd_driver;
618     CHECK_DRIVER_NULL(whd_driver);
619 
620     sae_password = (wsec_sae_password_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
621                                                                    sizeof(wsec_sae_password_t),
622                                                                    IOVAR_STR_SAE_PASSWORD);
623     CHECK_IOCTL_BUFFER(sae_password);
624     memset(sae_password, 0, sizeof(wsec_sae_password_t) );
625     memcpy(sae_password->password, security_key, key_length);
626     sae_password->password_len = htod16(key_length);
627     /* Delay required to allow radio firmware to be ready to receive PMK and avoid intermittent failure */
628     cy_rtos_delay_milliseconds(1);
629     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
630 
631     return WHD_SUCCESS;
632 }
633 
whd_wifi_enable_sup_set_passphrase(whd_interface_t ifp,const uint8_t * security_key_psk,uint8_t psk_length,whd_security_t auth_type)634 uint32_t whd_wifi_enable_sup_set_passphrase(whd_interface_t ifp, const uint8_t *security_key_psk, uint8_t psk_length,
635                                             whd_security_t auth_type)
636 {
637     whd_buffer_t buffer;
638     uint32_t *data;
639     uint32_t bss_index = 0;
640     whd_driver_t whd_driver;
641 
642     CHECK_IFP_NULL(ifp);
643 
644     whd_driver = ifp->whd_driver;
645 
646     CHECK_DRIVER_NULL(whd_driver);
647 
648     if ( (psk_length > (uint8_t)WSEC_MAX_PSK_LEN) ||
649          (psk_length < (uint8_t)WSEC_MIN_PSK_LEN) )
650     {
651         return WHD_INVALID_KEY;
652     }
653 
654     /* Map the interface to a BSS index */
655     bss_index = ifp->bsscfgidx;
656 
657     /* Set supplicant variable - mfg app doesn't support these iovars, so don't care if return fails */
658     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)8, "bsscfg:" IOVAR_STR_SUP_WPA);
659     CHECK_IOCTL_BUFFER(data);
660     data[0] = bss_index;
661     data[1] = (uint32_t)( ( ( (auth_type & WPA_SECURITY)  != 0 ) ||
662                             ( (auth_type & WPA2_SECURITY) != 0 ) ||
663                             (auth_type & WPA3_SECURITY) != 0 ) ? 1 : 0 );
664     (void)whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0);
665 
666     CHECK_RETURN(whd_wifi_set_passphrase(ifp, security_key_psk, psk_length) );
667 
668     return WHD_SUCCESS;
669 }
670 
whd_wifi_set_pmk(whd_interface_t ifp,const uint8_t * security_key,uint8_t key_length)671 whd_result_t whd_wifi_set_pmk(whd_interface_t ifp, const uint8_t *security_key, uint8_t key_length)
672 {
673     whd_buffer_t buffer;
674     whd_driver_t whd_driver;
675     wsec_pmk_t *pmk;
676     uint32_t i;
677 
678     if (!ifp || !security_key || (key_length != WSEC_PMK_LEN) )
679     {
680         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
681                            __func__, __LINE__) );
682         return WHD_WLAN_BADARG;
683     }
684 
685     whd_driver = ifp->whd_driver;
686     CHECK_DRIVER_NULL(whd_driver);
687 
688     pmk = (wsec_pmk_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(wsec_pmk_t) );
689     CHECK_IOCTL_BUFFER(pmk);
690 
691     memset(pmk, 0, sizeof(wsec_pmk_t) );
692     for (i = 0; i < key_length; i++)
693     {
694         snprintf( (char *)&pmk->key[2 * i], 3, "%02x", security_key[i] );
695     }
696     pmk->key_len = htod16(key_length << 1);
697     pmk->flags = htod16( (uint16_t)WSEC_PASSPHRASE );
698 
699     /* Delay required to allow radio firmware to be ready to receive PMK and avoid intermittent failure */
700     CHECK_RETURN(cy_rtos_delay_milliseconds(1) );
701 
702     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_WSEC_PMK, buffer, 0) );
703 
704     return WHD_SUCCESS;
705 }
706 
whd_wifi_set_pmksa(whd_interface_t ifp,const pmkid_t * pmkid)707 whd_result_t whd_wifi_set_pmksa(whd_interface_t ifp, const pmkid_t *pmkid)
708 {
709     whd_buffer_t buffer;
710     whd_buffer_t response;
711     uint16_t cnt;
712     pmkid_list_t *orig_pmkid_list;
713     pmkid_list_t *new_pmkid_list;
714     whd_driver_t whd_driver;
715 
716     if (!ifp || !pmkid)
717     {
718         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
719                            __func__, __LINE__) );
720         return WHD_WLAN_BADARG;
721     }
722 
723     whd_driver = ifp->whd_driver;
724 
725     CHECK_DRIVER_NULL(whd_driver);
726 
727     /* Get the current pmkid_list list */
728     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer,
729                                                 sizeof(uint32_t) + MAXPMKID *
730                                                 sizeof(pmkid_t), IOVAR_STR_PMKID_INFO) );
731     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
732 
733     /* Verify address is not currently registered */
734     orig_pmkid_list = (pmkid_list_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
735     CHECK_PACKET_NULL(orig_pmkid_list, WHD_NO_REGISTER_FUNCTION_POINTER);
736     orig_pmkid_list->npmkid = dtoh32(orig_pmkid_list->npmkid);
737     for (cnt = 0; cnt < orig_pmkid_list->npmkid; ++cnt)
738     {
739         /* Check if any address matches */
740         if (!memcmp(pmkid->BSSID.octet, orig_pmkid_list->pmkid[cnt].BSSID.octet, sizeof(whd_mac_t) ) )
741         {
742             break;
743         }
744     }
745 
746     if (cnt == MAXPMKID)
747     {
748         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
749         WPRINT_WHD_ERROR( ("Too manay PMKSA entrie cached %" PRIu32 "\n", orig_pmkid_list->npmkid) );
750         return WHD_WLAN_NORESOURCE;
751     }
752 
753     /* Add Extra Space for New PMKID and write the new multicast list */
754     if (cnt == orig_pmkid_list->npmkid)
755     {
756         new_pmkid_list = (pmkid_list_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
757                                                                   ( uint16_t )(sizeof(uint32_t) +
758                                                                                (orig_pmkid_list->npmkid + 1) *
759                                                                                sizeof(pmkid_t) ), IOVAR_STR_PMKID_INFO);
760         CHECK_IOCTL_BUFFER(new_pmkid_list);
761         new_pmkid_list->npmkid = orig_pmkid_list->npmkid + 1;
762         memcpy(new_pmkid_list->pmkid, orig_pmkid_list->pmkid, orig_pmkid_list->npmkid * sizeof(pmkid_t) );
763         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
764         memcpy(&new_pmkid_list->pmkid[new_pmkid_list->npmkid - 1], pmkid, sizeof(pmkid_t) );
765         new_pmkid_list->npmkid = htod32(new_pmkid_list->npmkid);
766     }
767     else
768     /* Replace Old PMKID for New PMKID under same BSSID and write the new multicast list */
769     {
770         new_pmkid_list = (pmkid_list_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
771                                                                   ( uint16_t )(sizeof(uint32_t) +
772                                                                                (orig_pmkid_list->npmkid) *
773                                                                                sizeof(pmkid_t) ), IOVAR_STR_PMKID_INFO);
774         CHECK_IOCTL_BUFFER(new_pmkid_list);
775         new_pmkid_list->npmkid = orig_pmkid_list->npmkid;
776         memcpy(new_pmkid_list->pmkid, orig_pmkid_list->pmkid, orig_pmkid_list->npmkid * sizeof(pmkid_t) );
777         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
778         memcpy(&new_pmkid_list->pmkid[cnt], pmkid, sizeof(pmkid_t) );
779         new_pmkid_list->npmkid = htod32(new_pmkid_list->npmkid);
780     }
781     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
782 }
783 
whd_wifi_pmkid_clear(whd_interface_t ifp)784 whd_result_t whd_wifi_pmkid_clear(whd_interface_t ifp)
785 {
786     whd_buffer_t buffer;
787     whd_driver_t whd_driver = (whd_driver_t)ifp->whd_driver;
788 
789     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer,
790                                                 0, IOVAR_STR_PMKID_CLEAR) );
791     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
792 
793     return WHD_SUCCESS;
794 }
795 
whd_wifi_set_roam_time_threshold(whd_interface_t ifp,uint32_t roam_time_threshold)796 whd_result_t whd_wifi_set_roam_time_threshold(whd_interface_t ifp, uint32_t roam_time_threshold)
797 {
798     if (!ifp || !roam_time_threshold)
799     {
800         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
801                            __func__, __LINE__) );
802         return WHD_WLAN_BADARG;
803     }
804 
805     return whd_wifi_set_iovar_value(ifp, IOVAR_STR_ROAM_TIME_THRESH, roam_time_threshold);
806 }
807 
whd_wifi_get_roam_time_threshold(whd_interface_t ifp,uint32_t * roam_time_threshold)808 whd_result_t whd_wifi_get_roam_time_threshold(whd_interface_t ifp, uint32_t *roam_time_threshold)
809 {
810     CHECK_IFP_NULL(ifp);
811 
812     return whd_wifi_get_iovar_value(ifp, IOVAR_STR_ROAM_TIME_THRESH, roam_time_threshold);
813 }
814 
whd_wifi_get_rssi(whd_interface_t ifp,int32_t * rssi)815 uint32_t whd_wifi_get_rssi(whd_interface_t ifp, int32_t *rssi)
816 {
817     CHECK_IFP_NULL(ifp);
818 
819     if (rssi == NULL)
820         return WHD_BADARG;
821     if (ifp->role == WHD_STA_ROLE)
822     {
823         return whd_wifi_get_ioctl_buffer(ifp, WLC_GET_RSSI, (uint8_t *)rssi, sizeof(*rssi) );
824     }
825     return WHD_BADARG;
826 }
827 
whd_wifi_get_ap_client_rssi(whd_interface_t ifp,int32_t * rssi,const whd_mac_t * client_mac)828 uint32_t whd_wifi_get_ap_client_rssi(whd_interface_t ifp, int32_t *rssi, const whd_mac_t *client_mac)
829 {
830     whd_buffer_t buffer;
831     whd_buffer_t response;
832     uint8_t *data = NULL;
833     client_rssi_t *client_rssi;
834     whd_driver_t whd_driver = ifp->whd_driver;
835 
836     /* WLAN expects buffer size to be 4-byte aligned */
837     client_rssi =
838         (client_rssi_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, ROUND_UP(sizeof(client_rssi_t),
839                                                                                 sizeof(uint32_t) ) );
840     CHECK_IOCTL_BUFFER(client_rssi);
841 
842     memcpy(&client_rssi->macs, client_mac, sizeof(*client_mac) );
843     client_rssi->rssi = 0;
844 
845     CHECK_RETURN_UNSUPPORTED_OK(whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_RSSI, buffer, &response) );
846     data = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
847     CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
848     memcpy(rssi, data, sizeof(int32_t) );
849     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
850 
851     return WHD_SUCCESS;
852 }
853 
854 /** Callback for join events
855  *  This is called when the WLC_E_SET_SSID event is received,
856  *  indicating that the system has joined successfully.
857  *  Wakes the thread which was doing the join, allowing it to resume.
858  */
whd_wifi_join_events_handler(whd_interface_t ifp,const whd_event_header_t * event_header,const uint8_t * event_data,void * handler_user_data)859 static void *whd_wifi_join_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
860                                           const uint8_t *event_data,
861                                           void *handler_user_data)
862 {
863     cy_semaphore_t *semaphore = (cy_semaphore_t *)handler_user_data;
864     whd_bool_t join_attempt_complete = WHD_FALSE;
865     whd_driver_t whd_driver = ifp->whd_driver;
866     whd_result_t result;
867 
868     UNUSED_PARAMETER(event_data);
869 
870     if (event_header->bsscfgidx >= WHD_INTERFACE_MAX)
871     {
872         WPRINT_WHD_DEBUG( ("%s: event_header: Bad interface\n", __FUNCTION__) );
873         return NULL;
874     }
875 
876     switch (event_header->event_type)
877     {
878         case WLC_E_PSK_SUP:
879             /* Ignore WLC_E_PSK_SUP event if link is not up */
880             if ( (whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] & JOIN_LINK_READY) != 0 )
881             {
882                 if (event_header->status == WLC_SUP_KEYED)
883                 {
884                     /* Successful WPA key exchange */
885                     whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] &= ~JOIN_SECURITY_FLAGS_MASK;
886                     whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_SECURITY_COMPLETE;
887                 }
888                 else
889                 {
890                     /* join has completed with an error */
891                     join_attempt_complete = WHD_TRUE;
892                     if ( (event_header->status == WLC_SUP_KEYXCHANGE_WAIT_M1) &&
893                          (event_header->reason == WLC_E_SUP_WPA_PSK_TMO) )
894                     {
895                         /* A timeout waiting for M1 may occur at the edge of the cell or if the AP is particularly slow. */
896                         WPRINT_WHD_DEBUG( ("Supplicant M1 timeout event\n") );
897                         whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_EAPOL_KEY_M1_TIMEOUT;
898                     }
899                     else if ( (event_header->status == WLC_SUP_KEYXCHANGE_WAIT_M3) &&
900                               (event_header->reason == WLC_E_SUP_WPA_PSK_TMO) )
901                     {
902                         /* A timeout waiting for M3 is an indicator that the passphrase may be incorrect. */
903                         WPRINT_WHD_DEBUG( ("Supplicant M3 timeout event\n") );
904                         whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_EAPOL_KEY_M3_TIMEOUT;
905                     }
906                     else if ( (event_header->status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
907                               (event_header->reason == WLC_E_SUP_WPA_PSK_TMO) )
908                     {
909                         /* A timeout waiting for G1 (group key) may occur at the edge of the cell. */
910                         WPRINT_WHD_DEBUG( ("Supplicant G1 timeout event\n") );
911                         whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_EAPOL_KEY_G1_TIMEOUT;
912                     }
913                     else
914                     {
915                         WPRINT_WHD_DEBUG( ("Unsuccessful supplicant event; status=0x%" PRIu32 "\n",
916                                            event_header->status) );
917                         /* Unknown failure during EAPOL key handshake */
918                         whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_EAPOL_KEY_FAILURE;
919                     }
920                 }
921             }
922             break;
923 
924         case WLC_E_SET_SSID:
925             if (event_header->status == WLC_E_STATUS_SUCCESS)
926             {
927                 /* SSID has been successfully set. */
928                 whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_SSID_SET;
929             }
930             /* We don't bail out on this event or things like WPS won't work if the AP is rebooting after configuration */
931             else if (event_header->status == WLC_E_STATUS_NO_NETWORKS)
932             {
933                 whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_NO_NETWORKS;
934             }
935             else
936             {
937                 join_attempt_complete = WHD_TRUE;
938             }
939             break;
940 
941         case WLC_E_LINK:
942             if ( (event_header->flags & WLC_EVENT_MSG_LINK) != 0 )
943             {
944                 whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_LINK_READY;
945             }
946             else
947             {
948                 whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] &= ~JOIN_LINK_READY;
949             }
950             break;
951 
952         case WLC_E_DEAUTH_IND:
953         case WLC_E_DISASSOC_IND:
954             whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] &=
955                 ~(JOIN_AUTHENTICATED | JOIN_LINK_READY);
956             break;
957 
958         case WLC_E_AUTH:
959             if (event_header->status == WLC_E_STATUS_SUCCESS)
960             {
961                 whd_driver->internal_info.whd_join_status[event_header->bsscfgidx] |= JOIN_AUTHENTICATED;
962             }
963             else if (event_header->status == WLC_E_STATUS_UNSOLICITED)
964             {
965                 WPRINT_WHD_DEBUG( ("Ignore UNSOLICITED pkt event\n") );
966             }
967             else
968             {
969                 /* We cannot authenticate. Perhaps we're blocked or at the edge of a cell. */
970                 join_attempt_complete = WHD_TRUE;
971             }
972             break;
973 
974         case WLC_E_CSA_COMPLETE_IND:
975             if (event_header->datalen >= sizeof(wl_chan_switch_t) )
976             {
977                 wl_chan_switch_t *wl_csa = (wl_chan_switch_t *)event_data;
978                 UNUSED_PARAMETER(wl_csa);
979                 WPRINT_WHD_INFO( ("CSA event => chan %d\n", (dtoh16(wl_csa->chspec) & 0xff) ) );
980             }
981             break;
982 
983         /* Note - These are listed to keep gcc pedantic checking happy */
984         case WLC_E_RRM:
985         case WLC_E_NONE:
986         case WLC_E_ROAM:
987         case WLC_E_JOIN:
988         case WLC_E_START:
989         case WLC_E_AUTH_IND:
990         case WLC_E_DEAUTH:
991         case WLC_E_ASSOC:
992         case WLC_E_ASSOC_IND:
993         case WLC_E_REASSOC:
994         case WLC_E_REASSOC_IND:
995         case WLC_E_DISASSOC:
996         case WLC_E_QUIET_START:
997         case WLC_E_QUIET_END:
998         case WLC_E_BEACON_RX:
999         case WLC_E_MIC_ERROR:
1000         case WLC_E_NDIS_LINK:
1001         case WLC_E_TXFAIL:
1002         case WLC_E_PMKID_CACHE:
1003         case WLC_E_RETROGRADE_TSF:
1004         case WLC_E_PRUNE:
1005         case WLC_E_AUTOAUTH:
1006         case WLC_E_EAPOL_MSG:
1007         case WLC_E_SCAN_COMPLETE:
1008         case WLC_E_ADDTS_IND:
1009         case WLC_E_DELTS_IND:
1010         case WLC_E_BCNSENT_IND:
1011         case WLC_E_BCNRX_MSG:
1012         case WLC_E_BCNLOST_MSG:
1013         case WLC_E_ROAM_PREP:
1014         case WLC_E_PFN_NET_FOUND:
1015         case WLC_E_PFN_NET_LOST:
1016         case WLC_E_RESET_COMPLETE:
1017         case WLC_E_JOIN_START:
1018         case WLC_E_ROAM_START:
1019         case WLC_E_ASSOC_START:
1020         case WLC_E_IBSS_ASSOC:
1021         case WLC_E_RADIO:
1022         case WLC_E_PSM_WATCHDOG:
1023         case WLC_E_CCX_ASSOC_START:
1024         case WLC_E_CCX_ASSOC_ABORT:
1025         case WLC_E_PROBREQ_MSG:
1026         case WLC_E_SCAN_CONFIRM_IND:
1027         case WLC_E_COUNTRY_CODE_CHANGED:
1028         case WLC_E_EXCEEDED_MEDIUM_TIME:
1029         case WLC_E_ICV_ERROR:
1030         case WLC_E_UNICAST_DECODE_ERROR:
1031         case WLC_E_MULTICAST_DECODE_ERROR:
1032         case WLC_E_TRACE:
1033         case WLC_E_BTA_HCI_EVENT:
1034         case WLC_E_IF:
1035         case WLC_E_PFN_BEST_BATCHING:
1036         case WLC_E_RSSI:
1037         case WLC_E_EXTLOG_MSG:
1038         case WLC_E_ACTION_FRAME:
1039         case WLC_E_ACTION_FRAME_COMPLETE:
1040         case WLC_E_PRE_ASSOC_IND:
1041         case WLC_E_PRE_REASSOC_IND:
1042         case WLC_E_CHANNEL_ADOPTED:
1043         case WLC_E_AP_STARTED:
1044         case WLC_E_DFS_AP_STOP:
1045         case WLC_E_DFS_AP_RESUME:
1046         case WLC_E_WAI_STA_EVENT:
1047         case WLC_E_WAI_MSG:
1048         case WLC_E_ESCAN_RESULT:
1049         case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
1050         case WLC_E_PROBRESP_MSG:
1051         case WLC_E_P2P_PROBREQ_MSG:
1052         case WLC_E_DCS_REQUEST:
1053         case WLC_E_FIFO_CREDIT_MAP:
1054         case WLC_E_ACTION_FRAME_RX:
1055         case WLC_E_WAKE_EVENT:
1056         case WLC_E_RM_COMPLETE:
1057         case WLC_E_HTSFSYNC:
1058         case WLC_E_OVERLAY_REQ:
1059         case WLC_E_EXCESS_PM_WAKE_EVENT:
1060         case WLC_E_PFN_SCAN_NONE:
1061         case WLC_E_PFN_SCAN_ALLGONE:
1062         case WLC_E_GTK_PLUMBED:
1063         case WLC_E_ASSOC_IND_NDIS:
1064         case WLC_E_REASSOC_IND_NDIS:
1065         case WLC_E_ASSOC_REQ_IE:
1066         case WLC_E_ASSOC_RESP_IE:
1067         case WLC_E_ASSOC_RECREATED:
1068         case WLC_E_ACTION_FRAME_RX_NDIS:
1069         case WLC_E_AUTH_REQ:
1070         case WLC_E_TDLS_PEER_EVENT:
1071         case WLC_E_SPEEDY_RECREATE_FAIL:
1072         case WLC_E_NATIVE:
1073         case WLC_E_PKTDELAY_IND:
1074         case WLC_E_AWDL_AW:
1075         case WLC_E_AWDL_ROLE:
1076         case WLC_E_AWDL_EVENT:
1077         case WLC_E_NIC_AF_TXS:
1078         case WLC_E_NAN:
1079         case WLC_E_BEACON_FRAME_RX:
1080         case WLC_E_SERVICE_FOUND:
1081         case WLC_E_GAS_FRAGMENT_RX:
1082         case WLC_E_GAS_COMPLETE:
1083         case WLC_E_P2PO_ADD_DEVICE:
1084         case WLC_E_P2PO_DEL_DEVICE:
1085         case WLC_E_WNM_STA_SLEEP:
1086         case WLC_E_TXFAIL_THRESH:
1087         case WLC_E_PROXD:
1088         case WLC_E_IBSS_COALESCE:
1089         case WLC_E_AWDL_RX_PRB_RESP:
1090         case WLC_E_AWDL_RX_ACT_FRAME:
1091         case WLC_E_AWDL_WOWL_NULLPKT:
1092         case WLC_E_AWDL_PHYCAL_STATUS:
1093         case WLC_E_AWDL_OOB_AF_STATUS:
1094         case WLC_E_AWDL_SCAN_STATUS:
1095         case WLC_E_AWDL_AW_START:
1096         case WLC_E_AWDL_AW_END:
1097         case WLC_E_AWDL_AW_EXT:
1098         case WLC_E_AWDL_PEER_CACHE_CONTROL:
1099         case WLC_E_CSA_START_IND:
1100         case WLC_E_CSA_DONE_IND:
1101         case WLC_E_CSA_FAILURE_IND:
1102         case WLC_E_CCA_CHAN_QUAL:
1103         case WLC_E_BSSID:
1104         case WLC_E_TX_STAT_ERROR:
1105         case WLC_E_BCMC_CREDIT_SUPPORT:
1106         case WLC_E_PSTA_PRIMARY_INTF_IND:
1107         case WLC_E_P2P_DISC_LISTEN_COMPLETE:
1108         case WLC_E_BT_WIFI_HANDOVER_REQ:
1109         case WLC_E_SPW_TXINHIBIT:
1110         case WLC_E_FBT_AUTH_REQ_IND:
1111         case WLC_E_RSSI_LQM:
1112         case WLC_E_PFN_GSCAN_FULL_RESULT:
1113         case WLC_E_PFN_SWC:
1114         case WLC_E_AUTHORIZED:
1115         case WLC_E_PROBREQ_MSG_RX:
1116         case WLC_E_PFN_SCAN_COMPLETE:
1117         case WLC_E_RMC_EVENT:
1118         case WLC_E_DPSTA_INTF_IND:
1119         case WLC_E_ULP:
1120         case WLC_E_LAST:
1121         default:
1122             whd_assert("Received event which was not registered\n", 0 != 0);
1123             break;
1124     }
1125 
1126     if (whd_wifi_is_ready_to_transceive(ifp) == WHD_SUCCESS)
1127     {
1128         join_attempt_complete = WHD_TRUE;
1129     }
1130 
1131     if (join_attempt_complete == WHD_TRUE)
1132     {
1133         if (semaphore != NULL)
1134         {
1135             result = cy_rtos_get_semaphore(&whd_driver->internal_info.active_join_mutex, CY_RTOS_NEVER_TIMEOUT,
1136                                            WHD_FALSE);
1137             if (result != WHD_SUCCESS)
1138             {
1139                 WPRINT_WHD_ERROR( ("Get semaphore failed in %s at %d \n", __func__, __LINE__) );
1140             }
1141             if (whd_driver->internal_info.active_join_semaphore != NULL)
1142             {
1143                 whd_assert("Unexpected semaphore\n", whd_driver->internal_info.active_join_semaphore == semaphore);
1144                 result = cy_rtos_set_semaphore(whd_driver->internal_info.active_join_semaphore, WHD_FALSE);
1145                 if (result != WHD_SUCCESS)
1146                 {
1147                     WPRINT_WHD_ERROR( ("Set semaphore failed in %s at %d \n", __func__, __LINE__) );
1148                 }
1149             }
1150             result = cy_rtos_set_semaphore(&whd_driver->internal_info.active_join_mutex, WHD_FALSE);
1151             if (result != WHD_SUCCESS)
1152             {
1153                 WPRINT_WHD_ERROR( ("Set semaphore failed in %s at %d \n", __func__, __LINE__) );
1154             }
1155         }
1156         return NULL;
1157     }
1158     else
1159     {
1160         return handler_user_data;
1161     }
1162 }
1163 
1164 /* Do any needed preparation prior to launching a join */
whd_wifi_active_join_init(whd_interface_t ifp,whd_security_t auth_type,const uint8_t * security_key,uint8_t key_length,cy_semaphore_t * semaphore)1165 static uint32_t whd_wifi_active_join_init(whd_interface_t ifp, whd_security_t auth_type, const uint8_t *security_key,
1166                                           uint8_t key_length, cy_semaphore_t *semaphore)
1167 {
1168     whd_driver_t whd_driver = ifp->whd_driver;
1169 
1170     if (whd_driver->internal_info.active_join_mutex_initted == WHD_FALSE)
1171     {
1172         CHECK_RETURN(cy_rtos_init_semaphore(&whd_driver->internal_info.active_join_mutex, 1, 0) );
1173         whd_driver->internal_info.active_join_mutex_initted = WHD_TRUE;
1174         CHECK_RETURN(cy_rtos_set_semaphore(&whd_driver->internal_info.active_join_mutex, WHD_FALSE) );
1175     }
1176 
1177     CHECK_RETURN(cy_rtos_get_semaphore(&whd_driver->internal_info.active_join_mutex, CY_RTOS_NEVER_TIMEOUT,
1178                                        WHD_FALSE) );
1179     whd_driver->internal_info.active_join_semaphore = semaphore;
1180     CHECK_RETURN(cy_rtos_set_semaphore(&whd_driver->internal_info.active_join_mutex, WHD_FALSE) );
1181 
1182     CHECK_RETURN(whd_wifi_prepare_join(ifp, auth_type, security_key, key_length, semaphore) );
1183     return WHD_SUCCESS;
1184 }
1185 
whd_wifi_prepare_join(whd_interface_t ifp,whd_security_t auth_type,const uint8_t * security_key,uint8_t key_length,cy_semaphore_t * semaphore)1186 static uint32_t whd_wifi_prepare_join(whd_interface_t ifp, whd_security_t auth_type,
1187                                       const uint8_t *security_key, uint8_t key_length,
1188                                       cy_semaphore_t *semaphore)
1189 {
1190     whd_buffer_t buffer;
1191     uint32_t auth_mfp = WL_MFP_NONE;
1192     whd_result_t retval = WHD_SUCCESS;
1193     whd_result_t check_result = WHD_SUCCESS;
1194     uint32_t *data;
1195     uint32_t *wpa_auth;
1196     uint32_t bss_index = 0;
1197     uint32_t auth;
1198     whd_driver_t whd_driver = ifp->whd_driver;
1199     uint16_t event_entry = 0xFF;
1200 
1201     (void)bss_index;
1202     if ( (auth_type == WHD_SECURITY_WPA2_FBT_ENT) || (auth_type == WHD_SECURITY_IBSS_OPEN) ||
1203          (auth_type == WHD_SECURITY_WPA2_FBT_PSK) )
1204     {
1205         return WHD_UNKNOWN_SECURITY_TYPE;
1206     }
1207     else if ( (auth_type & WEP_ENABLED) != 0 )
1208     {
1209         return WHD_WEP_NOT_ALLOWED;
1210     }
1211     if ( ( ( (key_length > (uint8_t)WSEC_MAX_PSK_LEN) || (key_length < (uint8_t)WSEC_MIN_PSK_LEN) ) &&
1212            ( (auth_type == WHD_SECURITY_WPA_TKIP_PSK) || (auth_type == WHD_SECURITY_WPA_AES_PSK) ||
1213              (auth_type == WHD_SECURITY_WPA2_AES_PSK) || (auth_type == WHD_SECURITY_WPA2_AES_PSK_SHA256) ||
1214              (auth_type == WHD_SECURITY_WPA2_TKIP_PSK) || (auth_type == WHD_SECURITY_WPA2_MIXED_PSK) ) ) ||
1215          ( (key_length > (uint8_t)WSEC_MAX_SAE_PASSWORD_LEN) &&
1216            ( (auth_type == WHD_SECURITY_WPA3_SAE) || (auth_type == WHD_SECURITY_WPA3_WPA2_PSK) ) ) )
1217     {
1218         return WHD_INVALID_KEY;
1219     }
1220 
1221     (void)auth_type, (void)security_key, (void)key_length, (void)semaphore;
1222 
1223     /* Clear the current join status */
1224     whd_driver->internal_info.whd_join_status[ifp->bsscfgidx] = 0;
1225 
1226     /* Setting wsec will overwrite mfp setting in older branches, store value before setting wsec */
1227     CHECK_RETURN(whd_wifi_get_iovar_value(ifp, IOVAR_STR_MFP, &auth_mfp) );
1228 
1229     /* Set Wireless Security Type */
1230     CHECK_RETURN(whd_wifi_set_ioctl_value(ifp, WLC_SET_WSEC, (uint32_t)(auth_type & 0xFF) ) );
1231 
1232     /* Enable Roaming in FW by default */
1233     CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_ROAM_OFF, 0) );
1234 
1235     /* Map the interface to a BSS index */
1236     bss_index = ifp->bsscfgidx;
1237 
1238     /* Set supplicant variable - mfg app doesn't support these iovars, so don't care if return fails */
1239     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)8, "bsscfg:" IOVAR_STR_SUP_WPA);
1240     CHECK_IOCTL_BUFFER(data);
1241     data[0] = htod32(bss_index);
1242     data[1] =
1243         htod32( ( uint32_t )( ( ( (auth_type & WPA_SECURITY) != 0 ) || ( (auth_type & WPA2_SECURITY) != 0 ) ||
1244                                 (auth_type & WPA3_SECURITY) != 0 ) ? 1 : 0 ) );
1245     (void)whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0);
1246 
1247     /* Set the EAPOL version to whatever the AP is using (-1) */
1248     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)8, "bsscfg:" IOVAR_STR_SUP_WPA2_EAPVER);
1249     CHECK_IOCTL_BUFFER(data);
1250     data[0] = htod32(bss_index);
1251     data[1] = htod32( ( uint32_t )-1 );
1252     (void)whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0);
1253 
1254     /* Send WPA Key */
1255     switch (auth_type)
1256     {
1257         case WHD_SECURITY_OPEN:
1258         case WHD_SECURITY_WPS_SECURE:
1259             break;
1260 
1261         case WHD_SECURITY_WPA_TKIP_PSK:
1262         case WHD_SECURITY_WPA_AES_PSK:
1263         case WHD_SECURITY_WPA_MIXED_PSK:
1264         case WHD_SECURITY_WPA2_AES_PSK:
1265         case WHD_SECURITY_WPA2_AES_PSK_SHA256:
1266         case WHD_SECURITY_WPA2_TKIP_PSK:
1267         case WHD_SECURITY_WPA2_MIXED_PSK:
1268         case WHD_SECURITY_WPA2_WPA_AES_PSK:
1269         case WHD_SECURITY_WPA2_WPA_MIXED_PSK:
1270             /* Set the EAPOL key packet timeout value, otherwise unsuccessful supplicant events aren't reported. If the IOVAR is unsupported then continue. */
1271             CHECK_RETURN_UNSUPPORTED_CONTINUE(whd_wifi_set_supplicant_key_timeout(ifp,
1272                                                                                   DEFAULT_EAPOL_KEY_PACKET_TIMEOUT) );
1273             CHECK_RETURN(whd_wifi_set_passphrase(ifp, security_key, key_length) );
1274             break;
1275 
1276         case WHD_SECURITY_WPA3_SAE:
1277         case WHD_SECURITY_WPA3_WPA2_PSK:
1278             if (auth_type == WHD_SECURITY_WPA3_WPA2_PSK)
1279             {
1280                 CHECK_RETURN(whd_wifi_enable_sup_set_passphrase(ifp, security_key, key_length, auth_type) );
1281             }
1282             /* Set the EAPOL key packet timeout value, otherwise unsuccessful supplicant events aren't reported. If the IOVAR is unsupported then continue. */
1283             CHECK_RETURN_UNSUPPORTED_CONTINUE(whd_wifi_set_supplicant_key_timeout(ifp,
1284                                                                                   DEFAULT_EAPOL_KEY_PACKET_TIMEOUT) );
1285             if (whd_driver->chip_info.fwcap_flags & (1 << WHD_FWCAP_SAE) )
1286             {
1287                 CHECK_RETURN(whd_wifi_sae_password(ifp, security_key, key_length) );
1288             }
1289             else
1290             {
1291                 /* Disable Roaming in FW, becuase our wpa3_external_supplicant's limitation.
1292                    If FW report WLC_E_EXT_AUTH_REQ during roaming, Host already called whd_wifi_stop_external_auth_request. */
1293                 CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_ROAM_OFF, 1) );
1294             }
1295             break;
1296 
1297         case WHD_SECURITY_WPA_TKIP_ENT:
1298         case WHD_SECURITY_WPA_AES_ENT:
1299         case WHD_SECURITY_WPA_MIXED_ENT:
1300         case WHD_SECURITY_WPA2_TKIP_ENT:
1301         case WHD_SECURITY_WPA2_AES_ENT:
1302         case WHD_SECURITY_WPA2_MIXED_ENT:
1303             /* Disable eapol timer by setting to value 0 */
1304             CHECK_RETURN_UNSUPPORTED_CONTINUE(whd_wifi_set_supplicant_key_timeout(ifp, 0) );
1305             break;
1306 #if 0
1307         case WHD_SECURITY_WPA2_FBT_ENT:
1308             /* Disable eapol timer by setting to value 0 */
1309             CHECK_RETURN_UNSUPPORTED_CONTINUE(whd_wifi_set_supplicant_key_timeout(ifp, 0) );
1310             break;
1311 #endif
1312         case WHD_SECURITY_FORCE_32_BIT:
1313         case WHD_SECURITY_UNKNOWN:
1314         default:
1315             whd_assert("whd_wifi_prepare_join: Unsupported security type\n", 0 != 0);
1316             break;
1317     }
1318     /* Set infrastructure mode */
1319     CHECK_RETURN(whd_wifi_set_ioctl_value(ifp, WLC_SET_INFRA, ( (auth_type & IBSS_ENABLED) == 0 ) ? 1 : 0) );
1320 
1321     if ( (auth_type == WHD_SECURITY_WPA3_SAE) || (auth_type == WHD_SECURITY_WPA3_WPA2_PSK) )
1322     {
1323         auth = WL_AUTH_SAE;
1324     }
1325     else
1326     {
1327         auth = WL_AUTH_OPEN_SYSTEM;
1328     }
1329     CHECK_RETURN(whd_wifi_set_ioctl_value(ifp, WLC_SET_AUTH, auth) );
1330 
1331     /* From PMF cert test plan,
1332      * 2.2 Out of Box Requirements
1333      * When WPA2 security is enabled on the DUT, then by defaults the DUT shall:
1334      * Enable Robust Management Frame Protection Capable (MFPC) functionality
1335      */
1336     if (auth_type == WHD_SECURITY_WPA3_SAE)
1337     {
1338         auth_mfp = WL_MFP_REQUIRED;
1339     }
1340     else if ( (auth_type == WHD_SECURITY_WPA3_WPA2_PSK) || (auth_type & WPA2_SECURITY) )
1341     {
1342         auth_mfp = WL_MFP_CAPABLE;
1343     }
1344 
1345     check_result = whd_wifi_set_iovar_value(ifp, IOVAR_STR_MFP, auth_mfp);
1346     if (check_result != WHD_SUCCESS)
1347     {
1348         WPRINT_WHD_DEBUG( ("Older chipsets might not support MFP..Ignore result\n") );
1349     }
1350 
1351     /* Set WPA authentication mode */
1352     wpa_auth = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)4);
1353     CHECK_IOCTL_BUFFER(wpa_auth);
1354 
1355     switch (auth_type)
1356     {
1357 #if 0
1358         case WHD_SECURITY_IBSS_OPEN:
1359             /* IBSS does not get authenticated onto an AP */
1360             whd_driver->internal_info.whd_join_status[ifp->bsscfgidx] |= JOIN_AUTHENTICATED;
1361 #endif
1362         /* intentional fall-thru */
1363         /* Disables Eclipse static analysis warning */
1364         /* no break */
1365         /* Fall-Through */
1366         case WHD_SECURITY_OPEN:
1367         case WHD_SECURITY_WPS_SECURE:
1368             *wpa_auth = WPA_AUTH_DISABLED;
1369             /* Open Networks do not have to complete security */
1370             whd_driver->internal_info.whd_join_status[ifp->bsscfgidx] |= JOIN_SECURITY_COMPLETE;
1371             break;
1372 
1373         case WHD_SECURITY_WPA_TKIP_PSK:
1374         case WHD_SECURITY_WPA_AES_PSK:
1375         case WHD_SECURITY_WPA_MIXED_PSK:
1376             *wpa_auth = (uint32_t)WPA_AUTH_PSK;
1377             break;
1378 
1379         case WHD_SECURITY_WPA2_AES_PSK:
1380         case WHD_SECURITY_WPA2_TKIP_PSK:
1381         case WHD_SECURITY_WPA2_MIXED_PSK:
1382         case WHD_SECURITY_WPA2_WPA_AES_PSK:
1383         case WHD_SECURITY_WPA2_WPA_MIXED_PSK:
1384             *wpa_auth = (uint32_t)WPA2_AUTH_PSK;
1385             break;
1386 
1387         case WHD_SECURITY_WPA2_AES_PSK_SHA256:
1388             *wpa_auth = (uint32_t)WPA2_AUTH_PSK_SHA256;
1389             break;
1390 
1391         case WHD_SECURITY_WPA3_SAE:
1392         case WHD_SECURITY_WPA3_WPA2_PSK:
1393             *wpa_auth = (uint32_t)WPA3_AUTH_SAE_PSK;
1394             break;
1395 
1396         case WHD_SECURITY_WPA_TKIP_ENT:
1397         case WHD_SECURITY_WPA_AES_ENT:
1398         case WHD_SECURITY_WPA_MIXED_ENT:
1399             *wpa_auth = (uint32_t)WPA_AUTH_UNSPECIFIED;
1400             break;
1401 
1402         case WHD_SECURITY_WPA2_TKIP_ENT:
1403         case WHD_SECURITY_WPA2_AES_ENT:
1404         case WHD_SECURITY_WPA2_MIXED_ENT:
1405             *wpa_auth = (uint32_t)WPA2_AUTH_UNSPECIFIED;
1406             break;
1407 #if 0
1408         case WHD_SECURITY_WPA2_FBT_ENT:
1409             *wpa_auth = ( uint32_t )(WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT);
1410             break;
1411 #endif
1412         case WHD_SECURITY_UNKNOWN:
1413         case WHD_SECURITY_FORCE_32_BIT:
1414         default:
1415             WPRINT_WHD_DEBUG( ("Unsupported Security type\n") );
1416             *wpa_auth = WPA_AUTH_DISABLED;
1417             break;
1418     }
1419     *wpa_auth = htod32(*wpa_auth);
1420     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_WPA_AUTH, buffer, 0) );
1421 
1422     if (ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY] != WHD_EVENT_NOT_REGISTERED)
1423     {
1424         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY]);
1425         ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
1426     }
1427 
1428     CHECK_RETURN(whd_management_set_event_handler(ifp, join_events, whd_wifi_join_events_handler, (void *)semaphore,
1429                                                   &event_entry) );
1430     if (event_entry >= WHD_EVENT_ENTRY_MAX)
1431     {
1432         WPRINT_WHD_ERROR( ("Join events registration failed in function %s and line %d", __func__, __LINE__) );
1433         return WHD_UNFINISHED;
1434     }
1435     ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY] = event_entry;
1436     whd_assert("Set join Event handler failed\n", retval == WHD_SUCCESS);
1437 
1438     return WHD_SUCCESS;
1439 }
1440 
1441 /* do any needed tear down after join
1442  * @param stack_semaphore - semaphore used to control execution if client_semaphore is NULL
1443  * @param client_semaphore - semaphore used to control execution if client passes this in
1444  */
whd_wifi_active_join_deinit(whd_interface_t ifp,cy_semaphore_t * stack_semaphore,whd_result_t result)1445 static void whd_wifi_active_join_deinit(whd_interface_t ifp, cy_semaphore_t *stack_semaphore, whd_result_t result)
1446 {
1447     whd_driver_t whd_driver = ifp->whd_driver;
1448     whd_result_t val;
1449     /* deinit join specific variables, with protection from mutex */
1450 
1451     val = cy_rtos_get_semaphore(&whd_driver->internal_info.active_join_mutex, CY_RTOS_NEVER_TIMEOUT, WHD_FALSE);
1452     if (val != WHD_SUCCESS)
1453         WPRINT_WHD_ERROR( ("Get semaphore failed in %s at %d \n", __func__, __LINE__) );
1454 
1455     whd_driver->internal_info.active_join_semaphore = NULL;
1456 
1457     cy_rtos_deinit_semaphore(stack_semaphore);
1458 
1459     if (WHD_SUCCESS != result)
1460     {
1461         WPRINT_WHD_INFO( ("Failed join (err %" PRIu32 ")\n", result) );
1462         ifp->role = WHD_INVALID_ROLE;
1463     }
1464 
1465     val = cy_rtos_set_semaphore(&whd_driver->internal_info.active_join_mutex, WHD_FALSE);
1466     if (val != WHD_SUCCESS)
1467         WPRINT_WHD_ERROR( ("Get semaphore failed in %s at %d \n", __func__, __LINE__) );
1468 
1469     /* we forced the chip to be up during join, now let it sleep */
1470     WHD_WLAN_LET_SLEEP(whd_driver);
1471 }
1472 
whd_wifi_join_wait_for_complete(whd_interface_t ifp,cy_semaphore_t * semaphore)1473 static uint32_t whd_wifi_join_wait_for_complete(whd_interface_t ifp, cy_semaphore_t *semaphore)
1474 {
1475     whd_result_t result;
1476     uint32_t start_time;
1477     uint32_t current_time;
1478     whd_bool_t done = WHD_FALSE;
1479 
1480     cy_rtos_get_time(&start_time);
1481 
1482     while (!done)
1483     {
1484         result = cy_rtos_get_semaphore(semaphore, DEFAULT_JOIN_ATTEMPT_TIMEOUT / 10, WHD_FALSE);
1485         whd_assert("Get semaphore failed", (result == CY_RSLT_SUCCESS) || (result == CY_RTOS_TIMEOUT) );
1486         REFERENCE_DEBUG_ONLY_VARIABLE(result);
1487 
1488         result = whd_wifi_is_ready_to_transceive(ifp);
1489         if (result == WHD_SUCCESS)
1490         {
1491             break;
1492         }
1493 
1494         cy_rtos_get_time(&current_time);
1495         done = (whd_bool_t)( (current_time - start_time) >= DEFAULT_JOIN_ATTEMPT_TIMEOUT );
1496     }
1497 
1498     if (result != WHD_SUCCESS)
1499     {
1500         CHECK_RETURN(whd_wifi_leave(ifp) );
1501         WPRINT_WHD_INFO( ("%s: not ready to transceive (err %" PRIu32 "); left network\n", __func__, result) );
1502     }
1503 
1504     return result;
1505 }
1506 
whd_wifi_check_join_status(whd_interface_t ifp)1507 static uint32_t whd_wifi_check_join_status(whd_interface_t ifp)
1508 {
1509     whd_driver_t whd_driver = ifp->whd_driver;
1510 
1511     if ( (uint32_t)ifp->bsscfgidx >= WHD_INTERFACE_MAX )
1512     {
1513         WPRINT_WHD_ERROR( ("%s: Bad interface %d\n", __FUNCTION__, ifp->bsscfgidx) );
1514         return WHD_INVALID_JOIN_STATUS;
1515     }
1516     switch (whd_driver->internal_info.whd_join_status[ifp->bsscfgidx])
1517     {
1518         case JOIN_NO_NETWORKS:
1519             return WHD_NETWORK_NOT_FOUND;
1520 
1521         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_EAPOL_KEY_M1_TIMEOUT:
1522             return WHD_EAPOL_KEY_PACKET_M1_TIMEOUT;
1523 
1524         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_EAPOL_KEY_M3_TIMEOUT:
1525         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SSID_SET | JOIN_EAPOL_KEY_M3_TIMEOUT:
1526             return WHD_EAPOL_KEY_PACKET_M3_TIMEOUT;
1527 
1528         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_EAPOL_KEY_G1_TIMEOUT:
1529         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SSID_SET | JOIN_EAPOL_KEY_G1_TIMEOUT:
1530             return WHD_EAPOL_KEY_PACKET_G1_TIMEOUT;
1531 
1532         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_EAPOL_KEY_FAILURE:
1533         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SSID_SET | JOIN_EAPOL_KEY_FAILURE:
1534             return WHD_EAPOL_KEY_FAILURE;
1535 
1536         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SSID_SET | JOIN_SECURITY_COMPLETE:
1537             return WHD_SUCCESS;
1538 
1539         case 0:
1540         case JOIN_SECURITY_COMPLETE: /* For open/WEP */
1541             return WHD_NOT_AUTHENTICATED;
1542 
1543         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SECURITY_COMPLETE:
1544             return WHD_JOIN_IN_PROGRESS;
1545 
1546         case JOIN_AUTHENTICATED | JOIN_LINK_READY:
1547         case JOIN_AUTHENTICATED | JOIN_LINK_READY | JOIN_SSID_SET:
1548             return WHD_NOT_KEYED;
1549 
1550         default:
1551             return WHD_INVALID_JOIN_STATUS;
1552     }
1553 }
1554 
whd_wifi_join_specific(whd_interface_t ifp,const whd_scan_result_t * ap,const uint8_t * security_key,uint8_t key_length)1555 uint32_t whd_wifi_join_specific(whd_interface_t ifp, const whd_scan_result_t *ap, const uint8_t *security_key,
1556                                 uint8_t key_length)
1557 {
1558     whd_buffer_t buffer;
1559     cy_semaphore_t join_semaphore;
1560     whd_result_t result;
1561     wl_extjoin_params_t *ext_join_params;
1562     wl_join_params_t *join_params;
1563     whd_security_t security = ap->security;
1564     uint16_t wl_band_for_channel = 0;
1565     whd_driver_t whd_driver;
1566 
1567     CHECK_IFP_NULL(ifp);
1568 
1569     whd_driver = ifp->whd_driver;
1570 
1571     CHECK_DRIVER_NULL(whd_driver);
1572 
1573     /* Keep WLAN awake while joining */
1574     WHD_WLAN_KEEP_AWAKE(whd_driver);
1575     ifp->role = WHD_STA_ROLE;
1576 
1577     if (ap->bss_type == WHD_BSS_TYPE_MESH)
1578     {
1579         return WHD_UNSUPPORTED;
1580     }
1581 
1582     if (ap->bss_type == WHD_BSS_TYPE_ADHOC)
1583     {
1584         security |= IBSS_ENABLED;
1585     }
1586 
1587     if (NULL_MAC(ap->BSSID.octet) )
1588     {
1589         WPRINT_WHD_ERROR( ("NULL address is not allowed/valid\n") );
1590         return WHD_BADARG;
1591     }
1592 
1593     if (BROADCAST_ID(ap->BSSID.octet) )
1594     {
1595         WPRINT_WHD_ERROR( ("Broadcast address is not allowed/valid in join with specific BSSID of AP\n") );
1596         return WHD_BADARG;
1597     }
1598 
1599     if ( (ap->SSID.length == 0) || (ap->SSID.length > (size_t)SSID_NAME_SIZE) )
1600     {
1601         WPRINT_WHD_ERROR( ("%s: failure: SSID length error\n", __func__) );
1602         return WHD_WLAN_BADSSIDLEN;
1603     }
1604 
1605     CHECK_RETURN(cy_rtos_init_semaphore(&join_semaphore, 1, 0) );
1606     result = whd_wifi_active_join_init(ifp, security, security_key, key_length, &join_semaphore);
1607 
1608     if (result == WHD_SUCCESS)
1609     {
1610         /* Check if soft AP is running, if so, move its current channel to the the destination AP */
1611         if ( (ifp->role == WHD_AP_ROLE) && (whd_wifi_is_ready_to_transceive(ifp) == WHD_SUCCESS) )
1612         {
1613             uint32_t current_softap_channel = 0;
1614             CHECK_RETURN(whd_wifi_get_channel(ifp, &current_softap_channel) );
1615             if (current_softap_channel != ap->channel)
1616             {
1617                 CHECK_RETURN(whd_wifi_set_channel(ifp, ap->channel) );
1618                 WPRINT_WHD_DEBUG( ("WARN: moving soft-AP channel from %" PRIu32 " to %d due to STA join\n",
1619                                    current_softap_channel, ap->channel) );
1620                 cy_rtos_delay_milliseconds(100);
1621             }
1622         }
1623 
1624         else
1625         {
1626             if (ap->bss_type == WHD_BSS_TYPE_ADHOC)
1627             {
1628                 CHECK_RETURN(whd_wifi_set_channel(ifp, ap->channel) );
1629             }
1630         }
1631 
1632         /* Join network */
1633         ext_join_params =
1634             (wl_extjoin_params_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(wl_extjoin_params_t), "join");
1635         CHECK_IOCTL_BUFFER(ext_join_params);
1636         memset(ext_join_params, 0, sizeof(wl_extjoin_params_t) );
1637 
1638         ext_join_params->ssid.SSID_len = ap->SSID.length;
1639         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
1640         memcpy(ext_join_params->ssid.SSID, ap->SSID.value, ext_join_params->ssid.SSID_len);
1641         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
1642         memcpy(&ext_join_params->assoc_params.bssid, &ap->BSSID, sizeof(whd_mac_t) );
1643         ext_join_params->scan_params.scan_type = 0;
1644         ext_join_params->scan_params.active_time = -1;
1645         ext_join_params->scan_params.home_time = -1;
1646         ext_join_params->scan_params.nprobes = -1;
1647         ext_join_params->scan_params.passive_time = -1;
1648         ext_join_params->assoc_params.bssid_cnt = 0;
1649         if (ap->channel)
1650         {
1651             ext_join_params->assoc_params.chanspec_num = (uint32_t)1;
1652             ext_join_params->assoc_params.chanspec_list[0] =
1653                 (wl_chanspec_t)htod16( (ap->channel |
1654                                         GET_C_VAR(whd_driver, CHANSPEC_BW_20) | GET_C_VAR(whd_driver,
1655                                                                                           CHANSPEC_CTL_SB_NONE) ) );
1656 
1657             /* set band properly */
1658             wl_band_for_channel = whd_channel_to_wl_band(whd_driver, ap->channel);
1659 
1660             ext_join_params->assoc_params.chanspec_list[0] |= wl_band_for_channel;
1661         }
1662         result = whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0);
1663 
1664         WPRINT_WHD_INFO( ("%s: set_ssid result (err %" PRIu32 "); left network\n", __func__, result) );
1665 
1666         /* Some firmware, e.g. for 4390, does not support the join IOVAR, so use the older IOCTL call instead */
1667         if (result == WHD_WLAN_UNSUPPORTED)
1668         {
1669             join_params =
1670                 (wl_join_params_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(wl_join_params_t) );
1671             CHECK_IOCTL_BUFFER(join_params);
1672             memset(join_params, 0, sizeof(wl_join_params_t) );
1673             DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
1674             memcpy(&join_params->ssid, &ext_join_params->ssid, sizeof(wlc_ssid_t) );
1675             ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
1676             memcpy(&join_params->params.bssid, &ap->BSSID, sizeof(whd_mac_t) );
1677             join_params->params.bssid_cnt = 0;
1678             if (ap->channel)
1679             {
1680                 join_params->params.chanspec_num = (uint32_t)1;
1681                 join_params->params.chanspec_list[0] =
1682                     (wl_chanspec_t)htod16( (ap->channel |
1683                                             GET_C_VAR(whd_driver,
1684                                                       CHANSPEC_BW_20) | GET_C_VAR(whd_driver, CHANSPEC_CTL_SB_NONE) ) );
1685 
1686                 /* set band properly */
1687                 join_params->params.chanspec_list[0] |= wl_band_for_channel;
1688             }
1689             result = whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_SSID, buffer, 0);
1690         }
1691 
1692         if (result == WHD_SUCCESS)
1693         {
1694 
1695             uint16_t chip_id = whd_chip_get_chip_id(whd_driver);
1696 
1697             CHECK_RETURN(whd_wifi_join_wait_for_complete(ifp, &join_semaphore) );
1698 
1699             if (chip_id == 0x4373)
1700             {
1701                 /* For 11 AC MAX throughput set the frame burst and MPDU per AMPDU */
1702                 CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_MPDU_PER_AMPDU, 16) );
1703             }
1704 
1705         }
1706         else
1707         {
1708             WPRINT_WHD_INFO( ("%s:3 not ready to transceive (err %" PRIu32 "); left network\n", __func__, result) );
1709         }
1710     }
1711     else
1712     {
1713         WPRINT_WHD_INFO( ("%s: active join init failed: (%" PRIu32 ")\n", __FUNCTION__, result) );
1714     }
1715     /* clean up from the join attempt */
1716     whd_wifi_active_join_deinit(ifp, &join_semaphore, result);
1717 
1718     CHECK_RETURN(result);
1719 
1720     return WHD_SUCCESS;
1721 }
1722 
whd_wifi_join(whd_interface_t ifp,const whd_ssid_t * ssid,whd_security_t auth_type,const uint8_t * security_key,uint8_t key_length)1723 uint32_t whd_wifi_join(whd_interface_t ifp, const whd_ssid_t *ssid, whd_security_t auth_type,
1724                        const uint8_t *security_key, uint8_t key_length)
1725 {
1726     cy_semaphore_t join_sema;
1727     whd_result_t result;
1728     whd_buffer_t buffer;
1729     wlc_ssid_t *ssid_params;
1730     whd_driver_t whd_driver;
1731 
1732     CHECK_IFP_NULL(ifp);
1733 
1734     whd_driver = ifp->whd_driver;
1735 
1736     CHECK_DRIVER_NULL(whd_driver);
1737 
1738     if (ssid == NULL)
1739     {
1740         WPRINT_WHD_ERROR( ("%s: failure: ssid is null\n", __func__) );
1741         return WHD_BADARG;
1742     }
1743 
1744     if ( (ssid->length == 0) || (ssid->length > (size_t)SSID_NAME_SIZE) )
1745     {
1746         WPRINT_WHD_ERROR( ("%s: failure: SSID length error\n", __func__) );
1747         return WHD_WLAN_BADSSIDLEN;
1748     }
1749 
1750     /* Keep WLAN awake while joining */
1751     WHD_WLAN_KEEP_AWAKE(whd_driver);
1752     ifp->role = WHD_STA_ROLE;
1753 
1754     CHECK_RETURN(cy_rtos_init_semaphore(&join_sema, 1, 0) );
1755     result = whd_wifi_active_join_init(ifp, auth_type, security_key, key_length, &join_sema);
1756 
1757     if (result == WHD_SUCCESS)
1758     {
1759         /* Join network */
1760         ssid_params = (struct wlc_ssid *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(wlc_ssid_t) );
1761         CHECK_IOCTL_BUFFER(ssid_params);
1762         memset(ssid_params, 0, sizeof(wlc_ssid_t) );
1763         ssid_params->SSID_len = htod32(ssid->length);
1764         memcpy(ssid_params->SSID, ssid->value, ssid_params->SSID_len);
1765         result = whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_SSID, buffer, 0);
1766 
1767         if (result == WHD_SUCCESS)
1768         {
1769             CHECK_RETURN(whd_wifi_join_wait_for_complete(ifp, &join_sema) );
1770         }
1771     }
1772 
1773     /* clean up from the join attempt */
1774     whd_wifi_active_join_deinit(ifp, &join_sema, result);
1775 
1776     return result;
1777 }
1778 
whd_wifi_leave(whd_interface_t ifp)1779 uint32_t whd_wifi_leave(whd_interface_t ifp)
1780 {
1781     whd_result_t result = WHD_SUCCESS;
1782     whd_driver_t whd_driver;
1783 
1784     CHECK_IFP_NULL(ifp);
1785 
1786     whd_driver = ifp->whd_driver;
1787 
1788     CHECK_DRIVER_NULL(whd_driver);
1789 
1790     /* If interface is greater than max return error */
1791     if (ifp->bsscfgidx >= WHD_INTERFACE_MAX)
1792     {
1793         WPRINT_WHD_ERROR( ("%s: Bad interface 2\n", __FUNCTION__) );
1794         return WHD_BADARG;
1795     }
1796     if (ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY] != WHD_EVENT_NOT_REGISTERED)
1797     {
1798         CHECK_RETURN(whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY]) );
1799         ifp->event_reg_list[WHD_JOIN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
1800     }
1801 
1802     /* Disassociate from AP */
1803     result = whd_wifi_set_ioctl_buffer(ifp, WLC_DISASSOC, NULL, 0);
1804 
1805     if (result != WHD_SUCCESS)
1806     {
1807         WPRINT_WHD_DEBUG( ("whd_sdpcm_send_ioctl(WLC_DISASSOC) failed:%" PRIu32 "\r\n", result) );
1808     }
1809 
1810     whd_driver->internal_info.whd_join_status[ifp->bsscfgidx] = 0;
1811     ifp->role = WHD_INVALID_ROLE;
1812 
1813     if (whd_driver->internal_info.active_join_mutex_initted == WHD_TRUE)
1814     {
1815         cy_rtos_deinit_semaphore(&whd_driver->internal_info.active_join_mutex);
1816         whd_driver->internal_info.active_join_mutex_initted = WHD_FALSE;
1817     }
1818     if (whd_driver->internal_info.active_join_semaphore)
1819     {
1820         cy_rtos_deinit_semaphore(whd_driver->internal_info.active_join_semaphore);
1821         whd_driver->internal_info.active_join_semaphore = NULL;
1822     }
1823 
1824 
1825     return WHD_SUCCESS;
1826 }
1827 
1828 /** Handles scan result events
1829  *
1830  *  This function receives scan record events, and parses them into a better format, then passes the results
1831  *  to the user application.
1832  *
1833  * @param event_header     : The event details
1834  * @param event_data       : The data for the event which contains the scan result structure
1835  * @param handler_user_data: data which will be passed to user application
1836  *
1837  * @returns : handler_user_data parameter
1838  *
1839  */
whd_wifi_scan_events_handler(whd_interface_t ifp,const whd_event_header_t * event_header,const uint8_t * event_data,void * handler_user_data)1840 static void *whd_wifi_scan_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
1841                                           const uint8_t *event_data,
1842                                           void *handler_user_data)
1843 {
1844     whd_scan_result_t *record;
1845     wl_escan_result_t *eresult;
1846     wl_bss_info_t *bss_info;
1847     uint16_t chanspec;
1848     uint32_t version;
1849     whd_tlv8_header_t *cp;
1850     uint32_t len;
1851     uint16_t ie_offset;
1852     uint32_t bss_info_length;
1853     country_info_ie_fixed_portion_t *country_info_ie;
1854     rsn_ie_fixed_portion_t *rsnie;
1855     wpa_ie_fixed_portion_t *wpaie = NULL;
1856     rsnx_ie_t *rsnxie = NULL;
1857     uint8_t rate_num;
1858     ht_capabilities_ie_t *ht_capabilities_ie = NULL;
1859     uint32_t count_tmp = 0;
1860     uint16_t temp16;
1861     uint16_t bss_count;
1862     whd_driver_t whd_driver = ifp->whd_driver;
1863 
1864     if (whd_driver->internal_info.scan_result_callback == NULL)
1865     {
1866         return handler_user_data;
1867     }
1868 
1869     if (event_header->status == WLC_E_STATUS_SUCCESS)
1870     {
1871         whd_driver->internal_info.scan_result_callback(NULL, handler_user_data, WHD_SCAN_COMPLETED_SUCCESSFULLY);
1872         whd_driver->internal_info.scan_result_callback = NULL;
1873         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY]);
1874         ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
1875         return handler_user_data;
1876     }
1877     if ( (event_header->status == WLC_E_STATUS_NEWSCAN) || (event_header->status == WLC_E_STATUS_NEWASSOC) ||
1878          (event_header->status == WLC_E_STATUS_ABORT) )
1879     {
1880         whd_driver->internal_info.scan_result_callback(NULL, handler_user_data, WHD_SCAN_ABORTED);
1881         whd_driver->internal_info.scan_result_callback = NULL;
1882         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY]);
1883         ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
1884         return handler_user_data;
1885     }
1886 
1887     if (event_header->status != WLC_E_STATUS_PARTIAL)
1888     {
1889         return handler_user_data;
1890     }
1891 
1892     eresult = (wl_escan_result_t *)event_data;
1893     bss_info = &eresult->bss_info[0];
1894     bss_count = dtoh16(eresult->bss_count);
1895 
1896     version = dtoh32(WHD_READ_32(&bss_info->version) );
1897     whd_minor_assert("wl_bss_info_t has wrong version", version == WL_BSS_INFO_VERSION);
1898 
1899     /* PNO bss info doesn't contain the correct bss info version */
1900     if (version != WL_BSS_INFO_VERSION)
1901     {
1902         whd_minor_assert("Invalid bss_info version returned by firmware\n", version != WL_BSS_INFO_VERSION);
1903 
1904         return handler_user_data;
1905     }
1906 
1907     whd_minor_assert("More than one result returned by firmware", bss_count == 1);
1908     if (bss_count != 1)
1909     {
1910         return handler_user_data;
1911     }
1912 
1913     /*
1914      * check the SSID length and bssinfo ie offset for buffer overflow
1915      */
1916     bss_info->ie_offset = dtoh16(bss_info->ie_offset);
1917     bss_info->ie_length = dtoh32(bss_info->ie_length);
1918     if ( (bss_info->SSID_len > sizeof(bss_info->SSID) ) || (bss_info->ie_offset < sizeof(wl_bss_info_t) ) ||
1919          (bss_info->ie_offset > (sizeof(wl_bss_info_t) + bss_info->ie_length) ) )
1920     {
1921         WPRINT_WHD_ERROR( ("Invalid bss length check %s: SSID_len:%d,ie_len:%" PRIu32 ",ie_off:%d\n", __FUNCTION__,
1922                            bss_info->SSID_len, bss_info->ie_length, bss_info->ie_offset) );
1923         whd_minor_assert(" bss length check failed\n", bss_info->SSID_len != sizeof(bss_info->SSID) );
1924         return handler_user_data;
1925     }
1926 
1927     /* Safe to access *whd_scan_result_ptr, as whd_scan_result_ptr == NULL case is handled above */
1928     record = (whd_scan_result_t *)(whd_driver->internal_info.whd_scan_result_ptr);
1929 
1930     /* Clear the last scan result data */
1931     memset(record, 0, sizeof(whd_scan_result_t) );
1932 
1933     /*
1934      * Totally ignore off channel results.  This can only happen with DSSS (1 and 2 Mb).  It is better to
1935      * totally ignore it when it happens.  It is hard to argue it is "significant" given that it can't
1936      * happen in 5G with OFDM (or other 2G modulations).  This is left here so that it could be
1937      * passed as a scan result for debugging only.
1938      */
1939     if (!(bss_info->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) )
1940     {
1941         record->flags |= WHD_SCAN_RESULT_FLAG_RSSI_OFF_CHANNEL;
1942         /* Comment out this return statement to pass along an off channel result for debugging */
1943         return handler_user_data;
1944     }
1945 
1946     /* Copy the SSID into the output record structure */
1947     record->SSID.length = (uint8_t)MIN_OF(sizeof(record->SSID.value), bss_info->SSID_len);
1948     memset(record->SSID.value, 0, sizeof(record->SSID.value) );
1949     memcpy(record->SSID.value, bss_info->SSID, record->SSID.length);
1950 
1951     /* Copy the BSSID into the output record structure */
1952     memcpy( (void *)record->BSSID.octet, (const void *)bss_info->BSSID.octet, sizeof(bss_info->BSSID.octet) );
1953 
1954     /* Copy the RSSI into the output record structure */
1955     record->signal_strength = ( int16_t )dtoh16( (WHD_READ_16(&bss_info->RSSI) ) );
1956 
1957     /* Find maximum data rate and put it in the output record structure */
1958     record->max_data_rate = 0;
1959     count_tmp = WHD_READ_32(&bss_info->rateset.count);
1960     if (count_tmp > 16)
1961     {
1962         count_tmp = 16;
1963     }
1964 
1965 #ifdef WPRINT_ENABLE_WHD_DEBUG
1966     /* print out scan results info */
1967     {
1968         char ea_buf[WHD_ETHER_ADDR_STR_LEN];
1969         char ssid_buf[SSID_NAME_SIZE + 1];
1970 
1971         WPRINT_WHD_DEBUG( ("Scan result: channel=%d signal=%d ssid=%s bssid=%s\n", record->channel,
1972                            record->signal_strength,
1973                            whd_ssid_to_string(record->SSID.value, record->SSID.length, ssid_buf,
1974                                               (uint8_t)sizeof(ssid_buf) ),
1975                            whd_ether_ntoa( (const uint8_t *)bss_info->BSSID.octet, ea_buf, sizeof(ea_buf) ) ) );
1976     }
1977 #endif /* WPRINT_ENABLE_WHD_DEBUG */
1978 
1979     for (rate_num = 0; rate_num < count_tmp; rate_num++)
1980     {
1981         uint32_t rate = RSPEC_TO_KBPS(bss_info->rateset.rates[rate_num]);
1982         if (record->max_data_rate < rate)
1983         {
1984             record->max_data_rate = rate;
1985         }
1986     }
1987 
1988     bss_info->capability = dtoh16(bss_info->capability);
1989 
1990     /* Write the BSS type into the output record structure */
1991     record->bss_type =
1992         ( (bss_info->capability & DOT11_CAP_ESS) !=
1993           0 ) ? WHD_BSS_TYPE_INFRASTRUCTURE : ( (bss_info->capability & DOT11_CAP_IBSS) !=
1994                                                 0 ) ? WHD_BSS_TYPE_ADHOC : WHD_BSS_TYPE_UNKNOWN;
1995 
1996     /* Determine the network security.
1997      * Some of this section has been copied from the standard broadcom host driver file wl/exe/wlu.c function wl_dump_wpa_rsn_ies
1998      */
1999 
2000     ie_offset = WHD_READ_16(&bss_info->ie_offset);
2001     cp = (whd_tlv8_header_t *)( ( (uint8_t *)bss_info ) + ie_offset );
2002     len = WHD_READ_32(&bss_info->ie_length);
2003     bss_info_length = WHD_READ_32(&bss_info->length);
2004 
2005     record->ie_ptr = (uint8_t *)cp;
2006     record->ie_len = len;
2007 
2008     /* Validate the length of the IE section */
2009     if ( (ie_offset > bss_info_length) || (len > bss_info_length - ie_offset) )
2010     {
2011         whd_minor_assert("Invalid ie length", 1 == 0);
2012         return handler_user_data;
2013     }
2014 
2015     /* Find an RSN IE (Robust-Security-Network Information-Element) */
2016     rsnie = (rsn_ie_fixed_portion_t *)whd_parse_dot11_tlvs(cp, len, DOT11_IE_ID_RSN);
2017 
2018     /* Find a WPA IE */
2019     if (rsnie == NULL)
2020     {
2021         whd_tlv8_header_t *parse = cp;
2022         uint32_t parse_len = len;
2023         while ( (wpaie =
2024                      (wpa_ie_fixed_portion_t *)whd_parse_tlvs(parse, parse_len, DOT11_IE_ID_VENDOR_SPECIFIC) ) != 0 )
2025         {
2026             if (whd_is_wpa_ie( (vendor_specific_ie_header_t *)wpaie, &parse, &parse_len ) != WHD_FALSE)
2027             {
2028                 break;
2029             }
2030         }
2031     }
2032 
2033     temp16 = WHD_READ_16(&bss_info->capability);
2034 
2035     /* Check if AP is configured for RSN */
2036     if ( (rsnie != NULL) &&
2037          (rsnie->tlv_header.length >= RSN_IE_MINIMUM_LENGTH + rsnie->pairwise_suite_count * sizeof(uint32_t) ) )
2038     {
2039         uint16_t a;
2040         uint32_t group_key_suite;
2041         akm_suite_portion_t *akm_suites;
2042         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2043         akm_suites = (akm_suite_portion_t *)&(rsnie->pairwise_suite_list[rsnie->pairwise_suite_count]);
2044         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2045         for (a = 0; a < akm_suites->akm_suite_count; ++a)
2046         {
2047             uint32_t akm_suite_list_item = ntoh32(akm_suites->akm_suite_list[a]) & 0xFF;
2048             if (akm_suite_list_item == (uint32_t)WHD_AKM_PSK)
2049             {
2050                 record->security |= WPA2_SECURITY;
2051             }
2052             if (akm_suite_list_item == (uint32_t)WHD_AKM_PSK_SHA256)
2053             {
2054                 record->security |= WPA2_SECURITY;
2055                 record->security |= WPA2_SHA256_SECURITY;
2056             }
2057             if (akm_suite_list_item == (uint32_t)WHD_AKM_SAE_SHA256)
2058             {
2059                 record->security |= WPA3_SECURITY;
2060             }
2061             if (akm_suite_list_item == (uint32_t)WHD_AKM_8021X)
2062             {
2063                 record->security |= WPA2_SECURITY;
2064                 record->security |= ENTERPRISE_ENABLED;
2065             }
2066             if (akm_suite_list_item == (uint32_t)WHD_AKM_FT_8021X)
2067             {
2068                 record->security |= WPA2_SECURITY;
2069                 record->security |= FBT_ENABLED;
2070                 record->security |= ENTERPRISE_ENABLED;
2071             }
2072             if (akm_suite_list_item == (uint32_t)WHD_AKM_FT_PSK)
2073             {
2074                 record->security |= WPA2_SECURITY;
2075                 record->security |= FBT_ENABLED;
2076             }
2077         }
2078 
2079         group_key_suite = ntoh32(rsnie->group_key_suite) & 0xFF;
2080         /* Check the RSN contents to see if there are any references to TKIP cipher (2) in the group key or pairwise keys, */
2081         /* If so it must be mixed mode. */
2082         if (group_key_suite == (uint32_t)WHD_CIPHER_TKIP)
2083         {
2084             record->security |= TKIP_ENABLED;
2085         }
2086         if (group_key_suite == (uint32_t)WHD_CIPHER_CCMP_128)
2087         {
2088             record->security |= AES_ENABLED;
2089         }
2090 
2091         for (a = 0; a < rsnie->pairwise_suite_count; ++a)
2092         {
2093             uint32_t pairwise_suite_list_item = ntoh32(rsnie->pairwise_suite_list[a]) & 0xFF;
2094             if (pairwise_suite_list_item == (uint32_t)WHD_CIPHER_TKIP)
2095             {
2096                 record->security |= TKIP_ENABLED;
2097             }
2098 
2099             if (pairwise_suite_list_item == (uint32_t)WHD_CIPHER_CCMP_128)
2100             {
2101                 record->security |= AES_ENABLED;
2102             }
2103         }
2104     }
2105     /* Check if AP is configured for WPA */
2106     else if ( (wpaie != NULL) &&
2107               (wpaie->vendor_specific_header.tlv_header.length >=
2108                WPA_IE_MINIMUM_LENGTH + wpaie->unicast_suite_count * sizeof(uint32_t) ) )
2109     {
2110         uint16_t a;
2111         uint32_t group_key_suite;
2112         akm_suite_portion_t *akm_suites;
2113 
2114         record->security = (whd_security_t)WPA_SECURITY;
2115         group_key_suite = ntoh32(wpaie->multicast_suite) & 0xFF;
2116         if (group_key_suite == (uint32_t)WHD_CIPHER_TKIP)
2117         {
2118             record->security |= TKIP_ENABLED;
2119         }
2120         if (group_key_suite == (uint32_t)WHD_CIPHER_CCMP_128)
2121         {
2122             record->security |= AES_ENABLED;
2123         }
2124 
2125         akm_suites = (akm_suite_portion_t *)&(wpaie->unicast_suite_list[wpaie->unicast_suite_count]);
2126         for (a = 0; a < akm_suites->akm_suite_count; ++a)
2127         {
2128             uint32_t akm_suite_list_item = ntoh32(akm_suites->akm_suite_list[a]) & 0xFF;
2129             if (akm_suite_list_item == (uint32_t)WHD_AKM_8021X)
2130             {
2131                 record->security |= ENTERPRISE_ENABLED;
2132             }
2133         }
2134 
2135         for (a = 0; a < wpaie->unicast_suite_count; ++a)
2136         {
2137             if (wpaie->unicast_suite_list[a][3] == (uint32_t)WHD_CIPHER_CCMP_128)
2138             {
2139                 record->security |= AES_ENABLED;
2140             }
2141         }
2142     }
2143     /* Check if AP is configured for WEP, that is, if the capabilities field indicates privacy, then security supports WEP */
2144     else if ( (temp16 & DOT11_CAP_PRIVACY) != 0 )
2145     {
2146         record->security = WHD_SECURITY_WEP_PSK;
2147     }
2148     else
2149     {
2150         /* Otherwise no security */
2151         record->security = WHD_SECURITY_OPEN;
2152     }
2153 
2154     /* Find a RSNX IE */
2155     rsnxie = (rsnx_ie_t *)whd_parse_tlvs(cp, len, DOT11_IE_ID_RSNX);
2156     if ( (rsnxie != NULL) && (rsnxie->tlv_header.length == DOT11_RSNX_CAP_LEN) &&
2157          (rsnxie->data[0] & (1 << DOT11_RSNX_SAE_H2E) ) )
2158     {
2159         record->flags |= WHD_SCAN_RESULT_FLAG_SAE_H2E;
2160     }
2161 
2162     /* Update the maximum data rate with 11n rates from the HT Capabilities IE */
2163     ht_capabilities_ie = (ht_capabilities_ie_t *)whd_parse_tlvs(cp, len, DOT11_IE_ID_HT_CAPABILITIES);
2164     if ( (ht_capabilities_ie != NULL) && (ht_capabilities_ie->tlv_header.length == HT_CAPABILITIES_IE_LENGTH) )
2165     {
2166         uint8_t a;
2167         uint8_t supports_40mhz =
2168             (ht_capabilities_ie->ht_capabilities_info & HT_CAPABILITIES_INFO_SUPPORTED_CHANNEL_WIDTH_SET) != 0 ? 1 : 0;
2169         uint8_t short_gi[2] =
2170         { (ht_capabilities_ie->ht_capabilities_info & HT_CAPABILITIES_INFO_SHORT_GI_FOR_20MHZ) != 0 ? 1 : 0,
2171           (ht_capabilities_ie->ht_capabilities_info & HT_CAPABILITIES_INFO_SHORT_GI_FOR_40MHZ) != 0 ? 1 : 0 };
2172 
2173         /* Find highest bit from MCS info */
2174         for (a = 31; a != 0xFF; --a)
2175         {
2176             if ( (ht_capabilities_ie->rx_mcs[a / 8] & (1 << (a % 8) ) ) != 0 )
2177             {
2178                 break;
2179             }
2180         }
2181         if (a != 0xFF)
2182         {
2183             record->max_data_rate =
2184                 ( uint32_t )(100UL * mcs_data_rate_lookup_table[a][supports_40mhz][short_gi[supports_40mhz]]);
2185         }
2186     }
2187 
2188     if (bss_info->flags & WL_BSS_FLAGS_FROM_BEACON)
2189     {
2190         record->flags |= WHD_SCAN_RESULT_FLAG_BEACON;
2191     }
2192 
2193     /* Get the channel for pre-N and control channel for n/HT or later */
2194     chanspec = dtoh16(WHD_READ_16(&bss_info->chanspec) );
2195     if (bss_info->n_cap)
2196     {
2197         /* Check control channel first.The channel that chanspec reports is the center frequency which might not be the same as
2198          * the 20 MHz channel that the beacons is on (primary or control channel) if it's an 802.11n/AC 40MHz or wider channel.
2199          */
2200         record->channel = bss_info->ctl_ch;
2201     }
2202     else
2203     {
2204         /* 11 a/b/g and 20MHz bandwidth only */
2205         record->channel = ( ( uint8_t )(chanspec & WL_CHANSPEC_CHAN_MASK) );
2206     }
2207 
2208     /* Find country info IE (Country-Information Information-Element) */
2209     country_info_ie = (country_info_ie_fixed_portion_t *)whd_parse_dot11_tlvs(cp, len, DOT11_IE_ID_COUNTRY);
2210     if ( (country_info_ie != NULL) && (country_info_ie->tlv_header.length >= COUNTRY_INFO_IE_MINIMUM_LENGTH) )
2211     {
2212         record->ccode[0] = UNSIGNED_CHAR_TO_CHAR(country_info_ie->ccode[0]);
2213         record->ccode[1] = UNSIGNED_CHAR_TO_CHAR(country_info_ie->ccode[1]);
2214     }
2215     record->band =
2216         ( (chanspec &
2217            GET_C_VAR(whd_driver,
2218                      CHANSPEC_BAND_MASK) ) ==
2219           GET_C_VAR(whd_driver, CHANSPEC_BAND_2G) ? WHD_802_11_BAND_2_4GHZ : WHD_802_11_BAND_5GHZ );
2220 
2221     whd_driver->internal_info.scan_result_callback(&whd_driver->internal_info.whd_scan_result_ptr, handler_user_data,
2222                                                    WHD_SCAN_INCOMPLETE);
2223 
2224     /* whd_driver->internal_info.scan_result_callback() can make whd_scan_result_ptr to NULL */
2225     if (whd_driver->internal_info.whd_scan_result_ptr == NULL)
2226     {
2227         whd_driver->internal_info.scan_result_callback(NULL, handler_user_data, WHD_SCAN_ABORTED);
2228         whd_driver->internal_info.scan_result_callback = NULL;
2229         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY]);
2230         ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
2231     }
2232 
2233     return handler_user_data;
2234 }
2235 
2236 /** Handles auth result events
2237  *
2238  *  This function receives scan record events, and parses them into a better format, then passes the results
2239  *  to the user application.
2240  *
2241  * @param event_header     : The event details
2242  * @param event_data       : The data for the event which contains the auth result structure
2243  * @param handler_user_data: data which will be passed to user application
2244  *
2245  * @returns : handler_user_data parameter
2246  *
2247  */
whd_wifi_auth_events_handler(whd_interface_t ifp,const whd_event_header_t * event_header,const uint8_t * event_data,void * handler_user_data)2248 static void *whd_wifi_auth_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
2249                                           const uint8_t *event_data,
2250                                           void *handler_user_data)
2251 {
2252     whd_driver_t whd_driver = ifp->whd_driver;
2253     whd_scan_result_t *record;
2254 
2255     if (whd_driver->internal_info.auth_result_callback == NULL)
2256     {
2257         WPRINT_WHD_ERROR( ("No set callback function in %s at %d \n", __func__, __LINE__) );
2258         return handler_user_data;
2259     }
2260     if (event_header->event_type == WLC_E_EXT_AUTH_REQ)
2261     {
2262         uint8_t flag = 0;
2263         if (whd_driver->internal_info.whd_scan_result_ptr)
2264         {
2265             record = (whd_scan_result_t *)(whd_driver->internal_info.whd_scan_result_ptr);
2266             if (record->flags & WHD_SCAN_RESULT_FLAG_SAE_H2E)
2267                 flag = 1;
2268             else
2269                 flag = 0;
2270 
2271         }
2272         whd_driver->internal_info.auth_result_callback( (void *)event_data, sizeof(whd_auth_req_status_t),
2273                                                         WHD_AUTH_EXT_REQ, &flag, handler_user_data );
2274         return handler_user_data;
2275     }
2276     else if (event_header->event_type == WLC_E_EXT_AUTH_FRAME_RX)
2277     {
2278         uint32_t mgmt_frame_len;
2279         wl_rx_mgmt_data_t *rxframe;
2280         uint8_t *frame;
2281 
2282         mgmt_frame_len = event_header->datalen - sizeof(wl_rx_mgmt_data_t);
2283         rxframe = (wl_rx_mgmt_data_t *)event_data;
2284         frame =  (uint8_t *)(rxframe + 1);
2285         whd_driver->internal_info.auth_result_callback( (void *)frame, mgmt_frame_len, WHD_AUTH_EXT_FRAME_RX, NULL,
2286                                                         handler_user_data );
2287         return handler_user_data;
2288 
2289     }
2290 
2291     return handler_user_data;
2292 }
2293 
whd_scan_count_handler(whd_scan_result_t ** result_ptr,void * user_data,whd_scan_status_t status)2294 static void whd_scan_count_handler(whd_scan_result_t **result_ptr, void *user_data, whd_scan_status_t status)
2295 {
2296     uint32_t result;
2297     whd_scan_userdata_t *scan_userdata = (whd_scan_userdata_t *)user_data;
2298 
2299     /* finished scan, either successfully or through an abort */
2300     if (status != WHD_SCAN_INCOMPLETE)
2301     {
2302         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2303         result = cy_rtos_set_semaphore(&scan_userdata->scan_semaphore, WHD_FALSE);
2304         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2305         if (result != WHD_SUCCESS)
2306             WPRINT_WHD_ERROR( ("Set semaphore failed in %s at %d \n", __func__, __LINE__) );
2307         return;
2308     }
2309 
2310     /* just count the available networks */
2311     scan_userdata->offset += 1;
2312 
2313     memset(*result_ptr, 0, sizeof(whd_scan_result_t) );
2314     return;
2315 }
2316 
whd_scan_result_handler(whd_scan_result_t ** result_ptr,void * user_data,whd_scan_status_t status)2317 static void whd_scan_result_handler(whd_scan_result_t **result_ptr, void *user_data, whd_scan_status_t status)
2318 {
2319     uint32_t result;
2320     whd_sync_scan_result_t *record;
2321     whd_scan_userdata_t *scan_userdata = (whd_scan_userdata_t *)user_data;
2322     whd_scan_result_t *current_result;
2323 
2324     /* Safe to access *scan_userdata. This static function registered only from whd_wifi_scan_synch and
2325      * not exposed for general use. The user_data is valid when passed in from whd_wifi_scan_synch.
2326      */
2327 
2328     /* finished scan, either successfully or through an abort */
2329     if (status != WHD_SCAN_INCOMPLETE)
2330     {
2331         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2332         result =  cy_rtos_set_semaphore(&scan_userdata->scan_semaphore, WHD_FALSE);
2333         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2334         if (result != WHD_SUCCESS)
2335             WPRINT_WHD_ERROR( ("Set semaphore failed in %s at %d \n", __func__, __LINE__) );
2336         return;
2337     }
2338 
2339     /* can't really keep anymore scan results */
2340     if (scan_userdata->offset == scan_userdata->count)
2341     {
2342         /*Offset and the count requested is reached. return with out saving the record details */
2343         memset(*result_ptr, 0, sizeof(whd_scan_result_t) );
2344         return;
2345     }
2346 
2347     /* Safe to access *result_ptr as result_ptr should only be NULL if the scan has completed or
2348      * been aborted, which is handled above
2349      */
2350     current_result = (whd_scan_result_t *)(*result_ptr);
2351 
2352     DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2353     /* Safe to access *scan_userdata, as noted above */
2354     record = (whd_sync_scan_result_t *)(&scan_userdata->aps[scan_userdata->offset]);
2355     ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2356 
2357     /* Copy the SSID into the output record structure */
2358     record->SSID.length = current_result->SSID.length;
2359     memset(record->SSID.value, 0, sizeof(record->SSID.value) );
2360     memcpy(record->SSID.value, current_result->SSID.value, record->SSID.length);
2361 
2362     /* Copy the BSSID into the output record structure */
2363     memcpy( (void *)record->BSSID.octet, (const void *)current_result->BSSID.octet,
2364             sizeof(current_result->BSSID.octet) );
2365 
2366     record->security = current_result->security;
2367     record->signal_strength = current_result->signal_strength;
2368     record->channel = current_result->channel;
2369 
2370     scan_userdata->offset += 1;
2371     memset(*result_ptr, 0, sizeof(whd_scan_result_t) );
2372     return;
2373 }
2374 
whd_wifi_scan_synch(whd_interface_t ifp,whd_sync_scan_result_t * scan_result,uint32_t * count)2375 uint32_t whd_wifi_scan_synch(whd_interface_t ifp,
2376                              whd_sync_scan_result_t *scan_result,
2377                              uint32_t *count
2378                              )
2379 {
2380     uint32_t result;
2381     whd_scan_result_t *scan_result_ptr;
2382     whd_scan_userdata_t scan_userdata;
2383     scan_userdata.count = *count;
2384     scan_userdata.aps = scan_result;
2385     scan_userdata.offset = 0;
2386 
2387     if (!ifp || !scan_result)
2388     {
2389         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
2390                            __func__, __LINE__) );
2391         return WHD_WLAN_BADARG;
2392     }
2393 
2394     DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2395     CHECK_RETURN(cy_rtos_init_semaphore(&scan_userdata.scan_semaphore, 1, 0) );
2396     ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2397 
2398     whd_scan_result_callback_t handler = (*count == 0)
2399                                          ? whd_scan_count_handler : whd_scan_result_handler;
2400 
2401     scan_result_ptr = (whd_scan_result_t *)whd_mem_malloc(sizeof(whd_scan_result_t) );
2402     if (scan_result_ptr == NULL)
2403     {
2404         goto error;
2405     }
2406     memset(scan_result_ptr, 0, sizeof(whd_scan_result_t) );
2407 
2408     if (whd_wifi_scan(ifp, WHD_SCAN_TYPE_ACTIVE, WHD_BSS_TYPE_ANY, NULL, NULL, NULL, NULL,
2409                       handler, (whd_scan_result_t *)scan_result_ptr, &scan_userdata) != WHD_SUCCESS)
2410     {
2411         WPRINT_WHD_INFO( ("Failed scan \n") );
2412         goto error;
2413     }
2414 
2415     DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2416     result = cy_rtos_get_semaphore(&scan_userdata.scan_semaphore, CY_RTOS_NEVER_TIMEOUT, WHD_FALSE);
2417     ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2418     whd_assert("Get semaphore failed", (result == CY_RSLT_SUCCESS) || (result == CY_RTOS_TIMEOUT) );
2419 
2420     DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
2421     result = cy_rtos_deinit_semaphore(&scan_userdata.scan_semaphore);
2422     ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
2423     if (WHD_SUCCESS != result)
2424     {
2425         WPRINT_WHD_INFO( ("Failed join (err %" PRIu32 ")\n", result) );
2426     }
2427     if (scan_result_ptr != NULL)
2428     {
2429         whd_mem_free(scan_result_ptr);
2430         scan_result_ptr = NULL;
2431     }
2432     *count = scan_userdata.offset;
2433 
2434     return WHD_SUCCESS;
2435 
2436 error:
2437     if (scan_result_ptr != NULL)
2438     {
2439         whd_mem_free(scan_result_ptr);
2440         scan_result_ptr = NULL;
2441     }
2442 
2443     return WHD_MALLOC_FAILURE;
2444 }
2445 
2446 /*
2447  * NOTE: search references of function wlu_get in wl/exe/wlu.c to find what format the returned IOCTL data is.
2448  */
whd_wifi_scan(whd_interface_t ifp,whd_scan_type_t scan_type,whd_bss_type_t bss_type,const whd_ssid_t * optional_ssid,const whd_mac_t * optional_mac,const uint16_t * optional_channel_list,const whd_scan_extended_params_t * optional_extended_params,whd_scan_result_callback_t callback,whd_scan_result_t * result_ptr,void * user_data)2449 uint32_t whd_wifi_scan(whd_interface_t ifp,
2450                        whd_scan_type_t scan_type,
2451                        whd_bss_type_t bss_type,
2452                        const whd_ssid_t *optional_ssid,
2453                        const whd_mac_t *optional_mac,
2454                        const uint16_t *optional_channel_list,
2455                        const whd_scan_extended_params_t *optional_extended_params,
2456                        whd_scan_result_callback_t callback,
2457                        whd_scan_result_t *result_ptr,
2458                        void *user_data
2459                        )
2460 {
2461     whd_buffer_t buffer;
2462     wl_escan_params_t *scan_params;
2463     uint16_t param_size = offsetof(wl_escan_params_t, params) + WL_SCAN_PARAMS_FIXED_SIZE;
2464     uint16_t channel_list_size = 0;
2465     whd_driver_t whd_driver = ifp->whd_driver;
2466     uint16_t event_entry = 0xFF;
2467 
2468     whd_assert("Bad args", callback != NULL);
2469 
2470     if ( (result_ptr == NULL) || (callback == NULL) )
2471     {
2472         return WHD_BADARG;
2473     }
2474 
2475     if (!( (scan_type == WHD_SCAN_TYPE_ACTIVE) || (scan_type == WHD_SCAN_TYPE_PASSIVE) ||
2476            (scan_type == WHD_SCAN_TYPE_PROHIBITED_CHANNELS) || (scan_type == WHD_SCAN_TYPE_NO_BSSID_FILTER) ) )
2477         return WHD_BADARG;
2478 
2479     if (!( (bss_type == WHD_BSS_TYPE_INFRASTRUCTURE) || (bss_type == WHD_BSS_TYPE_ADHOC) ||
2480            (bss_type == WHD_BSS_TYPE_ANY) ) )
2481         return WHD_BADARG;
2482 
2483     /* Determine size of channel_list, and add it to the parameter size so correct sized buffer can be allocated */
2484     if (optional_channel_list != NULL)
2485     {
2486         /* Look for entry with channel number 0, which suggests the end of channel_list */
2487         for (channel_list_size = 0; optional_channel_list[channel_list_size] != 0; channel_list_size++)
2488         {
2489         }
2490         param_size = ( uint16_t )(param_size + channel_list_size * sizeof(uint16_t) );
2491     }
2492 
2493     if (ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] != WHD_EVENT_NOT_REGISTERED)
2494     {
2495         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY]);
2496         ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
2497     }
2498     CHECK_RETURN(whd_management_set_event_handler(ifp, scan_events, whd_wifi_scan_events_handler, user_data,
2499                                                   &event_entry) );
2500     if (event_entry >= WHD_MAX_EVENT_SUBSCRIPTION)
2501     {
2502         WPRINT_WHD_ERROR( ("scan_events registration failed in function %s and line %d", __func__, __LINE__) );
2503         return WHD_UNFINISHED;
2504     }
2505     ifp->event_reg_list[WHD_SCAN_EVENT_ENTRY] = event_entry;
2506     /* Allocate a buffer for the IOCTL message */
2507     scan_params = (wl_escan_params_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, param_size, IOVAR_STR_ESCAN);
2508     CHECK_IOCTL_BUFFER(scan_params);
2509 
2510     /* Clear the scan parameters structure */
2511     memset(scan_params, 0, param_size);
2512 
2513     /* Fill in the appropriate details of the scan parameters structure */
2514     scan_params->version = htod32(ESCAN_REQ_VERSION);
2515     scan_params->action = htod16(WL_SCAN_ACTION_START);
2516     scan_params->params.scan_type = (int8_t)scan_type;
2517     scan_params->params.bss_type = (int8_t)bss_type;
2518 
2519     /* Fill out the SSID parameter if provided */
2520     if (optional_ssid != NULL)
2521     {
2522         scan_params->params.ssid.SSID_len = htod32(optional_ssid->length);
2523         memcpy(scan_params->params.ssid.SSID, optional_ssid->value, scan_params->params.ssid.SSID_len);
2524     }
2525 
2526     /* Fill out the BSSID parameter if provided */
2527     if (optional_mac != NULL)
2528     {
2529         memcpy(scan_params->params.bssid.octet, optional_mac, sizeof(whd_mac_t) );
2530     }
2531     else
2532     {
2533         memset(scan_params->params.bssid.octet, 0xff, sizeof(whd_mac_t) );
2534     }
2535 
2536     /* Fill out the extended parameters if provided */
2537     if (optional_extended_params != NULL)
2538     {
2539         scan_params->params.nprobes = (int32_t)htod32(optional_extended_params->number_of_probes_per_channel);
2540         scan_params->params.active_time =
2541             (int32_t)htod32(optional_extended_params->scan_active_dwell_time_per_channel_ms);
2542         scan_params->params.passive_time = (int32_t)htod32(
2543             optional_extended_params->scan_passive_dwell_time_per_channel_ms);
2544         scan_params->params.home_time = (int32_t)htod32(
2545             optional_extended_params->scan_home_channel_dwell_time_between_channels_ms);
2546     }
2547     else
2548     {
2549         scan_params->params.nprobes = (int32_t)htod32(-1);
2550         scan_params->params.active_time = (int32_t)htod32(-1);
2551         scan_params->params.passive_time = (int32_t)htod32(-1);
2552         scan_params->params.home_time = (int32_t)htod32(-1);
2553     }
2554 
2555     /* Copy the channel list parameter if provided */
2556     if ( (channel_list_size > 0) && (optional_channel_list != NULL) )
2557     {
2558         int i;
2559 
2560         for (i = 0; i < channel_list_size; i++)
2561         {
2562             scan_params->params.channel_list[i] = htod16(CH20MHZ_CHSPEC(optional_channel_list[i]) );
2563         }
2564         scan_params->params.channel_num = (int32_t)htod32(channel_list_size);
2565     }
2566 
2567     whd_driver->internal_info.scan_result_callback = callback;
2568     whd_driver->internal_info.whd_scan_result_ptr = result_ptr;
2569 
2570     /* Send the Incremental Scan IOVAR message - blocks until the response is received */
2571 
2572     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
2573 
2574     return WHD_SUCCESS;
2575 }
2576 
whd_wifi_stop_scan(whd_interface_t ifp)2577 uint32_t whd_wifi_stop_scan(whd_interface_t ifp)
2578 {
2579     whd_buffer_t buffer;
2580     wl_escan_params_t *scan_params;
2581     whd_driver_t whd_driver;
2582 
2583     CHECK_IFP_NULL(ifp);
2584     whd_driver = ifp->whd_driver;
2585     CHECK_DRIVER_NULL(whd_driver)
2586 
2587     /* Allocate a buffer for the IOCTL message */
2588     scan_params = (wl_escan_params_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(wl_escan_params_t),
2589                                                                 IOVAR_STR_ESCAN);
2590     CHECK_IOCTL_BUFFER(scan_params);
2591     /* Clear the scan parameters structure */
2592     memset(scan_params, 0, sizeof(wl_escan_params_t) );
2593 
2594     /* Fill in the appropriate details of the scan parameters structure */
2595     scan_params->version = htod32(ESCAN_REQ_VERSION);
2596     scan_params->action = htod16(WL_SCAN_ACTION_ABORT);
2597 
2598     /* Send the Scan IOVAR message to abort scan*/
2599     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, 0) );
2600 
2601     return WHD_SUCCESS;
2602 }
2603 
whd_wifi_external_auth_request(whd_interface_t ifp,whd_auth_result_callback_t callback,void * result_ptr,void * user_data)2604 uint32_t whd_wifi_external_auth_request(whd_interface_t ifp,
2605                                         whd_auth_result_callback_t callback,
2606                                         void *result_ptr,
2607                                         void *user_data
2608                                         )
2609 {
2610     CHECK_IFP_NULL(ifp);
2611     whd_driver_t whd_driver = ifp->whd_driver;
2612     uint16_t event_entry = 0xFF;
2613 
2614     whd_assert("Bad args", callback != NULL);
2615 
2616     if (ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY] != WHD_EVENT_NOT_REGISTERED)
2617     {
2618         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY]);
2619         ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
2620     }
2621     CHECK_RETURN(whd_management_set_event_handler(ifp, auth_events, whd_wifi_auth_events_handler, user_data,
2622                                                   &event_entry) );
2623     if (event_entry >= WHD_MAX_EVENT_SUBSCRIPTION)
2624     {
2625         WPRINT_WHD_ERROR( ("auth_events registration failed in function %s and line %d", __func__, __LINE__) );
2626         return WHD_UNFINISHED;
2627     }
2628     ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY] = event_entry;
2629 
2630 
2631     whd_driver->internal_info.auth_result_callback = callback;
2632 
2633     return WHD_SUCCESS;
2634 }
2635 
whd_wifi_stop_external_auth_request(whd_interface_t ifp)2636 uint32_t whd_wifi_stop_external_auth_request(whd_interface_t ifp)
2637 {
2638     whd_driver_t whd_driver;
2639 
2640     CHECK_IFP_NULL(ifp);
2641     whd_driver = ifp->whd_driver;
2642     CHECK_DRIVER_NULL(whd_driver)
2643 
2644     if (ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY] != WHD_EVENT_NOT_REGISTERED)
2645     {
2646         whd_wifi_deregister_event_handler(ifp, ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY]);
2647         ifp->event_reg_list[WHD_AUTH_EVENT_ENTRY] = WHD_EVENT_NOT_REGISTERED;
2648     }
2649     whd_driver->internal_info.auth_result_callback = NULL;
2650     return WHD_SUCCESS;
2651 }
2652 
whd_wifi_deauth_sta(whd_interface_t ifp,whd_mac_t * mac,whd_dot11_reason_code_t reason)2653 uint32_t  whd_wifi_deauth_sta(whd_interface_t ifp, whd_mac_t *mac, whd_dot11_reason_code_t reason)
2654 {
2655     whd_result_t result;
2656     scb_val_t *scb_val;
2657     whd_buffer_t buffer1;
2658     whd_driver_t whd_driver;
2659 
2660     CHECK_IFP_NULL(ifp);
2661 
2662     whd_driver = ifp->whd_driver;
2663 
2664     if (mac == NULL)
2665     {
2666         uint8_t *buffer = NULL;
2667         whd_maclist_t *clients = NULL;
2668         const whd_mac_t *current;
2669         wl_bss_info_t ap_info;
2670         whd_security_t sec;
2671         uint32_t max_clients = 0;
2672         size_t size = 0;
2673 
2674         result = whd_wifi_ap_get_max_assoc(ifp, &max_clients);
2675         if (result != WHD_SUCCESS)
2676         {
2677             WPRINT_WHD_ERROR( ("Failed to get max number of associated clients\n") );
2678             max_clients = 5;
2679         }
2680 
2681         size = (sizeof(uint32_t) + (max_clients * sizeof(whd_mac_t) ) );
2682         buffer = whd_mem_calloc(1, size);
2683 
2684         if (buffer == NULL)
2685         {
2686             WPRINT_WHD_ERROR( ("Unable to allocate memory for associated clients list, %s failed at line %d \n",
2687                                __func__, __LINE__) );
2688             return WHD_MALLOC_FAILURE;
2689         }
2690 
2691         clients = (whd_maclist_t *)buffer;
2692         clients->count = max_clients;
2693         memset(&ap_info, 0, sizeof(wl_bss_info_t) );
2694 
2695         result = whd_wifi_get_associated_client_list(ifp, clients, (uint16_t)size);
2696         if (result != WHD_SUCCESS)
2697         {
2698             WPRINT_WHD_ERROR( ("Failed to get client list, %s failed at line %d \n", __func__, __LINE__) );
2699             whd_mem_free(buffer);
2700             return result;
2701         }
2702 
2703         current = &clients->mac_list[0];
2704         result = whd_wifi_get_ap_info(ifp, &ap_info, &sec);
2705         if (result != WHD_SUCCESS)
2706         {
2707             WPRINT_WHD_ERROR( ("Function %s failed at line %d \n", __func__, __LINE__) );
2708             whd_mem_free(buffer);
2709             return result;
2710         }
2711 
2712 
2713         while ( (clients->count > 0) && (!(NULL_MAC(current->octet) ) ) )
2714         {
2715             if (memcmp(current->octet, &(ap_info.BSSID), sizeof(whd_mac_t) ) != 0)
2716             {
2717                 WPRINT_WHD_INFO( ("Deauthenticating STA MAC: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", current->octet[0],
2718                                   current->octet[1], current->octet[2], current->octet[3], current->octet[4],
2719                                   current->octet[5]) );
2720 
2721                 scb_val = (scb_val_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer1, sizeof(scb_val_t) );
2722                 if (scb_val == NULL)
2723                 {
2724                     WPRINT_WHD_ERROR( ("Buffer alloc failed in function %s at line %d \n", __func__, __LINE__) );
2725                     whd_mem_free(buffer);
2726                     return WHD_BUFFER_ALLOC_FAIL;
2727                 }
2728                 memset( (char *)scb_val, 0, sizeof(scb_val_t) );
2729                 memcpy( (char *)&scb_val->ea, (char *)current, sizeof(whd_mac_t) );
2730                 scb_val->val = (uint32_t)reason;
2731                 result = whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SCB_DEAUTHENTICATE_FOR_REASON, buffer1, 0);
2732 
2733                 if (result != WHD_SUCCESS)
2734                 {
2735                     WPRINT_WHD_ERROR( ("Failed to deauth client\n") );
2736                 }
2737             }
2738 
2739             --clients->count;
2740             ++current;
2741         }
2742 
2743         whd_mem_free(buffer);
2744 
2745         return WHD_SUCCESS;
2746     }
2747 
2748     scb_val = (scb_val_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer1, sizeof(scb_val_t) );
2749     CHECK_IOCTL_BUFFER(scb_val);
2750     memset( (char *)scb_val, 0, sizeof(scb_val_t) );
2751     memcpy( (char *)&scb_val->ea, (char *)mac, sizeof(whd_mac_t) );
2752     scb_val->val = (uint32_t)reason;
2753     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SCB_DEAUTHENTICATE_FOR_REASON, buffer1, 0) );
2754 
2755     return WHD_SUCCESS;
2756 }
2757 
whd_wifi_get_mac_address(whd_interface_t ifp,whd_mac_t * mac)2758 uint32_t whd_wifi_get_mac_address(whd_interface_t ifp, whd_mac_t *mac)
2759 {
2760     whd_buffer_t buffer;
2761     whd_buffer_t response;
2762     whd_driver_t whd_driver;
2763 
2764     CHECK_IFP_NULL(ifp);
2765 
2766     if (mac == NULL)
2767         return WHD_BADARG;
2768 
2769     whd_driver = ifp->whd_driver;
2770 
2771     CHECK_DRIVER_NULL(whd_driver);
2772 
2773     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(whd_mac_t), IOVAR_STR_CUR_ETHERADDR) );
2774 
2775     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
2776 
2777     memcpy(mac, whd_buffer_get_current_piece_data_pointer(whd_driver, response), sizeof(whd_mac_t) );
2778     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
2779 
2780     return WHD_SUCCESS;
2781 }
2782 
whd_wifi_get_bssid(whd_interface_t ifp,whd_mac_t * bssid)2783 uint32_t whd_wifi_get_bssid(whd_interface_t ifp, whd_mac_t *bssid)
2784 {
2785     whd_buffer_t buffer;
2786     whd_buffer_t response;
2787     whd_result_t result;
2788     whd_driver_t whd_driver;
2789     uint8_t  *data = NULL;
2790     CHECK_IFP_NULL(ifp);
2791 
2792     if (bssid == NULL)
2793         return WHD_BADARG;
2794 
2795     whd_driver = ifp->whd_driver;
2796 
2797     CHECK_DRIVER_NULL(whd_driver);
2798 
2799     if ( (ifp->role == WHD_STA_ROLE) || (ifp->role == WHD_AP_ROLE) )
2800     {
2801         memset(bssid, 0, sizeof(whd_mac_t) );
2802         CHECK_IOCTL_BUFFER(whd_cdc_get_ioctl_buffer(whd_driver, &buffer, sizeof(whd_mac_t) ) );
2803         if ( (result =
2804                   whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_BSSID, buffer, &response) ) == WHD_SUCCESS )
2805         {
2806             data = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
2807             CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
2808             memcpy(bssid->octet, data, sizeof(whd_mac_t) );
2809             CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
2810         }
2811         return result;
2812     }
2813     else if (ifp->role == WHD_INVALID_ROLE)
2814     {
2815         WPRINT_WHD_ERROR( ("STA not associated with AP\n") );
2816         return WHD_WLAN_NOTASSOCIATED;
2817     }
2818     else
2819     {
2820         return WHD_UNSUPPORTED;
2821     }
2822 }
2823 
whd_wifi_ap_get_max_assoc(whd_interface_t ifp,uint32_t * max_assoc)2824 uint32_t whd_wifi_ap_get_max_assoc(whd_interface_t ifp, uint32_t *max_assoc)
2825 {
2826     if (!ifp || !max_assoc)
2827     {
2828         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
2829                            __func__, __LINE__) );
2830         return WHD_WLAN_BADARG;
2831     }
2832 
2833     return whd_wifi_get_iovar_value(ifp, IOVAR_STR_MAX_ASSOC, max_assoc);
2834 }
2835 
whd_wifi_get_associated_client_list(whd_interface_t ifp,void * client_list_buffer,uint16_t buffer_length)2836 uint32_t whd_wifi_get_associated_client_list(whd_interface_t ifp, void *client_list_buffer, uint16_t buffer_length)
2837 {
2838     whd_buffer_t buffer;
2839     whd_buffer_t response;
2840     whd_result_t result;
2841     whd_maclist_t *data = NULL;
2842     uint8_t *pdata = NULL;
2843     whd_driver_t whd_driver;
2844 
2845     CHECK_IFP_NULL(ifp);
2846 
2847     whd_driver = ifp->whd_driver;
2848 
2849     CHECK_DRIVER_NULL(whd_driver);
2850 
2851     /* Check if soft AP interface is up, if not, return a count of 0 as a result */
2852     result = whd_wifi_is_ready_to_transceive(ifp);
2853     if ( (result == WHD_SUCCESS) && (ifp->role == WHD_AP_ROLE) )
2854     {
2855         data = (whd_maclist_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, buffer_length);
2856         CHECK_IOCTL_BUFFER(data);
2857         memset(data, 0, buffer_length);
2858         data->count = htod32( ( (whd_maclist_t *)client_list_buffer )->count );
2859 
2860         CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_ASSOCLIST, buffer, &response) );
2861         pdata = whd_buffer_get_current_piece_data_pointer(whd_driver,  response);
2862         CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
2863         memcpy(client_list_buffer, (void *)pdata,
2864                (size_t)MIN_OF(whd_buffer_get_current_piece_size(whd_driver, response), buffer_length) );
2865 
2866         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
2867     }
2868     else if (result == WHD_INTERFACE_NOT_UP)
2869     {
2870         /* not up, so can't have associated clients */
2871         ( (whd_maclist_t *)client_list_buffer )->count = 0;
2872     }
2873     else
2874     {
2875         WPRINT_WHD_ERROR( ("Invalid Interface\n") );
2876         return WHD_INVALID_INTERFACE;
2877     }
2878     return result;
2879 }
2880 
whd_wifi_get_ap_info(whd_interface_t ifp,wl_bss_info_t * ap_info,whd_security_t * security)2881 uint32_t whd_wifi_get_ap_info(whd_interface_t ifp, wl_bss_info_t *ap_info, whd_security_t *security)
2882 {
2883     whd_buffer_t buffer;
2884     whd_buffer_t response;
2885     uint32_t *data;
2886     uint8_t  *pdata = NULL;
2887     uint32_t security_value; /* hold misc security values */
2888     whd_driver_t whd_driver;
2889     CHECK_IFP_NULL(ifp);
2890 
2891     if ( (ap_info == NULL) || (security == NULL) )
2892         return WHD_BADARG;
2893 
2894     whd_driver = ifp->whd_driver;
2895 
2896     CHECK_DRIVER_NULL(whd_driver);
2897     /* Read the BSS info */
2898     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, WLC_IOCTL_SMLEN);
2899     CHECK_IOCTL_BUFFER(data);
2900     *data = WLC_IOCTL_SMLEN;
2901     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_BSS_INFO, buffer, &response) );
2902     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
2903     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
2904     memcpy(ap_info, (void *)(pdata + 4), sizeof(wl_bss_info_t) );
2905     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
2906 
2907     /* Read the WSEC setting */
2908     CHECK_RETURN(whd_wifi_get_ioctl_value(ifp, WLC_GET_WSEC, &security_value) );
2909     security_value = security_value & SECURITY_MASK;
2910     *security = ( whd_security_t )(security_value);
2911 
2912     if (*security == WHD_SECURITY_WEP_PSK)
2913     {
2914         /* Read the WEP auth setting */
2915         CHECK_RETURN(whd_wifi_get_ioctl_value(ifp, WLC_GET_AUTH, &security_value) );
2916 
2917         if (security_value == SHARED_AUTH)
2918         {
2919             *security |= SHARED_ENABLED;
2920         }
2921     }
2922     else if ( (*security & (TKIP_ENABLED | AES_ENABLED) ) != 0 )
2923     {
2924         /* Read the WPA auth setting */
2925         CHECK_RETURN(whd_wifi_get_ioctl_value(ifp, WLC_GET_WPA_AUTH, &security_value) );
2926 
2927         if (security_value == WPA2_AUTH_PSK)
2928         {
2929             *security |= WPA2_SECURITY;
2930         }
2931         else if (security_value == WPA_AUTH_PSK)
2932         {
2933             *security |= WPA_SECURITY;
2934         }
2935     }
2936     else if (*security != WHD_SECURITY_OPEN)
2937     {
2938         *security = WHD_SECURITY_UNKNOWN;
2939         WPRINT_WHD_ERROR( ("Unknown security type, %s failed at line %d \n", __func__, __LINE__) );
2940         return WHD_UNKNOWN_SECURITY_TYPE;
2941     }
2942 
2943     return WHD_SUCCESS;
2944 }
2945 
whd_wifi_enable_powersave(whd_interface_t ifp)2946 uint32_t whd_wifi_enable_powersave(whd_interface_t ifp)
2947 {
2948     whd_buffer_t buffer;
2949     uint32_t *data;
2950     whd_driver_t whd_driver;
2951     CHECK_IFP_NULL(ifp);
2952 
2953     whd_driver = ifp->whd_driver;
2954 
2955     CHECK_DRIVER_NULL(whd_driver);
2956 
2957     /* Set legacy powersave mode - PM1 */
2958     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)4);
2959     CHECK_IOCTL_BUFFER(data);
2960     *data = htod32( (uint32_t)PM1_POWERSAVE_MODE );
2961 
2962     RETURN_WITH_ASSERT(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_PM, buffer, NULL) );
2963 }
2964 
whd_wifi_get_powersave_mode(whd_interface_t ifp,uint32_t * value)2965 uint32_t whd_wifi_get_powersave_mode(whd_interface_t ifp, uint32_t *value)
2966 {
2967     whd_driver_t whd_driver;
2968 
2969     CHECK_IFP_NULL(ifp);
2970 
2971     if (value == NULL)
2972         return WHD_BADARG;
2973 
2974     whd_driver = ifp->whd_driver;
2975 
2976     CHECK_DRIVER_NULL(whd_driver);
2977 
2978     return whd_wifi_get_ioctl_value(ifp, WLC_GET_PM, value);
2979 }
2980 
whd_wifi_enable_powersave_with_throughput(whd_interface_t ifp,uint16_t return_to_sleep_delay_ms)2981 uint32_t whd_wifi_enable_powersave_with_throughput(whd_interface_t ifp, uint16_t return_to_sleep_delay_ms)
2982 {
2983     whd_buffer_t buffer;
2984     uint32_t *data;
2985     whd_driver_t whd_driver;
2986     uint16_t chip_id;
2987     CHECK_IFP_NULL(ifp);
2988 
2989     whd_driver = ifp->whd_driver;
2990 
2991     CHECK_DRIVER_NULL(whd_driver);
2992 
2993     if (return_to_sleep_delay_ms < PM2_SLEEP_RET_TIME_MIN)
2994     {
2995         WPRINT_WHD_ERROR( ("Delay too short, %s failed at line %d \n", __func__, __LINE__) );
2996         return WHD_DELAY_TOO_SHORT;
2997     }
2998     else if (return_to_sleep_delay_ms > PM2_SLEEP_RET_TIME_MAX)
2999     {
3000         WPRINT_WHD_ERROR( ("Delay too long, %s failed at line %d \n", __func__, __LINE__) );
3001         return WHD_DELAY_TOO_LONG;
3002     }
3003 
3004     /* Set the maximum time to wait before going back to sleep */
3005     CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_PM2_SLEEP_RET,
3006                                           (uint32_t)(return_to_sleep_delay_ms / 10) * 10) );
3007     chip_id = whd_chip_get_chip_id(whd_driver);
3008 
3009     if (chip_id == 43362)
3010     {
3011         CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_PM_LIMIT, NULL_FRAMES_WITH_PM_SET_LIMIT) );
3012     }
3013 
3014     /* set PM2 fast return to sleep powersave mode */
3015     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)4);
3016     CHECK_IOCTL_BUFFER(data);
3017     *data = htod32( (uint32_t)PM2_POWERSAVE_MODE );
3018 
3019     RETURN_WITH_ASSERT(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_PM, buffer, NULL) );
3020 }
3021 
whd_wifi_disable_powersave(whd_interface_t ifp)3022 uint32_t whd_wifi_disable_powersave(whd_interface_t ifp)
3023 {
3024     whd_buffer_t buffer;
3025     whd_driver_t whd_driver;
3026 
3027     CHECK_IFP_NULL(ifp);
3028 
3029     whd_driver = ifp->whd_driver;
3030 
3031     CHECK_DRIVER_NULL(whd_driver);
3032 
3033     uint32_t *data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)4);
3034 
3035     CHECK_IOCTL_BUFFER(data);
3036     *data = htod32( (uint32_t)NO_POWERSAVE_MODE );
3037     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, WLC_SET_PM, buffer, NULL) );
3038     return WHD_SUCCESS;
3039 }
3040 
whd_wifi_register_multicast_address(whd_interface_t ifp,const whd_mac_t * mac)3041 uint32_t whd_wifi_register_multicast_address(whd_interface_t ifp, const whd_mac_t *mac)
3042 {
3043     whd_buffer_t buffer;
3044     whd_buffer_t response;
3045     uint16_t a;
3046     mcast_list_t *orig_mcast_list;
3047     mcast_list_t *new_mcast_list;
3048     whd_driver_t whd_driver;
3049 
3050     if (!ifp || !mac || !ETHER_ISMULTI(mac) )
3051     {
3052         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3053                            __func__, __LINE__) );
3054         return WHD_WLAN_BADARG;
3055     }
3056 
3057     whd_driver = ifp->whd_driver;
3058 
3059     CHECK_DRIVER_NULL(whd_driver);
3060 
3061     /* Get the current multicast list */
3062     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer,
3063                                                 sizeof(uint32_t) + MAX_SUPPORTED_MCAST_ENTRIES *
3064                                                 sizeof(whd_mac_t), IOVAR_STR_MCAST_LIST) );
3065     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3066 
3067     /* Verify address is not currently registered */
3068     orig_mcast_list = (mcast_list_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3069     CHECK_PACKET_NULL(orig_mcast_list, WHD_NO_REGISTER_FUNCTION_POINTER);
3070     orig_mcast_list->entry_count = dtoh32(orig_mcast_list->entry_count);
3071     for (a = 0; a < orig_mcast_list->entry_count; ++a)
3072     {
3073         /* Check if any address matches */
3074         if (0 == memcmp(mac, &orig_mcast_list->macs[a], sizeof(whd_mac_t) ) )
3075         {
3076             /* A matching address has been found so we can stop now. */
3077             CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3078             return WHD_SUCCESS;
3079         }
3080     }
3081 
3082     /* Add the provided address to the list and write the new multicast list */
3083     new_mcast_list = (mcast_list_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
3084                                                               ( uint16_t )(sizeof(uint32_t) +
3085                                                                            (orig_mcast_list->entry_count + 1) *
3086                                                                            sizeof(whd_mac_t) ),
3087                                                               IOVAR_STR_MCAST_LIST);
3088     CHECK_IOCTL_BUFFER(new_mcast_list);
3089     new_mcast_list->entry_count = orig_mcast_list->entry_count;
3090     memcpy(new_mcast_list->macs, orig_mcast_list->macs, orig_mcast_list->entry_count * sizeof(whd_mac_t) );
3091     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3092     memcpy(&new_mcast_list->macs[new_mcast_list->entry_count], mac, sizeof(whd_mac_t) );
3093     ++new_mcast_list->entry_count;
3094     new_mcast_list->entry_count = htod32(new_mcast_list->entry_count);
3095     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3096 
3097 }
3098 
whd_wifi_unregister_multicast_address(whd_interface_t ifp,const whd_mac_t * mac)3099 uint32_t whd_wifi_unregister_multicast_address(whd_interface_t ifp, const whd_mac_t *mac)
3100 {
3101     whd_buffer_t buffer;
3102     whd_buffer_t response;
3103     uint16_t a;
3104     mcast_list_t *orig_mcast_list;
3105     whd_driver_t whd_driver;
3106 
3107     if (!ifp || !mac || !ETHER_ISMULTI(mac) )
3108     {
3109         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3110                            __func__, __LINE__) );
3111         return WHD_WLAN_BADARG;
3112     }
3113 
3114     whd_driver = ifp->whd_driver;
3115 
3116     CHECK_DRIVER_NULL(whd_driver);
3117 
3118     /* Get the current multicast list */
3119     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer,
3120                                                 sizeof(uint32_t) + MAX_SUPPORTED_MCAST_ENTRIES *
3121                                                 sizeof(whd_mac_t), IOVAR_STR_MCAST_LIST) );
3122     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3123 
3124     /* Find the address, assuming it is part of the list */
3125     orig_mcast_list = (mcast_list_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3126     orig_mcast_list->entry_count = dtoh32(orig_mcast_list->entry_count);
3127     if (orig_mcast_list->entry_count != 0)
3128     {
3129         mcast_list_t *new_mcast_list = (mcast_list_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
3130                                                                                 ( uint16_t )(sizeof(uint32_t) +
3131                                                                                              (orig_mcast_list->
3132                                                                                               entry_count - 1) *
3133                                                                                              sizeof(whd_mac_t) ),
3134                                                                                 IOVAR_STR_MCAST_LIST);
3135         CHECK_IOCTL_BUFFER(new_mcast_list);
3136 
3137         for (a = 0; a < orig_mcast_list->entry_count; ++a)
3138         {
3139             WPRINT_WHD_INFO( ("MAC: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", orig_mcast_list->macs[a].octet[0],
3140                               orig_mcast_list->macs[a].octet[1], orig_mcast_list->macs[a].octet[2],
3141                               orig_mcast_list->macs[a].octet[3], orig_mcast_list->macs[a].octet[4],
3142                               orig_mcast_list->macs[a].octet[5]) );
3143             if (0 == memcmp(mac, &orig_mcast_list->macs[a], sizeof(whd_mac_t) ) )
3144             {
3145                 /* Copy the existing list up to the matching address */
3146                 memcpy(new_mcast_list->macs, orig_mcast_list->macs, a * sizeof(whd_mac_t) );
3147 
3148                 /* Skip the current address and copy the remaining entries */
3149                 memcpy(&new_mcast_list->macs[a], &orig_mcast_list->macs[a + 1],
3150                        ( size_t )(orig_mcast_list->entry_count - a - 1) * sizeof(whd_mac_t) );
3151 
3152                 new_mcast_list->entry_count = orig_mcast_list->entry_count - 1;
3153                 CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3154                 new_mcast_list->entry_count = htod32(new_mcast_list->entry_count);
3155                 RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3156             }
3157         }
3158         /* There was something in the list, but the request MAC wasn't there */
3159         CHECK_RETURN(whd_buffer_release(whd_driver, buffer, WHD_NETWORK_TX) );
3160     }
3161     /* If we get here than the address wasn't in the list or the list was empty */
3162     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3163     WPRINT_WHD_ERROR( ("whd_wifi_unregister_multicast_address address not registered yet \n") );
3164     return WHD_DOES_NOT_EXIST;
3165 }
3166 
whd_wifi_set_listen_interval(whd_interface_t ifp,uint8_t listen_interval,whd_listen_interval_time_unit_t time_unit)3167 uint32_t whd_wifi_set_listen_interval(whd_interface_t ifp, uint8_t listen_interval,
3168                                       whd_listen_interval_time_unit_t time_unit)
3169 {
3170     uint8_t listen_interval_dtim;
3171 
3172     CHECK_IFP_NULL(ifp);
3173 
3174     switch (time_unit)
3175     {
3176         case WHD_LISTEN_INTERVAL_TIME_UNIT_DTIM:
3177         {
3178             listen_interval_dtim = listen_interval;
3179             break;
3180         }
3181         case WHD_LISTEN_INTERVAL_TIME_UNIT_BEACON:
3182         {
3183             /* If the wake interval measured in DTIMs is set to 0, the wake interval is measured in beacon periods */
3184             listen_interval_dtim = 0;
3185 
3186             /* The wake period is measured in beacon periods, set the value as required */
3187             CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_LISTEN_INTERVAL_BEACON, listen_interval) );
3188             break;
3189         }
3190         default:
3191             WPRINT_WHD_ERROR( ("whd_wifi_set_listen_interval: Invalid Time unit specified \n") );
3192             return WHD_BADARG;
3193     }
3194 
3195     CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_LISTEN_INTERVAL_DTIM, listen_interval_dtim) );
3196 
3197     CHECK_RETURN(whd_wifi_set_iovar_value(ifp, IOVAR_STR_LISTEN_INTERVAL_ASSOC, listen_interval) );
3198 
3199     return WHD_SUCCESS;
3200 
3201 }
3202 
whd_wifi_get_listen_interval(whd_interface_t ifp,whd_listen_interval_t * li)3203 uint32_t whd_wifi_get_listen_interval(whd_interface_t ifp, whd_listen_interval_t *li)
3204 {
3205     whd_buffer_t buffer;
3206     whd_buffer_t response;
3207     int *data;
3208     uint8_t *pdata = NULL;
3209     whd_driver_t whd_driver;
3210 
3211     CHECK_IFP_NULL(ifp);
3212 
3213     if (li == NULL)
3214         return WHD_BADARG;
3215 
3216     whd_driver = ifp->whd_driver;
3217 
3218     CHECK_DRIVER_NULL(whd_driver);
3219 
3220     data = (int *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, 4, IOVAR_STR_LISTEN_INTERVAL_BEACON);
3221     CHECK_IOCTL_BUFFER(data);
3222     memset(data, 0, 1);
3223     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3224     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3225     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
3226     memcpy( (uint8_t *)&(li->beacon), (char *)pdata, 1 );
3227     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3228 
3229     data = (int *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, 4, IOVAR_STR_LISTEN_INTERVAL_DTIM);
3230     CHECK_IOCTL_BUFFER(data);
3231     memset(data, 0, 1);
3232     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3233     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3234     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
3235     memcpy( (uint8_t *)&(li->dtim), (char *)pdata, 1 );
3236     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3237 
3238     data = (int *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, 4, IOVAR_STR_LISTEN_INTERVAL_ASSOC);
3239     CHECK_IOCTL_BUFFER(data);
3240     memset(data, 0, 4);
3241     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3242     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3243     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
3244     memcpy( (uint16_t *)&(li->assoc), (char *)pdata, 2 );
3245     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3246 
3247     return WHD_SUCCESS;
3248 }
3249 
whd_wifi_is_ready_to_transceive(whd_interface_t ifp)3250 uint32_t whd_wifi_is_ready_to_transceive(whd_interface_t ifp)
3251 {
3252     whd_driver_t whd_driver;
3253 
3254     CHECK_IFP_NULL(ifp);
3255 
3256     whd_driver = ifp->whd_driver;
3257 
3258     CHECK_DRIVER_NULL(whd_driver);
3259 
3260     switch (ifp->role)
3261     {
3262         case WHD_AP_ROLE:
3263             return (whd_wifi_get_ap_is_up(whd_driver) == WHD_TRUE) ? WHD_SUCCESS : WHD_INTERFACE_NOT_UP;
3264 
3265         case WHD_STA_ROLE:
3266             return whd_wifi_check_join_status(ifp);
3267 
3268         /* Disables Eclipse static analysis warning */
3269         /* No break needed due to returns in all case paths */
3270         /* no break */
3271         /* Fall Through */
3272         case WHD_P2P_ROLE:
3273         case WHD_INVALID_ROLE:
3274 
3275         default:
3276             return WHD_UNKNOWN_INTERFACE;
3277     }
3278 }
3279 
whd_wifi_get_acparams(whd_interface_t ifp,edcf_acparam_t * acp)3280 uint32_t whd_wifi_get_acparams(whd_interface_t ifp, edcf_acparam_t *acp)
3281 {
3282     whd_buffer_t buffer;
3283     whd_buffer_t response;
3284     whd_driver_t whd_driver;
3285     uint8_t *pdata = NULL;
3286 
3287     if (!ifp || !acp)
3288     {
3289         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3290                            __func__, __LINE__) );
3291         return WHD_WLAN_BADARG;
3292     }
3293     whd_driver = ifp->whd_driver;
3294 
3295     CHECK_DRIVER_NULL(whd_driver);
3296 
3297     int *data = (int *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, 64, IOVAR_STR_AC_PARAMS_STA);
3298 
3299     CHECK_IOCTL_BUFFER(data);
3300     memset(data, 0, 64);
3301     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3302     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3303     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
3304     memcpy( (char *)acp, (char *)pdata, (sizeof(edcf_acparam_t) * 4) );
3305     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3306 
3307     return WHD_SUCCESS;
3308 }
3309 
whd_wifi_get_channels(whd_interface_t ifp,whd_list_t * channel_list)3310 uint32_t whd_wifi_get_channels(whd_interface_t ifp, whd_list_t *channel_list)
3311 {
3312     whd_buffer_t buffer;
3313     whd_buffer_t response;
3314     whd_list_t *list;
3315     whd_driver_t whd_driver;
3316     uint16_t buffer_length;
3317 
3318     if (!ifp || !channel_list)
3319     {
3320         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3321                            __func__, __LINE__) );
3322         return WHD_WLAN_BADARG;
3323     }
3324     if (!channel_list->count)
3325     {
3326         WPRINT_WHD_ERROR( ("channel_list->count is zero and max channel is %d in func %s at line %d \n",
3327                            WL_NUMCHANNELS, __func__, __LINE__) );
3328         return WHD_WLAN_BADARG;
3329     }
3330 
3331     whd_driver = ifp->whd_driver;
3332 
3333     CHECK_DRIVER_NULL(whd_driver);
3334 
3335     buffer_length = sizeof(uint32_t) * (WL_NUMCHANNELS + 1);
3336 
3337     list = (whd_list_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, buffer_length);
3338     CHECK_IOCTL_BUFFER(list);
3339 
3340     memset(list, 0, buffer_length);
3341     list->count = htod32(WL_NUMCHANNELS);
3342     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_VALID_CHANNELS, buffer, &response) );
3343 
3344     list = (whd_list_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3345     memcpy(channel_list, list,
3346            (size_t)MIN_OF(whd_buffer_get_current_piece_size(whd_driver, response),
3347                           (sizeof(uint32_t) * (channel_list->count + 1) ) ) );
3348 
3349     whd_buffer_release(whd_driver, response, WHD_NETWORK_RX);
3350 
3351     return WHD_SUCCESS;
3352 }
3353 
whd_wifi_manage_custom_ie(whd_interface_t ifp,whd_custom_ie_action_t action,const uint8_t * oui,uint8_t subtype,const void * data,uint16_t length,uint16_t which_packets)3354 uint32_t whd_wifi_manage_custom_ie(whd_interface_t ifp, whd_custom_ie_action_t action, const uint8_t *oui,
3355                                    uint8_t subtype, const void *data, uint16_t length, uint16_t which_packets)
3356 {
3357     whd_buffer_t buffer;
3358     vndr_ie_setbuf_t *ie_setbuf;
3359     uint32_t *iovar_data;
3360     whd_driver_t whd_driver;
3361 
3362     if (!ifp || !oui || !data)
3363     {
3364         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3365                            __func__, __LINE__) );
3366         return WHD_WLAN_BADARG;
3367     }
3368 
3369     /* VNDR_IE = OUI + subtype + data_length */
3370     if (VNDR_IE_MAX_LEN < WIFI_IE_OUI_LENGTH + 1 + length)
3371     {
3372         WPRINT_WHD_ERROR( ("Invalid length :%u in func %s\n", length, __func__) );
3373         return WHD_WLAN_BADARG;
3374     }
3375 
3376     if (which_packets & VENDOR_IE_UNKNOWN)
3377     {
3378         WPRINT_WHD_ERROR( ("Unsupported packet ID(%x) in func %s\n", which_packets, __func__) );
3379         return WHD_WLAN_BADARG;
3380     }
3381 
3382     whd_driver = ifp->whd_driver;
3383 
3384     CHECK_DRIVER_NULL(whd_driver);
3385 
3386     whd_assert("Bad Args", oui != NULL);
3387 
3388     iovar_data =
3389         (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)(sizeof(vndr_ie_setbuf_t) + length + 4),
3390                                              "bsscfg:" IOVAR_STR_VENDOR_IE);
3391     CHECK_IOCTL_BUFFER(iovar_data);
3392     *iovar_data = ifp->bsscfgidx;
3393     ie_setbuf = (vndr_ie_setbuf_t *)(iovar_data + 1);
3394 
3395     /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
3396     if (action == WHD_ADD_CUSTOM_IE)
3397     {
3398         memcpy( (char *)ie_setbuf->cmd, "add", 3 );
3399     }
3400     else
3401     {
3402         memcpy( (char *)ie_setbuf->cmd, "del", 3 );
3403     }
3404     ie_setbuf->cmd[3] = 0;
3405 
3406     /* Set the values */
3407     ie_setbuf->vndr_ie_buffer.iecount = (int32_t)htod32(1);
3408 
3409     ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag = htod32(which_packets);
3410     ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = 0xdd;
3411     ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len =
3412         ( uint8_t )(length + sizeof(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui) + 1);                                                              /* +1: one byte for sub type */
3413 
3414     /* Stop lint warning about vndr_ie_list array element not yet being defined */
3415     memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, (size_t)WIFI_IE_OUI_LENGTH);
3416 
3417     ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] = subtype;
3418 
3419     memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[1], data, length);
3420 
3421     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3422 }
3423 
whd_wifi_send_action_frame(whd_interface_t ifp,whd_af_params_t * af_params)3424 uint32_t whd_wifi_send_action_frame(whd_interface_t ifp, whd_af_params_t *af_params)
3425 {
3426     whd_buffer_t buffer;
3427     whd_af_params_t *af_frame;
3428     whd_driver_t whd_driver;
3429     CHECK_IFP_NULL(ifp);
3430 
3431     whd_driver = ifp->whd_driver;
3432 
3433     CHECK_DRIVER_NULL(whd_driver);
3434 
3435     if ( (af_params == NULL) || (af_params->action_frame.len > ACTION_FRAME_SIZE) )
3436     {
3437         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n", __func__, __LINE__) );
3438         return WHD_WLAN_BADARG;
3439     }
3440 
3441     af_frame = (whd_af_params_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, WL_WIFI_AF_PARAMS_SIZE,
3442                                                            IOVAR_STR_ACTION_FRAME);
3443     CHECK_IOCTL_BUFFER (af_frame);
3444     memcpy(af_frame, af_params, WL_WIFI_AF_PARAMS_SIZE);
3445     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3446 }
3447 
whd_wifi_send_auth_frame(whd_interface_t ifp,whd_auth_params_t * auth_params)3448 whd_result_t whd_wifi_send_auth_frame(whd_interface_t ifp, whd_auth_params_t *auth_params)
3449 {
3450     whd_buffer_t buffer;
3451     whd_auth_params_t *auth_frame;
3452     whd_driver_t whd_driver;
3453     uint16_t auth_frame_len;
3454     CHECK_IFP_NULL(ifp);
3455 
3456     whd_driver = ifp->whd_driver;
3457 
3458     CHECK_DRIVER_NULL(whd_driver);
3459 
3460     if (auth_params == NULL)
3461     {
3462         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n", __func__, __LINE__) );
3463         return WHD_WLAN_BADARG;
3464     }
3465     /* FW doesn't need MAC Header Length  */
3466     auth_params->len -= DOT11_MGMT_HDR_LEN;
3467     auth_frame_len = OFFSET(whd_auth_params_t, data) + auth_params->len;
3468     auth_frame = (whd_auth_params_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, auth_frame_len,
3469                                                                IOVAR_STR_MGMT_FRAME);
3470     CHECK_IOCTL_BUFFER (auth_frame);
3471     memcpy(auth_frame, auth_params, OFFSET(whd_auth_params_t, data) );
3472     memcpy(auth_frame->data, &auth_params->data[DOT11_MGMT_HDR_LEN], auth_params->len);
3473     auth_frame->dwell_time = MGMT_AUTH_FRAME_DWELL_TIME;
3474     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3475 }
3476 
whd_wifi_he_omi(whd_interface_t ifp,whd_he_omi_params_t * he_omi_params)3477 uint32_t whd_wifi_he_omi(whd_interface_t ifp, whd_he_omi_params_t *he_omi_params)
3478 {
3479     (void)ifp;
3480     (void)he_omi_params;
3481     return WHD_SUCCESS;
3482 }
3483 
whd_wifi_bss_max_idle(whd_interface_t ifp,uint16_t period)3484 uint32_t whd_wifi_bss_max_idle(whd_interface_t ifp, uint16_t period)
3485 {
3486     (void)ifp;
3487     (void)period;
3488     return WHD_SUCCESS;
3489 }
3490 
whd_wifi_itwt_setup(whd_interface_t ifp,whd_itwt_setup_params_t * twt_params)3491 uint32_t whd_wifi_itwt_setup(whd_interface_t ifp, whd_itwt_setup_params_t *twt_params)
3492 {
3493     (void)ifp;
3494     (void)twt_params;
3495     return WHD_SUCCESS;
3496 }
3497 
whd_wifi_btwt_join(whd_interface_t ifp,whd_btwt_join_params_t * twt_params)3498 uint32_t whd_wifi_btwt_join(whd_interface_t ifp, whd_btwt_join_params_t *twt_params)
3499 {
3500     (void)ifp;
3501     (void)twt_params;
3502     return WHD_SUCCESS;
3503 }
3504 
whd_wifi_twt_teardown(whd_interface_t ifp,whd_twt_teardown_params_t * twt_params)3505 uint32_t whd_wifi_twt_teardown(whd_interface_t ifp, whd_twt_teardown_params_t *twt_params)
3506 {
3507     (void)ifp;
3508     (void)twt_params;
3509     return WHD_SUCCESS;
3510 }
3511 
whd_wifi_twt_information_frame(whd_interface_t ifp,whd_twt_information_params_t * twt_params)3512 uint32_t whd_wifi_twt_information_frame(whd_interface_t ifp, whd_twt_information_params_t *twt_params)
3513 {
3514     (void)ifp;
3515     (void)twt_params;
3516     return WHD_SUCCESS;
3517 }
3518 
whd_wifi_btwt_config(whd_interface_t ifp,whd_btwt_config_params_t * twt_params)3519 uint32_t whd_wifi_btwt_config(whd_interface_t ifp, whd_btwt_config_params_t *twt_params)
3520 {
3521     (void)ifp;
3522     (void)twt_params;
3523     return WHD_SUCCESS;
3524 }
3525 
whd_wifi_set_ioctl_value(whd_interface_t ifp,uint32_t ioctl,uint32_t value)3526 uint32_t whd_wifi_set_ioctl_value(whd_interface_t ifp, uint32_t ioctl, uint32_t value)
3527 {
3528     whd_buffer_t buffer;
3529     uint32_t *data;
3530     whd_driver_t whd_driver;
3531 
3532     CHECK_IFP_NULL(ifp);
3533 
3534     whd_driver = ifp->whd_driver;
3535 
3536     CHECK_DRIVER_NULL(whd_driver);
3537 
3538     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)sizeof(value) );
3539     CHECK_IOCTL_BUFFER(data);
3540     *data = htod32(value);
3541     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, ioctl, buffer, 0) );
3542 
3543     return WHD_SUCCESS;
3544 }
3545 
whd_wifi_get_ioctl_value(whd_interface_t ifp,uint32_t ioctl,uint32_t * value)3546 uint32_t whd_wifi_get_ioctl_value(whd_interface_t ifp, uint32_t ioctl, uint32_t *value)
3547 {
3548     whd_buffer_t buffer;
3549     whd_buffer_t response;
3550     whd_driver_t whd_driver;
3551     uint8_t  *data = NULL;
3552 
3553     if (value == NULL)
3554         return WHD_BADARG;
3555 
3556     CHECK_IFP_NULL(ifp);
3557 
3558     whd_driver = ifp->whd_driver;
3559 
3560     CHECK_DRIVER_NULL(whd_driver);
3561 
3562     CHECK_IOCTL_BUFFER(whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)sizeof(*value) ) );
3563     CHECK_RETURN_UNSUPPORTED_OK(whd_cdc_send_ioctl(ifp, CDC_GET, ioctl, buffer, &response) );
3564     data = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3565     CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
3566     *value = dtoh32(*(uint32_t *)data);
3567 
3568     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3569 
3570     return WHD_SUCCESS;
3571 }
3572 
whd_wifi_set_ioctl_buffer(whd_interface_t ifp,uint32_t ioctl,void * in_buffer,uint16_t in_buffer_length)3573 uint32_t whd_wifi_set_ioctl_buffer(whd_interface_t ifp, uint32_t ioctl, void *in_buffer, uint16_t in_buffer_length)
3574 {
3575     whd_buffer_t buffer;
3576     uint32_t *data;
3577     whd_driver_t whd_driver = ifp->whd_driver;
3578 
3579     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, in_buffer_length);
3580     CHECK_IOCTL_BUFFER(data);
3581 
3582     memcpy(data, in_buffer, in_buffer_length);
3583 
3584     CHECK_RETURN(whd_cdc_send_ioctl(ifp, CDC_SET, ioctl, buffer, NULL) );
3585 
3586     return WHD_SUCCESS;
3587 }
3588 
whd_wifi_get_ioctl_buffer(whd_interface_t ifp,uint32_t ioctl,uint8_t * out_buffer,uint16_t out_length)3589 uint32_t whd_wifi_get_ioctl_buffer(whd_interface_t ifp, uint32_t ioctl, uint8_t *out_buffer, uint16_t out_length)
3590 {
3591     whd_buffer_t buffer;
3592     uint32_t *data;
3593     whd_buffer_t response;
3594     whd_result_t result;
3595     whd_driver_t whd_driver;
3596 
3597     CHECK_IFP_NULL(ifp);
3598 
3599     whd_driver = ifp->whd_driver;
3600     data = (uint32_t *)whd_cdc_get_ioctl_buffer(whd_driver, &buffer, out_length);
3601     CHECK_IOCTL_BUFFER(data);
3602     memcpy(data, out_buffer, out_length);
3603 
3604     result = whd_cdc_send_ioctl(ifp, CDC_GET, ioctl, buffer, &response);
3605 
3606     /* it worked: copy the result to the output buffer */
3607     if (WHD_SUCCESS == result)
3608     {
3609         data = (uint32_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3610         CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
3611         *data = dtoh32(*data);
3612         memcpy(out_buffer, data, out_length);
3613         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3614     }
3615 
3616     CHECK_RETURN(result);
3617 
3618     return WHD_SUCCESS;
3619 }
3620 
whd_wifi_set_iovar_void(whd_interface_t ifp,const char * iovar)3621 uint32_t whd_wifi_set_iovar_void(whd_interface_t ifp, const char *iovar)
3622 {
3623     whd_buffer_t buffer;
3624     whd_driver_t whd_driver = ifp->whd_driver;
3625 
3626     whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)0, iovar);
3627 
3628     return whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL);
3629 }
3630 
whd_wifi_set_iovar_value(whd_interface_t ifp,const char * iovar,uint32_t value)3631 uint32_t whd_wifi_set_iovar_value(whd_interface_t ifp, const char *iovar, uint32_t value)
3632 {
3633     whd_buffer_t buffer;
3634     uint32_t *data;
3635     whd_driver_t whd_driver = ifp->whd_driver;
3636 
3637     data = (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)sizeof(value), iovar);
3638     CHECK_IOCTL_BUFFER(data);
3639     *data = htod32(value);
3640     return whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL);
3641 }
3642 
whd_wifi_get_iovar_value(whd_interface_t ifp,const char * iovar,uint32_t * value)3643 uint32_t whd_wifi_get_iovar_value(whd_interface_t ifp, const char *iovar, uint32_t *value)
3644 {
3645     whd_buffer_t buffer;
3646     whd_buffer_t response;
3647     whd_driver_t whd_driver = ifp->whd_driver;
3648     uint8_t *data = NULL;
3649 
3650     if (value == NULL)
3651         return WHD_BADARG;
3652 
3653     CHECK_IOCTL_BUFFER(whd_cdc_get_iovar_buffer(whd_driver, &buffer, 4, iovar) );
3654     CHECK_RETURN_UNSUPPORTED_OK(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
3655     data = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3656     CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
3657     *value = dtoh32(*(uint32_t *)data);
3658     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3659 
3660     return WHD_SUCCESS;
3661 }
3662 
whd_wifi_set_iovar_buffer(whd_interface_t ifp,const char * iovar,void * in_buffer,uint16_t in_buffer_length)3663 uint32_t whd_wifi_set_iovar_buffer(whd_interface_t ifp, const char *iovar, void *in_buffer, uint16_t in_buffer_length)
3664 {
3665     return whd_wifi_set_iovar_buffers(ifp, iovar, (const void **)&in_buffer, (const uint16_t *)&in_buffer_length, 1);
3666 }
3667 
whd_wifi_get_iovar_buffer(whd_interface_t ifp,const char * iovar_name,uint8_t * out_buffer,uint16_t out_length)3668 uint32_t whd_wifi_get_iovar_buffer(whd_interface_t ifp, const char *iovar_name, uint8_t *out_buffer,
3669                                    uint16_t out_length)
3670 {
3671     uint32_t *data;
3672     whd_buffer_t buffer;
3673     whd_buffer_t response;
3674     whd_result_t result;
3675     whd_driver_t whd_driver = ifp->whd_driver;
3676 
3677     data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)out_length, iovar_name);
3678     CHECK_IOCTL_BUFFER(data);
3679 
3680     result = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
3681 
3682     /* it worked: copy the result to the output buffer */
3683     if (WHD_SUCCESS == result)
3684     {
3685         data = (uint32_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3686         *data = dtoh32(*data);
3687         memcpy(out_buffer, data, out_length);
3688         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3689     }
3690 
3691     return result;
3692 }
3693 
3694 /*
3695  * format an iovar buffer
3696  */
3697 static whd_result_t
whd_iovar_mkbuf(const char * name,char * data,uint32_t datalen,char * iovar_buf,uint16_t buflen)3698 whd_iovar_mkbuf(const char *name, char *data, uint32_t datalen, char *iovar_buf, uint16_t buflen)
3699 {
3700     uint32_t iovar_len;
3701 
3702     iovar_len = strlen(name) + 1;
3703 
3704     /* check for overflow */
3705     if ( (iovar_len + datalen) > buflen )
3706     {
3707         return WHD_BADARG;
3708     }
3709 
3710     /* copy data to the buffer past the end of the iovar name string */
3711     if (datalen > 0)
3712         memmove(&iovar_buf[iovar_len], data, datalen);
3713 
3714     /* copy the name to the beginning of the buffer */
3715     strncpy(iovar_buf, name, (iovar_len - 1) );
3716 
3717     return WHD_SUCCESS;
3718 }
3719 
whd_wifi_get_iovar_buffer_with_param(whd_interface_t ifp,const char * iovar_name,void * param,uint32_t paramlen,uint8_t * out_buffer,uint32_t out_length)3720 whd_result_t whd_wifi_get_iovar_buffer_with_param(whd_interface_t ifp, const char *iovar_name, void *param,
3721                                                   uint32_t paramlen, uint8_t *out_buffer, uint32_t out_length)
3722 {
3723     uint32_t *data;
3724     whd_buffer_t buffer;
3725     whd_buffer_t response;
3726     whd_result_t result;
3727     whd_driver_t whd_driver;
3728 
3729     if (!ifp || !iovar_name || !param || !out_buffer)
3730     {
3731         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
3732                            __func__, __LINE__) );
3733         return WHD_WLAN_BADARG;
3734     }
3735 
3736     whd_driver = (whd_driver_t)ifp->whd_driver;
3737 
3738     /* Format the input string */
3739     result = whd_iovar_mkbuf(iovar_name, param, paramlen, (char *)out_buffer, (uint16_t)out_length);
3740     if (result != WHD_SUCCESS)
3741         return result;
3742 
3743     data = whd_cdc_get_ioctl_buffer(whd_driver, &buffer, (uint16_t)out_length);
3744 
3745     if (data == NULL)
3746         return WHD_WLAN_NOMEM;
3747 
3748     memcpy(data, out_buffer, out_length);
3749 
3750     result = (whd_result_t)whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_VAR, buffer, &response);
3751 
3752     if (result == WHD_SUCCESS)
3753     {
3754         memcpy(out_buffer, whd_buffer_get_current_piece_data_pointer(whd_driver, response),
3755                (size_t)MIN_OF(whd_buffer_get_current_piece_size(whd_driver, response), out_length) );
3756         CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3757     }
3758 
3759     return result;
3760 }
3761 
whd_wifi_set_iovar_buffers(whd_interface_t ifp,const char * iovar,const void ** in_buffers,const uint16_t * lengths,const uint8_t num_buffers)3762 uint32_t whd_wifi_set_iovar_buffers(whd_interface_t ifp, const char *iovar, const void **in_buffers,
3763                                     const uint16_t *lengths, const uint8_t num_buffers)
3764 {
3765     whd_buffer_t buffer;
3766     uint32_t *data;
3767     int tot_in_buffer_length = 0;
3768     uint8_t buffer_num = 0;
3769     whd_driver_t whd_driver = ifp->whd_driver;
3770 
3771     /* get total length of all buffers: they will be copied into memory one after the other. */
3772     for (; buffer_num < num_buffers; buffer_num++)
3773     {
3774         tot_in_buffer_length += lengths[buffer_num];
3775     }
3776 
3777     /* get a valid buffer */
3778     data = (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)tot_in_buffer_length, iovar);
3779     CHECK_IOCTL_BUFFER(data);
3780 
3781     /* copy all data into buffer */
3782     for (buffer_num = 0; buffer_num < num_buffers; buffer_num++)
3783     {
3784         memcpy(data, in_buffers[buffer_num], lengths[buffer_num]);
3785         data += lengths[buffer_num];
3786     }
3787 
3788     /* send iovar */
3789     return whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL);
3790 }
3791 
whd_wifi_get_clm_version(whd_interface_t ifp,char * version,uint8_t length)3792 uint32_t whd_wifi_get_clm_version(whd_interface_t ifp, char *version, uint8_t length)
3793 {
3794     whd_result_t result;
3795 
3796     CHECK_IFP_NULL(ifp);
3797 
3798     if (version == NULL)
3799         return WHD_BADARG;
3800 
3801     version[0] = '\0';
3802 
3803     result = whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_CLMVER, (uint8_t *)version, length);
3804     if ( (result == WHD_SUCCESS) && version[0] )
3805     {
3806         uint8_t version_length;
3807         char *p;
3808 
3809         version_length = strlen(version);
3810 
3811         /* -2 becase \0 termination needs a char and strlen doesn't include length of \0 */
3812         if (version_length > length - 2)
3813             version_length = length - 2;
3814         version[version_length + 1] = '\0';
3815 
3816         /* Replace all newline/linefeed characters with space character */
3817         p = version;
3818         while ( (p = strchr(p, '\n') ) != NULL )
3819         {
3820             *p = ' ';
3821         }
3822     }
3823 
3824     CHECK_RETURN(result);
3825     return WHD_SUCCESS;
3826 }
3827 
whd_wifi_get_wifi_version(whd_interface_t ifp,char * buf,uint8_t length)3828 uint32_t whd_wifi_get_wifi_version(whd_interface_t ifp, char *buf, uint8_t length)
3829 {
3830     whd_result_t result;
3831     uint8_t ver_len;
3832 
3833     CHECK_IFP_NULL(ifp);
3834 
3835     if (buf == NULL)
3836         return WHD_BADARG;
3837 
3838     result = whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_VERSION, (uint8_t *)buf, length);
3839 
3840     ver_len = strlen(buf);
3841 
3842     if (ver_len > length - 2)
3843         ver_len = length - 2;
3844 
3845     if ( (ver_len > 1) && (buf[ver_len + 1] == '\n') )
3846     {
3847         buf[ver_len + 1] = '\0';
3848     }
3849 
3850     CHECK_RETURN(result);
3851     return WHD_SUCCESS;
3852 }
3853 
whd_network_get_ifidx_from_ifp(whd_interface_t ifp,uint8_t * ifidx)3854 uint32_t whd_network_get_ifidx_from_ifp(whd_interface_t ifp, uint8_t *ifidx)
3855 {
3856     CHECK_IFP_NULL(ifp);
3857 
3858     if (!ifidx)
3859         return WHD_BADARG;
3860 
3861     *ifidx = ifp->ifidx;
3862 
3863     return WHD_SUCCESS;
3864 }
3865 
whd_network_get_bsscfgidx_from_ifp(whd_interface_t ifp,uint8_t * bsscfgidx)3866 uint32_t whd_network_get_bsscfgidx_from_ifp(whd_interface_t ifp, uint8_t *bsscfgidx)
3867 {
3868     CHECK_IFP_NULL(ifp);
3869 
3870     if (!bsscfgidx)
3871         return WHD_BADARG;
3872 
3873     *bsscfgidx = ifp->bsscfgidx;
3874 
3875     return WHD_SUCCESS;
3876 }
3877 
whd_wifi_ap_set_beacon_interval(whd_interface_t ifp,uint16_t interval)3878 uint32_t whd_wifi_ap_set_beacon_interval(whd_interface_t ifp, uint16_t interval)
3879 {
3880     CHECK_IFP_NULL(ifp);
3881 
3882     CHECK_RETURN(whd_wifi_set_ioctl_value(ifp, WLC_SET_BCNPRD, interval) );
3883     return WHD_SUCCESS;
3884 }
3885 
whd_wifi_ap_set_dtim_interval(whd_interface_t ifp,uint16_t interval)3886 uint32_t whd_wifi_ap_set_dtim_interval(whd_interface_t ifp, uint16_t interval)
3887 {
3888     CHECK_IFP_NULL(ifp);
3889 
3890     CHECK_RETURN(whd_wifi_set_ioctl_value(ifp, WLC_SET_DTIMPRD, interval) );
3891     return WHD_SUCCESS;
3892 }
3893 
whd_wifi_get_bss_info(whd_interface_t ifp,wl_bss_info_t * bi)3894 uint32_t whd_wifi_get_bss_info(whd_interface_t ifp, wl_bss_info_t *bi)
3895 {
3896     whd_buffer_t buffer, response;
3897     uint32_t result;
3898     uint8_t  *data;
3899     whd_driver_t whd_driver;
3900 
3901     CHECK_IFP_NULL(ifp);
3902 
3903     whd_driver = ifp->whd_driver;
3904 
3905     CHECK_DRIVER_NULL(whd_driver);
3906 
3907     if (bi == NULL)
3908         return WHD_BADARG;
3909 
3910     if (whd_cdc_get_ioctl_buffer(whd_driver, &buffer, WLC_IOCTL_SMLEN) == NULL)
3911     {
3912         WPRINT_WHD_INFO( ("%s: Unable to malloc WLC_GET_BSS_INFO buffer\n", __FUNCTION__) );
3913         return WHD_SUCCESS;
3914     }
3915     result = whd_cdc_send_ioctl(ifp, CDC_GET, WLC_GET_BSS_INFO, buffer, &response);
3916     if (result != WHD_SUCCESS)
3917     {
3918         WPRINT_WHD_INFO( ("%s: WLC_GET_BSS_INFO Failed\n", __FUNCTION__) );
3919         return result;
3920     }
3921     data = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
3922     CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
3923     memcpy(bi, data  + 4, sizeof(wl_bss_info_t) );
3924 
3925     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
3926 
3927     return WHD_SUCCESS;
3928 }
3929 
whd_wifi_set_coex_config(whd_interface_t ifp,whd_coex_config_t * coex_config)3930 uint32_t whd_wifi_set_coex_config(whd_interface_t ifp, whd_coex_config_t *coex_config)
3931 {
3932     CHECK_IFP_NULL(ifp);
3933 
3934     if (coex_config == NULL)
3935         return WHD_BADARG;
3936 
3937     return whd_wifi_set_iovar_buffer(ifp, IOVAR_STR_BTC_LESCAN_PARAMS, &coex_config->le_scan_params,
3938                                      sizeof(whd_btc_lescan_params_t) );
3939 }
3940 
whd_wifi_set_auth_status(whd_interface_t ifp,whd_auth_req_status_t * params)3941 whd_result_t whd_wifi_set_auth_status(whd_interface_t ifp, whd_auth_req_status_t *params)
3942 {
3943     whd_buffer_t buffer;
3944     whd_driver_t whd_driver;
3945     whd_auth_req_status_t *auth_status;
3946 
3947     CHECK_IFP_NULL(ifp);
3948 
3949     whd_driver = ifp->whd_driver;
3950 
3951     CHECK_DRIVER_NULL(whd_driver);
3952 
3953     if (params == NULL)
3954     {
3955         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n", __func__, __LINE__) );
3956         return WHD_WLAN_BADARG;
3957     }
3958 
3959     auth_status = (whd_auth_req_status_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(whd_auth_req_status_t),
3960                                                                     IOVAR_STR_AUTH_STATUS);
3961     CHECK_IOCTL_BUFFER (auth_status);
3962     memcpy(auth_status, params, sizeof(whd_auth_req_status_t) );
3963     if (params->flags == DOT11_SC_SUCCESS)
3964     {
3965         auth_status->flags = WL_EXTAUTH_SUCCESS;
3966     }
3967     else
3968     {
3969         auth_status->flags = WL_EXTAUTH_FAIL;
3970     }
3971     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
3972 }
3973 
whd_wifi_get_fwcap(whd_interface_t ifp,uint32_t * value)3974 whd_result_t whd_wifi_get_fwcap(whd_interface_t ifp, uint32_t *value)
3975 {
3976     whd_driver_t whd_driver;
3977 
3978     CHECK_IFP_NULL(ifp);
3979 
3980     whd_driver = ifp->whd_driver;
3981 
3982     CHECK_DRIVER_NULL(whd_driver);
3983 
3984     *value = whd_driver->chip_info.fwcap_flags;
3985     return WHD_SUCCESS;
3986 }
3987 
3988 /*
3989  * ARP Offload version
3990  *    ARP version in the WLAN Firmware
3991  *
3992  * @param[in]    ifp            - whd interface Instance
3993  * @param[out]    version        - pointer to store version #
3994  *
3995  * @return @ref whd_result_t
3996  */
whd_arp_version(whd_interface_t ifp,uint32_t * value)3997 whd_result_t whd_arp_version(whd_interface_t ifp, uint32_t *value)
3998 {
3999     CHECK_IFP_NULL(ifp);
4000 
4001     return whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARP_VERSION, value);
4002 }
4003 
whd_arp_peerage_get(whd_interface_t ifp,uint32_t * value)4004 whd_result_t whd_arp_peerage_get(whd_interface_t ifp, uint32_t *value)
4005 {
4006     CHECK_IFP_NULL(ifp);
4007 
4008     return whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARP_PEERAGE, value);
4009 }
4010 
whd_arp_peerage_set(whd_interface_t ifp,uint32_t value)4011 whd_result_t whd_arp_peerage_set(whd_interface_t ifp, uint32_t value)
4012 {
4013     CHECK_IFP_NULL(ifp);
4014 
4015     return whd_wifi_set_iovar_value(ifp, IOVAR_STR_ARP_PEERAGE, value);
4016 }
4017 
whd_arp_arpoe_get(whd_interface_t ifp,uint32_t * value)4018 whd_result_t whd_arp_arpoe_get(whd_interface_t ifp, uint32_t *value)
4019 {
4020     CHECK_IFP_NULL(ifp);
4021 
4022     return whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARPOE, value);
4023 }
4024 
whd_arp_arpoe_set(whd_interface_t ifp,uint32_t value)4025 whd_result_t whd_arp_arpoe_set(whd_interface_t ifp, uint32_t value)
4026 {
4027     CHECK_IFP_NULL(ifp);
4028 
4029     return whd_wifi_set_iovar_value(ifp, IOVAR_STR_ARPOE, value);
4030 }
4031 
whd_arp_cache_clear(whd_interface_t ifp)4032 whd_result_t whd_arp_cache_clear(whd_interface_t ifp)
4033 {
4034     whd_result_t whd_ret;
4035     CHECK_IFP_NULL(ifp);
4036 
4037     whd_ret = whd_wifi_set_iovar_void(ifp, IOVAR_STR_ARP_TABLE_CLEAR);
4038     return whd_ret;
4039 }
4040 
whd_arp_features_get(whd_interface_t ifp,uint32_t * features)4041 whd_result_t whd_arp_features_get(whd_interface_t ifp, uint32_t *features)
4042 {
4043     if ( (ifp == NULL) || (features == NULL) )
4044     {
4045         return WHD_BADARG;
4046     }
4047 
4048     if (whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_ARP_OL, (uint8_t *)features, sizeof(uint32_t) ) != WHD_SUCCESS)
4049     {
4050         WPRINT_WHD_ERROR( ("%s() failed to get arp_ol for features\n", __func__) );
4051         return WHD_IOCTL_FAIL;
4052     }
4053 
4054     return WHD_SUCCESS;
4055 }
4056 
whd_arp_features_set(whd_interface_t ifp,uint32_t features)4057 whd_result_t whd_arp_features_set(whd_interface_t ifp, uint32_t features)
4058 {
4059     CHECK_IFP_NULL(ifp);
4060 
4061     return whd_wifi_set_iovar_buffer(ifp, IOVAR_STR_ARP_OL, (uint8_t *)&features, sizeof(features) );
4062 }
4063 
whd_arp_features_print(uint32_t features,const char * title)4064 whd_result_t whd_arp_features_print(uint32_t features, const char *title)
4065 {
4066     if (title != NULL)
4067     {
4068         WPRINT_MACRO( ("%s\n", title) );
4069     }
4070     WPRINT_MACRO( ("            features     : 0x%x\n", (int)features) );
4071     WPRINT_MACRO( ("            agent_enabled: (0x%x) %s\n", (int)(features & ARP_OL_AGENT),
4072                    (features & ARP_OL_AGENT) ? "Enabled" : "  disabled") );
4073     WPRINT_MACRO( ("            snoop_enabled: (0x%x) %s\n", (int)(features & ARP_OL_SNOOP),
4074                    (features & ARP_OL_SNOOP) ? "Enabled" : "  disabled") );
4075     WPRINT_MACRO( ("  host_auto_reply_enabled: (0x%x) %s\n", (int)(features & ARP_OL_HOST_AUTO_REPLY),
4076                    (features & ARP_OL_HOST_AUTO_REPLY) ? "Enabled" : "  disabled") );
4077     WPRINT_MACRO( ("  peer_auto_reply_enabled: (0x%x) %s\n", (int)(features & ARP_OL_PEER_AUTO_REPLY),
4078                    (features & ARP_OL_PEER_AUTO_REPLY) ? "Enabled" : "  disabled") );
4079 
4080     return WHD_SUCCESS;
4081 }
4082 
whd_arp_hostip_list_add(whd_interface_t ifp,uint32_t * host_ipv4_list,uint32_t count)4083 whd_result_t whd_arp_hostip_list_add(whd_interface_t ifp, uint32_t *host_ipv4_list, uint32_t count)
4084 {
4085     uint32_t filled = 0;
4086     uint32_t current_ipv4_list[ARP_MULTIHOMING_MAX];
4087     CHECK_IFP_NULL(ifp);
4088 
4089     whd_result_t whd_ret = WHD_SUCCESS;
4090     if (host_ipv4_list == NULL)
4091     {
4092         WPRINT_WHD_ERROR( ("%s() BAD ARGS ifp:%p host_ipv4_list:%u count %d\n", __func__, ifp, (int)host_ipv4_list,
4093                            (int)count) );
4094         return WHD_BADARG;
4095     }
4096     /* check if unique */
4097     whd_ret = whd_arp_hostip_list_get(ifp, ARP_MULTIHOMING_MAX, current_ipv4_list, &filled);
4098     if ( (whd_ret == WHD_SUCCESS) && (filled > 0) )
4099     {
4100         uint32_t curr_index;
4101         uint32_t new_index;
4102 
4103         for (curr_index = 0; curr_index < filled; curr_index++)
4104         {
4105             for (new_index = 0; new_index < count; new_index++)
4106             {
4107                 WPRINT_WHD_DEBUG( ("%s() curr:%ld of %ld curr:0x%lx new:%ld of %ld:0x%lx\n", __func__, curr_index,
4108                                    filled, current_ipv4_list[curr_index],
4109                                    new_index, count, host_ipv4_list[new_index]) );
4110                 if (current_ipv4_list[curr_index] == host_ipv4_list[new_index])
4111                 {
4112                     /* decrement count */
4113                     count--;
4114                     if (new_index < count)
4115                     {
4116                         /* copy next one down */
4117                         WPRINT_WHD_DEBUG( ("move %ld (+1) of %ld \n", new_index, count) );
4118                         host_ipv4_list[new_index] = host_ipv4_list[new_index + 1];
4119 
4120                     }
4121                     break;
4122                 }
4123             }
4124         }
4125     }
4126     else if (whd_ret != WHD_SUCCESS)
4127     {
4128         WPRINT_WHD_DEBUG( ("%s() whd_arp_hostip_list_get() failed:%d\n", __func__, (int)whd_ret) );
4129     }
4130 
4131     if (count > 0)
4132     {
4133         uint32_t new_index;
4134         WPRINT_WHD_DEBUG( ("%s() whd_wifi_set_iovar_buffer( %p, %lx)\n", __func__, host_ipv4_list, count) );
4135         for (new_index = 0; new_index < count; new_index++)
4136         {
4137             WPRINT_WHD_DEBUG( ("  0x%lx\n", host_ipv4_list[new_index]) );
4138         }
4139         whd_ret = whd_wifi_set_iovar_buffer(ifp, IOVAR_STR_ARP_HOSTIP, host_ipv4_list, (count * sizeof(uint32_t) ) );
4140         if (whd_ret != WHD_SUCCESS)
4141         {
4142             WPRINT_WHD_ERROR( ("Failed to set arp_hostip 0x%x error:%d\n", (int)host_ipv4_list[0], (int)whd_ret) );
4143         }
4144     }
4145     return whd_ret;
4146 }
4147 
whd_arp_hostip_list_add_string(whd_interface_t ifp,const char * ip_addr)4148 whd_result_t whd_arp_hostip_list_add_string(whd_interface_t ifp, const char *ip_addr)
4149 {
4150     /* convert string to uint32_t */
4151     uint32_t addr;
4152     CHECK_IFP_NULL(ifp);
4153 
4154     whd_str_to_ip(ip_addr, strlen(ip_addr), &addr);
4155 
4156     return whd_arp_hostip_list_add(ifp, &addr, 1);
4157 }
4158 
whd_arp_hostip_list_clear_id(whd_interface_t ifp,uint32_t ipv4_addr)4159 whd_result_t whd_arp_hostip_list_clear_id(whd_interface_t ifp, uint32_t ipv4_addr)
4160 {
4161     whd_result_t whd_ret;
4162     uint32_t filled;
4163     uint32_t host_ipv4_list[ARP_MULTIHOMING_MAX];
4164     CHECK_IFP_NULL(ifp);
4165 
4166     if (ipv4_addr == 0x00l)
4167     {
4168         return WHD_BADARG;
4169     }
4170     memset(host_ipv4_list, 0x00, sizeof(host_ipv4_list) );
4171     whd_ret = whd_arp_hostip_list_get(ifp, ARP_MULTIHOMING_MAX, host_ipv4_list, &filled);
4172     if ( (whd_ret == WHD_SUCCESS) && (filled > 0) )
4173     {
4174         uint32_t index;
4175 
4176         /* clear the list in the WLAN processor */
4177         whd_ret = whd_wifi_set_iovar_void(ifp, IOVAR_STR_ARP_HOSTIP_CLEAR);
4178         if (whd_ret != WHD_SUCCESS)
4179         {
4180             WPRINT_WHD_ERROR( ("%d %s() whd_wifi_set_iovar_void() failed:%d\n", __LINE__, __func__, (int)whd_ret) );
4181             return whd_ret;
4182         }
4183 
4184         /* remove the one address from the list and re-write arp_hostip list */
4185         for (index = 0; index < filled; index++)
4186         {
4187             WPRINT_WHD_DEBUG( ("%d %s() drop() 0x%lx == 0x%lx ? %s\n", __LINE__, __func__, host_ipv4_list[index],
4188                                ipv4_addr, (host_ipv4_list[index] == ipv4_addr) ? "DROP" : "") );
4189             if (host_ipv4_list[index] == ipv4_addr)
4190             {
4191                 uint32_t drop;
4192                 /* drop this one, move rest up */
4193                 for (drop = index; drop < (filled - 1); drop++)
4194                 {
4195                     host_ipv4_list[drop] = host_ipv4_list[drop + 1];
4196                 }
4197                 filled--;
4198                 /* IP addresses must be added one at a time */
4199                 for (drop = 0; drop < filled; drop++)
4200                 {
4201                     whd_ret = whd_arp_hostip_list_add(ifp, &host_ipv4_list[drop], sizeof(uint32_t) );
4202                 }
4203                 break;
4204             }
4205         }
4206     }
4207     else if (whd_ret != WHD_SUCCESS)
4208     {
4209         WPRINT_WHD_DEBUG( ("%s() whd_arp_hostip_list_get() failed:%d\n", __func__, (int)whd_ret) );
4210     }
4211     return WHD_SUCCESS;
4212 }
4213 
whd_arp_hostip_list_clear_id_string(whd_interface_t ifp,const char * ip_addr)4214 whd_result_t whd_arp_hostip_list_clear_id_string(whd_interface_t ifp, const char *ip_addr)
4215 {
4216     /* convert string to uint32_t */
4217     uint32_t addr;
4218     CHECK_IFP_NULL(ifp);
4219 
4220     whd_str_to_ip(ip_addr, strlen(ip_addr), &addr);
4221 
4222     return whd_arp_hostip_list_clear_id(ifp, addr);
4223 }
4224 
whd_arp_hostip_list_clear(whd_interface_t ifp)4225 whd_result_t whd_arp_hostip_list_clear(whd_interface_t ifp)
4226 {
4227     CHECK_IFP_NULL(ifp);
4228     return whd_wifi_set_iovar_void(ifp, IOVAR_STR_ARP_HOSTIP_CLEAR);
4229 }
4230 
whd_arp_hostip_list_get(whd_interface_t ifp,uint32_t count,uint32_t * host_ipv4_list,uint32_t * filled)4231 whd_result_t whd_arp_hostip_list_get(whd_interface_t ifp, uint32_t count, uint32_t *host_ipv4_list, uint32_t *filled)
4232 {
4233     whd_result_t whd_ret = WHD_SUCCESS;
4234     uint32_t temp[ARP_MULTIHOMING_MAX];
4235     arp_ol_stats_t arp_stats;               /* WL struct, not ours! */
4236     CHECK_IFP_NULL(ifp);
4237 
4238     if ( (host_ipv4_list == NULL) || (filled == NULL) )
4239     {
4240         return WHD_BADARG;
4241     }
4242 
4243     /* set up the buffer to retrieve the stats data */
4244     memset(&arp_stats, 0x00, sizeof(arp_ol_stats_t) );
4245     whd_ret = whd_wifi_get_iovar_buffer(ifp, "arp_stats", (uint8_t *)&arp_stats, sizeof(arp_ol_stats_t) );
4246     if (whd_ret != WHD_SUCCESS)
4247     {
4248         WPRINT_WHD_ERROR( ("%s() failed to get arp_stats\n", __func__) );
4249         return WHD_IOCTL_FAIL;
4250     }
4251 
4252     *filled = 0;
4253     whd_ret =  whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_ARP_HOSTIP, (uint8_t *)&temp, sizeof(temp) );
4254     /* transfer the info */
4255     if (whd_ret == WHD_SUCCESS)
4256     {
4257         uint32_t index;
4258         for (index = 0; (index < count) && (index < arp_stats.host_ip_entries); index++)
4259         {
4260             /* only IPv4 !!! */
4261             if (htod32(temp[index]) != 0L)
4262             {
4263                 host_ipv4_list[*filled] =  temp[index];
4264                 *filled = *filled + 1;
4265             }
4266         }
4267     }
4268     return whd_ret;
4269 }
4270 
whd_arp_stats_clear(whd_interface_t ifp)4271 whd_result_t whd_arp_stats_clear(whd_interface_t ifp)
4272 {
4273     whd_result_t whd_ret;
4274     CHECK_IFP_NULL(ifp);
4275     whd_ret = whd_wifi_set_iovar_void(ifp, IOVAR_STR_ARP_STATS_CLEAR);
4276     return whd_ret;
4277 }
4278 
whd_arp_stats_get(whd_interface_t ifp,whd_arp_stats_t * arp_stats)4279 whd_result_t whd_arp_stats_get(whd_interface_t ifp, whd_arp_stats_t *arp_stats)
4280 {
4281     whd_result_t whd_ret;
4282     uint32_t filled;
4283     static whd_arp_stats_t arp_stats_test;  /* read twice to make sure we match */
4284     CHECK_IFP_NULL(ifp);
4285 
4286     if (arp_stats == NULL)
4287     {
4288         return WHD_BADARG;
4289     }
4290 
4291     /* set up the buffer to retreive the data */
4292     memcpy(&arp_stats_test, arp_stats, sizeof(whd_arp_stats_t) );
4293     memset(arp_stats, 0xFF, sizeof(whd_arp_stats_t) );
4294 
4295     /* read multiple times to make sure we got valid data */
4296     do
4297     {
4298         /* get them until they match */
4299         whd_ret =
4300             whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_ARP_STATS,   (uint8_t *)&arp_stats->stats,
4301                                       sizeof(arp_ol_stats_t) );
4302         if (whd_ret != WHD_SUCCESS)
4303         {
4304             WPRINT_WHD_ERROR( ("%s() failed to get arp_stats\n", __func__) );
4305             return WHD_IOCTL_FAIL;
4306         }
4307         /* get all feature info in one call */
4308         whd_ret =
4309             whd_wifi_get_iovar_buffer(ifp, IOVAR_STR_ARP_OL, (uint8_t *)&arp_stats->features_enabled,
4310                                       sizeof(arp_stats->features_enabled) );
4311         if (whd_ret != WHD_SUCCESS)
4312         {
4313             WPRINT_WHD_ERROR( ("%s() failed to get arp_ol\n", __func__) );
4314             return WHD_IOCTL_FAIL;
4315         }
4316         whd_ret = whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARP_VERSION, &(arp_stats->version) );
4317         if (whd_ret != WHD_SUCCESS)
4318         {
4319             WPRINT_WHD_ERROR( ("%s() failed to get arp_version\n", __func__) );
4320             return WHD_IOCTL_FAIL;
4321         }
4322         whd_ret = whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARP_PEERAGE, &(arp_stats->peerage) );
4323         if (whd_ret != WHD_SUCCESS)
4324         {
4325             WPRINT_WHD_ERROR( ("%s() failed to get arp_peerage\n", __func__) );
4326             return WHD_IOCTL_FAIL;
4327         }
4328         whd_ret = whd_wifi_get_iovar_value(ifp, IOVAR_STR_ARPOE, &(arp_stats->arpoe) );
4329         if (whd_ret != WHD_SUCCESS)
4330         {
4331             WPRINT_WHD_ERROR( ("%s() failed to get some settings\n", __func__) );
4332             return WHD_IOCTL_FAIL;
4333         }
4334 
4335         /* set endian correctly */
4336         arp_stats->stats.host_ip_entries     = dtoh32(arp_stats->stats.host_ip_entries);
4337         arp_stats->stats.host_ip_overflow     = dtoh32(arp_stats->stats.host_ip_overflow);
4338         arp_stats->stats.arp_table_entries     = dtoh32(arp_stats->stats.arp_table_entries);
4339         arp_stats->stats.arp_table_overflow = dtoh32(arp_stats->stats.arp_table_overflow);
4340         arp_stats->stats.host_request         = dtoh32(arp_stats->stats.host_request);
4341         arp_stats->stats.host_reply         = dtoh32(arp_stats->stats.host_reply);
4342         arp_stats->stats.host_service         = dtoh32(arp_stats->stats.host_service);
4343         arp_stats->stats.peer_request         = dtoh32(arp_stats->stats.peer_request);
4344         arp_stats->stats.peer_request_drop     = dtoh32(arp_stats->stats.peer_request_drop);
4345         arp_stats->stats.peer_reply         = dtoh32(arp_stats->stats.peer_reply);
4346         arp_stats->stats.peer_reply_drop     = dtoh32(arp_stats->stats.peer_reply_drop);
4347         arp_stats->stats.peer_service         = dtoh32(arp_stats->stats.peer_service);
4348 
4349         whd_ret = whd_arp_hostip_list_get(ifp, ARP_MULTIHOMING_MAX, arp_stats->host_ip_list, &filled);
4350         if (whd_ret != WHD_SUCCESS)
4351         {
4352             WPRINT_WHD_ERROR( ("%s() failed to get host_ip_list\n", __func__) );
4353             return WHD_IOCTL_FAIL;
4354         }
4355 
4356         if (memcmp(&arp_stats_test, arp_stats, sizeof(whd_arp_stats_t) ) == 0)
4357         {
4358             break;
4359         }
4360 
4361         memcpy(&arp_stats_test, arp_stats, sizeof(whd_arp_stats_t) );
4362     } while (1);
4363 
4364     return whd_ret;
4365 }
4366 
whd_arp_stats_print(whd_arp_stats_t * arp_stats,const char * title)4367 whd_result_t whd_arp_stats_print(whd_arp_stats_t *arp_stats, const char *title)
4368 {
4369     uint32_t index;
4370 
4371     if (arp_stats == NULL)
4372     {
4373         return WHD_BADARG;
4374     }
4375 
4376     if (title != NULL)
4377     {
4378         WPRINT_MACRO( ("%s\n", title) );
4379     }
4380     WPRINT_MACRO( ("                  version: 0x%lx\n", (unsigned long int)arp_stats->version) );
4381     WPRINT_MACRO( ("          host_ip_entries: %d\n", (int)arp_stats->stats.host_ip_entries) );
4382     WPRINT_MACRO( ("         host_ip_overflow: %d\n", (int)arp_stats->stats.host_ip_overflow) );
4383     WPRINT_MACRO( ("        arp_table_entries: %d\n", (int)arp_stats->stats.arp_table_entries) );
4384     WPRINT_MACRO( ("       arp_table_overflow: %d\n", (int)arp_stats->stats.arp_table_overflow) );
4385     WPRINT_MACRO( ("             host_request: %d\n", (int)arp_stats->stats.host_request) );
4386     WPRINT_MACRO( ("               host_reply: %d\n", (int)arp_stats->stats.host_reply) );
4387     WPRINT_MACRO( ("             host_service: %d\n", (int)arp_stats->stats.host_service) );
4388     WPRINT_MACRO( ("             peer_request: %d\n", (int)arp_stats->stats.peer_request) );
4389     WPRINT_MACRO( ("        peer_request_drop: %d\n", (int)arp_stats->stats.peer_request_drop) );
4390     WPRINT_MACRO( ("               peer_reply: %d\n", (int)arp_stats->stats.peer_reply) );
4391     WPRINT_MACRO( ("          peer_reply_drop: %d\n", (int)arp_stats->stats.peer_reply_drop) );
4392     WPRINT_MACRO( ("             peer_service: %d\n", (int)arp_stats->stats.peer_service) );
4393     WPRINT_MACRO( ("                  peerage: %d\n", (int)arp_stats->peerage) );
4394     WPRINT_MACRO( ("                    arpoe: %d %s\n", (int)arp_stats->arpoe,
4395                    (arp_stats->arpoe != 0) ? "Enabled" : "  disabled") );
4396 
4397     whd_arp_features_print(arp_stats->features_enabled, NULL);
4398 
4399     if (arp_stats->stats.host_ip_entries > 0)
4400     {
4401         WPRINT_MACRO( ("WLAN Device Host IP entries\n") );
4402         for (index = 0; index < arp_stats->stats.host_ip_entries; index++)
4403         {
4404             uint32_t ipv4_addr = arp_stats->host_ip_list[index];
4405             char ipv4_string[32];
4406             memset(ipv4_string, 0x00, sizeof(ipv4_string) );
4407             whd_ip4_to_string(&ipv4_addr, ipv4_string);
4408             WPRINT_MACRO( ("  %d of %d IPV4: 0x%x %s\n", (int)index, (int)arp_stats->stats.host_ip_entries,
4409                            (int)arp_stats->host_ip_list[index], ipv4_string) );
4410         }
4411     }
4412     return WHD_SUCCESS;
4413 }
4414 
4415 whd_result_t
whd_wifi_toggle_packet_filter(whd_interface_t ifp,uint8_t filter_id,whd_bool_t enable)4416 whd_wifi_toggle_packet_filter(whd_interface_t ifp, uint8_t filter_id, whd_bool_t enable)
4417 {
4418     whd_buffer_t buffer;
4419     whd_driver_t whd_driver;
4420 
4421     CHECK_IFP_NULL(ifp);
4422 
4423     whd_driver = ifp->whd_driver;
4424     wl_pkt_filter_enable_t *data = (wl_pkt_filter_enable_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer,
4425                                                                                       sizeof(wl_pkt_filter_enable_t),
4426                                                                                       IOVAR_STR_PKT_FILTER_ENABLE);
4427     CHECK_IOCTL_BUFFER(data);
4428     data->id     = (uint32_t)filter_id;
4429     data->enable = (uint32_t)enable;
4430     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
4431 }
4432 
4433 whd_result_t
whd_pf_enable_packet_filter(whd_interface_t ifp,uint8_t filter_id)4434 whd_pf_enable_packet_filter(whd_interface_t ifp, uint8_t filter_id)
4435 {
4436     return whd_wifi_toggle_packet_filter(ifp, filter_id, WHD_TRUE);
4437 }
4438 
4439 whd_result_t
whd_pf_disable_packet_filter(whd_interface_t ifp,uint8_t filter_id)4440 whd_pf_disable_packet_filter(whd_interface_t ifp, uint8_t filter_id)
4441 {
4442     return whd_wifi_toggle_packet_filter(ifp, filter_id, WHD_FALSE);
4443 }
4444 
4445 whd_result_t
whd_pf_add_packet_filter(whd_interface_t ifp,const whd_packet_filter_t * settings)4446 whd_pf_add_packet_filter(whd_interface_t ifp, const whd_packet_filter_t *settings)
4447 {
4448     wl_pkt_filter_t *packet_filter;
4449     whd_driver_t whd_driver;
4450     whd_buffer_t buffer;
4451     uint32_t buffer_length =
4452         (uint32_t)( (2 * (uint32_t)settings->mask_size) + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN );
4453 
4454     CHECK_IFP_NULL(ifp);
4455 
4456     whd_driver = ifp->whd_driver;
4457 
4458     packet_filter = (wl_pkt_filter_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)buffer_length,
4459                                                                 IOVAR_STR_PKT_FILTER_ADD);
4460     CHECK_IOCTL_BUFFER(packet_filter);
4461 
4462     /* Copy filter entries */
4463     packet_filter->id                   = settings->id;
4464     packet_filter->type                 = 0;
4465     packet_filter->negate_match         = settings->rule;
4466     packet_filter->u.pattern.offset     = (uint32_t)settings->offset;
4467     packet_filter->u.pattern.size_bytes = settings->mask_size;
4468 
4469     /* Copy mask */
4470     memcpy(packet_filter->u.pattern.mask_and_pattern, settings->mask, settings->mask_size);
4471 
4472     /* Copy filter pattern */
4473     memcpy(packet_filter->u.pattern.mask_and_pattern + settings->mask_size, settings->pattern, settings->mask_size);
4474 
4475     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
4476 }
4477 
4478 whd_result_t
whd_pf_remove_packet_filter(whd_interface_t ifp,uint8_t filter_id)4479 whd_pf_remove_packet_filter(whd_interface_t ifp, uint8_t filter_id)
4480 {
4481     whd_buffer_t buffer;
4482     whd_driver_t whd_driver;
4483     CHECK_IFP_NULL(ifp);
4484 
4485     whd_driver = ifp->whd_driver;
4486 
4487     uint32_t *data = (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(uint32_t),
4488                                                           IOVAR_STR_PKT_FILTER_DELETE);
4489     CHECK_IOCTL_BUFFER(data);
4490     *data = (uint32_t)filter_id;
4491     RETURN_WITH_ASSERT(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
4492 }
4493 
4494 whd_result_t
whd_pf_get_packet_filter_stats(whd_interface_t ifp,uint8_t filter_id,whd_pkt_filter_stats_t * stats)4495 whd_pf_get_packet_filter_stats(whd_interface_t ifp, uint8_t filter_id, whd_pkt_filter_stats_t *stats)
4496 {
4497     whd_buffer_t buffer;
4498     whd_buffer_t response;
4499     whd_driver_t whd_driver;
4500     uint8_t *pdata;
4501 
4502     CHECK_IFP_NULL(ifp);
4503 
4504     whd_driver = ifp->whd_driver;
4505 
4506     uint32_t *data =
4507         (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, sizeof(uint32_t) + sizeof(wl_pkt_filter_stats_t),
4508                                              IOVAR_STR_PKT_FILTER_STATS);
4509     CHECK_IOCTL_BUFFER(data);
4510 
4511     memset(data, 0, sizeof(uint32_t) + sizeof(wl_pkt_filter_stats_t) );
4512     *data = (uint32_t)filter_id;
4513 
4514     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
4515     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
4516     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
4517     memcpy( (char *)stats, (char *)pdata, (sizeof(wl_pkt_filter_stats_t) ) );
4518     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_TX) );
4519 
4520     return WHD_SUCCESS;
4521 }
4522 
4523 whd_result_t
whd_wifi_clear_packet_filter_stats(whd_interface_t ifp,uint32_t filter_id)4524 whd_wifi_clear_packet_filter_stats(whd_interface_t ifp, uint32_t filter_id)
4525 {
4526     RETURN_WITH_ASSERT(whd_wifi_set_iovar_value(ifp, IOVAR_STR_PKT_FILTER_CLEAR_STATS, (uint32_t)filter_id) );
4527 }
4528 
4529 whd_result_t
whd_pf_get_packet_filter_mask_and_pattern(whd_interface_t ifp,uint8_t filter_id,uint32_t max_size,uint8_t * mask,uint8_t * pattern,uint32_t * size_out)4530 whd_pf_get_packet_filter_mask_and_pattern(whd_interface_t ifp, uint8_t filter_id, uint32_t max_size, uint8_t *mask,
4531                                           uint8_t *pattern, uint32_t *size_out)
4532 {
4533     whd_bool_t enabled_list;
4534     whd_driver_t whd_driver;
4535     CHECK_IFP_NULL(ifp);
4536 
4537     whd_driver = ifp->whd_driver;
4538 
4539     for (enabled_list = WHD_FALSE; enabled_list <= WHD_TRUE; enabled_list++)
4540     {
4541 
4542         whd_buffer_t buffer;
4543         whd_buffer_t response;
4544         uint32_t *data;
4545         wl_pkt_filter_list_t *filter_list;
4546         wl_pkt_filter_t *filter_ptr;
4547         uint32_t i;
4548         wl_pkt_filter_t *in_filter;
4549 
4550         data = whd_cdc_get_iovar_buffer(whd_driver, &buffer, PACKET_FILTER_LIST_BUFFER_MAX_LEN,
4551                                         IOVAR_STR_PKT_FILTER_LIST);
4552         CHECK_IOCTL_BUFFER(data);
4553         *data = (uint32_t)enabled_list;
4554 
4555         CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response) );
4556 
4557         filter_list  = (wl_pkt_filter_list_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
4558         filter_ptr   = filter_list->filter;
4559         for (i = 0; i < filter_list->num; i++)
4560         {
4561             in_filter  = filter_ptr;
4562 
4563             if (in_filter->id == filter_id)
4564             {
4565                 *size_out = MIN_OF(in_filter->u.pattern.size_bytes, max_size);
4566                 memcpy (mask,    in_filter->u.pattern.mask_and_pattern, *size_out);
4567                 memcpy (pattern, in_filter->u.pattern.mask_and_pattern + in_filter->u.pattern.size_bytes, *size_out);
4568                 CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
4569                 if (*size_out < in_filter->u.pattern.size_bytes)
4570                 {
4571                     return WHD_PARTIAL_RESULTS;
4572                 }
4573                 return WHD_SUCCESS;
4574             }
4575 
4576             /* Update WL filter pointer */
4577             filter_ptr =
4578                 (wl_pkt_filter_t *)( (char *)filter_ptr +
4579                                      (WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 *
4580                                       in_filter->u.pattern.size_bytes) );
4581 
4582             /* WLAN returns word-aligned filter list */
4583             filter_ptr = (wl_pkt_filter_t *)ROUND_UP( (unsigned long)filter_ptr, 4 );
4584         }
4585     }
4586     return WHD_FILTER_NOT_FOUND;
4587 }
4588 
4589 /* Set/Get TKO retry & interval parameters */
4590 whd_result_t
whd_tko_param(whd_interface_t ifp,whd_tko_retry_t * whd_retry,uint8_t set)4591 whd_tko_param(whd_interface_t ifp, whd_tko_retry_t *whd_retry, uint8_t set)
4592 {
4593     uint32_t len = 0;
4594     uint8_t *data = NULL;
4595     wl_tko_t *tko = NULL;
4596     whd_buffer_t buffer;
4597     whd_buffer_t response;
4598     wl_tko_param_t *wl_param_p = NULL;
4599     whd_result_t result = WHD_SUCCESS;
4600     whd_driver_t whd_driver;
4601     CHECK_IFP_NULL(ifp);
4602 
4603     whd_driver = ifp->whd_driver;
4604 
4605     len = (int)(WHD_PAYLOAD_MTU - strlen(IOVAR_STR_TKO) - 1);
4606     data = (uint8_t * )whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, IOVAR_STR_TKO);
4607     if (data == NULL)
4608     {
4609         WPRINT_WHD_ERROR( ("%s: Failed to get iovar buf\n", __func__) );
4610         return WHD_IOCTL_FAIL;
4611     }
4612 
4613     tko = (wl_tko_t *)data;
4614     tko->subcmd_id = WL_TKO_SUBCMD_PARAM;
4615     tko->len = TKO_DATA_OFFSET;
4616     wl_param_p = (wl_tko_param_t *)tko->data;
4617     tko->len += sizeof(wl_tko_param_t);
4618 
4619     tko->subcmd_id = htod16(tko->subcmd_id);
4620     tko->len = htod16(tko->len);
4621 
4622     if (set)
4623     {
4624         /* SET parameters */
4625 
4626         /* Set defaults if needed */
4627         wl_param_p->interval = whd_retry->tko_interval ==
4628                                0 ? TCP_KEEPALIVE_OFFLOAD_INTERVAL_SEC : whd_retry->tko_interval;
4629         wl_param_p->retry_count = whd_retry->tko_retry_count ==
4630                                   0 ? TCP_KEEPALIVE_OFFLOAD_RETRY_COUNT : whd_retry->tko_retry_count;
4631         wl_param_p->retry_interval = whd_retry->tko_retry_interval ==
4632                                      0 ? TCP_KEEPALIVE_OFFLOAD_RETRY_INTERVAL_SEC : whd_retry->tko_retry_interval;
4633 
4634         result = whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL);
4635         if (result != WHD_SUCCESS)
4636         {
4637             WPRINT_WHD_ERROR( ("%s: Cannot set params\n", __func__) );
4638         }
4639     }
4640     else
4641     {
4642         /* GET paramters */
4643         wl_tko_param_t tko_param_real;
4644 
4645         result = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
4646         if (result == WHD_SUCCESS)
4647         {
4648             wl_param_p = &tko_param_real;
4649             memcpy( (char *)wl_param_p,
4650                     (char *)whd_buffer_get_current_piece_data_pointer(whd_driver, response) + TKO_DATA_OFFSET,
4651                     (sizeof(wl_tko_param_t) ) );
4652             CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_TX) );
4653 
4654             /* Copy items from wl level struct to higher level struct */
4655             whd_retry->tko_interval = wl_param_p->interval;
4656             whd_retry->tko_retry_interval = wl_param_p->retry_interval;
4657             whd_retry->tko_retry_count = wl_param_p->retry_count;
4658         }
4659         else
4660         {
4661             WPRINT_WHD_ERROR( ("%s: Cannot get params.\n", __func__) );
4662         }
4663     }
4664 
4665     return result;
4666 }
4667 
4668 /* Query Status */
4669 whd_result_t
whd_tko_get_status(whd_interface_t ifp,whd_tko_status_t * whd_status)4670 whd_tko_get_status(whd_interface_t ifp, whd_tko_status_t *whd_status)
4671 {
4672     whd_result_t result = WHD_SUCCESS;
4673     uint32_t len = 0;
4674     uint8_t *data = NULL;
4675     wl_tko_t *tko = NULL;
4676     whd_buffer_t buffer;
4677     whd_buffer_t response;
4678     whd_driver_t whd_driver;
4679     CHECK_IFP_NULL(ifp);
4680 
4681     whd_driver = ifp->whd_driver;
4682 
4683     /* Get a buffer */
4684     len = (int)(100 - strlen(IOVAR_STR_TKO) - 1);
4685     data = (uint8_t * )whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, IOVAR_STR_TKO);
4686     CHECK_IOCTL_BUFFER(data);
4687 
4688     /* Fill buffer with request */
4689     tko = (wl_tko_t *)data;
4690     tko->subcmd_id = WL_TKO_SUBCMD_STATUS;
4691     tko->len = TKO_DATA_OFFSET;
4692 
4693     tko->len += sizeof(wl_tko_status_t);
4694 
4695     tko->subcmd_id = htod16(tko->subcmd_id);
4696     tko->len = htod16(tko->len);
4697 
4698     /* Make request and get result */
4699     result = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
4700     if (result != WHD_SUCCESS)
4701     {
4702         WPRINT_WHD_ERROR( ("%s: send iovar failed\n", __func__) );
4703         return result;
4704     }
4705 
4706     /* Parse result */
4707     tko = (wl_tko_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
4708     if (tko)
4709     {
4710         len = htod16(tko->len);
4711 
4712         if (len >= MAX_TKO_CONN + 1)   /* MAX_TKO status's + 1 for the count */
4713         {
4714             memcpy(whd_status, tko->data, MAX_TKO_CONN + 1);
4715         }
4716     }
4717     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_TX) );
4718     return result;
4719 }
4720 
4721 /* Query FW for number tko max tcp connections */
4722 whd_result_t
whd_tko_max_assoc(whd_interface_t ifp,uint8_t * max)4723 whd_tko_max_assoc(whd_interface_t ifp, uint8_t *max)
4724 {
4725     uint32_t len = 0;
4726     uint8_t *data = NULL;
4727     uint8_t *pdata = NULL;
4728     wl_tko_t *tko = NULL;
4729     whd_buffer_t buffer;
4730     whd_buffer_t response;
4731     wl_tko_max_tcp_t *tko_max_tcp = NULL;
4732     wl_tko_max_tcp_t tcp_result;
4733     whd_driver_t whd_driver;
4734     whd_result_t result = WHD_SUCCESS;
4735     CHECK_IFP_NULL(ifp);
4736 
4737     whd_driver = ifp->whd_driver;
4738 
4739     len = (int)(100 - strlen(IOVAR_STR_TKO) - 1);
4740     data = (uint8_t * )whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, IOVAR_STR_TKO);
4741     CHECK_IOCTL_BUFFER(data);
4742 
4743     tko = (wl_tko_t *)data;
4744 
4745     tko->subcmd_id = WL_TKO_SUBCMD_MAX_TCP;
4746     tko->len = TKO_DATA_OFFSET;
4747 
4748     tko_max_tcp = (wl_tko_max_tcp_t *)tko->data;
4749     tko->len += sizeof(wl_tko_max_tcp_t);
4750 
4751     tko->subcmd_id = htod16(tko->subcmd_id);
4752     tko->len = htod16(tko->len);
4753 
4754     result = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
4755     if (result != WHD_SUCCESS)
4756     {
4757         WPRINT_WHD_ERROR( ("%s: send iovar failed\n", __func__) );
4758         return result;
4759     }
4760     tko_max_tcp = &tcp_result;
4761     pdata = whd_buffer_get_current_piece_data_pointer(whd_driver, response);
4762     CHECK_PACKET_NULL(pdata, WHD_NO_REGISTER_FUNCTION_POINTER);
4763     memcpy( (char *)tko_max_tcp,
4764             (char *)pdata + TKO_DATA_OFFSET,
4765             (sizeof(wl_tko_max_tcp_t) ) );
4766     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_TX) );
4767 
4768     *max = tko_max_tcp->max;
4769     return WHD_SUCCESS;
4770 }
4771 
4772 /* Exercise GET of wl_tko_connect_t IOVAR */
4773 /* Given a index, return info about that index */
4774 whd_result_t
whd_tko_get_FW_connect(whd_interface_t ifp,uint8_t index,whd_tko_connect_t * whd_connect,uint16_t buflen)4775 whd_tko_get_FW_connect(whd_interface_t ifp, uint8_t index, whd_tko_connect_t *whd_connect, uint16_t buflen)
4776 {
4777     uint32_t len = 0;
4778     uint8_t *data = NULL;
4779     wl_tko_t *tko = NULL;
4780     wl_tko_connect_t *connect = NULL;
4781     whd_result_t result = WHD_SUCCESS;
4782     whd_buffer_t response;
4783     whd_buffer_t buffer;
4784     whd_driver_t whd_driver;
4785     CHECK_IFP_NULL(ifp);
4786 
4787     whd_driver = ifp->whd_driver;
4788     CHECK_DRIVER_NULL(whd_driver);
4789 
4790     len = (int)(WHD_PAYLOAD_MTU - strlen(IOVAR_STR_TKO) - 1);
4791     data = (uint8_t * )whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, IOVAR_STR_TKO);
4792     CHECK_IOCTL_BUFFER(data);
4793 
4794     tko = (wl_tko_t *)data;
4795 
4796     tko->subcmd_id = WL_TKO_SUBCMD_CONNECT;
4797     tko->len = offsetof(wl_tko_t, data);
4798     connect = (wl_tko_connect_t *)tko->data;
4799     connect->index = index;
4800 
4801     tko->subcmd_id = htod16(tko->subcmd_id);
4802     tko->len = htod16(tko->len);
4803 
4804     result = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
4805     if (result != WHD_SUCCESS)
4806     {
4807         WPRINT_WHD_ERROR( ("%s: send iovar failed\n", __func__) );
4808         return result;
4809     }
4810     tko = (wl_tko_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
4811     tko->subcmd_id = dtoh16(tko->subcmd_id);
4812     tko->len = dtoh16(tko->len);
4813 
4814     if (tko->subcmd_id  != WL_TKO_SUBCMD_CONNECT)
4815     {
4816         WPRINT_WHD_ERROR( ("%s: IOVAR returned garbage!\n", __func__) );
4817         return WHD_BADARG;
4818     }
4819     connect = (wl_tko_connect_t *)tko->data;
4820     if (tko->len >= sizeof(*connect) )
4821     {
4822         connect->local_port = dtoh16(connect->local_port);
4823         connect->remote_port = dtoh16(connect->remote_port);
4824         connect->local_seq = dtoh32(connect->local_seq);
4825         connect->remote_seq = dtoh32(connect->remote_seq);
4826         if (connect->ip_addr_type != 0)
4827         {
4828             WPRINT_WHD_ERROR( ("%s: Address type not IPV4\n", __func__) );
4829             return WHD_BADARG;
4830         }
4831         if (connect->ip_addr_type == 0)
4832         {
4833             /* IPv4 */
4834             uint16_t mylen;
4835             mylen = sizeof(wl_tko_connect_t) + (2 * IPV4_ADDR_LEN) + connect->request_len + connect->response_len;
4836             if (buflen < mylen)
4837             {
4838                 WPRINT_WHD_ERROR( ("%s: Buf len (%d) too small , need %d\n", __func__, buflen, mylen) );
4839                 return WHD_BADARG;
4840             }
4841 
4842             /*
4843              * Assumes whd_tko_connect_t and wl_tko_connect_t are the same.
4844              * If/when they become different (due to different FW versions, etc) than
4845              * this may have to be copied field by field instead.
4846              */
4847             memcpy(whd_connect, connect, MIN_OF(mylen, buflen) );
4848         }
4849     }
4850     return WHD_SUCCESS;
4851 }
4852 
4853 whd_result_t
whd_tko_toggle(whd_interface_t ifp,whd_bool_t enable)4854 whd_tko_toggle(whd_interface_t ifp, whd_bool_t enable)
4855 {
4856     uint32_t len = 0;
4857     uint8_t *data = NULL;
4858     wl_tko_t *tko = NULL;
4859     whd_buffer_t buffer;
4860     wl_tko_enable_t *tko_enable = NULL;
4861     whd_driver_t whd_driver;
4862     whd_result_t result;
4863     CHECK_IFP_NULL(ifp);
4864 
4865     whd_driver = ifp->whd_driver;
4866 
4867 
4868 
4869     len = (int)(WHD_PAYLOAD_MTU - strlen(IOVAR_STR_TKO) - 1);
4870     data = (uint8_t * )whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, IOVAR_STR_TKO);
4871     CHECK_IOCTL_BUFFER(data);
4872 
4873     tko = (wl_tko_t *)data;
4874 
4875     tko->subcmd_id = WL_TKO_SUBCMD_ENABLE;
4876     tko->len = TKO_DATA_OFFSET;
4877 
4878     tko_enable = (wl_tko_enable_t *)tko->data;
4879     tko_enable->enable = enable;
4880 
4881     tko->len += sizeof(wl_tko_enable_t);
4882 
4883     tko->subcmd_id = htod16(tko->subcmd_id);
4884     tko->len = htod16(tko->len);
4885 
4886     /* invoke SET iovar */
4887     result = whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL);
4888     if (result != WHD_SUCCESS)
4889     {
4890         WPRINT_WHD_ERROR( ("%s: tko %s FAILED\n", __func__, (enable == WHD_TRUE ? "enable" : "disable") ) );
4891         return result;
4892     }
4893     else
4894     {
4895         WPRINT_WHD_ERROR( ("%s: Successfully %s\n", __func__, (enable == WHD_TRUE ? "enabled" : "disabled") ) );
4896     }
4897     return result;
4898 }
4899 
4900