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