LCOV - code coverage report
Current view: top level - wpa_supplicant - ctrl_iface.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 4492 5005 89.8 %
Date: 2015-02-03 Functions: 188 188 100.0 %

          Line data    Source code
       1             : /*
       2             :  * WPA Supplicant / Control interface (shared code for all backends)
       3             :  * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : #ifdef CONFIG_TESTING_OPTIONS
      11             : #include <net/ethernet.h>
      12             : #include <netinet/ip.h>
      13             : #endif /* CONFIG_TESTING_OPTIONS */
      14             : 
      15             : #include "utils/common.h"
      16             : #include "utils/eloop.h"
      17             : #include "utils/uuid.h"
      18             : #include "common/version.h"
      19             : #include "common/ieee802_11_defs.h"
      20             : #include "common/ieee802_11_common.h"
      21             : #include "common/wpa_ctrl.h"
      22             : #include "crypto/tls.h"
      23             : #include "ap/hostapd.h"
      24             : #include "eap_peer/eap.h"
      25             : #include "eapol_supp/eapol_supp_sm.h"
      26             : #include "rsn_supp/wpa.h"
      27             : #include "rsn_supp/preauth.h"
      28             : #include "rsn_supp/pmksa_cache.h"
      29             : #include "l2_packet/l2_packet.h"
      30             : #include "wps/wps.h"
      31             : #include "config.h"
      32             : #include "wpa_supplicant_i.h"
      33             : #include "driver_i.h"
      34             : #include "wps_supplicant.h"
      35             : #include "ibss_rsn.h"
      36             : #include "ap.h"
      37             : #include "p2p_supplicant.h"
      38             : #include "p2p/p2p.h"
      39             : #include "hs20_supplicant.h"
      40             : #include "wifi_display.h"
      41             : #include "notify.h"
      42             : #include "bss.h"
      43             : #include "scan.h"
      44             : #include "ctrl_iface.h"
      45             : #include "interworking.h"
      46             : #include "blacklist.h"
      47             : #include "autoscan.h"
      48             : #include "wnm_sta.h"
      49             : #include "offchannel.h"
      50             : #include "drivers/driver.h"
      51             : #include "mesh.h"
      52             : 
      53             : static int wpa_supplicant_global_iface_list(struct wpa_global *global,
      54             :                                             char *buf, int len);
      55             : static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
      56             :                                                   char *buf, int len);
      57             : static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
      58             :                                         char *val);
      59             : 
      60           4 : static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
      61             : {
      62             :         char *pos;
      63           4 :         u8 addr[ETH_ALEN], *filter = NULL, *n;
      64           4 :         size_t count = 0;
      65             : 
      66           4 :         pos = val;
      67          10 :         while (pos) {
      68           5 :                 if (*pos == '\0')
      69           2 :                         break;
      70           3 :                 if (hwaddr_aton(pos, addr)) {
      71           1 :                         os_free(filter);
      72           1 :                         return -1;
      73             :                 }
      74           2 :                 n = os_realloc_array(filter, count + 1, ETH_ALEN);
      75           2 :                 if (n == NULL) {
      76           0 :                         os_free(filter);
      77           0 :                         return -1;
      78             :                 }
      79           2 :                 filter = n;
      80           2 :                 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
      81           2 :                 count++;
      82             : 
      83           2 :                 pos = os_strchr(pos, ' ');
      84           2 :                 if (pos)
      85           1 :                         pos++;
      86             :         }
      87             : 
      88           3 :         wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
      89           3 :         os_free(wpa_s->bssid_filter);
      90           3 :         wpa_s->bssid_filter = filter;
      91           3 :         wpa_s->bssid_filter_count = count;
      92             : 
      93           3 :         return 0;
      94             : }
      95             : 
      96             : 
      97          16 : static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
      98             : {
      99             :         char *pos;
     100          16 :         u8 addr[ETH_ALEN], *bssid = NULL, *n;
     101          16 :         struct wpa_ssid_value *ssid = NULL, *ns;
     102          16 :         size_t count = 0, ssid_count = 0;
     103             :         struct wpa_ssid *c;
     104             : 
     105             :         /*
     106             :          * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
     107             :          * SSID_SPEC ::= ssid <SSID_HEX>
     108             :          * BSSID_SPEC ::= bssid <BSSID_HEX>
     109             :          */
     110             : 
     111          16 :         pos = val;
     112          42 :         while (pos) {
     113          19 :                 if (*pos == '\0')
     114           2 :                         break;
     115          17 :                 if (os_strncmp(pos, "bssid ", 6) == 0) {
     116             :                         int res;
     117           9 :                         pos += 6;
     118           9 :                         res = hwaddr_aton2(pos, addr);
     119           9 :                         if (res < 0) {
     120           2 :                                 os_free(ssid);
     121           2 :                                 os_free(bssid);
     122           2 :                                 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
     123             :                                            "BSSID value '%s'", pos);
     124           2 :                                 return -1;
     125             :                         }
     126           7 :                         pos += res;
     127           7 :                         n = os_realloc_array(bssid, count + 1, ETH_ALEN);
     128           7 :                         if (n == NULL) {
     129           0 :                                 os_free(ssid);
     130           0 :                                 os_free(bssid);
     131           0 :                                 return -1;
     132             :                         }
     133           7 :                         bssid = n;
     134           7 :                         os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
     135           7 :                         count++;
     136           8 :                 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
     137             :                         char *end;
     138           7 :                         pos += 5;
     139             : 
     140           7 :                         end = pos;
     141         118 :                         while (*end) {
     142         105 :                                 if (*end == '\0' || *end == ' ')
     143             :                                         break;
     144         104 :                                 end++;
     145             :                         }
     146             : 
     147           7 :                         ns = os_realloc_array(ssid, ssid_count + 1,
     148             :                                               sizeof(struct wpa_ssid_value));
     149           7 :                         if (ns == NULL) {
     150           0 :                                 os_free(ssid);
     151           0 :                                 os_free(bssid);
     152           0 :                                 return -1;
     153             :                         }
     154           7 :                         ssid = ns;
     155             : 
     156          11 :                         if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
     157           4 :                             hexstr2bin(pos, ssid[ssid_count].ssid,
     158           4 :                                        (end - pos) / 2) < 0) {
     159           4 :                                 os_free(ssid);
     160           4 :                                 os_free(bssid);
     161           4 :                                 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
     162             :                                            "SSID value '%s'", pos);
     163           4 :                                 return -1;
     164             :                         }
     165           3 :                         ssid[ssid_count].ssid_len = (end - pos) / 2;
     166           6 :                         wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
     167           3 :                                           ssid[ssid_count].ssid,
     168           3 :                                           ssid[ssid_count].ssid_len);
     169           3 :                         ssid_count++;
     170           3 :                         pos = end;
     171             :                 } else {
     172           1 :                         wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
     173             :                                    "'%s'", pos);
     174           1 :                         os_free(ssid);
     175           1 :                         os_free(bssid);
     176           1 :                         return -1;
     177             :                 }
     178             : 
     179          10 :                 pos = os_strchr(pos, ' ');
     180          10 :                 if (pos)
     181           3 :                         pos++;
     182             :         }
     183             : 
     184           9 :         wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
     185           9 :         os_free(wpa_s->disallow_aps_bssid);
     186           9 :         wpa_s->disallow_aps_bssid = bssid;
     187           9 :         wpa_s->disallow_aps_bssid_count = count;
     188             : 
     189           9 :         wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
     190           9 :         os_free(wpa_s->disallow_aps_ssid);
     191           9 :         wpa_s->disallow_aps_ssid = ssid;
     192           9 :         wpa_s->disallow_aps_ssid_count = ssid_count;
     193             : 
     194           9 :         if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
     195           4 :                 return 0;
     196             : 
     197           5 :         c = wpa_s->current_ssid;
     198           5 :         if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
     199           1 :                 return 0;
     200             : 
     201           6 :         if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
     202           2 :             !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
     203           1 :                 return 0;
     204             : 
     205           3 :         wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
     206             :                    "because current AP was marked disallowed");
     207             : 
     208             : #ifdef CONFIG_SME
     209           3 :         wpa_s->sme.prev_bssid_set = 0;
     210             : #endif /* CONFIG_SME */
     211           3 :         wpa_s->reassociate = 1;
     212           3 :         wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
     213           3 :         wpa_supplicant_req_scan(wpa_s, 0, 0);
     214             : 
     215           3 :         return 0;
     216             : }
     217             : 
     218             : 
     219             : #ifndef CONFIG_NO_CONFIG_BLOBS
     220          13 : static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
     221             : {
     222          13 :         char *name = pos;
     223             :         struct wpa_config_blob *blob;
     224             :         size_t len;
     225             : 
     226          13 :         pos = os_strchr(pos, ' ');
     227          13 :         if (pos == NULL)
     228           1 :                 return -1;
     229          12 :         *pos++ = '\0';
     230          12 :         len = os_strlen(pos);
     231          12 :         if (len & 1)
     232           1 :                 return -1;
     233             : 
     234          11 :         wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
     235          11 :         blob = os_zalloc(sizeof(*blob));
     236          11 :         if (blob == NULL)
     237           0 :                 return -1;
     238          11 :         blob->name = os_strdup(name);
     239          11 :         blob->data = os_malloc(len / 2);
     240          11 :         if (blob->name == NULL || blob->data == NULL) {
     241           0 :                 wpa_config_free_blob(blob);
     242           0 :                 return -1;
     243             :         }
     244             : 
     245          11 :         if (hexstr2bin(pos, blob->data, len / 2) < 0) {
     246           1 :                 wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
     247           1 :                 wpa_config_free_blob(blob);
     248           1 :                 return -1;
     249             :         }
     250          10 :         blob->len = len / 2;
     251             : 
     252          10 :         wpa_config_set_blob(wpa_s->conf, blob);
     253             : 
     254          10 :         return 0;
     255             : }
     256             : #endif /* CONFIG_NO_CONFIG_BLOBS */
     257             : 
     258             : 
     259           5 : static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
     260             : {
     261             :         char *params;
     262             :         char *pos;
     263           5 :         int *freqs = NULL;
     264             :         int ret;
     265             : 
     266           5 :         if (atoi(cmd)) {
     267           4 :                 params = os_strchr(cmd, ' ');
     268           4 :                 os_free(wpa_s->manual_sched_scan_freqs);
     269           4 :                 if (params) {
     270           2 :                         params++;
     271           2 :                         pos = os_strstr(params, "freq=");
     272           2 :                         if (pos)
     273           2 :                                 freqs = freq_range_to_channel_list(wpa_s,
     274             :                                                                    pos + 5);
     275             :                 }
     276           4 :                 wpa_s->manual_sched_scan_freqs = freqs;
     277           4 :                 ret = wpas_start_pno(wpa_s);
     278             :         } else {
     279           1 :                 ret = wpas_stop_pno(wpa_s);
     280             :         }
     281           5 :         return ret;
     282             : }
     283             : 
     284             : 
     285       19677 : static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
     286             :                                          char *cmd)
     287             : {
     288             :         char *value;
     289       19677 :         int ret = 0;
     290             : 
     291       19677 :         value = os_strchr(cmd, ' ');
     292       19677 :         if (value == NULL)
     293           2 :                 return -1;
     294       19675 :         *value++ = '\0';
     295             : 
     296       19675 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
     297       19675 :         if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
     298           1 :                 eapol_sm_configure(wpa_s->eapol,
     299             :                                    atoi(value), -1, -1, -1);
     300       19674 :         } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
     301           3 :                 eapol_sm_configure(wpa_s->eapol,
     302             :                                    -1, atoi(value), -1, -1);
     303       19671 :         } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
     304           1 :                 eapol_sm_configure(wpa_s->eapol,
     305             :                                    -1, -1, atoi(value), -1);
     306       19670 :         } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
     307           1 :                 eapol_sm_configure(wpa_s->eapol,
     308             :                                    -1, -1, -1, atoi(value));
     309       19669 :         } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
     310           3 :                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
     311           3 :                                      atoi(value)))
     312           1 :                         ret = -1;
     313       19666 :         } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
     314             :                    0) {
     315           2 :                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
     316           2 :                                      atoi(value)))
     317           1 :                         ret = -1;
     318       19664 :         } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
     319           4 :                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
     320           1 :                         ret = -1;
     321       19660 :         } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
     322           3 :                 wpa_s->wps_fragment_size = atoi(value);
     323             : #ifdef CONFIG_WPS_TESTING
     324       19657 :         } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
     325             :                 long int val;
     326           5 :                 val = strtol(value, NULL, 0);
     327           5 :                 if (val < 0 || val > 0xff) {
     328           2 :                         ret = -1;
     329           2 :                         wpa_printf(MSG_DEBUG, "WPS: Invalid "
     330             :                                    "wps_version_number %ld", val);
     331             :                 } else {
     332           3 :                         wps_version_number = val;
     333           6 :                         wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
     334             :                                    "version %u.%u",
     335           3 :                                    (wps_version_number & 0xf0) >> 4,
     336             :                                    wps_version_number & 0x0f);
     337             :                 }
     338       19652 :         } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
     339           1 :                 wps_testing_dummy_cred = atoi(value);
     340           1 :                 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
     341             :                            wps_testing_dummy_cred);
     342       19651 :         } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
     343           3 :                 wps_corrupt_pkhash = atoi(value);
     344           3 :                 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
     345             :                            wps_corrupt_pkhash);
     346             : #endif /* CONFIG_WPS_TESTING */
     347       19648 :         } else if (os_strcasecmp(cmd, "ampdu") == 0) {
     348           1 :                 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
     349           1 :                         ret = -1;
     350             : #ifdef CONFIG_TDLS
     351             : #ifdef CONFIG_TDLS_TESTING
     352       19647 :         } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
     353             :                 extern unsigned int tdls_testing;
     354          10 :                 tdls_testing = strtol(value, NULL, 0);
     355          10 :                 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
     356             : #endif /* CONFIG_TDLS_TESTING */
     357       19637 :         } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
     358           2 :                 int disabled = atoi(value);
     359           2 :                 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
     360           2 :                 if (disabled) {
     361           1 :                         if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
     362           0 :                                 ret = -1;
     363           1 :                 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
     364           0 :                         ret = -1;
     365           2 :                 wpa_tdls_enable(wpa_s->wpa, !disabled);
     366             : #endif /* CONFIG_TDLS */
     367       19635 :         } else if (os_strcasecmp(cmd, "pno") == 0) {
     368           5 :                 ret = wpas_ctrl_pno(wpa_s, value);
     369       19630 :         } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
     370           0 :                 int disabled = atoi(value);
     371           0 :                 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
     372           0 :                         ret = -1;
     373           0 :                 else if (disabled)
     374           0 :                         wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
     375       19630 :         } else if (os_strcasecmp(cmd, "uapsd") == 0) {
     376           7 :                 if (os_strcmp(value, "disable") == 0)
     377           1 :                         wpa_s->set_sta_uapsd = 0;
     378             :                 else {
     379             :                         int be, bk, vi, vo;
     380             :                         char *pos;
     381             :                         /* format: BE,BK,VI,VO;max SP Length */
     382           6 :                         be = atoi(value);
     383           6 :                         pos = os_strchr(value, ',');
     384           6 :                         if (pos == NULL)
     385           2 :                                 return -1;
     386           4 :                         pos++;
     387           4 :                         bk = atoi(pos);
     388           4 :                         pos = os_strchr(pos, ',');
     389           4 :                         if (pos == NULL)
     390           1 :                                 return -1;
     391           3 :                         pos++;
     392           3 :                         vi = atoi(pos);
     393           3 :                         pos = os_strchr(pos, ',');
     394           3 :                         if (pos == NULL)
     395           1 :                                 return -1;
     396           2 :                         pos++;
     397           2 :                         vo = atoi(pos);
     398             :                         /* ignore max SP Length for now */
     399             : 
     400           2 :                         wpa_s->set_sta_uapsd = 1;
     401           2 :                         wpa_s->sta_uapsd = 0;
     402           2 :                         if (be)
     403           1 :                                 wpa_s->sta_uapsd |= BIT(0);
     404           2 :                         if (bk)
     405           1 :                                 wpa_s->sta_uapsd |= BIT(1);
     406           2 :                         if (vi)
     407           1 :                                 wpa_s->sta_uapsd |= BIT(2);
     408           2 :                         if (vo)
     409           1 :                                 wpa_s->sta_uapsd |= BIT(3);
     410             :                 }
     411       19623 :         } else if (os_strcasecmp(cmd, "ps") == 0) {
     412           4 :                 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
     413             : #ifdef CONFIG_WIFI_DISPLAY
     414       19619 :         } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
     415          25 :                 int enabled = !!atoi(value);
     416          25 :                 if (enabled && !wpa_s->global->p2p)
     417           0 :                         ret = -1;
     418             :                 else
     419          25 :                         wifi_display_enable(wpa_s->global, enabled);
     420             : #endif /* CONFIG_WIFI_DISPLAY */
     421       19594 :         } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
     422           4 :                 ret = set_bssid_filter(wpa_s, value);
     423       19590 :         } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
     424          16 :                 ret = set_disallow_aps(wpa_s, value);
     425       19574 :         } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
     426           3 :                 wpa_s->no_keep_alive = !!atoi(value);
     427             : #ifdef CONFIG_TESTING_OPTIONS
     428       19571 :         } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
     429          15 :                 wpa_s->ext_mgmt_frame_handling = !!atoi(value);
     430       19556 :         } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
     431          19 :                 wpa_s->ext_eapol_frame_io = !!atoi(value);
     432             : #ifdef CONFIG_AP
     433          19 :                 if (wpa_s->ap_iface) {
     434           4 :                         wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
     435           2 :                                 wpa_s->ext_eapol_frame_io;
     436             :                 }
     437             : #endif /* CONFIG_AP */
     438       19537 :         } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
     439           2 :                 wpa_s->extra_roc_dur = atoi(value);
     440       19535 :         } else if (os_strcasecmp(cmd, "test_failure") == 0) {
     441           4 :                 wpa_s->test_failure = atoi(value);
     442             : #endif /* CONFIG_TESTING_OPTIONS */
     443             : #ifndef CONFIG_NO_CONFIG_BLOBS
     444       19531 :         } else if (os_strcmp(cmd, "blob") == 0) {
     445          13 :                 ret = wpas_ctrl_set_blob(wpa_s, value);
     446             : #endif /* CONFIG_NO_CONFIG_BLOBS */
     447       19518 :         } else if (os_strcasecmp(cmd, "setband") == 0) {
     448           7 :                 if (os_strcmp(value, "AUTO") == 0)
     449           4 :                         wpa_s->setband = WPA_SETBAND_AUTO;
     450           3 :                 else if (os_strcmp(value, "5G") == 0)
     451           1 :                         wpa_s->setband = WPA_SETBAND_5G;
     452           2 :                 else if (os_strcmp(value, "2G") == 0)
     453           1 :                         wpa_s->setband = WPA_SETBAND_2G;
     454             :                 else
     455           1 :                         ret = -1;
     456             :         } else {
     457       19511 :                 value[-1] = '=';
     458       19511 :                 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
     459       19511 :                 if (ret == 0)
     460       19505 :                         wpa_supplicant_update_config(wpa_s);
     461             :         }
     462             : 
     463       19671 :         return ret;
     464             : }
     465             : 
     466             : 
     467          16 : static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
     468             :                                          char *cmd, char *buf, size_t buflen)
     469             : {
     470          16 :         int res = -1;
     471             : 
     472          16 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
     473             : 
     474          16 :         if (os_strcmp(cmd, "version") == 0) {
     475           1 :                 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
     476          15 :         } else if (os_strcasecmp(cmd, "country") == 0) {
     477           2 :                 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
     478           4 :                         res = os_snprintf(buf, buflen, "%c%c",
     479           2 :                                           wpa_s->conf->country[0],
     480           2 :                                           wpa_s->conf->country[1]);
     481             : #ifdef CONFIG_WIFI_DISPLAY
     482          13 :         } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
     483             :                 int enabled;
     484           2 :                 if (wpa_s->global->p2p == NULL ||
     485           1 :                     wpa_s->global->p2p_disabled)
     486           0 :                         enabled = 0;
     487             :                 else
     488           1 :                         enabled = wpa_s->global->wifi_display;
     489           1 :                 res = os_snprintf(buf, buflen, "%d", enabled);
     490             : #endif /* CONFIG_WIFI_DISPLAY */
     491             : #ifdef CONFIG_TESTING_GET_GTK
     492             :         } else if (os_strcmp(cmd, "gtk") == 0) {
     493             :                 if (wpa_s->last_gtk_len == 0)
     494             :                         return -1;
     495             :                 res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
     496             :                                        wpa_s->last_gtk_len);
     497             :                 return res;
     498             : #endif /* CONFIG_TESTING_GET_GTK */
     499          12 :         } else if (os_strcmp(cmd, "tls_library") == 0) {
     500          11 :                 res = tls_get_library_version(buf, buflen);
     501             :         }
     502             : 
     503          16 :         if (os_snprintf_error(buflen, res))
     504           1 :                 return -1;
     505          15 :         return res;
     506             : }
     507             : 
     508             : 
     509             : #ifdef IEEE8021X_EAPOL
     510          16 : static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
     511             :                                              char *addr)
     512             : {
     513             :         u8 bssid[ETH_ALEN];
     514          16 :         struct wpa_ssid *ssid = wpa_s->current_ssid;
     515             : 
     516          16 :         if (hwaddr_aton(addr, bssid)) {
     517           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
     518             :                            "'%s'", addr);
     519           1 :                 return -1;
     520             :         }
     521             : 
     522          15 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
     523          15 :         rsn_preauth_deinit(wpa_s->wpa);
     524          15 :         if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
     525           5 :                 return -1;
     526             : 
     527          10 :         return 0;
     528             : }
     529             : #endif /* IEEE8021X_EAPOL */
     530             : 
     531             : 
     532             : #ifdef CONFIG_PEERKEY
     533             : /* MLME-STKSTART.request(peer) */
     534           6 : static int wpa_supplicant_ctrl_iface_stkstart(
     535             :         struct wpa_supplicant *wpa_s, char *addr)
     536             : {
     537             :         u8 peer[ETH_ALEN];
     538             : 
     539           6 :         if (hwaddr_aton(addr, peer)) {
     540           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
     541             :                            "address '%s'", addr);
     542           1 :                 return -1;
     543             :         }
     544             : 
     545          30 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
     546          30 :                    MAC2STR(peer));
     547             : 
     548           5 :         return wpa_sm_stkstart(wpa_s->wpa, peer);
     549             : }
     550             : #endif /* CONFIG_PEERKEY */
     551             : 
     552             : 
     553             : #ifdef CONFIG_TDLS
     554             : 
     555           3 : static int wpa_supplicant_ctrl_iface_tdls_discover(
     556             :         struct wpa_supplicant *wpa_s, char *addr)
     557             : {
     558             :         u8 peer[ETH_ALEN];
     559             :         int ret;
     560             : 
     561           3 :         if (hwaddr_aton(addr, peer)) {
     562           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
     563             :                            "address '%s'", addr);
     564           1 :                 return -1;
     565             :         }
     566             : 
     567          12 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
     568          12 :                    MAC2STR(peer));
     569             : 
     570           2 :         if (wpa_tdls_is_external_setup(wpa_s->wpa))
     571           2 :                 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
     572             :         else
     573           0 :                 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
     574             : 
     575           2 :         return ret;
     576             : }
     577             : 
     578             : 
     579          29 : static int wpa_supplicant_ctrl_iface_tdls_setup(
     580             :         struct wpa_supplicant *wpa_s, char *addr)
     581             : {
     582             :         u8 peer[ETH_ALEN];
     583             :         int ret;
     584             : 
     585          29 :         if (hwaddr_aton(addr, peer)) {
     586           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
     587             :                            "address '%s'", addr);
     588           1 :                 return -1;
     589             :         }
     590             : 
     591         168 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
     592         168 :                    MAC2STR(peer));
     593             : 
     594          28 :         if ((wpa_s->conf->tdls_external_control) &&
     595           0 :             wpa_tdls_is_external_setup(wpa_s->wpa))
     596           0 :                 return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
     597             : 
     598          28 :         wpa_tdls_remove(wpa_s->wpa, peer);
     599             : 
     600          28 :         if (wpa_tdls_is_external_setup(wpa_s->wpa))
     601          28 :                 ret = wpa_tdls_start(wpa_s->wpa, peer);
     602             :         else
     603           0 :                 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
     604             : 
     605          28 :         return ret;
     606             : }
     607             : 
     608             : 
     609          13 : static int wpa_supplicant_ctrl_iface_tdls_teardown(
     610             :         struct wpa_supplicant *wpa_s, char *addr)
     611             : {
     612             :         u8 peer[ETH_ALEN];
     613             :         int ret;
     614             : 
     615          13 :         if (os_strcmp(addr, "*") == 0) {
     616             :                 /* remove everyone */
     617           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
     618           2 :                 wpa_tdls_teardown_peers(wpa_s->wpa);
     619           2 :                 return 0;
     620             :         }
     621             : 
     622          11 :         if (hwaddr_aton(addr, peer)) {
     623           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
     624             :                            "address '%s'", addr);
     625           1 :                 return -1;
     626             :         }
     627             : 
     628          60 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
     629          60 :                    MAC2STR(peer));
     630             : 
     631          10 :         if ((wpa_s->conf->tdls_external_control) &&
     632           0 :             wpa_tdls_is_external_setup(wpa_s->wpa))
     633           0 :                 return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
     634             : 
     635          10 :         if (wpa_tdls_is_external_setup(wpa_s->wpa))
     636          10 :                 ret = wpa_tdls_teardown_link(
     637             :                         wpa_s->wpa, peer,
     638             :                         WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
     639             :         else
     640           0 :                 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
     641             : 
     642          10 :         return ret;
     643             : }
     644             : 
     645             : 
     646           1 : static int ctrl_iface_get_capability_tdls(
     647             :         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
     648             : {
     649             :         int ret;
     650             : 
     651           2 :         ret = os_snprintf(buf, buflen, "%s\n",
     652           1 :                           wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
     653           1 :                           (wpa_s->drv_flags &
     654             :                            WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
     655           1 :                            "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
     656           1 :         if (os_snprintf_error(buflen, ret))
     657           0 :                 return -1;
     658           1 :         return ret;
     659             : }
     660             : 
     661             : 
     662           8 : static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
     663             :         struct wpa_supplicant *wpa_s, char *cmd)
     664             : {
     665             :         u8 peer[ETH_ALEN];
     666             :         struct hostapd_freq_params freq_params;
     667             :         u8 oper_class;
     668             :         char *pos, *end;
     669             : 
     670           8 :         if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
     671           0 :                 wpa_printf(MSG_INFO,
     672             :                            "tdls_chanswitch: Only supported with external setup");
     673           0 :                 return -1;
     674             :         }
     675             : 
     676           8 :         os_memset(&freq_params, 0, sizeof(freq_params));
     677             : 
     678           8 :         pos = os_strchr(cmd, ' ');
     679           8 :         if (pos == NULL)
     680           1 :                 return -1;
     681           7 :         *pos++ = '\0';
     682             : 
     683           7 :         oper_class = strtol(pos, &end, 10);
     684           7 :         if (pos == end) {
     685           3 :                 wpa_printf(MSG_INFO,
     686             :                            "tdls_chanswitch: Invalid op class provided");
     687           3 :                 return -1;
     688             :         }
     689             : 
     690           4 :         pos = end;
     691           4 :         freq_params.freq = atoi(pos);
     692           4 :         if (freq_params.freq == 0) {
     693           1 :                 wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
     694           1 :                 return -1;
     695             :         }
     696             : 
     697             : #define SET_FREQ_SETTING(str) \
     698             :         do { \
     699             :                 const char *pos2 = os_strstr(pos, " " #str "="); \
     700             :                 if (pos2) { \
     701             :                         pos2 += sizeof(" " #str "=") - 1; \
     702             :                         freq_params.str = atoi(pos2); \
     703             :                 } \
     704             :         } while (0)
     705             : 
     706           3 :         SET_FREQ_SETTING(center_freq1);
     707           3 :         SET_FREQ_SETTING(center_freq2);
     708           3 :         SET_FREQ_SETTING(bandwidth);
     709           3 :         SET_FREQ_SETTING(sec_channel_offset);
     710             : #undef SET_FREQ_SETTING
     711             : 
     712           3 :         freq_params.ht_enabled = !!os_strstr(pos, " ht");
     713           3 :         freq_params.vht_enabled = !!os_strstr(pos, " vht");
     714             : 
     715           3 :         if (hwaddr_aton(cmd, peer)) {
     716           0 :                 wpa_printf(MSG_DEBUG,
     717             :                            "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
     718             :                            cmd);
     719           0 :                 return -1;
     720             :         }
     721             : 
     722          24 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
     723             :                    " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
     724          18 :                    MAC2STR(peer), oper_class, freq_params.freq,
     725             :                    freq_params.center_freq1, freq_params.center_freq2,
     726             :                    freq_params.bandwidth, freq_params.sec_channel_offset,
     727           3 :                    freq_params.ht_enabled ? " HT" : "",
     728           3 :                    freq_params.vht_enabled ? " VHT" : "");
     729             : 
     730           3 :         return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
     731             :                                            &freq_params);
     732             : }
     733             : 
     734             : 
     735           4 : static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
     736             :         struct wpa_supplicant *wpa_s, char *cmd)
     737             : {
     738             :         u8 peer[ETH_ALEN];
     739             : 
     740           4 :         if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
     741           0 :                 wpa_printf(MSG_INFO,
     742             :                            "tdls_chanswitch: Only supported with external setup");
     743           0 :                 return -1;
     744             :         }
     745             : 
     746           4 :         if (hwaddr_aton(cmd, peer)) {
     747           1 :                 wpa_printf(MSG_DEBUG,
     748             :                            "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
     749             :                            cmd);
     750           1 :                 return -1;
     751             :         }
     752             : 
     753          18 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
     754          18 :                    MAC2STR(peer));
     755             : 
     756           3 :         return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
     757             : }
     758             : 
     759             : #endif /* CONFIG_TDLS */
     760             : 
     761             : 
     762          16 : static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
     763             : {
     764          16 :         char *token, *context = NULL;
     765          16 :         struct wmm_ac_ts_setup_params params = {
     766             :                 .tsid = 0xff,
     767             :                 .direction = 0xff,
     768             :         };
     769             : 
     770         128 :         while ((token = str_token(cmd, " ", &context))) {
     771         177 :                 if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
     772         149 :                     sscanf(token, "up=%i", &params.user_priority) == 1 ||
     773          68 :                     sscanf(token, "nominal_msdu_size=%i",
     774          55 :                            &params.nominal_msdu_size) == 1 ||
     775          55 :                     sscanf(token, "mean_data_rate=%i",
     776          42 :                            &params.mean_data_rate) == 1 ||
     777          42 :                     sscanf(token, "min_phy_rate=%i",
     778          29 :                            &params.minimum_phy_rate) == 1 ||
     779          29 :                     sscanf(token, "sba=%i",
     780             :                            &params.surplus_bandwidth_allowance) == 1)
     781          80 :                         continue;
     782             : 
     783          16 :                 if (os_strcasecmp(token, "downlink") == 0) {
     784          13 :                         params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
     785           3 :                 } else if (os_strcasecmp(token, "uplink") == 0) {
     786           1 :                         params.direction = WMM_TSPEC_DIRECTION_UPLINK;
     787           2 :                 } else if (os_strcasecmp(token, "bidi") == 0) {
     788           1 :                         params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
     789           1 :                 } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
     790           1 :                         params.fixed_nominal_msdu = 1;
     791             :                 } else {
     792           0 :                         wpa_printf(MSG_DEBUG,
     793             :                                    "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
     794             :                                    token);
     795           0 :                         return -1;
     796             :                 }
     797             : 
     798             :         }
     799             : 
     800          16 :         return wpas_wmm_ac_addts(wpa_s, &params);
     801             : }
     802             : 
     803             : 
     804           3 : static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
     805             : {
     806           3 :         u8 tsid = atoi(cmd);
     807             : 
     808           3 :         return wpas_wmm_ac_delts(wpa_s, tsid);
     809             : }
     810             : 
     811             : 
     812             : #ifdef CONFIG_IEEE80211R
     813         115 : static int wpa_supplicant_ctrl_iface_ft_ds(
     814             :         struct wpa_supplicant *wpa_s, char *addr)
     815             : {
     816             :         u8 target_ap[ETH_ALEN];
     817             :         struct wpa_bss *bss;
     818             :         const u8 *mdie;
     819             : 
     820         115 :         if (hwaddr_aton(addr, target_ap)) {
     821           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
     822             :                            "address '%s'", addr);
     823           1 :                 return -1;
     824             :         }
     825             : 
     826         114 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
     827             : 
     828         114 :         bss = wpa_bss_get_bssid(wpa_s, target_ap);
     829         114 :         if (bss)
     830         113 :                 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
     831             :         else
     832           1 :                 mdie = NULL;
     833             : 
     834         114 :         return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
     835             : }
     836             : #endif /* CONFIG_IEEE80211R */
     837             : 
     838             : 
     839             : #ifdef CONFIG_WPS
     840          43 : static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
     841             :                                              char *cmd)
     842             : {
     843          43 :         u8 bssid[ETH_ALEN], *_bssid = bssid;
     844             : #ifdef CONFIG_P2P
     845             :         u8 p2p_dev_addr[ETH_ALEN];
     846             : #endif /* CONFIG_P2P */
     847             : #ifdef CONFIG_AP
     848          43 :         u8 *_p2p_dev_addr = NULL;
     849             : #endif /* CONFIG_AP */
     850             : 
     851          43 :         if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
     852          15 :                 _bssid = NULL;
     853             : #ifdef CONFIG_P2P
     854          28 :         } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
     855           2 :                 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
     856           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
     857             :                                    "P2P Device Address '%s'",
     858             :                                    cmd + 13);
     859           1 :                         return -1;
     860             :                 }
     861           1 :                 _p2p_dev_addr = p2p_dev_addr;
     862             : #endif /* CONFIG_P2P */
     863          26 :         } else if (hwaddr_aton(cmd, bssid)) {
     864           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
     865             :                            cmd);
     866           1 :                 return -1;
     867             :         }
     868             : 
     869             : #ifdef CONFIG_AP
     870          41 :         if (wpa_s->ap_iface)
     871           7 :                 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
     872             : #endif /* CONFIG_AP */
     873             : 
     874          34 :         return wpas_wps_start_pbc(wpa_s, _bssid, 0);
     875             : }
     876             : 
     877             : 
     878         197 : static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
     879             :                                              char *cmd, char *buf,
     880             :                                              size_t buflen)
     881             : {
     882         197 :         u8 bssid[ETH_ALEN], *_bssid = bssid;
     883             :         char *pin;
     884             :         int ret;
     885             : 
     886         197 :         pin = os_strchr(cmd, ' ');
     887         197 :         if (pin)
     888          67 :                 *pin++ = '\0';
     889             : 
     890         197 :         if (os_strcmp(cmd, "any") == 0)
     891          52 :                 _bssid = NULL;
     892         145 :         else if (os_strcmp(cmd, "get") == 0) {
     893         128 :                 ret = wps_generate_pin();
     894         128 :                 goto done;
     895          17 :         } else if (hwaddr_aton(cmd, bssid)) {
     896           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
     897             :                            cmd);
     898           1 :                 return -1;
     899             :         }
     900             : 
     901             : #ifdef CONFIG_AP
     902          68 :         if (wpa_s->ap_iface) {
     903          47 :                 int timeout = 0;
     904             :                 char *pos;
     905             : 
     906          47 :                 if (pin) {
     907          47 :                         pos = os_strchr(pin, ' ');
     908          47 :                         if (pos) {
     909           1 :                                 *pos++ = '\0';
     910           1 :                                 timeout = atoi(pos);
     911             :                         }
     912             :                 }
     913             : 
     914          47 :                 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
     915             :                                                  buf, buflen, timeout);
     916             :         }
     917             : #endif /* CONFIG_AP */
     918             : 
     919          21 :         if (pin) {
     920          20 :                 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
     921             :                                          DEV_PW_DEFAULT);
     922          20 :                 if (ret < 0)
     923           0 :                         return -1;
     924          20 :                 ret = os_snprintf(buf, buflen, "%s", pin);
     925          20 :                 if (os_snprintf_error(buflen, ret))
     926           0 :                         return -1;
     927          20 :                 return ret;
     928             :         }
     929             : 
     930           1 :         ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
     931           1 :         if (ret < 0)
     932           0 :                 return -1;
     933             : 
     934             : done:
     935             :         /* Return the generated PIN */
     936         129 :         ret = os_snprintf(buf, buflen, "%08d", ret);
     937         129 :         if (os_snprintf_error(buflen, ret))
     938           0 :                 return -1;
     939         129 :         return ret;
     940             : }
     941             : 
     942             : 
     943          17 : static int wpa_supplicant_ctrl_iface_wps_check_pin(
     944             :         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
     945             : {
     946             :         char pin[9];
     947             :         size_t len;
     948             :         char *pos;
     949             :         int ret;
     950             : 
     951          17 :         wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
     952             :                               (u8 *) cmd, os_strlen(cmd));
     953         156 :         for (pos = cmd, len = 0; *pos != '\0'; pos++) {
     954         140 :                 if (*pos < '0' || *pos > '9')
     955           6 :                         continue;
     956         134 :                 pin[len++] = *pos;
     957         134 :                 if (len == 9) {
     958           1 :                         wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
     959           1 :                         return -1;
     960             :                 }
     961             :         }
     962          16 :         if (len != 4 && len != 8) {
     963           1 :                 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
     964           1 :                 return -1;
     965             :         }
     966          15 :         pin[len] = '\0';
     967             : 
     968          15 :         if (len == 8) {
     969             :                 unsigned int pin_val;
     970          15 :                 pin_val = atoi(pin);
     971          15 :                 if (!wps_pin_valid(pin_val)) {
     972           1 :                         wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
     973           1 :                         ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
     974           1 :                         if (os_snprintf_error(buflen, ret))
     975           0 :                                 return -1;
     976           1 :                         return ret;
     977             :                 }
     978             :         }
     979             : 
     980          14 :         ret = os_snprintf(buf, buflen, "%s", pin);
     981          14 :         if (os_snprintf_error(buflen, ret))
     982           0 :                 return -1;
     983             : 
     984          14 :         return ret;
     985             : }
     986             : 
     987             : 
     988             : #ifdef CONFIG_WPS_NFC
     989             : 
     990           4 : static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
     991             :                                              char *cmd)
     992             : {
     993           4 :         u8 bssid[ETH_ALEN], *_bssid = bssid;
     994             : 
     995           4 :         if (cmd == NULL || cmd[0] == '\0')
     996           3 :                 _bssid = NULL;
     997           1 :         else if (hwaddr_aton(cmd, bssid))
     998           1 :                 return -1;
     999             : 
    1000           3 :         return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
    1001             :                                   0, 0);
    1002             : }
    1003             : 
    1004             : 
    1005           3 : static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
    1006             :         struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
    1007             : {
    1008             :         int ndef;
    1009             :         struct wpabuf *buf;
    1010             :         int res;
    1011             :         char *pos;
    1012             : 
    1013           3 :         pos = os_strchr(cmd, ' ');
    1014           3 :         if (pos)
    1015           1 :                 *pos++ = '\0';
    1016           3 :         if (os_strcmp(cmd, "WPS") == 0)
    1017           1 :                 ndef = 0;
    1018           2 :         else if (os_strcmp(cmd, "NDEF") == 0)
    1019           1 :                 ndef = 1;
    1020             :         else
    1021           1 :                 return -1;
    1022             : 
    1023           2 :         buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
    1024           2 :         if (buf == NULL)
    1025           1 :                 return -1;
    1026             : 
    1027           1 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1028             :                                          wpabuf_len(buf));
    1029           1 :         reply[res++] = '\n';
    1030           1 :         reply[res] = '\0';
    1031             : 
    1032           1 :         wpabuf_free(buf);
    1033             : 
    1034           1 :         return res;
    1035             : }
    1036             : 
    1037             : 
    1038          14 : static int wpa_supplicant_ctrl_iface_wps_nfc_token(
    1039             :         struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
    1040             : {
    1041             :         int ndef;
    1042             :         struct wpabuf *buf;
    1043             :         int res;
    1044             : 
    1045          14 :         if (os_strcmp(cmd, "WPS") == 0)
    1046           1 :                 ndef = 0;
    1047          13 :         else if (os_strcmp(cmd, "NDEF") == 0)
    1048          12 :                 ndef = 1;
    1049             :         else
    1050           1 :                 return -1;
    1051             : 
    1052          13 :         buf = wpas_wps_nfc_token(wpa_s, ndef);
    1053          13 :         if (buf == NULL)
    1054           0 :                 return -1;
    1055             : 
    1056          13 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1057             :                                          wpabuf_len(buf));
    1058          13 :         reply[res++] = '\n';
    1059          13 :         reply[res] = '\0';
    1060             : 
    1061          13 :         wpabuf_free(buf);
    1062             : 
    1063          13 :         return res;
    1064             : }
    1065             : 
    1066             : 
    1067          37 : static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
    1068             :         struct wpa_supplicant *wpa_s, char *pos)
    1069             : {
    1070             :         size_t len;
    1071             :         struct wpabuf *buf;
    1072             :         int ret;
    1073             :         char *freq;
    1074          37 :         int forced_freq = 0;
    1075             : 
    1076          37 :         freq = strstr(pos, " freq=");
    1077          37 :         if (freq) {
    1078           1 :                 *freq = '\0';
    1079           1 :                 freq += 6;
    1080           1 :                 forced_freq = atoi(freq);
    1081             :         }
    1082             : 
    1083          37 :         len = os_strlen(pos);
    1084          37 :         if (len & 0x01)
    1085           1 :                 return -1;
    1086          36 :         len /= 2;
    1087             : 
    1088          36 :         buf = wpabuf_alloc(len);
    1089          36 :         if (buf == NULL)
    1090           0 :                 return -1;
    1091          36 :         if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
    1092           1 :                 wpabuf_free(buf);
    1093           1 :                 return -1;
    1094             :         }
    1095             : 
    1096          35 :         ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
    1097          35 :         wpabuf_free(buf);
    1098             : 
    1099          35 :         return ret;
    1100             : }
    1101             : 
    1102             : 
    1103          12 : static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
    1104             :                                               char *reply, size_t max_len,
    1105             :                                               int ndef)
    1106             : {
    1107             :         struct wpabuf *buf;
    1108             :         int res;
    1109             : 
    1110          12 :         buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
    1111          12 :         if (buf == NULL)
    1112           0 :                 return -1;
    1113             : 
    1114          12 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1115             :                                          wpabuf_len(buf));
    1116          12 :         reply[res++] = '\n';
    1117          12 :         reply[res] = '\0';
    1118             : 
    1119          12 :         wpabuf_free(buf);
    1120             : 
    1121          12 :         return res;
    1122             : }
    1123             : 
    1124             : 
    1125             : #ifdef CONFIG_P2P
    1126          10 : static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
    1127             :                                               char *reply, size_t max_len,
    1128             :                                               int ndef)
    1129             : {
    1130             :         struct wpabuf *buf;
    1131             :         int res;
    1132             : 
    1133          10 :         buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
    1134          10 :         if (buf == NULL) {
    1135           0 :                 wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
    1136           0 :                 return -1;
    1137             :         }
    1138             : 
    1139          10 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1140             :                                          wpabuf_len(buf));
    1141          10 :         reply[res++] = '\n';
    1142          10 :         reply[res] = '\0';
    1143             : 
    1144          10 :         wpabuf_free(buf);
    1145             : 
    1146          10 :         return res;
    1147             : }
    1148             : #endif /* CONFIG_P2P */
    1149             : 
    1150             : 
    1151          28 : static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
    1152             :                                           char *cmd, char *reply,
    1153             :                                           size_t max_len)
    1154             : {
    1155             :         char *pos;
    1156             :         int ndef;
    1157             : 
    1158          28 :         pos = os_strchr(cmd, ' ');
    1159          28 :         if (pos == NULL)
    1160           1 :                 return -1;
    1161          27 :         *pos++ = '\0';
    1162             : 
    1163          27 :         if (os_strcmp(cmd, "WPS") == 0)
    1164           4 :                 ndef = 0;
    1165          23 :         else if (os_strcmp(cmd, "NDEF") == 0)
    1166          22 :                 ndef = 1;
    1167             :         else
    1168           1 :                 return -1;
    1169             : 
    1170          26 :         if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
    1171          14 :                 if (!ndef)
    1172           2 :                         return -1;
    1173          12 :                 return wpas_ctrl_nfc_get_handover_req_wps(
    1174             :                         wpa_s, reply, max_len, ndef);
    1175             :         }
    1176             : 
    1177             : #ifdef CONFIG_P2P
    1178          12 :         if (os_strcmp(pos, "P2P-CR") == 0) {
    1179          10 :                 return wpas_ctrl_nfc_get_handover_req_p2p(
    1180             :                         wpa_s, reply, max_len, ndef);
    1181             :         }
    1182             : #endif /* CONFIG_P2P */
    1183             : 
    1184           2 :         return -1;
    1185             : }
    1186             : 
    1187             : 
    1188           6 : static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
    1189             :                                               char *reply, size_t max_len,
    1190             :                                               int ndef, int cr, char *uuid)
    1191             : {
    1192             :         struct wpabuf *buf;
    1193             :         int res;
    1194             : 
    1195           6 :         buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
    1196           6 :         if (buf == NULL)
    1197           2 :                 return -1;
    1198             : 
    1199           4 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1200             :                                          wpabuf_len(buf));
    1201           4 :         reply[res++] = '\n';
    1202           4 :         reply[res] = '\0';
    1203             : 
    1204           4 :         wpabuf_free(buf);
    1205             : 
    1206           4 :         return res;
    1207             : }
    1208             : 
    1209             : 
    1210             : #ifdef CONFIG_P2P
    1211          20 : static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
    1212             :                                               char *reply, size_t max_len,
    1213             :                                               int ndef, int tag)
    1214             : {
    1215             :         struct wpabuf *buf;
    1216             :         int res;
    1217             : 
    1218          20 :         buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
    1219          20 :         if (buf == NULL)
    1220           0 :                 return -1;
    1221             : 
    1222          20 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1223             :                                          wpabuf_len(buf));
    1224          20 :         reply[res++] = '\n';
    1225          20 :         reply[res] = '\0';
    1226             : 
    1227          20 :         wpabuf_free(buf);
    1228             : 
    1229          20 :         return res;
    1230             : }
    1231             : #endif /* CONFIG_P2P */
    1232             : 
    1233             : 
    1234          32 : static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
    1235             :                                           char *cmd, char *reply,
    1236             :                                           size_t max_len)
    1237             : {
    1238             :         char *pos, *pos2;
    1239             :         int ndef;
    1240             : 
    1241          32 :         pos = os_strchr(cmd, ' ');
    1242          32 :         if (pos == NULL)
    1243           1 :                 return -1;
    1244          31 :         *pos++ = '\0';
    1245             : 
    1246          31 :         if (os_strcmp(cmd, "WPS") == 0)
    1247           5 :                 ndef = 0;
    1248          26 :         else if (os_strcmp(cmd, "NDEF") == 0)
    1249          25 :                 ndef = 1;
    1250             :         else
    1251           1 :                 return -1;
    1252             : 
    1253          30 :         pos2 = os_strchr(pos, ' ');
    1254          30 :         if (pos2)
    1255           4 :                 *pos2++ = '\0';
    1256          30 :         if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
    1257           8 :                 if (!ndef)
    1258           2 :                         return -1;
    1259           6 :                 return wpas_ctrl_nfc_get_handover_sel_wps(
    1260             :                         wpa_s, reply, max_len, ndef,
    1261           6 :                         os_strcmp(pos, "WPS-CR") == 0, pos2);
    1262             :         }
    1263             : 
    1264             : #ifdef CONFIG_P2P
    1265          22 :         if (os_strcmp(pos, "P2P-CR") == 0) {
    1266          10 :                 return wpas_ctrl_nfc_get_handover_sel_p2p(
    1267             :                         wpa_s, reply, max_len, ndef, 0);
    1268             :         }
    1269             : 
    1270          12 :         if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
    1271          10 :                 return wpas_ctrl_nfc_get_handover_sel_p2p(
    1272             :                         wpa_s, reply, max_len, ndef, 1);
    1273             :         }
    1274             : #endif /* CONFIG_P2P */
    1275             : 
    1276           2 :         return -1;
    1277             : }
    1278             : 
    1279             : 
    1280          40 : static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
    1281             :                                          char *cmd)
    1282             : {
    1283             :         size_t len;
    1284             :         struct wpabuf *req, *sel;
    1285             :         int ret;
    1286             :         char *pos, *role, *type, *pos2;
    1287             : #ifdef CONFIG_P2P
    1288             :         char *freq;
    1289          40 :         int forced_freq = 0;
    1290             : 
    1291          40 :         freq = strstr(cmd, " freq=");
    1292          40 :         if (freq) {
    1293           1 :                 *freq = '\0';
    1294           1 :                 freq += 6;
    1295           1 :                 forced_freq = atoi(freq);
    1296             :         }
    1297             : #endif /* CONFIG_P2P */
    1298             : 
    1299          40 :         role = cmd;
    1300          40 :         pos = os_strchr(role, ' ');
    1301          40 :         if (pos == NULL) {
    1302           2 :                 wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
    1303           2 :                 return -1;
    1304             :         }
    1305          38 :         *pos++ = '\0';
    1306             : 
    1307          38 :         type = pos;
    1308          38 :         pos = os_strchr(type, ' ');
    1309          38 :         if (pos == NULL) {
    1310           1 :                 wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
    1311           1 :                 return -1;
    1312             :         }
    1313          37 :         *pos++ = '\0';
    1314             : 
    1315          37 :         pos2 = os_strchr(pos, ' ');
    1316          37 :         if (pos2 == NULL) {
    1317           1 :                 wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
    1318           1 :                 return -1;
    1319             :         }
    1320          36 :         *pos2++ = '\0';
    1321             : 
    1322          36 :         len = os_strlen(pos);
    1323          36 :         if (len & 0x01) {
    1324           1 :                 wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
    1325           1 :                 return -1;
    1326             :         }
    1327          35 :         len /= 2;
    1328             : 
    1329          35 :         req = wpabuf_alloc(len);
    1330          35 :         if (req == NULL) {
    1331           0 :                 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
    1332           0 :                 return -1;
    1333             :         }
    1334          35 :         if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
    1335           1 :                 wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
    1336           1 :                 wpabuf_free(req);
    1337           1 :                 return -1;
    1338             :         }
    1339             : 
    1340          34 :         len = os_strlen(pos2);
    1341          34 :         if (len & 0x01) {
    1342           1 :                 wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
    1343           1 :                 wpabuf_free(req);
    1344           1 :                 return -1;
    1345             :         }
    1346          33 :         len /= 2;
    1347             : 
    1348          33 :         sel = wpabuf_alloc(len);
    1349          33 :         if (sel == NULL) {
    1350           0 :                 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
    1351           0 :                 wpabuf_free(req);
    1352           0 :                 return -1;
    1353             :         }
    1354          33 :         if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
    1355           1 :                 wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
    1356           1 :                 wpabuf_free(req);
    1357           1 :                 wpabuf_free(sel);
    1358           1 :                 return -1;
    1359             :         }
    1360             : 
    1361          64 :         wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
    1362          64 :                    role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
    1363             : 
    1364          32 :         if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
    1365          11 :                 ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
    1366             : #ifdef CONFIG_AP
    1367          21 :         } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
    1368             :         {
    1369           4 :                 ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
    1370           8 :                 if (ret < 0)
    1371           3 :                         ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
    1372             : #endif /* CONFIG_AP */
    1373             : #ifdef CONFIG_P2P
    1374          17 :         } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
    1375             :         {
    1376           8 :                 ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
    1377           9 :         } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
    1378             :         {
    1379           8 :                 ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
    1380             :                                                    forced_freq);
    1381             : #endif /* CONFIG_P2P */
    1382             :         } else {
    1383           1 :                 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
    1384             :                            "reported: role=%s type=%s", role, type);
    1385           1 :                 ret = -1;
    1386             :         }
    1387          32 :         wpabuf_free(req);
    1388          32 :         wpabuf_free(sel);
    1389             : 
    1390          32 :         if (ret)
    1391           1 :                 wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
    1392             : 
    1393          32 :         return ret;
    1394             : }
    1395             : 
    1396             : #endif /* CONFIG_WPS_NFC */
    1397             : 
    1398             : 
    1399          45 : static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
    1400             :                                              char *cmd)
    1401             : {
    1402             :         u8 bssid[ETH_ALEN];
    1403             :         char *pin;
    1404             :         char *new_ssid;
    1405             :         char *new_auth;
    1406             :         char *new_encr;
    1407             :         char *new_key;
    1408             :         struct wps_new_ap_settings ap;
    1409             : 
    1410          45 :         pin = os_strchr(cmd, ' ');
    1411          45 :         if (pin == NULL)
    1412           1 :                 return -1;
    1413          44 :         *pin++ = '\0';
    1414             : 
    1415          44 :         if (hwaddr_aton(cmd, bssid)) {
    1416           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
    1417             :                            cmd);
    1418           1 :                 return -1;
    1419             :         }
    1420             : 
    1421          43 :         new_ssid = os_strchr(pin, ' ');
    1422          43 :         if (new_ssid == NULL)
    1423          24 :                 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
    1424          19 :         *new_ssid++ = '\0';
    1425             : 
    1426          19 :         new_auth = os_strchr(new_ssid, ' ');
    1427          19 :         if (new_auth == NULL)
    1428           1 :                 return -1;
    1429          18 :         *new_auth++ = '\0';
    1430             : 
    1431          18 :         new_encr = os_strchr(new_auth, ' ');
    1432          18 :         if (new_encr == NULL)
    1433           1 :                 return -1;
    1434          17 :         *new_encr++ = '\0';
    1435             : 
    1436          17 :         new_key = os_strchr(new_encr, ' ');
    1437          17 :         if (new_key == NULL)
    1438           1 :                 return -1;
    1439          16 :         *new_key++ = '\0';
    1440             : 
    1441          16 :         os_memset(&ap, 0, sizeof(ap));
    1442          16 :         ap.ssid_hex = new_ssid;
    1443          16 :         ap.auth = new_auth;
    1444          16 :         ap.encr = new_encr;
    1445          16 :         ap.key_hex = new_key;
    1446          16 :         return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
    1447             : }
    1448             : 
    1449             : 
    1450             : #ifdef CONFIG_AP
    1451          16 : static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
    1452             :                                                 char *cmd, char *buf,
    1453             :                                                 size_t buflen)
    1454             : {
    1455          16 :         int timeout = 300;
    1456             :         char *pos;
    1457             :         const char *pin_txt;
    1458             : 
    1459          16 :         if (!wpa_s->ap_iface)
    1460           1 :                 return -1;
    1461             : 
    1462          15 :         pos = os_strchr(cmd, ' ');
    1463          15 :         if (pos)
    1464           3 :                 *pos++ = '\0';
    1465             : 
    1466          15 :         if (os_strcmp(cmd, "disable") == 0) {
    1467           1 :                 wpas_wps_ap_pin_disable(wpa_s);
    1468           1 :                 return os_snprintf(buf, buflen, "OK\n");
    1469             :         }
    1470             : 
    1471          14 :         if (os_strcmp(cmd, "random") == 0) {
    1472           2 :                 if (pos)
    1473           1 :                         timeout = atoi(pos);
    1474           2 :                 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
    1475           2 :                 if (pin_txt == NULL)
    1476           0 :                         return -1;
    1477           2 :                 return os_snprintf(buf, buflen, "%s", pin_txt);
    1478             :         }
    1479             : 
    1480          12 :         if (os_strcmp(cmd, "get") == 0) {
    1481           8 :                 pin_txt = wpas_wps_ap_pin_get(wpa_s);
    1482           8 :                 if (pin_txt == NULL)
    1483           2 :                         return -1;
    1484           6 :                 return os_snprintf(buf, buflen, "%s", pin_txt);
    1485             :         }
    1486             : 
    1487           4 :         if (os_strcmp(cmd, "set") == 0) {
    1488             :                 char *pin;
    1489           3 :                 if (pos == NULL)
    1490           1 :                         return -1;
    1491           2 :                 pin = pos;
    1492           2 :                 pos = os_strchr(pos, ' ');
    1493           2 :                 if (pos) {
    1494           1 :                         *pos++ = '\0';
    1495           1 :                         timeout = atoi(pos);
    1496             :                 }
    1497           2 :                 if (os_strlen(pin) > buflen)
    1498           0 :                         return -1;
    1499           2 :                 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
    1500           0 :                         return -1;
    1501           2 :                 return os_snprintf(buf, buflen, "%s", pin);
    1502             :         }
    1503             : 
    1504           1 :         return -1;
    1505             : }
    1506             : #endif /* CONFIG_AP */
    1507             : 
    1508             : 
    1509             : #ifdef CONFIG_WPS_ER
    1510           5 : static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
    1511             :                                                 char *cmd)
    1512             : {
    1513           5 :         char *uuid = cmd, *pin, *pos;
    1514           5 :         u8 addr_buf[ETH_ALEN], *addr = NULL;
    1515           5 :         pin = os_strchr(uuid, ' ');
    1516           5 :         if (pin == NULL)
    1517           1 :                 return -1;
    1518           4 :         *pin++ = '\0';
    1519           4 :         pos = os_strchr(pin, ' ');
    1520           4 :         if (pos) {
    1521           4 :                 *pos++ = '\0';
    1522           4 :                 if (hwaddr_aton(pos, addr_buf) == 0)
    1523           4 :                         addr = addr_buf;
    1524             :         }
    1525           4 :         return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
    1526             : }
    1527             : 
    1528             : 
    1529           2 : static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
    1530             :                                                   char *cmd)
    1531             : {
    1532           2 :         char *uuid = cmd, *pin;
    1533           2 :         pin = os_strchr(uuid, ' ');
    1534           2 :         if (pin == NULL)
    1535           1 :                 return -1;
    1536           1 :         *pin++ = '\0';
    1537           1 :         return wpas_wps_er_learn(wpa_s, uuid, pin);
    1538             : }
    1539             : 
    1540             : 
    1541           9 : static int wpa_supplicant_ctrl_iface_wps_er_set_config(
    1542             :         struct wpa_supplicant *wpa_s, char *cmd)
    1543             : {
    1544           9 :         char *uuid = cmd, *id;
    1545           9 :         id = os_strchr(uuid, ' ');
    1546           9 :         if (id == NULL)
    1547           1 :                 return -1;
    1548           8 :         *id++ = '\0';
    1549           8 :         return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
    1550             : }
    1551             : 
    1552             : 
    1553           6 : static int wpa_supplicant_ctrl_iface_wps_er_config(
    1554             :         struct wpa_supplicant *wpa_s, char *cmd)
    1555             : {
    1556             :         char *pin;
    1557             :         char *new_ssid;
    1558             :         char *new_auth;
    1559             :         char *new_encr;
    1560             :         char *new_key;
    1561             :         struct wps_new_ap_settings ap;
    1562             : 
    1563           6 :         pin = os_strchr(cmd, ' ');
    1564           6 :         if (pin == NULL)
    1565           1 :                 return -1;
    1566           5 :         *pin++ = '\0';
    1567             : 
    1568           5 :         new_ssid = os_strchr(pin, ' ');
    1569           5 :         if (new_ssid == NULL)
    1570           1 :                 return -1;
    1571           4 :         *new_ssid++ = '\0';
    1572             : 
    1573           4 :         new_auth = os_strchr(new_ssid, ' ');
    1574           4 :         if (new_auth == NULL)
    1575           1 :                 return -1;
    1576           3 :         *new_auth++ = '\0';
    1577             : 
    1578           3 :         new_encr = os_strchr(new_auth, ' ');
    1579           3 :         if (new_encr == NULL)
    1580           1 :                 return -1;
    1581           2 :         *new_encr++ = '\0';
    1582             : 
    1583           2 :         new_key = os_strchr(new_encr, ' ');
    1584           2 :         if (new_key == NULL)
    1585           1 :                 return -1;
    1586           1 :         *new_key++ = '\0';
    1587             : 
    1588           1 :         os_memset(&ap, 0, sizeof(ap));
    1589           1 :         ap.ssid_hex = new_ssid;
    1590           1 :         ap.auth = new_auth;
    1591           1 :         ap.encr = new_encr;
    1592           1 :         ap.key_hex = new_key;
    1593           1 :         return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
    1594             : }
    1595             : 
    1596             : 
    1597             : #ifdef CONFIG_WPS_NFC
    1598           5 : static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
    1599             :         struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
    1600             : {
    1601             :         int ndef;
    1602             :         struct wpabuf *buf;
    1603             :         int res;
    1604             :         char *uuid;
    1605             : 
    1606           5 :         uuid = os_strchr(cmd, ' ');
    1607           5 :         if (uuid == NULL)
    1608           1 :                 return -1;
    1609           4 :         *uuid++ = '\0';
    1610             : 
    1611           4 :         if (os_strcmp(cmd, "WPS") == 0)
    1612           1 :                 ndef = 0;
    1613           3 :         else if (os_strcmp(cmd, "NDEF") == 0)
    1614           2 :                 ndef = 1;
    1615             :         else
    1616           1 :                 return -1;
    1617             : 
    1618           3 :         buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
    1619           3 :         if (buf == NULL)
    1620           1 :                 return -1;
    1621             : 
    1622           2 :         res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
    1623             :                                          wpabuf_len(buf));
    1624           2 :         reply[res++] = '\n';
    1625           2 :         reply[res] = '\0';
    1626             : 
    1627           2 :         wpabuf_free(buf);
    1628             : 
    1629           2 :         return res;
    1630             : }
    1631             : #endif /* CONFIG_WPS_NFC */
    1632             : #endif /* CONFIG_WPS_ER */
    1633             : 
    1634             : #endif /* CONFIG_WPS */
    1635             : 
    1636             : 
    1637             : #ifdef CONFIG_IBSS_RSN
    1638           2 : static int wpa_supplicant_ctrl_iface_ibss_rsn(
    1639             :         struct wpa_supplicant *wpa_s, char *addr)
    1640             : {
    1641             :         u8 peer[ETH_ALEN];
    1642             : 
    1643           2 :         if (hwaddr_aton(addr, peer)) {
    1644           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
    1645             :                            "address '%s'", addr);
    1646           1 :                 return -1;
    1647             :         }
    1648             : 
    1649           6 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
    1650           6 :                    MAC2STR(peer));
    1651             : 
    1652           1 :         return ibss_rsn_start(wpa_s->ibss_rsn, peer);
    1653             : }
    1654             : #endif /* CONFIG_IBSS_RSN */
    1655             : 
    1656             : 
    1657          49 : static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
    1658             :                                               char *rsp)
    1659             : {
    1660             : #ifdef IEEE8021X_EAPOL
    1661             :         char *pos, *id_pos;
    1662             :         int id;
    1663             :         struct wpa_ssid *ssid;
    1664             : 
    1665          49 :         pos = os_strchr(rsp, '-');
    1666          49 :         if (pos == NULL)
    1667           1 :                 return -1;
    1668          48 :         *pos++ = '\0';
    1669          48 :         id_pos = pos;
    1670          48 :         pos = os_strchr(pos, ':');
    1671          48 :         if (pos == NULL)
    1672           2 :                 return -1;
    1673          46 :         *pos++ = '\0';
    1674          46 :         id = atoi(id_pos);
    1675          46 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
    1676          46 :         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
    1677             :                               (u8 *) pos, os_strlen(pos));
    1678             : 
    1679          46 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    1680          46 :         if (ssid == NULL) {
    1681           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
    1682             :                            "to update", id);
    1683           1 :                 return -1;
    1684             :         }
    1685             : 
    1686          45 :         return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
    1687             :                                                          pos);
    1688             : #else /* IEEE8021X_EAPOL */
    1689             :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
    1690             :         return -1;
    1691             : #endif /* IEEE8021X_EAPOL */
    1692             : }
    1693             : 
    1694             : 
    1695        6574 : static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
    1696             :                                             const char *params,
    1697             :                                             char *buf, size_t buflen)
    1698             : {
    1699             :         char *pos, *end, tmp[30];
    1700             :         int res, verbose, wps, ret;
    1701             : #ifdef CONFIG_HS20
    1702             :         const u8 *hs20;
    1703             : #endif /* CONFIG_HS20 */
    1704             :         const u8 *sess_id;
    1705             :         size_t sess_id_len;
    1706             : 
    1707        6574 :         if (os_strcmp(params, "-DRIVER") == 0)
    1708        4057 :                 return wpa_drv_status(wpa_s, buf, buflen);
    1709        2517 :         verbose = os_strcmp(params, "-VERBOSE") == 0;
    1710        2517 :         wps = os_strcmp(params, "-WPS") == 0;
    1711        2517 :         pos = buf;
    1712        2517 :         end = buf + buflen;
    1713        2517 :         if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
    1714        1970 :                 struct wpa_ssid *ssid = wpa_s->current_ssid;
    1715       11820 :                 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
    1716       11820 :                                   MAC2STR(wpa_s->bssid));
    1717        1970 :                 if (os_snprintf_error(end - pos, ret))
    1718           0 :                         return pos - buf;
    1719        1970 :                 pos += ret;
    1720        1970 :                 ret = os_snprintf(pos, end - pos, "freq=%u\n",
    1721             :                                   wpa_s->assoc_freq);
    1722        1970 :                 if (os_snprintf_error(end - pos, ret))
    1723           0 :                         return pos - buf;
    1724        1970 :                 pos += ret;
    1725        1970 :                 if (ssid) {
    1726        1970 :                         u8 *_ssid = ssid->ssid;
    1727        1970 :                         size_t ssid_len = ssid->ssid_len;
    1728             :                         u8 ssid_buf[MAX_SSID_LEN];
    1729        1970 :                         if (ssid_len == 0) {
    1730           1 :                                 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
    1731           1 :                                 if (_res < 0)
    1732           0 :                                         ssid_len = 0;
    1733             :                                 else
    1734           1 :                                         ssid_len = _res;
    1735           1 :                                 _ssid = ssid_buf;
    1736             :                         }
    1737        1970 :                         ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
    1738             :                                           wpa_ssid_txt(_ssid, ssid_len),
    1739             :                                           ssid->id);
    1740        1970 :                         if (os_snprintf_error(end - pos, ret))
    1741           0 :                                 return pos - buf;
    1742        1970 :                         pos += ret;
    1743             : 
    1744        1972 :                         if (wps && ssid->passphrase &&
    1745           4 :                             wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
    1746           4 :                             (ssid->mode == WPAS_MODE_AP ||
    1747           2 :                              ssid->mode == WPAS_MODE_P2P_GO)) {
    1748           2 :                                 ret = os_snprintf(pos, end - pos,
    1749             :                                                   "passphrase=%s\n",
    1750             :                                                   ssid->passphrase);
    1751           2 :                                 if (os_snprintf_error(end - pos, ret))
    1752           0 :                                         return pos - buf;
    1753           2 :                                 pos += ret;
    1754             :                         }
    1755        1970 :                         if (ssid->id_str) {
    1756           1 :                                 ret = os_snprintf(pos, end - pos,
    1757             :                                                   "id_str=%s\n",
    1758             :                                                   ssid->id_str);
    1759           1 :                                 if (os_snprintf_error(end - pos, ret))
    1760           0 :                                         return pos - buf;
    1761           1 :                                 pos += ret;
    1762             :                         }
    1763             : 
    1764        1970 :                         switch (ssid->mode) {
    1765             :                         case WPAS_MODE_INFRA:
    1766        1756 :                                 ret = os_snprintf(pos, end - pos,
    1767             :                                                   "mode=station\n");
    1768        1756 :                                 break;
    1769             :                         case WPAS_MODE_IBSS:
    1770          33 :                                 ret = os_snprintf(pos, end - pos,
    1771             :                                                   "mode=IBSS\n");
    1772          33 :                                 break;
    1773             :                         case WPAS_MODE_AP:
    1774           9 :                                 ret = os_snprintf(pos, end - pos,
    1775             :                                                   "mode=AP\n");
    1776           9 :                                 break;
    1777             :                         case WPAS_MODE_P2P_GO:
    1778         170 :                                 ret = os_snprintf(pos, end - pos,
    1779             :                                                   "mode=P2P GO\n");
    1780         170 :                                 break;
    1781             :                         case WPAS_MODE_P2P_GROUP_FORMATION:
    1782           2 :                                 ret = os_snprintf(pos, end - pos,
    1783             :                                                   "mode=P2P GO - group "
    1784             :                                                   "formation\n");
    1785           2 :                                 break;
    1786             :                         default:
    1787           0 :                                 ret = 0;
    1788           0 :                                 break;
    1789             :                         }
    1790        1970 :                         if (os_snprintf_error(end - pos, ret))
    1791           0 :                                 return pos - buf;
    1792        1970 :                         pos += ret;
    1793             :                 }
    1794             : 
    1795             : #ifdef CONFIG_AP
    1796        1970 :                 if (wpa_s->ap_iface) {
    1797         181 :                         pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
    1798         181 :                                                             end - pos,
    1799             :                                                             verbose);
    1800             :                 } else
    1801             : #endif /* CONFIG_AP */
    1802        1789 :                 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
    1803             :         }
    1804             : #ifdef CONFIG_SAE
    1805        4487 :         if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
    1806             : #ifdef CONFIG_AP
    1807        3759 :             !wpa_s->ap_iface &&
    1808             : #endif /* CONFIG_AP */
    1809        1789 :             wpa_s->sme.sae.state == SAE_ACCEPTED) {
    1810          27 :                 ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
    1811             :                                   wpa_s->sme.sae.group);
    1812          27 :                 if (os_snprintf_error(end - pos, ret))
    1813           0 :                         return pos - buf;
    1814          27 :                 pos += ret;
    1815             :         }
    1816             : #endif /* CONFIG_SAE */
    1817        2517 :         ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
    1818             :                           wpa_supplicant_state_txt(wpa_s->wpa_state));
    1819        2517 :         if (os_snprintf_error(end - pos, ret))
    1820           0 :                 return pos - buf;
    1821        2517 :         pos += ret;
    1822             : 
    1823        5034 :         if (wpa_s->l2 &&
    1824        2517 :             l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
    1825           1 :                 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
    1826           1 :                 if (os_snprintf_error(end - pos, ret))
    1827           0 :                         return pos - buf;
    1828           1 :                 pos += ret;
    1829             :         }
    1830             : 
    1831             : #ifdef CONFIG_P2P
    1832        2517 :         if (wpa_s->global->p2p) {
    1833       15036 :                 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
    1834       15036 :                                   "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
    1835        2506 :                 if (os_snprintf_error(end - pos, ret))
    1836           0 :                         return pos - buf;
    1837        2506 :                 pos += ret;
    1838             :         }
    1839             : #endif /* CONFIG_P2P */
    1840             : 
    1841       15102 :         ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
    1842       15102 :                           MAC2STR(wpa_s->own_addr));
    1843        2517 :         if (os_snprintf_error(end - pos, ret))
    1844           0 :                 return pos - buf;
    1845        2517 :         pos += ret;
    1846             : 
    1847             : #ifdef CONFIG_HS20
    1848        4306 :         if (wpa_s->current_bss &&
    1849        1789 :             (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
    1850          47 :                                           HS20_IE_VENDOR_TYPE)) &&
    1851          94 :             wpa_s->wpa_proto == WPA_PROTO_RSN &&
    1852          47 :             wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
    1853          47 :                 int release = 1;
    1854          47 :                 if (hs20[1] >= 5) {
    1855          47 :                         u8 rel_num = (hs20[6] & 0xf0) >> 4;
    1856          47 :                         release = rel_num + 1;
    1857             :                 }
    1858          47 :                 ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
    1859          47 :                 if (os_snprintf_error(end - pos, ret))
    1860           0 :                         return pos - buf;
    1861          47 :                 pos += ret;
    1862             :         }
    1863             : 
    1864        2517 :         if (wpa_s->current_ssid) {
    1865             :                 struct wpa_cred *cred;
    1866             :                 char *type;
    1867             : 
    1868        3998 :                 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
    1869             :                         size_t i;
    1870             : 
    1871          48 :                         if (wpa_s->current_ssid->parent_cred != cred)
    1872           3 :                                 continue;
    1873             : 
    1874          45 :                         if (cred->provisioning_sp) {
    1875           6 :                                 ret = os_snprintf(pos, end - pos,
    1876             :                                                   "provisioning_sp=%s\n",
    1877             :                                                   cred->provisioning_sp);
    1878           6 :                                 if (os_snprintf_error(end - pos, ret))
    1879           0 :                                         return pos - buf;
    1880           6 :                                 pos += ret;
    1881             :                         }
    1882             : 
    1883          45 :                         if (!cred->domain)
    1884          21 :                                 goto no_domain;
    1885             : 
    1886          24 :                         i = 0;
    1887          24 :                         if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
    1888          24 :                                 struct wpabuf *names =
    1889          24 :                                         wpa_s->current_bss->anqp->domain_name;
    1890          25 :                                 for (i = 0; names && i < cred->num_domain; i++)
    1891             :                                 {
    1892          20 :                                         if (domain_name_list_contains(
    1893          20 :                                                     names, cred->domain[i], 1))
    1894          19 :                                                 break;
    1895             :                                 }
    1896          24 :                                 if (i == cred->num_domain)
    1897           1 :                                         i = 0; /* show first entry by default */
    1898             :                         }
    1899          24 :                         ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
    1900          24 :                                           cred->domain[i]);
    1901          24 :                         if (os_snprintf_error(end - pos, ret))
    1902           0 :                                 return pos - buf;
    1903          24 :                         pos += ret;
    1904             : 
    1905             :                 no_domain:
    1906          90 :                         if (wpa_s->current_bss == NULL ||
    1907          45 :                             wpa_s->current_bss->anqp == NULL)
    1908           0 :                                 res = -1;
    1909             :                         else
    1910          45 :                                 res = interworking_home_sp_cred(
    1911             :                                         wpa_s, cred,
    1912          45 :                                         wpa_s->current_bss->anqp->domain_name);
    1913          45 :                         if (res > 0)
    1914          23 :                                 type = "home";
    1915          22 :                         else if (res == 0)
    1916           3 :                                 type = "roaming";
    1917             :                         else
    1918          19 :                                 type = "unknown";
    1919             : 
    1920          45 :                         ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
    1921          45 :                         if (os_snprintf_error(end - pos, ret))
    1922           0 :                                 return pos - buf;
    1923          45 :                         pos += ret;
    1924             : 
    1925          45 :                         break;
    1926             :                 }
    1927             :         }
    1928             : #endif /* CONFIG_HS20 */
    1929             : 
    1930        4778 :         if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
    1931        2261 :             wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
    1932         261 :                 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
    1933             :                                           verbose);
    1934         261 :                 if (res >= 0)
    1935         261 :                         pos += res;
    1936             :         }
    1937             : 
    1938        2517 :         sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
    1939        2517 :         if (sess_id) {
    1940         246 :                 char *start = pos;
    1941             : 
    1942         246 :                 ret = os_snprintf(pos, end - pos, "eap_session_id=");
    1943         246 :                 if (os_snprintf_error(end - pos, ret))
    1944           0 :                         return start - buf;
    1945         246 :                 pos += ret;
    1946         246 :                 ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
    1947         246 :                 if (ret <= 0)
    1948           0 :                         return start - buf;
    1949         246 :                 pos += ret;
    1950         246 :                 ret = os_snprintf(pos, end - pos, "\n");
    1951         246 :                 if (os_snprintf_error(end - pos, ret))
    1952           0 :                         return start - buf;
    1953         246 :                 pos += ret;
    1954             :         }
    1955             : 
    1956        2517 :         res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
    1957        2517 :         if (res >= 0)
    1958        2517 :                 pos += res;
    1959             : 
    1960             : #ifdef CONFIG_WPS
    1961             :         {
    1962             :                 char uuid_str[100];
    1963        2517 :                 uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
    1964        2517 :                 ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
    1965        2517 :                 if (os_snprintf_error(end - pos, ret))
    1966           0 :                         return pos - buf;
    1967        2517 :                 pos += ret;
    1968             :         }
    1969             : #endif /* CONFIG_WPS */
    1970             : 
    1971             : #ifdef ANDROID
    1972             :         /*
    1973             :          * Allow using the STATUS command with default behavior, say for debug,
    1974             :          * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
    1975             :          * events with STATUS-NO_EVENTS.
    1976             :          */
    1977             :         if (os_strcmp(params, "-NO_EVENTS")) {
    1978             :                 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
    1979             :                              "id=%d state=%d BSSID=" MACSTR " SSID=%s",
    1980             :                              wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
    1981             :                              wpa_s->wpa_state,
    1982             :                              MAC2STR(wpa_s->bssid),
    1983             :                              wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
    1984             :                              wpa_ssid_txt(wpa_s->current_ssid->ssid,
    1985             :                                           wpa_s->current_ssid->ssid_len) : "");
    1986             :                 if (wpa_s->wpa_state == WPA_COMPLETED) {
    1987             :                         struct wpa_ssid *ssid = wpa_s->current_ssid;
    1988             :                         wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
    1989             :                                      "- connection to " MACSTR
    1990             :                                      " completed %s [id=%d id_str=%s]",
    1991             :                                      MAC2STR(wpa_s->bssid), "(auth)",
    1992             :                                      ssid ? ssid->id : -1,
    1993             :                                      ssid && ssid->id_str ? ssid->id_str : "");
    1994             :                 }
    1995             :         }
    1996             : #endif /* ANDROID */
    1997             : 
    1998        2517 :         return pos - buf;
    1999             : }
    2000             : 
    2001             : 
    2002           5 : static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
    2003             :                                            char *cmd)
    2004             : {
    2005             :         char *pos;
    2006             :         int id;
    2007             :         struct wpa_ssid *ssid;
    2008             :         u8 bssid[ETH_ALEN];
    2009             : 
    2010             :         /* cmd: "<network id> <BSSID>" */
    2011           5 :         pos = os_strchr(cmd, ' ');
    2012           5 :         if (pos == NULL)
    2013           1 :                 return -1;
    2014           4 :         *pos++ = '\0';
    2015           4 :         id = atoi(cmd);
    2016           4 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
    2017           4 :         if (hwaddr_aton(pos, bssid)) {
    2018           1 :                 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
    2019           1 :                 return -1;
    2020             :         }
    2021             : 
    2022           3 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    2023           3 :         if (ssid == NULL) {
    2024           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
    2025             :                            "to update", id);
    2026           1 :                 return -1;
    2027             :         }
    2028             : 
    2029           2 :         os_memcpy(ssid->bssid, bssid, ETH_ALEN);
    2030           2 :         ssid->bssid_set = !is_zero_ether_addr(bssid);
    2031             : 
    2032           2 :         return 0;
    2033             : }
    2034             : 
    2035             : 
    2036          12 : static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
    2037             :                                                char *cmd, char *buf,
    2038             :                                                size_t buflen)
    2039             : {
    2040             :         u8 bssid[ETH_ALEN];
    2041             :         struct wpa_blacklist *e;
    2042             :         char *pos, *end;
    2043             :         int ret;
    2044             : 
    2045             :         /* cmd: "BLACKLIST [<BSSID>]" */
    2046          12 :         if (*cmd == '\0') {
    2047           5 :                 pos = buf;
    2048           5 :                 end = buf + buflen;
    2049           5 :                 e = wpa_s->blacklist;
    2050          15 :                 while (e) {
    2051          30 :                         ret = os_snprintf(pos, end - pos, MACSTR "\n",
    2052          30 :                                           MAC2STR(e->bssid));
    2053           5 :                         if (os_snprintf_error(end - pos, ret))
    2054           0 :                                 return pos - buf;
    2055           5 :                         pos += ret;
    2056           5 :                         e = e->next;
    2057             :                 }
    2058           5 :                 return pos - buf;
    2059             :         }
    2060             : 
    2061           7 :         cmd++;
    2062           7 :         if (os_strncmp(cmd, "clear", 5) == 0) {
    2063           2 :                 wpa_blacklist_clear(wpa_s);
    2064           2 :                 os_memcpy(buf, "OK\n", 3);
    2065           2 :                 return 3;
    2066             :         }
    2067             : 
    2068           5 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
    2069           5 :         if (hwaddr_aton(cmd, bssid)) {
    2070           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
    2071           1 :                 return -1;
    2072             :         }
    2073             : 
    2074             :         /*
    2075             :          * Add the BSSID twice, so its count will be 2, causing it to be
    2076             :          * skipped when processing scan results.
    2077             :          */
    2078           4 :         ret = wpa_blacklist_add(wpa_s, bssid);
    2079           4 :         if (ret < 0)
    2080           1 :                 return -1;
    2081           3 :         ret = wpa_blacklist_add(wpa_s, bssid);
    2082           3 :         if (ret < 0)
    2083           0 :                 return -1;
    2084           3 :         os_memcpy(buf, "OK\n", 3);
    2085           3 :         return 3;
    2086             : }
    2087             : 
    2088             : 
    2089          10 : static const char * debug_level_str(int level)
    2090             : {
    2091          10 :         switch (level) {
    2092             :         case MSG_EXCESSIVE:
    2093           1 :                 return "EXCESSIVE";
    2094             :         case MSG_MSGDUMP:
    2095           5 :                 return "MSGDUMP";
    2096             :         case MSG_DEBUG:
    2097           1 :                 return "DEBUG";
    2098             :         case MSG_INFO:
    2099           1 :                 return "INFO";
    2100             :         case MSG_WARNING:
    2101           1 :                 return "WARNING";
    2102             :         case MSG_ERROR:
    2103           1 :                 return "ERROR";
    2104             :         default:
    2105           0 :                 return "?";
    2106             :         }
    2107             : }
    2108             : 
    2109             : 
    2110          11 : static int str_to_debug_level(const char *s)
    2111             : {
    2112          11 :         if (os_strcasecmp(s, "EXCESSIVE") == 0)
    2113           1 :                 return MSG_EXCESSIVE;
    2114          10 :         if (os_strcasecmp(s, "MSGDUMP") == 0)
    2115           5 :                 return MSG_MSGDUMP;
    2116           5 :         if (os_strcasecmp(s, "DEBUG") == 0)
    2117           1 :                 return MSG_DEBUG;
    2118           4 :         if (os_strcasecmp(s, "INFO") == 0)
    2119           1 :                 return MSG_INFO;
    2120           3 :         if (os_strcasecmp(s, "WARNING") == 0)
    2121           1 :                 return MSG_WARNING;
    2122           2 :         if (os_strcasecmp(s, "ERROR") == 0)
    2123           1 :                 return MSG_ERROR;
    2124           1 :         return -1;
    2125             : }
    2126             : 
    2127             : 
    2128          21 : static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
    2129             :                                                char *cmd, char *buf,
    2130             :                                                size_t buflen)
    2131             : {
    2132             :         char *pos, *end, *stamp;
    2133             :         int ret;
    2134             : 
    2135             :         /* cmd: "LOG_LEVEL [<level>]" */
    2136          21 :         if (*cmd == '\0') {
    2137          10 :                 pos = buf;
    2138          10 :                 end = buf + buflen;
    2139          10 :                 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
    2140             :                                   "Timestamp: %d\n",
    2141             :                                   debug_level_str(wpa_debug_level),
    2142             :                                   wpa_debug_timestamp);
    2143          10 :                 if (os_snprintf_error(end - pos, ret))
    2144           0 :                         ret = 0;
    2145             : 
    2146          10 :                 return ret;
    2147             :         }
    2148             : 
    2149          36 :         while (*cmd == ' ')
    2150          14 :                 cmd++;
    2151             : 
    2152          11 :         stamp = os_strchr(cmd, ' ');
    2153          11 :         if (stamp) {
    2154           3 :                 *stamp++ = '\0';
    2155           9 :                 while (*stamp == ' ') {
    2156           3 :                         stamp++;
    2157             :                 }
    2158             :         }
    2159             : 
    2160          11 :         if (cmd && os_strlen(cmd)) {
    2161          11 :                 int level = str_to_debug_level(cmd);
    2162          11 :                 if (level < 0)
    2163           1 :                         return -1;
    2164          10 :                 wpa_debug_level = level;
    2165             :         }
    2166             : 
    2167          10 :         if (stamp && os_strlen(stamp))
    2168           3 :                 wpa_debug_timestamp = atoi(stamp);
    2169             : 
    2170          10 :         os_memcpy(buf, "OK\n", 3);
    2171          10 :         return 3;
    2172             : }
    2173             : 
    2174             : 
    2175          25 : static int wpa_supplicant_ctrl_iface_list_networks(
    2176             :         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
    2177             : {
    2178             :         char *pos, *end, *prev;
    2179             :         struct wpa_ssid *ssid;
    2180             :         int ret;
    2181             : 
    2182          25 :         pos = buf;
    2183          25 :         end = buf + buflen;
    2184          25 :         ret = os_snprintf(pos, end - pos,
    2185             :                           "network id / ssid / bssid / flags\n");
    2186          25 :         if (os_snprintf_error(end - pos, ret))
    2187           0 :                 return pos - buf;
    2188          25 :         pos += ret;
    2189             : 
    2190          25 :         ssid = wpa_s->conf->ssid;
    2191             : 
    2192             :         /* skip over ssids until we find next one */
    2193          25 :         if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
    2194           1 :                 int last_id = atoi(cmd + 8);
    2195           1 :                 if (last_id != -1) {
    2196        1000 :                         while (ssid != NULL && ssid->id <= last_id) {
    2197         998 :                                 ssid = ssid->next;
    2198             :                         }
    2199             :                 }
    2200             :         }
    2201             : 
    2202         289 :         while (ssid) {
    2203         240 :                 prev = pos;
    2204         480 :                 ret = os_snprintf(pos, end - pos, "%d\t%s",
    2205             :                                   ssid->id,
    2206         240 :                                   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
    2207         240 :                 if (os_snprintf_error(end - pos, ret))
    2208           0 :                         return prev - buf;
    2209         240 :                 pos += ret;
    2210         240 :                 if (ssid->bssid_set) {
    2211          78 :                         ret = os_snprintf(pos, end - pos, "\t" MACSTR,
    2212          78 :                                           MAC2STR(ssid->bssid));
    2213             :                 } else {
    2214         227 :                         ret = os_snprintf(pos, end - pos, "\tany");
    2215             :                 }
    2216         240 :                 if (os_snprintf_error(end - pos, ret))
    2217           0 :                         return prev - buf;
    2218         240 :                 pos += ret;
    2219         960 :                 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
    2220         240 :                                   ssid == wpa_s->current_ssid ?
    2221             :                                   "[CURRENT]" : "",
    2222         240 :                                   ssid->disabled ? "[DISABLED]" : "",
    2223         240 :                                   ssid->disabled_until.sec ?
    2224             :                                   "[TEMP-DISABLED]" : "",
    2225         240 :                                   ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
    2226             :                                   "");
    2227         240 :                 if (os_snprintf_error(end - pos, ret))
    2228           1 :                         return prev - buf;
    2229         239 :                 pos += ret;
    2230         239 :                 ret = os_snprintf(pos, end - pos, "\n");
    2231         239 :                 if (os_snprintf_error(end - pos, ret))
    2232           0 :                         return prev - buf;
    2233         239 :                 pos += ret;
    2234             : 
    2235         239 :                 ssid = ssid->next;
    2236             :         }
    2237             : 
    2238          24 :         return pos - buf;
    2239             : }
    2240             : 
    2241             : 
    2242         322 : static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
    2243             : {
    2244             :         int ret;
    2245         322 :         ret = os_snprintf(pos, end - pos, "-");
    2246         322 :         if (os_snprintf_error(end - pos, ret))
    2247           0 :                 return pos;
    2248         322 :         pos += ret;
    2249         322 :         ret = wpa_write_ciphers(pos, end, cipher, "+");
    2250         322 :         if (ret < 0)
    2251           0 :                 return pos;
    2252         322 :         pos += ret;
    2253         322 :         return pos;
    2254             : }
    2255             : 
    2256             : 
    2257         322 : static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
    2258             :                                     const u8 *ie, size_t ie_len)
    2259             : {
    2260             :         struct wpa_ie_data data;
    2261             :         char *start;
    2262             :         int ret;
    2263             : 
    2264         322 :         ret = os_snprintf(pos, end - pos, "[%s-", proto);
    2265         322 :         if (os_snprintf_error(end - pos, ret))
    2266           0 :                 return pos;
    2267         322 :         pos += ret;
    2268             : 
    2269         322 :         if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
    2270           0 :                 ret = os_snprintf(pos, end - pos, "?]");
    2271           0 :                 if (os_snprintf_error(end - pos, ret))
    2272           0 :                         return pos;
    2273           0 :                 pos += ret;
    2274           0 :                 return pos;
    2275             :         }
    2276             : 
    2277         322 :         start = pos;
    2278         322 :         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
    2279         189 :                 ret = os_snprintf(pos, end - pos, "%sEAP",
    2280             :                                   pos == start ? "" : "+");
    2281         189 :                 if (os_snprintf_error(end - pos, ret))
    2282           0 :                         return pos;
    2283         189 :                 pos += ret;
    2284             :         }
    2285         322 :         if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
    2286         113 :                 ret = os_snprintf(pos, end - pos, "%sPSK",
    2287             :                                   pos == start ? "" : "+");
    2288         113 :                 if (os_snprintf_error(end - pos, ret))
    2289           0 :                         return pos;
    2290         113 :                 pos += ret;
    2291             :         }
    2292         322 :         if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
    2293           1 :                 ret = os_snprintf(pos, end - pos, "%sNone",
    2294             :                                   pos == start ? "" : "+");
    2295           1 :                 if (os_snprintf_error(end - pos, ret))
    2296           0 :                         return pos;
    2297           1 :                 pos += ret;
    2298             :         }
    2299         322 :         if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
    2300           3 :                 ret = os_snprintf(pos, end - pos, "%sSAE",
    2301             :                                   pos == start ? "" : "+");
    2302           3 :                 if (os_snprintf_error(end - pos, ret))
    2303           0 :                         return pos;
    2304           3 :                 pos += ret;
    2305             :         }
    2306             : #ifdef CONFIG_IEEE80211R
    2307         322 :         if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
    2308           7 :                 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
    2309             :                                   pos == start ? "" : "+");
    2310           7 :                 if (os_snprintf_error(end - pos, ret))
    2311           0 :                         return pos;
    2312           7 :                 pos += ret;
    2313             :         }
    2314         322 :         if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
    2315          18 :                 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
    2316             :                                   pos == start ? "" : "+");
    2317          18 :                 if (os_snprintf_error(end - pos, ret))
    2318           0 :                         return pos;
    2319          18 :                 pos += ret;
    2320             :         }
    2321         322 :         if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
    2322           4 :                 ret = os_snprintf(pos, end - pos, "%sFT/SAE",
    2323             :                                   pos == start ? "" : "+");
    2324           4 :                 if (os_snprintf_error(end - pos, ret))
    2325           0 :                         return pos;
    2326           4 :                 pos += ret;
    2327             :         }
    2328             : #endif /* CONFIG_IEEE80211R */
    2329             : #ifdef CONFIG_IEEE80211W
    2330         322 :         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
    2331           3 :                 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
    2332             :                                   pos == start ? "" : "+");
    2333           3 :                 if (os_snprintf_error(end - pos, ret))
    2334           0 :                         return pos;
    2335           3 :                 pos += ret;
    2336             :         }
    2337         322 :         if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
    2338           3 :                 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
    2339             :                                   pos == start ? "" : "+");
    2340           3 :                 if (os_snprintf_error(end - pos, ret))
    2341           0 :                         return pos;
    2342           3 :                 pos += ret;
    2343             :         }
    2344             : #endif /* CONFIG_IEEE80211W */
    2345             : 
    2346             : #ifdef CONFIG_SUITEB
    2347         322 :         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
    2348           1 :                 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
    2349             :                                   pos == start ? "" : "+");
    2350           1 :                 if (os_snprintf_error(end - pos, ret))
    2351           0 :                         return pos;
    2352           1 :                 pos += ret;
    2353             :         }
    2354             : #endif /* CONFIG_SUITEB */
    2355             : 
    2356             : #ifdef CONFIG_SUITEB192
    2357         322 :         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
    2358           1 :                 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
    2359             :                                   pos == start ? "" : "+");
    2360           1 :                 if (os_snprintf_error(end - pos, ret))
    2361           0 :                         return pos;
    2362           1 :                 pos += ret;
    2363             :         }
    2364             : #endif /* CONFIG_SUITEB192 */
    2365             : 
    2366         322 :         pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
    2367             : 
    2368         322 :         if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
    2369           4 :                 ret = os_snprintf(pos, end - pos, "-preauth");
    2370           4 :                 if (os_snprintf_error(end - pos, ret))
    2371           0 :                         return pos;
    2372           4 :                 pos += ret;
    2373             :         }
    2374             : 
    2375         322 :         ret = os_snprintf(pos, end - pos, "]");
    2376         322 :         if (os_snprintf_error(end - pos, ret))
    2377           0 :                 return pos;
    2378         322 :         pos += ret;
    2379             : 
    2380         322 :         return pos;
    2381             : }
    2382             : 
    2383             : 
    2384             : #ifdef CONFIG_WPS
    2385         436 : static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
    2386             :                                             char *pos, char *end,
    2387             :                                             struct wpabuf *wps_ie)
    2388             : {
    2389             :         int ret;
    2390             :         const char *txt;
    2391             : 
    2392         436 :         if (wps_ie == NULL)
    2393         329 :                 return pos;
    2394         107 :         if (wps_is_selected_pbc_registrar(wps_ie))
    2395          30 :                 txt = "[WPS-PBC]";
    2396          77 :         else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
    2397          26 :                 txt = "[WPS-AUTH]";
    2398          51 :         else if (wps_is_selected_pin_registrar(wps_ie))
    2399           1 :                 txt = "[WPS-PIN]";
    2400             :         else
    2401          50 :                 txt = "[WPS]";
    2402             : 
    2403         107 :         ret = os_snprintf(pos, end - pos, "%s", txt);
    2404         107 :         if (!os_snprintf_error(end - pos, ret))
    2405         107 :                 pos += ret;
    2406         107 :         wpabuf_free(wps_ie);
    2407         107 :         return pos;
    2408             : }
    2409             : #endif /* CONFIG_WPS */
    2410             : 
    2411             : 
    2412         436 : static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
    2413             :                                         char *pos, char *end,
    2414             :                                         const struct wpa_bss *bss)
    2415             : {
    2416             : #ifdef CONFIG_WPS
    2417             :         struct wpabuf *wps_ie;
    2418         436 :         wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
    2419         436 :         return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
    2420             : #else /* CONFIG_WPS */
    2421             :         return pos;
    2422             : #endif /* CONFIG_WPS */
    2423             : }
    2424             : 
    2425             : 
    2426             : /* Format one result on one text line into a buffer. */
    2427          38 : static int wpa_supplicant_ctrl_iface_scan_result(
    2428             :         struct wpa_supplicant *wpa_s,
    2429             :         const struct wpa_bss *bss, char *buf, size_t buflen)
    2430             : {
    2431             :         char *pos, *end;
    2432             :         int ret;
    2433             :         const u8 *ie, *ie2, *p2p, *mesh;
    2434             : 
    2435          38 :         mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
    2436          38 :         p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
    2437          38 :         if (!p2p)
    2438          34 :                 p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
    2439          38 :         if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
    2440           0 :             os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
    2441             :             0)
    2442           0 :                 return 0; /* Do not show P2P listen discovery results here */
    2443             : 
    2444          38 :         pos = buf;
    2445          38 :         end = buf + buflen;
    2446             : 
    2447         266 :         ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
    2448         228 :                           MAC2STR(bss->bssid), bss->freq, bss->level);
    2449          38 :         if (os_snprintf_error(end - pos, ret))
    2450           0 :                 return -1;
    2451          38 :         pos += ret;
    2452          38 :         ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
    2453          38 :         if (ie)
    2454           2 :                 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
    2455          38 :         ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
    2456          38 :         if (ie2) {
    2457          16 :                 pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
    2458          16 :                                             ie2, 2 + ie2[1]);
    2459             :         }
    2460          38 :         pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
    2461          38 :         if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
    2462           2 :                 ret = os_snprintf(pos, end - pos, "[WEP]");
    2463           2 :                 if (os_snprintf_error(end - pos, ret))
    2464           0 :                         return -1;
    2465           2 :                 pos += ret;
    2466             :         }
    2467          38 :         if (mesh) {
    2468           1 :                 ret = os_snprintf(pos, end - pos, "[MESH]");
    2469           1 :                 if (os_snprintf_error(end - pos, ret))
    2470           0 :                         return -1;
    2471           1 :                 pos += ret;
    2472             :         }
    2473          38 :         if (bss_is_dmg(bss)) {
    2474             :                 const char *s;
    2475           0 :                 ret = os_snprintf(pos, end - pos, "[DMG]");
    2476           0 :                 if (os_snprintf_error(end - pos, ret))
    2477           0 :                         return -1;
    2478           0 :                 pos += ret;
    2479           0 :                 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
    2480             :                 case IEEE80211_CAP_DMG_IBSS:
    2481           0 :                         s = "[IBSS]";
    2482           0 :                         break;
    2483             :                 case IEEE80211_CAP_DMG_AP:
    2484           0 :                         s = "[ESS]";
    2485           0 :                         break;
    2486             :                 case IEEE80211_CAP_DMG_PBSS:
    2487           0 :                         s = "[PBSS]";
    2488           0 :                         break;
    2489             :                 default:
    2490           0 :                         s = "";
    2491           0 :                         break;
    2492             :                 }
    2493           0 :                 ret = os_snprintf(pos, end - pos, "%s", s);
    2494           0 :                 if (os_snprintf_error(end - pos, ret))
    2495           0 :                         return -1;
    2496           0 :                 pos += ret;
    2497             :         } else {
    2498          38 :                 if (bss->caps & IEEE80211_CAP_IBSS) {
    2499           1 :                         ret = os_snprintf(pos, end - pos, "[IBSS]");
    2500           1 :                         if (os_snprintf_error(end - pos, ret))
    2501           0 :                                 return -1;
    2502           1 :                         pos += ret;
    2503             :                 }
    2504          38 :                 if (bss->caps & IEEE80211_CAP_ESS) {
    2505          36 :                         ret = os_snprintf(pos, end - pos, "[ESS]");
    2506          36 :                         if (os_snprintf_error(end - pos, ret))
    2507           0 :                                 return -1;
    2508          36 :                         pos += ret;
    2509             :                 }
    2510             :         }
    2511          38 :         if (p2p) {
    2512           5 :                 ret = os_snprintf(pos, end - pos, "[P2P]");
    2513           5 :                 if (os_snprintf_error(end - pos, ret))
    2514           0 :                         return -1;
    2515           5 :                 pos += ret;
    2516             :         }
    2517             : #ifdef CONFIG_HS20
    2518          38 :         if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
    2519           1 :                 ret = os_snprintf(pos, end - pos, "[HS20]");
    2520           1 :                 if (os_snprintf_error(end - pos, ret))
    2521           0 :                         return -1;
    2522           1 :                 pos += ret;
    2523             :         }
    2524             : #endif /* CONFIG_HS20 */
    2525             : 
    2526          76 :         ret = os_snprintf(pos, end - pos, "\t%s",
    2527          38 :                           wpa_ssid_txt(bss->ssid, bss->ssid_len));
    2528          38 :         if (os_snprintf_error(end - pos, ret))
    2529           0 :                 return -1;
    2530          38 :         pos += ret;
    2531             : 
    2532          38 :         ret = os_snprintf(pos, end - pos, "\n");
    2533          38 :         if (os_snprintf_error(end - pos, ret))
    2534           0 :                 return -1;
    2535          38 :         pos += ret;
    2536             : 
    2537          38 :         return pos - buf;
    2538             : }
    2539             : 
    2540             : 
    2541          31 : static int wpa_supplicant_ctrl_iface_scan_results(
    2542             :         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
    2543             : {
    2544             :         char *pos, *end;
    2545             :         struct wpa_bss *bss;
    2546             :         int ret;
    2547             : 
    2548          31 :         pos = buf;
    2549          31 :         end = buf + buflen;
    2550          31 :         ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
    2551             :                           "flags / ssid\n");
    2552          31 :         if (os_snprintf_error(end - pos, ret))
    2553           0 :                 return pos - buf;
    2554          31 :         pos += ret;
    2555             : 
    2556          69 :         dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
    2557          38 :                 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
    2558          38 :                                                             end - pos);
    2559          38 :                 if (ret < 0 || ret >= end - pos)
    2560           0 :                         return pos - buf;
    2561          38 :                 pos += ret;
    2562             :         }
    2563             : 
    2564          31 :         return pos - buf;
    2565             : }
    2566             : 
    2567             : 
    2568             : #ifdef CONFIG_MESH
    2569             : 
    2570           4 : static int wpa_supplicant_ctrl_iface_mesh_interface_add(
    2571             :         struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
    2572             : {
    2573             :         char *pos, ifname[IFNAMSIZ + 1];
    2574             : 
    2575           4 :         ifname[0] = '\0';
    2576             : 
    2577           4 :         pos = os_strstr(cmd, "ifname=");
    2578           4 :         if (pos) {
    2579           2 :                 pos += 7;
    2580           2 :                 os_strlcpy(ifname, pos, sizeof(ifname));
    2581             :         }
    2582             : 
    2583           4 :         if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
    2584           0 :                 return -1;
    2585             : 
    2586           4 :         os_strlcpy(reply, ifname, max_len);
    2587           4 :         return os_strlen(ifname);
    2588             : }
    2589             : 
    2590             : 
    2591          32 : static int wpa_supplicant_ctrl_iface_mesh_group_add(
    2592             :         struct wpa_supplicant *wpa_s, char *cmd)
    2593             : {
    2594             :         int id;
    2595             :         struct wpa_ssid *ssid;
    2596             : 
    2597          32 :         id = atoi(cmd);
    2598          32 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
    2599             : 
    2600          32 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    2601          32 :         if (ssid == NULL) {
    2602           1 :                 wpa_printf(MSG_DEBUG,
    2603             :                            "CTRL_IFACE: Could not find network id=%d", id);
    2604           1 :                 return -1;
    2605             :         }
    2606          31 :         if (ssid->mode != WPAS_MODE_MESH) {
    2607           1 :                 wpa_printf(MSG_DEBUG,
    2608             :                            "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
    2609           1 :                 return -1;
    2610             :         }
    2611          39 :         if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
    2612           9 :             ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
    2613           1 :                 wpa_printf(MSG_ERROR,
    2614             :                            "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
    2615           1 :                 return -1;
    2616             :         }
    2617             : 
    2618             :         /*
    2619             :          * TODO: If necessary write our own group_add function,
    2620             :          * for now we can reuse select_network
    2621             :          */
    2622          29 :         wpa_supplicant_select_network(wpa_s, ssid);
    2623             : 
    2624          29 :         return 0;
    2625             : }
    2626             : 
    2627             : 
    2628          17 : static int wpa_supplicant_ctrl_iface_mesh_group_remove(
    2629             :         struct wpa_supplicant *wpa_s, char *cmd)
    2630             : {
    2631             :         struct wpa_supplicant *orig;
    2632             :         struct wpa_global *global;
    2633          17 :         int found = 0;
    2634             : 
    2635          17 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
    2636             : 
    2637          17 :         global = wpa_s->global;
    2638          17 :         orig = wpa_s;
    2639             : 
    2640          24 :         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
    2641          19 :                 if (os_strcmp(wpa_s->ifname, cmd) == 0) {
    2642          12 :                         found = 1;
    2643          12 :                         break;
    2644             :                 }
    2645             :         }
    2646          17 :         if (!found) {
    2647           5 :                 wpa_printf(MSG_ERROR,
    2648             :                            "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
    2649             :                            cmd);
    2650           5 :                 return -1;
    2651             :         }
    2652          12 :         if (wpa_s->mesh_if_created && wpa_s == orig) {
    2653           2 :                 wpa_printf(MSG_ERROR,
    2654             :                            "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
    2655           2 :                 return -1;
    2656             :         }
    2657             : 
    2658          10 :         wpa_s->reassociate = 0;
    2659          10 :         wpa_s->disconnected = 1;
    2660          10 :         wpa_supplicant_cancel_sched_scan(wpa_s);
    2661          10 :         wpa_supplicant_cancel_scan(wpa_s);
    2662             : 
    2663             :         /*
    2664             :          * TODO: If necessary write our own group_remove function,
    2665             :          * for now we can reuse deauthenticate
    2666             :          */
    2667          10 :         wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
    2668             : 
    2669          10 :         if (wpa_s->mesh_if_created)
    2670           4 :                 wpa_supplicant_remove_iface(global, wpa_s, 0);
    2671             : 
    2672          10 :         return 0;
    2673             : }
    2674             : 
    2675             : #endif /* CONFIG_MESH */
    2676             : 
    2677             : 
    2678        1386 : static int wpa_supplicant_ctrl_iface_select_network(
    2679             :         struct wpa_supplicant *wpa_s, char *cmd)
    2680             : {
    2681             :         int id;
    2682             :         struct wpa_ssid *ssid;
    2683             :         char *pos;
    2684             : 
    2685             :         /* cmd: "<network id>" or "any" */
    2686        1386 :         if (os_strncmp(cmd, "any", 3) == 0) {
    2687           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
    2688           1 :                 ssid = NULL;
    2689             :         } else {
    2690        1385 :                 id = atoi(cmd);
    2691        1385 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
    2692             : 
    2693        1385 :                 ssid = wpa_config_get_network(wpa_s->conf, id);
    2694        1385 :                 if (ssid == NULL) {
    2695           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    2696             :                                    "network id=%d", id);
    2697           1 :                         return -1;
    2698             :                 }
    2699        1384 :                 if (ssid->disabled == 2) {
    2700           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
    2701             :                                    "SELECT_NETWORK with persistent P2P group");
    2702           1 :                         return -1;
    2703             :                 }
    2704             :         }
    2705             : 
    2706        1384 :         pos = os_strstr(cmd, " freq=");
    2707        1384 :         if (pos) {
    2708          28 :                 int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
    2709          28 :                 if (freqs) {
    2710          28 :                         wpa_s->scan_req = MANUAL_SCAN_REQ;
    2711          28 :                         os_free(wpa_s->manual_scan_freqs);
    2712          28 :                         wpa_s->manual_scan_freqs = freqs;
    2713             :                 }
    2714             :         }
    2715             : 
    2716        1384 :         wpa_supplicant_select_network(wpa_s, ssid);
    2717             : 
    2718        1384 :         return 0;
    2719             : }
    2720             : 
    2721             : 
    2722          28 : static int wpa_supplicant_ctrl_iface_enable_network(
    2723             :         struct wpa_supplicant *wpa_s, char *cmd)
    2724             : {
    2725             :         int id;
    2726             :         struct wpa_ssid *ssid;
    2727             : 
    2728             :         /* cmd: "<network id>" or "all" */
    2729          28 :         if (os_strcmp(cmd, "all") == 0) {
    2730           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
    2731           1 :                 ssid = NULL;
    2732             :         } else {
    2733          27 :                 id = atoi(cmd);
    2734          27 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
    2735             : 
    2736          27 :                 ssid = wpa_config_get_network(wpa_s->conf, id);
    2737          27 :                 if (ssid == NULL) {
    2738           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    2739             :                                    "network id=%d", id);
    2740           1 :                         return -1;
    2741             :                 }
    2742          26 :                 if (ssid->disabled == 2) {
    2743           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
    2744             :                                    "ENABLE_NETWORK with persistent P2P group");
    2745           1 :                         return -1;
    2746             :                 }
    2747             : 
    2748          25 :                 if (os_strstr(cmd, " no-connect")) {
    2749          23 :                         ssid->disabled = 0;
    2750          23 :                         return 0;
    2751             :                 }
    2752             :         }
    2753           3 :         wpa_supplicant_enable_network(wpa_s, ssid);
    2754             : 
    2755           3 :         return 0;
    2756             : }
    2757             : 
    2758             : 
    2759           6 : static int wpa_supplicant_ctrl_iface_disable_network(
    2760             :         struct wpa_supplicant *wpa_s, char *cmd)
    2761             : {
    2762             :         int id;
    2763             :         struct wpa_ssid *ssid;
    2764             : 
    2765             :         /* cmd: "<network id>" or "all" */
    2766           6 :         if (os_strcmp(cmd, "all") == 0) {
    2767           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
    2768           2 :                 ssid = NULL;
    2769             :         } else {
    2770           4 :                 id = atoi(cmd);
    2771           4 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
    2772             : 
    2773           4 :                 ssid = wpa_config_get_network(wpa_s->conf, id);
    2774           4 :                 if (ssid == NULL) {
    2775           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    2776             :                                    "network id=%d", id);
    2777           1 :                         return -1;
    2778             :                 }
    2779           3 :                 if (ssid->disabled == 2) {
    2780           1 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
    2781             :                                    "DISABLE_NETWORK with persistent P2P "
    2782             :                                    "group");
    2783           1 :                         return -1;
    2784             :                 }
    2785             :         }
    2786           4 :         wpa_supplicant_disable_network(wpa_s, ssid);
    2787             : 
    2788           4 :         return 0;
    2789             : }
    2790             : 
    2791             : 
    2792        2401 : static int wpa_supplicant_ctrl_iface_add_network(
    2793             :         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
    2794             : {
    2795             :         struct wpa_ssid *ssid;
    2796             :         int ret;
    2797             : 
    2798        2401 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
    2799             : 
    2800        2401 :         ssid = wpa_config_add_network(wpa_s->conf);
    2801        2401 :         if (ssid == NULL)
    2802           0 :                 return -1;
    2803             : 
    2804        2401 :         wpas_notify_network_added(wpa_s, ssid);
    2805             : 
    2806        2401 :         ssid->disabled = 1;
    2807        2401 :         wpa_config_set_network_defaults(ssid);
    2808             : 
    2809        2401 :         ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
    2810        2401 :         if (os_snprintf_error(buflen, ret))
    2811           0 :                 return -1;
    2812        2401 :         return ret;
    2813             : }
    2814             : 
    2815             : 
    2816        3875 : static int wpa_supplicant_ctrl_iface_remove_network(
    2817             :         struct wpa_supplicant *wpa_s, char *cmd)
    2818             : {
    2819             :         int id;
    2820             :         struct wpa_ssid *ssid;
    2821             :         int was_disabled;
    2822             : 
    2823             :         /* cmd: "<network id>" or "all" */
    2824        3875 :         if (os_strcmp(cmd, "all") == 0) {
    2825        3755 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
    2826        3755 :                 if (wpa_s->sched_scanning)
    2827           0 :                         wpa_supplicant_cancel_sched_scan(wpa_s);
    2828             : 
    2829        3755 :                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
    2830        3755 :                 if (wpa_s->current_ssid) {
    2831             : #ifdef CONFIG_SME
    2832         595 :                         wpa_s->sme.prev_bssid_set = 0;
    2833             : #endif /* CONFIG_SME */
    2834         595 :                         wpa_sm_set_config(wpa_s->wpa, NULL);
    2835         595 :                         eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
    2836         595 :                         wpa_supplicant_deauthenticate(
    2837             :                                 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
    2838             :                 }
    2839        3755 :                 ssid = wpa_s->conf->ssid;
    2840        9999 :                 while (ssid) {
    2841        2489 :                         struct wpa_ssid *remove_ssid = ssid;
    2842        2489 :                         id = ssid->id;
    2843        2489 :                         ssid = ssid->next;
    2844        2489 :                         if (wpa_s->last_ssid == remove_ssid)
    2845        1309 :                                 wpa_s->last_ssid = NULL;
    2846        2489 :                         wpas_notify_network_removed(wpa_s, remove_ssid);
    2847        2489 :                         wpa_config_remove_network(wpa_s->conf, id);
    2848             :                 }
    2849        3755 :                 return 0;
    2850             :         }
    2851             : 
    2852         120 :         id = atoi(cmd);
    2853         120 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
    2854             : 
    2855         120 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    2856         120 :         if (ssid)
    2857         119 :                 wpas_notify_network_removed(wpa_s, ssid);
    2858         120 :         if (ssid == NULL) {
    2859           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
    2860             :                            "id=%d", id);
    2861           1 :                 return -1;
    2862             :         }
    2863             : 
    2864         119 :         if (wpa_s->last_ssid == ssid)
    2865          83 :                 wpa_s->last_ssid = NULL;
    2866             : 
    2867         119 :         if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
    2868             : #ifdef CONFIG_SME
    2869         118 :                 wpa_s->sme.prev_bssid_set = 0;
    2870             : #endif /* CONFIG_SME */
    2871             :                 /*
    2872             :                  * Invalidate the EAP session cache if the current or
    2873             :                  * previously used network is removed.
    2874             :                  */
    2875         118 :                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
    2876             :         }
    2877             : 
    2878         119 :         if (ssid == wpa_s->current_ssid) {
    2879          95 :                 wpa_sm_set_config(wpa_s->wpa, NULL);
    2880          95 :                 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
    2881             : 
    2882          95 :                 wpa_supplicant_deauthenticate(wpa_s,
    2883             :                                               WLAN_REASON_DEAUTH_LEAVING);
    2884             :         }
    2885             : 
    2886         119 :         was_disabled = ssid->disabled;
    2887             : 
    2888         119 :         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
    2889           0 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
    2890             :                            "network id=%d", id);
    2891           0 :                 return -1;
    2892             :         }
    2893             : 
    2894         119 :         if (!was_disabled && wpa_s->sched_scanning) {
    2895           0 :                 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
    2896             :                            "network from filters");
    2897           0 :                 wpa_supplicant_cancel_sched_scan(wpa_s);
    2898           0 :                 wpa_supplicant_req_scan(wpa_s, 0, 0);
    2899             :         }
    2900             : 
    2901         119 :         return 0;
    2902             : }
    2903             : 
    2904             : 
    2905        7591 : static int wpa_supplicant_ctrl_iface_update_network(
    2906             :         struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
    2907             :         char *name, char *value)
    2908             : {
    2909        7591 :         if (wpa_config_set(ssid, name, value, 0) < 0) {
    2910          33 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
    2911             :                            "variable '%s'", name);
    2912          33 :                 return -1;
    2913             :         }
    2914             : 
    2915       15094 :         if (os_strcmp(name, "bssid") != 0 &&
    2916        7536 :             os_strcmp(name, "priority") != 0)
    2917        7535 :                 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
    2918             : 
    2919        7558 :         if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
    2920             :                 /*
    2921             :                  * Invalidate the EAP session cache if anything in the current
    2922             :                  * or previously used configuration changes.
    2923             :                  */
    2924        7534 :                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
    2925             :         }
    2926             : 
    2927        7815 :         if ((os_strcmp(name, "psk") == 0 &&
    2928        7818 :              value[0] == '"' && ssid->ssid_len) ||
    2929        8707 :             (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
    2930         245 :                 wpa_config_update_psk(ssid);
    2931        7313 :         else if (os_strcmp(name, "priority") == 0)
    2932           1 :                 wpa_config_update_prio_list(wpa_s->conf);
    2933        7312 :         else if (os_strcmp(name, "no_auto_peer") == 0)
    2934           2 :                 ssid->no_auto_peer = atoi(value);
    2935             : 
    2936        7558 :         return 0;
    2937             : }
    2938             : 
    2939             : 
    2940        7590 : static int wpa_supplicant_ctrl_iface_set_network(
    2941             :         struct wpa_supplicant *wpa_s, char *cmd)
    2942             : {
    2943             :         int id, ret, prev_bssid_set;
    2944             :         struct wpa_ssid *ssid;
    2945             :         char *name, *value;
    2946             :         u8 prev_bssid[ETH_ALEN];
    2947             : 
    2948             :         /* cmd: "<network id> <variable name> <value>" */
    2949        7590 :         name = os_strchr(cmd, ' ');
    2950        7590 :         if (name == NULL)
    2951           1 :                 return -1;
    2952        7589 :         *name++ = '\0';
    2953             : 
    2954        7589 :         value = os_strchr(name, ' ');
    2955        7589 :         if (value == NULL)
    2956           1 :                 return -1;
    2957        7588 :         *value++ = '\0';
    2958             : 
    2959        7588 :         id = atoi(cmd);
    2960        7588 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
    2961             :                    id, name);
    2962        7588 :         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
    2963             :                               (u8 *) value, os_strlen(value));
    2964             : 
    2965        7588 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    2966        7588 :         if (ssid == NULL) {
    2967           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
    2968             :                            "id=%d", id);
    2969           1 :                 return -1;
    2970             :         }
    2971             : 
    2972        7587 :         prev_bssid_set = ssid->bssid_set;
    2973        7587 :         os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
    2974        7587 :         ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
    2975             :                                                        value);
    2976       15141 :         if (ret == 0 &&
    2977       15087 :             (ssid->bssid_set != prev_bssid_set ||
    2978        7533 :              os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
    2979          22 :                 wpas_notify_network_bssid_set_changed(wpa_s, ssid);
    2980        7587 :         return ret;
    2981             : }
    2982             : 
    2983             : 
    2984          56 : static int wpa_supplicant_ctrl_iface_get_network(
    2985             :         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
    2986             : {
    2987             :         int id;
    2988             :         size_t res;
    2989             :         struct wpa_ssid *ssid;
    2990             :         char *name, *value;
    2991             : 
    2992             :         /* cmd: "<network id> <variable name>" */
    2993          56 :         name = os_strchr(cmd, ' ');
    2994          56 :         if (name == NULL || buflen == 0)
    2995           1 :                 return -1;
    2996          55 :         *name++ = '\0';
    2997             : 
    2998          55 :         id = atoi(cmd);
    2999          55 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
    3000             :                    id, name);
    3001             : 
    3002          55 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    3003          55 :         if (ssid == NULL) {
    3004           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
    3005             :                            "id=%d", id);
    3006           1 :                 return -1;
    3007             :         }
    3008             : 
    3009          54 :         value = wpa_config_get_no_key(ssid, name);
    3010          54 :         if (value == NULL) {
    3011           7 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
    3012             :                            "variable '%s'", name);
    3013           7 :                 return -1;
    3014             :         }
    3015             : 
    3016          47 :         res = os_strlcpy(buf, value, buflen);
    3017          47 :         if (res >= buflen) {
    3018           0 :                 os_free(value);
    3019           0 :                 return -1;
    3020             :         }
    3021             : 
    3022          47 :         os_free(value);
    3023             : 
    3024          47 :         return res;
    3025             : }
    3026             : 
    3027             : 
    3028          10 : static int wpa_supplicant_ctrl_iface_dup_network(
    3029             :         struct wpa_supplicant *wpa_s, char *cmd)
    3030             : {
    3031             :         struct wpa_ssid *ssid_s, *ssid_d;
    3032             :         char *name, *id, *value;
    3033             :         int id_s, id_d, ret;
    3034             : 
    3035             :         /* cmd: "<src network id> <dst network id> <variable name>" */
    3036          10 :         id = os_strchr(cmd, ' ');
    3037          10 :         if (id == NULL)
    3038           1 :                 return -1;
    3039           9 :         *id++ = '\0';
    3040             : 
    3041           9 :         name = os_strchr(id, ' ');
    3042           9 :         if (name == NULL)
    3043           2 :                 return -1;
    3044           7 :         *name++ = '\0';
    3045             : 
    3046           7 :         id_s = atoi(cmd);
    3047           7 :         id_d = atoi(id);
    3048           7 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'",
    3049             :                    id_s, id_d, name);
    3050             : 
    3051           7 :         ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
    3052           7 :         if (ssid_s == NULL) {
    3053           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    3054             :                            "network id=%d", id_s);
    3055           1 :                 return -1;
    3056             :         }
    3057             : 
    3058           6 :         ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
    3059           6 :         if (ssid_d == NULL) {
    3060           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    3061             :                            "network id=%d", id_d);
    3062           1 :                 return -1;
    3063             :         }
    3064             : 
    3065           5 :         value = wpa_config_get(ssid_s, name);
    3066           5 :         if (value == NULL) {
    3067           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
    3068             :                            "variable '%s'", name);
    3069           1 :                 return -1;
    3070             :         }
    3071             : 
    3072           4 :         ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name,
    3073             :                                                        value);
    3074             : 
    3075           4 :         os_free(value);
    3076             : 
    3077           4 :         return ret;
    3078             : }
    3079             : 
    3080             : 
    3081           8 : static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
    3082             :                                                 char *buf, size_t buflen)
    3083             : {
    3084             :         char *pos, *end;
    3085             :         struct wpa_cred *cred;
    3086             :         int ret;
    3087             : 
    3088           8 :         pos = buf;
    3089           8 :         end = buf + buflen;
    3090           8 :         ret = os_snprintf(pos, end - pos,
    3091             :                           "cred id / realm / username / domain / imsi\n");
    3092           8 :         if (os_snprintf_error(end - pos, ret))
    3093           0 :                 return pos - buf;
    3094           8 :         pos += ret;
    3095             : 
    3096           8 :         cred = wpa_s->conf->cred;
    3097         111 :         while (cred) {
    3098         388 :                 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
    3099          96 :                                   cred->id, cred->realm ? cred->realm : "",
    3100          96 :                                   cred->username ? cred->username : "",
    3101         100 :                                   cred->domain ? cred->domain[0] : "",
    3102          96 :                                   cred->imsi ? cred->imsi : "");
    3103          96 :                 if (os_snprintf_error(end - pos, ret))
    3104           1 :                         return pos - buf;
    3105          95 :                 pos += ret;
    3106             : 
    3107          95 :                 cred = cred->next;
    3108             :         }
    3109             : 
    3110           7 :         return pos - buf;
    3111             : }
    3112             : 
    3113             : 
    3114         223 : static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
    3115             :                                               char *buf, size_t buflen)
    3116             : {
    3117             :         struct wpa_cred *cred;
    3118             :         int ret;
    3119             : 
    3120         223 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
    3121             : 
    3122         223 :         cred = wpa_config_add_cred(wpa_s->conf);
    3123         223 :         if (cred == NULL)
    3124           0 :                 return -1;
    3125             : 
    3126         223 :         wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
    3127             : 
    3128         223 :         ret = os_snprintf(buf, buflen, "%d\n", cred->id);
    3129         223 :         if (os_snprintf_error(buflen, ret))
    3130           0 :                 return -1;
    3131         223 :         return ret;
    3132             : }
    3133             : 
    3134             : 
    3135         221 : static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
    3136             :                                  struct wpa_cred *cred)
    3137             : {
    3138             :         struct wpa_ssid *ssid;
    3139             :         char str[20];
    3140             :         int id;
    3141             : 
    3142         221 :         if (cred == NULL) {
    3143           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
    3144           1 :                 return -1;
    3145             :         }
    3146             : 
    3147         220 :         id = cred->id;
    3148         220 :         if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
    3149           0 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
    3150           0 :                 return -1;
    3151             :         }
    3152             : 
    3153         220 :         wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
    3154             : 
    3155             :         /* Remove any network entry created based on the removed credential */
    3156         220 :         ssid = wpa_s->conf->ssid;
    3157         464 :         while (ssid) {
    3158          24 :                 if (ssid->parent_cred == cred) {
    3159             :                         int res;
    3160             : 
    3161          21 :                         wpa_printf(MSG_DEBUG, "Remove network id %d since it "
    3162             :                                    "used the removed credential", ssid->id);
    3163          21 :                         res = os_snprintf(str, sizeof(str), "%d", ssid->id);
    3164          21 :                         if (os_snprintf_error(sizeof(str), res))
    3165           0 :                                 str[sizeof(str) - 1] = '\0';
    3166          21 :                         ssid = ssid->next;
    3167          21 :                         wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
    3168             :                 } else
    3169           3 :                         ssid = ssid->next;
    3170             :         }
    3171             : 
    3172         220 :         return 0;
    3173             : }
    3174             : 
    3175             : 
    3176        3318 : static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
    3177             :                                                  char *cmd)
    3178             : {
    3179             :         int id;
    3180             :         struct wpa_cred *cred, *prev;
    3181             : 
    3182             :         /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
    3183             :          * "provisioning_sp=<FQDN> */
    3184        3318 :         if (os_strcmp(cmd, "all") == 0) {
    3185        3173 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
    3186        3173 :                 cred = wpa_s->conf->cred;
    3187        6420 :                 while (cred) {
    3188          74 :                         prev = cred;
    3189          74 :                         cred = cred->next;
    3190          74 :                         wpas_ctrl_remove_cred(wpa_s, prev);
    3191             :                 }
    3192        3173 :                 return 0;
    3193             :         }
    3194             : 
    3195         145 :         if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
    3196           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
    3197             :                            cmd + 8);
    3198           1 :                 cred = wpa_s->conf->cred;
    3199           5 :                 while (cred) {
    3200           3 :                         prev = cred;
    3201           3 :                         cred = cred->next;
    3202           3 :                         if (prev->domain) {
    3203             :                                 size_t i;
    3204           8 :                                 for (i = 0; i < prev->num_domain; i++) {
    3205           3 :                                         if (os_strcmp(prev->domain[i], cmd + 8)
    3206             :                                             != 0)
    3207           1 :                                                 continue;
    3208           2 :                                         wpas_ctrl_remove_cred(wpa_s, prev);
    3209           2 :                                         break;
    3210             :                                 }
    3211             :                         }
    3212             :                 }
    3213           1 :                 return 0;
    3214             :         }
    3215             : 
    3216         144 :         if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
    3217           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
    3218             :                            cmd + 16);
    3219           1 :                 cred = wpa_s->conf->cred;
    3220           5 :                 while (cred) {
    3221           3 :                         prev = cred;
    3222           3 :                         cred = cred->next;
    3223           6 :                         if (prev->provisioning_sp &&
    3224           3 :                             os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
    3225           2 :                                 wpas_ctrl_remove_cred(wpa_s, prev);
    3226             :                 }
    3227           1 :                 return 0;
    3228             :         }
    3229             : 
    3230         143 :         id = atoi(cmd);
    3231         143 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
    3232             : 
    3233         143 :         cred = wpa_config_get_cred(wpa_s->conf, id);
    3234         143 :         return wpas_ctrl_remove_cred(wpa_s, cred);
    3235             : }
    3236             : 
    3237             : 
    3238         746 : static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
    3239             :                                               char *cmd)
    3240             : {
    3241             :         int id;
    3242             :         struct wpa_cred *cred;
    3243             :         char *name, *value;
    3244             : 
    3245             :         /* cmd: "<cred id> <variable name> <value>" */
    3246         746 :         name = os_strchr(cmd, ' ');
    3247         746 :         if (name == NULL)
    3248           1 :                 return -1;
    3249         745 :         *name++ = '\0';
    3250             : 
    3251         745 :         value = os_strchr(name, ' ');
    3252         745 :         if (value == NULL)
    3253           1 :                 return -1;
    3254         744 :         *value++ = '\0';
    3255             : 
    3256         744 :         id = atoi(cmd);
    3257         744 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
    3258             :                    id, name);
    3259         744 :         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
    3260             :                               (u8 *) value, os_strlen(value));
    3261             : 
    3262         744 :         cred = wpa_config_get_cred(wpa_s->conf, id);
    3263         744 :         if (cred == NULL) {
    3264           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
    3265             :                            id);
    3266           1 :                 return -1;
    3267             :         }
    3268             : 
    3269         743 :         if (wpa_config_set_cred(cred, name, value, 0) < 0) {
    3270          13 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
    3271             :                            "variable '%s'", name);
    3272          13 :                 return -1;
    3273             :         }
    3274             : 
    3275         730 :         wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
    3276             : 
    3277         730 :         return 0;
    3278             : }
    3279             : 
    3280             : 
    3281          39 : static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
    3282             :                                               char *cmd, char *buf,
    3283             :                                               size_t buflen)
    3284             : {
    3285             :         int id;
    3286             :         size_t res;
    3287             :         struct wpa_cred *cred;
    3288             :         char *name, *value;
    3289             : 
    3290             :         /* cmd: "<cred id> <variable name>" */
    3291          39 :         name = os_strchr(cmd, ' ');
    3292          39 :         if (name == NULL)
    3293           1 :                 return -1;
    3294          38 :         *name++ = '\0';
    3295             : 
    3296          38 :         id = atoi(cmd);
    3297          38 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
    3298             :                    id, name);
    3299             : 
    3300          38 :         cred = wpa_config_get_cred(wpa_s->conf, id);
    3301          38 :         if (cred == NULL) {
    3302           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
    3303             :                            id);
    3304           1 :                 return -1;
    3305             :         }
    3306             : 
    3307          37 :         value = wpa_config_get_cred_no_key(cred, name);
    3308          37 :         if (value == NULL) {
    3309           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
    3310             :                            name);
    3311           1 :                 return -1;
    3312             :         }
    3313             : 
    3314          36 :         res = os_strlcpy(buf, value, buflen);
    3315          36 :         if (res >= buflen) {
    3316           0 :                 os_free(value);
    3317           0 :                 return -1;
    3318             :         }
    3319             : 
    3320          36 :         os_free(value);
    3321             : 
    3322          36 :         return res;
    3323             : }
    3324             : 
    3325             : 
    3326             : #ifndef CONFIG_NO_CONFIG_WRITE
    3327           4 : static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
    3328             : {
    3329             :         int ret;
    3330             : 
    3331           4 :         if (!wpa_s->conf->update_config) {
    3332           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
    3333             :                            "to update configuration (update_config=0)");
    3334           1 :                 return -1;
    3335             :         }
    3336             : 
    3337           3 :         ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
    3338           3 :         if (ret) {
    3339           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
    3340             :                            "update configuration");
    3341             :         } else {
    3342           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
    3343             :                            " updated");
    3344             :         }
    3345             : 
    3346           3 :         return ret;
    3347             : }
    3348             : #endif /* CONFIG_NO_CONFIG_WRITE */
    3349             : 
    3350             : 
    3351             : struct cipher_info {
    3352             :         unsigned int capa;
    3353             :         const char *name;
    3354             :         int group_only;
    3355             : };
    3356             : 
    3357             : static const struct cipher_info ciphers[] = {
    3358             :         { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
    3359             :         { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
    3360             :         { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
    3361             :         { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
    3362             :         { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
    3363             :         { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
    3364             :         { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
    3365             :         { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
    3366             : };
    3367             : 
    3368             : static const struct cipher_info ciphers_group_mgmt[] = {
    3369             :         { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
    3370             :         { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
    3371             :         { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
    3372             :         { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
    3373             : };
    3374             : 
    3375             : 
    3376           8 : static int ctrl_iface_get_capability_pairwise(int res, char *strict,
    3377             :                                               struct wpa_driver_capa *capa,
    3378             :                                               char *buf, size_t buflen)
    3379             : {
    3380             :         int ret;
    3381             :         char *pos, *end;
    3382             :         size_t len;
    3383             :         unsigned int i;
    3384             : 
    3385           8 :         pos = buf;
    3386           8 :         end = pos + buflen;
    3387             : 
    3388           8 :         if (res < 0) {
    3389           0 :                 if (strict)
    3390           0 :                         return 0;
    3391           0 :                 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
    3392           0 :                 if (len >= buflen)
    3393           0 :                         return -1;
    3394           0 :                 return len;
    3395             :         }
    3396             : 
    3397          72 :         for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
    3398          64 :                 if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
    3399          40 :                         ret = os_snprintf(pos, end - pos, "%s%s",
    3400             :                                           pos == buf ? "" : " ",
    3401             :                                           ciphers[i].name);
    3402          40 :                         if (os_snprintf_error(end - pos, ret))
    3403           0 :                                 return pos - buf;
    3404          40 :                         pos += ret;
    3405             :                 }
    3406             :         }
    3407             : 
    3408           8 :         return pos - buf;
    3409             : }
    3410             : 
    3411             : 
    3412           1 : static int ctrl_iface_get_capability_group(int res, char *strict,
    3413             :                                            struct wpa_driver_capa *capa,
    3414             :                                            char *buf, size_t buflen)
    3415             : {
    3416             :         int ret;
    3417             :         char *pos, *end;
    3418             :         size_t len;
    3419             :         unsigned int i;
    3420             : 
    3421           1 :         pos = buf;
    3422           1 :         end = pos + buflen;
    3423             : 
    3424           1 :         if (res < 0) {
    3425           0 :                 if (strict)
    3426           0 :                         return 0;
    3427           0 :                 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
    3428           0 :                 if (len >= buflen)
    3429           0 :                         return -1;
    3430           0 :                 return len;
    3431             :         }
    3432             : 
    3433           9 :         for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
    3434           8 :                 if (capa->enc & ciphers[i].capa) {
    3435           7 :                         ret = os_snprintf(pos, end - pos, "%s%s",
    3436             :                                           pos == buf ? "" : " ",
    3437             :                                           ciphers[i].name);
    3438           7 :                         if (os_snprintf_error(end - pos, ret))
    3439           0 :                                 return pos - buf;
    3440           7 :                         pos += ret;
    3441             :                 }
    3442             :         }
    3443             : 
    3444           1 :         return pos - buf;
    3445             : }
    3446             : 
    3447             : 
    3448           6 : static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
    3449             :                                                 struct wpa_driver_capa *capa,
    3450             :                                                 char *buf, size_t buflen)
    3451             : {
    3452             :         int ret;
    3453             :         char *pos, *end;
    3454             :         unsigned int i;
    3455             : 
    3456           6 :         pos = buf;
    3457           6 :         end = pos + buflen;
    3458             : 
    3459           6 :         if (res < 0)
    3460           0 :                 return 0;
    3461             : 
    3462          30 :         for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
    3463          24 :                 if (capa->enc & ciphers_group_mgmt[i].capa) {
    3464          24 :                         ret = os_snprintf(pos, end - pos, "%s%s",
    3465             :                                           pos == buf ? "" : " ",
    3466             :                                           ciphers_group_mgmt[i].name);
    3467          24 :                         if (os_snprintf_error(end - pos, ret))
    3468           0 :                                 return pos - buf;
    3469          24 :                         pos += ret;
    3470             :                 }
    3471             :         }
    3472             : 
    3473           6 :         return pos - buf;
    3474             : }
    3475             : 
    3476             : 
    3477           3 : static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
    3478             :                                               struct wpa_driver_capa *capa,
    3479             :                                               char *buf, size_t buflen)
    3480             : {
    3481             :         int ret;
    3482             :         char *pos, *end;
    3483             :         size_t len;
    3484             : 
    3485           3 :         pos = buf;
    3486           3 :         end = pos + buflen;
    3487             : 
    3488           3 :         if (res < 0) {
    3489           0 :                 if (strict)
    3490           0 :                         return 0;
    3491           0 :                 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
    3492             :                                  "NONE", buflen);
    3493           0 :                 if (len >= buflen)
    3494           0 :                         return -1;
    3495           0 :                 return len;
    3496             :         }
    3497             : 
    3498           3 :         ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
    3499           3 :         if (os_snprintf_error(end - pos, ret))
    3500           0 :                 return pos - buf;
    3501           3 :         pos += ret;
    3502             : 
    3503           3 :         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
    3504             :                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
    3505           3 :                 ret = os_snprintf(pos, end - pos, " WPA-EAP");
    3506           3 :                 if (os_snprintf_error(end - pos, ret))
    3507           0 :                         return pos - buf;
    3508           3 :                 pos += ret;
    3509             :         }
    3510             : 
    3511           3 :         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
    3512             :                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
    3513           3 :                 ret = os_snprintf(pos, end - pos, " WPA-PSK");
    3514           3 :                 if (os_snprintf_error(end - pos, ret))
    3515           0 :                         return pos - buf;
    3516           3 :                 pos += ret;
    3517             :         }
    3518             : 
    3519           3 :         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
    3520           0 :                 ret = os_snprintf(pos, end - pos, " WPA-NONE");
    3521           0 :                 if (os_snprintf_error(end - pos, ret))
    3522           0 :                         return pos - buf;
    3523           0 :                 pos += ret;
    3524             :         }
    3525             : 
    3526             : #ifdef CONFIG_SUITEB
    3527           3 :         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
    3528           3 :                 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
    3529           3 :                 if (os_snprintf_error(end - pos, ret))
    3530           0 :                         return pos - buf;
    3531           3 :                 pos += ret;
    3532             :         }
    3533             : #endif /* CONFIG_SUITEB */
    3534             : #ifdef CONFIG_SUITEB192
    3535           3 :         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
    3536           3 :                 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
    3537           3 :                 if (os_snprintf_error(end - pos, ret))
    3538           0 :                         return pos - buf;
    3539           3 :                 pos += ret;
    3540             :         }
    3541             : #endif /* CONFIG_SUITEB192 */
    3542             : 
    3543           3 :         return pos - buf;
    3544             : }
    3545             : 
    3546             : 
    3547           1 : static int ctrl_iface_get_capability_proto(int res, char *strict,
    3548             :                                            struct wpa_driver_capa *capa,
    3549             :                                            char *buf, size_t buflen)
    3550             : {
    3551             :         int ret;
    3552             :         char *pos, *end;
    3553             :         size_t len;
    3554             : 
    3555           1 :         pos = buf;
    3556           1 :         end = pos + buflen;
    3557             : 
    3558           1 :         if (res < 0) {
    3559           0 :                 if (strict)
    3560           0 :                         return 0;
    3561           0 :                 len = os_strlcpy(buf, "RSN WPA", buflen);
    3562           0 :                 if (len >= buflen)
    3563           0 :                         return -1;
    3564           0 :                 return len;
    3565             :         }
    3566             : 
    3567           1 :         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
    3568             :                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
    3569           1 :                 ret = os_snprintf(pos, end - pos, "%sRSN",
    3570             :                                   pos == buf ? "" : " ");
    3571           1 :                 if (os_snprintf_error(end - pos, ret))
    3572           0 :                         return pos - buf;
    3573           1 :                 pos += ret;
    3574             :         }
    3575             : 
    3576           1 :         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
    3577             :                               WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
    3578           1 :                 ret = os_snprintf(pos, end - pos, "%sWPA",
    3579             :                                   pos == buf ? "" : " ");
    3580           1 :                 if (os_snprintf_error(end - pos, ret))
    3581           0 :                         return pos - buf;
    3582           1 :                 pos += ret;
    3583             :         }
    3584             : 
    3585           1 :         return pos - buf;
    3586             : }
    3587             : 
    3588             : 
    3589          18 : static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
    3590             :                                               int res, char *strict,
    3591             :                                               struct wpa_driver_capa *capa,
    3592             :                                               char *buf, size_t buflen)
    3593             : {
    3594             :         int ret;
    3595             :         char *pos, *end;
    3596             :         size_t len;
    3597             : 
    3598          18 :         pos = buf;
    3599          18 :         end = pos + buflen;
    3600             : 
    3601          18 :         if (res < 0) {
    3602           0 :                 if (strict)
    3603           0 :                         return 0;
    3604           0 :                 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
    3605           0 :                 if (len >= buflen)
    3606           0 :                         return -1;
    3607           0 :                 return len;
    3608             :         }
    3609             : 
    3610          18 :         if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
    3611          18 :                 ret = os_snprintf(pos, end - pos, "%sOPEN",
    3612             :                                   pos == buf ? "" : " ");
    3613          18 :                 if (os_snprintf_error(end - pos, ret))
    3614           0 :                         return pos - buf;
    3615          18 :                 pos += ret;
    3616             :         }
    3617             : 
    3618          18 :         if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
    3619          18 :                 ret = os_snprintf(pos, end - pos, "%sSHARED",
    3620             :                                   pos == buf ? "" : " ");
    3621          18 :                 if (os_snprintf_error(end - pos, ret))
    3622           0 :                         return pos - buf;
    3623          18 :                 pos += ret;
    3624             :         }
    3625             : 
    3626          18 :         if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
    3627          18 :                 ret = os_snprintf(pos, end - pos, "%sLEAP",
    3628             :                                   pos == buf ? "" : " ");
    3629          18 :                 if (os_snprintf_error(end - pos, ret))
    3630           0 :                         return pos - buf;
    3631          18 :                 pos += ret;
    3632             :         }
    3633             : 
    3634             : #ifdef CONFIG_SAE
    3635          18 :         if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
    3636          18 :                 ret = os_snprintf(pos, end - pos, "%sSAE",
    3637             :                                   pos == buf ? "" : " ");
    3638          18 :                 if (os_snprintf_error(end - pos, ret))
    3639           0 :                         return pos - buf;
    3640          18 :                 pos += ret;
    3641             :         }
    3642             : #endif /* CONFIG_SAE */
    3643             : 
    3644          18 :         return pos - buf;
    3645             : }
    3646             : 
    3647             : 
    3648          18 : static int ctrl_iface_get_capability_modes(int res, char *strict,
    3649             :                                            struct wpa_driver_capa *capa,
    3650             :                                            char *buf, size_t buflen)
    3651             : {
    3652             :         int ret;
    3653             :         char *pos, *end;
    3654             :         size_t len;
    3655             : 
    3656          18 :         pos = buf;
    3657          18 :         end = pos + buflen;
    3658             : 
    3659          18 :         if (res < 0) {
    3660           0 :                 if (strict)
    3661           0 :                         return 0;
    3662           0 :                 len = os_strlcpy(buf, "IBSS AP", buflen);
    3663           0 :                 if (len >= buflen)
    3664           0 :                         return -1;
    3665           0 :                 return len;
    3666             :         }
    3667             : 
    3668          18 :         if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
    3669          18 :                 ret = os_snprintf(pos, end - pos, "%sIBSS",
    3670             :                                   pos == buf ? "" : " ");
    3671          18 :                 if (os_snprintf_error(end - pos, ret))
    3672           0 :                         return pos - buf;
    3673          18 :                 pos += ret;
    3674             :         }
    3675             : 
    3676          18 :         if (capa->flags & WPA_DRIVER_FLAGS_AP) {
    3677          18 :                 ret = os_snprintf(pos, end - pos, "%sAP",
    3678             :                                   pos == buf ? "" : " ");
    3679          18 :                 if (os_snprintf_error(end - pos, ret))
    3680           0 :                         return pos - buf;
    3681          18 :                 pos += ret;
    3682             :         }
    3683             : 
    3684             : #ifdef CONFIG_MESH
    3685          18 :         if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
    3686          18 :                 ret = os_snprintf(pos, end - pos, "%sMESH",
    3687             :                                   pos == buf ? "" : " ");
    3688          18 :                 if (os_snprintf_error(end - pos, ret))
    3689           0 :                         return pos - buf;
    3690          18 :                 pos += ret;
    3691             :         }
    3692             : #endif /* CONFIG_MESH */
    3693             : 
    3694          18 :         return pos - buf;
    3695             : }
    3696             : 
    3697             : 
    3698           1 : static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
    3699             :                                               char *buf, size_t buflen)
    3700             : {
    3701             :         struct hostapd_channel_data *chnl;
    3702             :         int ret, i, j;
    3703             :         char *pos, *end, *hmode;
    3704             : 
    3705           1 :         pos = buf;
    3706           1 :         end = pos + buflen;
    3707             : 
    3708           4 :         for (j = 0; j < wpa_s->hw.num_modes; j++) {
    3709           3 :                 switch (wpa_s->hw.modes[j].mode) {
    3710             :                 case HOSTAPD_MODE_IEEE80211B:
    3711           1 :                         hmode = "B";
    3712           1 :                         break;
    3713             :                 case HOSTAPD_MODE_IEEE80211G:
    3714           1 :                         hmode = "G";
    3715           1 :                         break;
    3716             :                 case HOSTAPD_MODE_IEEE80211A:
    3717           1 :                         hmode = "A";
    3718           1 :                         break;
    3719             :                 case HOSTAPD_MODE_IEEE80211AD:
    3720           0 :                         hmode = "AD";
    3721           0 :                         break;
    3722             :                 default:
    3723           0 :                         continue;
    3724             :                 }
    3725           3 :                 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
    3726           3 :                 if (os_snprintf_error(end - pos, ret))
    3727           0 :                         return pos - buf;
    3728           3 :                 pos += ret;
    3729           3 :                 chnl = wpa_s->hw.modes[j].channels;
    3730          55 :                 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
    3731          52 :                         if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
    3732           0 :                                 continue;
    3733          52 :                         ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
    3734          52 :                         if (os_snprintf_error(end - pos, ret))
    3735           0 :                                 return pos - buf;
    3736          52 :                         pos += ret;
    3737             :                 }
    3738           3 :                 ret = os_snprintf(pos, end - pos, "\n");
    3739           3 :                 if (os_snprintf_error(end - pos, ret))
    3740           0 :                         return pos - buf;
    3741           3 :                 pos += ret;
    3742             :         }
    3743             : 
    3744           1 :         return pos - buf;
    3745             : }
    3746             : 
    3747             : 
    3748           1 : static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
    3749             :                                           char *buf, size_t buflen)
    3750             : {
    3751             :         struct hostapd_channel_data *chnl;
    3752             :         int ret, i, j;
    3753             :         char *pos, *end, *hmode;
    3754             : 
    3755           1 :         pos = buf;
    3756           1 :         end = pos + buflen;
    3757             : 
    3758           4 :         for (j = 0; j < wpa_s->hw.num_modes; j++) {
    3759           3 :                 switch (wpa_s->hw.modes[j].mode) {
    3760             :                 case HOSTAPD_MODE_IEEE80211B:
    3761           1 :                         hmode = "B";
    3762           1 :                         break;
    3763             :                 case HOSTAPD_MODE_IEEE80211G:
    3764           1 :                         hmode = "G";
    3765           1 :                         break;
    3766             :                 case HOSTAPD_MODE_IEEE80211A:
    3767           1 :                         hmode = "A";
    3768           1 :                         break;
    3769             :                 case HOSTAPD_MODE_IEEE80211AD:
    3770           0 :                         hmode = "AD";
    3771           0 :                         break;
    3772             :                 default:
    3773           0 :                         continue;
    3774             :                 }
    3775           3 :                 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
    3776             :                                   hmode);
    3777           3 :                 if (os_snprintf_error(end - pos, ret))
    3778           0 :                         return pos - buf;
    3779           3 :                 pos += ret;
    3780           3 :                 chnl = wpa_s->hw.modes[j].channels;
    3781          55 :                 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
    3782          52 :                         if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
    3783           0 :                                 continue;
    3784         208 :                         ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
    3785         104 :                                           chnl[i].chan, chnl[i].freq,
    3786          52 :                                           chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
    3787             :                                           " (NO_IR)" : "",
    3788          52 :                                           chnl[i].flag & HOSTAPD_CHAN_RADAR ?
    3789             :                                           " (DFS)" : "");
    3790             : 
    3791          52 :                         if (os_snprintf_error(end - pos, ret))
    3792           0 :                                 return pos - buf;
    3793          52 :                         pos += ret;
    3794             :                 }
    3795           3 :                 ret = os_snprintf(pos, end - pos, "\n");
    3796           3 :                 if (os_snprintf_error(end - pos, ret))
    3797           0 :                         return pos - buf;
    3798           3 :                 pos += ret;
    3799             :         }
    3800             : 
    3801           1 :         return pos - buf;
    3802             : }
    3803             : 
    3804             : 
    3805          84 : static int wpa_supplicant_ctrl_iface_get_capability(
    3806             :         struct wpa_supplicant *wpa_s, const char *_field, char *buf,
    3807             :         size_t buflen)
    3808             : {
    3809             :         struct wpa_driver_capa capa;
    3810             :         int res;
    3811             :         char *strict;
    3812             :         char field[30];
    3813             :         size_t len;
    3814             : 
    3815             :         /* Determine whether or not strict checking was requested */
    3816          84 :         len = os_strlcpy(field, _field, sizeof(field));
    3817          84 :         if (len >= sizeof(field))
    3818           1 :                 return -1;
    3819          83 :         strict = os_strchr(field, ' ');
    3820          83 :         if (strict != NULL) {
    3821           2 :                 *strict++ = '\0';
    3822           2 :                 if (os_strcmp(strict, "strict") != 0)
    3823           1 :                         return -1;
    3824             :         }
    3825             : 
    3826          82 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
    3827             :                 field, strict ? strict : "");
    3828             : 
    3829          82 :         if (os_strcmp(field, "eap") == 0) {
    3830          17 :                 return eap_get_names(buf, buflen);
    3831             :         }
    3832             : 
    3833          65 :         res = wpa_drv_get_capa(wpa_s, &capa);
    3834             : 
    3835          65 :         if (os_strcmp(field, "pairwise") == 0)
    3836           8 :                 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
    3837             :                                                           buf, buflen);
    3838             : 
    3839          57 :         if (os_strcmp(field, "group") == 0)
    3840           1 :                 return ctrl_iface_get_capability_group(res, strict, &capa,
    3841             :                                                        buf, buflen);
    3842             : 
    3843          56 :         if (os_strcmp(field, "group_mgmt") == 0)
    3844           6 :                 return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
    3845             :                                                             buf, buflen);
    3846             : 
    3847          50 :         if (os_strcmp(field, "key_mgmt") == 0)
    3848           3 :                 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
    3849             :                                                           buf, buflen);
    3850             : 
    3851          47 :         if (os_strcmp(field, "proto") == 0)
    3852           1 :                 return ctrl_iface_get_capability_proto(res, strict, &capa,
    3853             :                                                        buf, buflen);
    3854             : 
    3855          46 :         if (os_strcmp(field, "auth_alg") == 0)
    3856          18 :                 return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
    3857             :                                                           &capa, buf, buflen);
    3858             : 
    3859          28 :         if (os_strcmp(field, "modes") == 0)
    3860          18 :                 return ctrl_iface_get_capability_modes(res, strict, &capa,
    3861             :                                                        buf, buflen);
    3862             : 
    3863          10 :         if (os_strcmp(field, "channels") == 0)
    3864           1 :                 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
    3865             : 
    3866           9 :         if (os_strcmp(field, "freq") == 0)
    3867           1 :                 return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
    3868             : 
    3869             : #ifdef CONFIG_TDLS
    3870           8 :         if (os_strcmp(field, "tdls") == 0)
    3871           1 :                 return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
    3872             : #endif /* CONFIG_TDLS */
    3873             : 
    3874             : #ifdef CONFIG_ERP
    3875           7 :         if (os_strcmp(field, "erp") == 0) {
    3876           6 :                 res = os_snprintf(buf, buflen, "ERP");
    3877           6 :                 if (os_snprintf_error(buflen, res))
    3878           0 :                         return -1;
    3879           6 :                 return res;
    3880             :         }
    3881             : #endif /* CONFIG_EPR */
    3882             : 
    3883           1 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
    3884             :                    field);
    3885             : 
    3886           1 :         return -1;
    3887             : }
    3888             : 
    3889             : 
    3890             : #ifdef CONFIG_INTERWORKING
    3891         492 : static char * anqp_add_hex(char *pos, char *end, const char *title,
    3892             :                            struct wpabuf *data)
    3893             : {
    3894         492 :         char *start = pos;
    3895             :         size_t i;
    3896             :         int ret;
    3897             :         const u8 *d;
    3898             : 
    3899         492 :         if (data == NULL)
    3900         399 :                 return start;
    3901             : 
    3902          93 :         ret = os_snprintf(pos, end - pos, "%s=", title);
    3903          93 :         if (os_snprintf_error(end - pos, ret))
    3904           0 :                 return start;
    3905          93 :         pos += ret;
    3906             : 
    3907          93 :         d = wpabuf_head_u8(data);
    3908        3485 :         for (i = 0; i < wpabuf_len(data); i++) {
    3909        3392 :                 ret = os_snprintf(pos, end - pos, "%02x", *d++);
    3910        3392 :                 if (os_snprintf_error(end - pos, ret))
    3911           0 :                         return start;
    3912        3392 :                 pos += ret;
    3913             :         }
    3914             : 
    3915          93 :         ret = os_snprintf(pos, end - pos, "\n");
    3916          93 :         if (os_snprintf_error(end - pos, ret))
    3917           0 :                 return start;
    3918          93 :         pos += ret;
    3919             : 
    3920          93 :         return pos;
    3921             : }
    3922             : #endif /* CONFIG_INTERWORKING */
    3923             : 
    3924             : 
    3925         562 : static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    3926             :                           unsigned long mask, char *buf, size_t buflen)
    3927             : {
    3928             :         size_t i;
    3929             :         int ret;
    3930             :         char *pos, *end;
    3931             :         const u8 *ie, *ie2;
    3932             : 
    3933         562 :         pos = buf;
    3934         562 :         end = buf + buflen;
    3935             : 
    3936         562 :         if (mask & WPA_BSS_MASK_ID) {
    3937         421 :                 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
    3938         421 :                 if (os_snprintf_error(end - pos, ret))
    3939           0 :                         return 0;
    3940         421 :                 pos += ret;
    3941             :         }
    3942             : 
    3943         562 :         if (mask & WPA_BSS_MASK_BSSID) {
    3944        3234 :                 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
    3945        3234 :                                   MAC2STR(bss->bssid));
    3946         539 :                 if (os_snprintf_error(end - pos, ret))
    3947           0 :                         return 0;
    3948         539 :                 pos += ret;
    3949             :         }
    3950             : 
    3951         562 :         if (mask & WPA_BSS_MASK_FREQ) {
    3952         398 :                 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
    3953         398 :                 if (os_snprintf_error(end - pos, ret))
    3954           0 :                         return 0;
    3955         398 :                 pos += ret;
    3956             :         }
    3957             : 
    3958         562 :         if (mask & WPA_BSS_MASK_BEACON_INT) {
    3959         398 :                 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
    3960         398 :                                   bss->beacon_int);
    3961         398 :                 if (os_snprintf_error(end - pos, ret))
    3962           0 :                         return 0;
    3963         398 :                 pos += ret;
    3964             :         }
    3965             : 
    3966         562 :         if (mask & WPA_BSS_MASK_CAPABILITIES) {
    3967         398 :                 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
    3968         398 :                                   bss->caps);
    3969         398 :                 if (os_snprintf_error(end - pos, ret))
    3970           0 :                         return 0;
    3971         398 :                 pos += ret;
    3972             :         }
    3973             : 
    3974         562 :         if (mask & WPA_BSS_MASK_QUAL) {
    3975         398 :                 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
    3976         398 :                 if (os_snprintf_error(end - pos, ret))
    3977           0 :                         return 0;
    3978         398 :                 pos += ret;
    3979             :         }
    3980             : 
    3981         562 :         if (mask & WPA_BSS_MASK_NOISE) {
    3982         398 :                 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
    3983         398 :                 if (os_snprintf_error(end - pos, ret))
    3984           0 :                         return 0;
    3985         398 :                 pos += ret;
    3986             :         }
    3987             : 
    3988         562 :         if (mask & WPA_BSS_MASK_LEVEL) {
    3989         398 :                 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
    3990         398 :                 if (os_snprintf_error(end - pos, ret))
    3991           0 :                         return 0;
    3992         398 :                 pos += ret;
    3993             :         }
    3994             : 
    3995         562 :         if (mask & WPA_BSS_MASK_TSF) {
    3996         398 :                 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
    3997         398 :                                   (unsigned long long) bss->tsf);
    3998         398 :                 if (os_snprintf_error(end - pos, ret))
    3999           0 :                         return 0;
    4000         398 :                 pos += ret;
    4001             :         }
    4002             : 
    4003         562 :         if (mask & WPA_BSS_MASK_AGE) {
    4004             :                 struct os_reltime now;
    4005             : 
    4006         398 :                 os_get_reltime(&now);
    4007         796 :                 ret = os_snprintf(pos, end - pos, "age=%d\n",
    4008         796 :                                   (int) (now.sec - bss->last_update.sec));
    4009         398 :                 if (os_snprintf_error(end - pos, ret))
    4010           0 :                         return 0;
    4011         398 :                 pos += ret;
    4012             :         }
    4013             : 
    4014         562 :         if (mask & WPA_BSS_MASK_IE) {
    4015         398 :                 ret = os_snprintf(pos, end - pos, "ie=");
    4016         398 :                 if (os_snprintf_error(end - pos, ret))
    4017           0 :                         return 0;
    4018         398 :                 pos += ret;
    4019             : 
    4020         398 :                 ie = (const u8 *) (bss + 1);
    4021       73584 :                 for (i = 0; i < bss->ie_len; i++) {
    4022       73186 :                         ret = os_snprintf(pos, end - pos, "%02x", *ie++);
    4023       73186 :                         if (os_snprintf_error(end - pos, ret))
    4024           0 :                                 return 0;
    4025       73186 :                         pos += ret;
    4026             :                 }
    4027             : 
    4028         398 :                 ret = os_snprintf(pos, end - pos, "\n");
    4029         398 :                 if (os_snprintf_error(end - pos, ret))
    4030           0 :                         return 0;
    4031         398 :                 pos += ret;
    4032             :         }
    4033             : 
    4034         562 :         if (mask & WPA_BSS_MASK_FLAGS) {
    4035         398 :                 ret = os_snprintf(pos, end - pos, "flags=");
    4036         398 :                 if (os_snprintf_error(end - pos, ret))
    4037           0 :                         return 0;
    4038         398 :                 pos += ret;
    4039             : 
    4040         398 :                 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
    4041         398 :                 if (ie)
    4042          18 :                         pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
    4043          18 :                                                     2 + ie[1]);
    4044         398 :                 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
    4045         398 :                 if (ie2)
    4046         286 :                         pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
    4047         286 :                                                     2 + ie2[1]);
    4048         398 :                 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
    4049         398 :                 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
    4050           2 :                         ret = os_snprintf(pos, end - pos, "[WEP]");
    4051           2 :                         if (os_snprintf_error(end - pos, ret))
    4052           0 :                                 return 0;
    4053           2 :                         pos += ret;
    4054             :                 }
    4055         398 :                 if (bss_is_dmg(bss)) {
    4056             :                         const char *s;
    4057           0 :                         ret = os_snprintf(pos, end - pos, "[DMG]");
    4058           0 :                         if (os_snprintf_error(end - pos, ret))
    4059           0 :                                 return 0;
    4060           0 :                         pos += ret;
    4061           0 :                         switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
    4062             :                         case IEEE80211_CAP_DMG_IBSS:
    4063           0 :                                 s = "[IBSS]";
    4064           0 :                                 break;
    4065             :                         case IEEE80211_CAP_DMG_AP:
    4066           0 :                                 s = "[ESS]";
    4067           0 :                                 break;
    4068             :                         case IEEE80211_CAP_DMG_PBSS:
    4069           0 :                                 s = "[PBSS]";
    4070           0 :                                 break;
    4071             :                         default:
    4072           0 :                                 s = "";
    4073           0 :                                 break;
    4074             :                         }
    4075           0 :                         ret = os_snprintf(pos, end - pos, "%s", s);
    4076           0 :                         if (os_snprintf_error(end - pos, ret))
    4077           0 :                                 return 0;
    4078           0 :                         pos += ret;
    4079             :                 } else {
    4080         398 :                         if (bss->caps & IEEE80211_CAP_IBSS) {
    4081           2 :                                 ret = os_snprintf(pos, end - pos, "[IBSS]");
    4082           2 :                                 if (os_snprintf_error(end - pos, ret))
    4083           0 :                                         return 0;
    4084           2 :                                 pos += ret;
    4085             :                         }
    4086         398 :                         if (bss->caps & IEEE80211_CAP_ESS) {
    4087         395 :                                 ret = os_snprintf(pos, end - pos, "[ESS]");
    4088         395 :                                 if (os_snprintf_error(end - pos, ret))
    4089           0 :                                         return 0;
    4090         395 :                                 pos += ret;
    4091             :                         }
    4092             :                 }
    4093         789 :                 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
    4094         391 :                     wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
    4095           7 :                         ret = os_snprintf(pos, end - pos, "[P2P]");
    4096           7 :                         if (os_snprintf_error(end - pos, ret))
    4097           0 :                                 return 0;
    4098           7 :                         pos += ret;
    4099             :                 }
    4100             : #ifdef CONFIG_HS20
    4101         398 :                 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
    4102         128 :                         ret = os_snprintf(pos, end - pos, "[HS20]");
    4103         128 :                         if (os_snprintf_error(end - pos, ret))
    4104           0 :                                 return 0;
    4105         128 :                         pos += ret;
    4106             :                 }
    4107             : #endif /* CONFIG_HS20 */
    4108             : 
    4109         398 :                 ret = os_snprintf(pos, end - pos, "\n");
    4110         398 :                 if (os_snprintf_error(end - pos, ret))
    4111           0 :                         return 0;
    4112         398 :                 pos += ret;
    4113             :         }
    4114             : 
    4115         562 :         if (mask & WPA_BSS_MASK_SSID) {
    4116         796 :                 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
    4117         398 :                                   wpa_ssid_txt(bss->ssid, bss->ssid_len));
    4118         398 :                 if (os_snprintf_error(end - pos, ret))
    4119           0 :                         return 0;
    4120         398 :                 pos += ret;
    4121             :         }
    4122             : 
    4123             : #ifdef CONFIG_WPS
    4124         562 :         if (mask & WPA_BSS_MASK_WPS_SCAN) {
    4125         398 :                 ie = (const u8 *) (bss + 1);
    4126         398 :                 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
    4127         398 :                 if (ret < 0 || ret >= end - pos)
    4128           0 :                         return 0;
    4129         398 :                 pos += ret;
    4130             :         }
    4131             : #endif /* CONFIG_WPS */
    4132             : 
    4133             : #ifdef CONFIG_P2P
    4134         562 :         if (mask & WPA_BSS_MASK_P2P_SCAN) {
    4135         398 :                 ie = (const u8 *) (bss + 1);
    4136         398 :                 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
    4137         398 :                 if (ret < 0 || ret >= end - pos)
    4138           0 :                         return 0;
    4139         398 :                 pos += ret;
    4140             :         }
    4141             : #endif /* CONFIG_P2P */
    4142             : 
    4143             : #ifdef CONFIG_WIFI_DISPLAY
    4144         562 :         if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
    4145             :                 struct wpabuf *wfd;
    4146         398 :                 ie = (const u8 *) (bss + 1);
    4147         398 :                 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
    4148             :                                                   WFD_IE_VENDOR_TYPE);
    4149         398 :                 if (wfd) {
    4150           2 :                         ret = os_snprintf(pos, end - pos, "wfd_subelems=");
    4151           2 :                         if (os_snprintf_error(end - pos, ret)) {
    4152           0 :                                 wpabuf_free(wfd);
    4153           0 :                                 return 0;
    4154             :                         }
    4155           2 :                         pos += ret;
    4156             : 
    4157           4 :                         pos += wpa_snprintf_hex(pos, end - pos,
    4158           2 :                                                 wpabuf_head(wfd),
    4159             :                                                 wpabuf_len(wfd));
    4160           2 :                         wpabuf_free(wfd);
    4161             : 
    4162           2 :                         ret = os_snprintf(pos, end - pos, "\n");
    4163           2 :                         if (os_snprintf_error(end - pos, ret))
    4164           0 :                                 return 0;
    4165           2 :                         pos += ret;
    4166             :                 }
    4167             :         }
    4168             : #endif /* CONFIG_WIFI_DISPLAY */
    4169             : 
    4170             : #ifdef CONFIG_INTERWORKING
    4171         562 :         if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
    4172          41 :                 struct wpa_bss_anqp *anqp = bss->anqp;
    4173          41 :                 pos = anqp_add_hex(pos, end, "anqp_venue_name",
    4174             :                                    anqp->venue_name);
    4175          41 :                 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
    4176             :                                    anqp->network_auth_type);
    4177          41 :                 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
    4178             :                                    anqp->roaming_consortium);
    4179          41 :                 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
    4180             :                                    anqp->ip_addr_type_availability);
    4181          41 :                 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
    4182             :                                    anqp->nai_realm);
    4183          41 :                 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
    4184          41 :                 pos = anqp_add_hex(pos, end, "anqp_domain_name",
    4185             :                                    anqp->domain_name);
    4186             : #ifdef CONFIG_HS20
    4187          41 :                 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
    4188             :                                    anqp->hs20_operator_friendly_name);
    4189          41 :                 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
    4190             :                                    anqp->hs20_wan_metrics);
    4191          41 :                 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
    4192             :                                    anqp->hs20_connection_capability);
    4193          41 :                 pos = anqp_add_hex(pos, end, "hs20_operating_class",
    4194             :                                    anqp->hs20_operating_class);
    4195          41 :                 pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
    4196             :                                    anqp->hs20_osu_providers_list);
    4197             : #endif /* CONFIG_HS20 */
    4198             :         }
    4199             : #endif /* CONFIG_INTERWORKING */
    4200             : 
    4201             : #ifdef CONFIG_MESH
    4202         562 :         if (mask & WPA_BSS_MASK_MESH_SCAN) {
    4203         398 :                 ie = (const u8 *) (bss + 1);
    4204         398 :                 ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
    4205         398 :                 if (ret < 0 || ret >= end - pos)
    4206           0 :                         return 0;
    4207         398 :                 pos += ret;
    4208             :         }
    4209             : #endif /* CONFIG_MESH */
    4210             : 
    4211         562 :         if (mask & WPA_BSS_MASK_DELIM) {
    4212           2 :                 ret = os_snprintf(pos, end - pos, "====\n");
    4213           2 :                 if (os_snprintf_error(end - pos, ret))
    4214           0 :                         return 0;
    4215           2 :                 pos += ret;
    4216             :         }
    4217             : 
    4218         562 :         return pos - buf;
    4219             : }
    4220             : 
    4221             : 
    4222         744 : static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
    4223             :                                          const char *cmd, char *buf,
    4224             :                                          size_t buflen)
    4225             : {
    4226             :         u8 bssid[ETH_ALEN];
    4227             :         size_t i;
    4228             :         struct wpa_bss *bss;
    4229         744 :         struct wpa_bss *bsslast = NULL;
    4230             :         struct dl_list *next;
    4231         744 :         int ret = 0;
    4232             :         int len;
    4233         744 :         char *ctmp, *end = buf + buflen;
    4234         744 :         unsigned long mask = WPA_BSS_MASK_ALL;
    4235             : 
    4236         744 :         if (os_strncmp(cmd, "RANGE=", 6) == 0) {
    4237         109 :                 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
    4238         100 :                         bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
    4239             :                                             list_id);
    4240         100 :                         bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
    4241             :                                                list_id);
    4242             :                 } else { /* N1-N2 */
    4243             :                         unsigned int id1, id2;
    4244             : 
    4245           9 :                         if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
    4246           1 :                                 wpa_printf(MSG_INFO, "Wrong BSS range "
    4247             :                                            "format");
    4248           1 :                                 return 0;
    4249             :                         }
    4250             : 
    4251           8 :                         if (*(cmd + 6) == '-')
    4252           1 :                                 id1 = 0;
    4253             :                         else
    4254           7 :                                 id1 = atoi(cmd + 6);
    4255           8 :                         ctmp++;
    4256           8 :                         if (*ctmp >= '0' && *ctmp <= '9')
    4257           6 :                                 id2 = atoi(ctmp);
    4258             :                         else
    4259           2 :                                 id2 = (unsigned int) -1;
    4260           8 :                         bss = wpa_bss_get_id_range(wpa_s, id1, id2);
    4261           8 :                         if (id2 == (unsigned int) -1)
    4262           2 :                                 bsslast = dl_list_last(&wpa_s->bss_id,
    4263             :                                                        struct wpa_bss,
    4264             :                                                        list_id);
    4265             :                         else {
    4266           6 :                                 bsslast = wpa_bss_get_id(wpa_s, id2);
    4267           6 :                                 if (bsslast == NULL && bss && id2 > id1) {
    4268           1 :                                         struct wpa_bss *tmp = bss;
    4269             :                                         for (;;) {
    4270           2 :                                                 next = tmp->list_id.next;
    4271           2 :                                                 if (next == &wpa_s->bss_id)
    4272           1 :                                                         break;
    4273           1 :                                                 tmp = dl_list_entry(
    4274             :                                                         next, struct wpa_bss,
    4275             :                                                         list_id);
    4276           1 :                                                 if (tmp->id > id2)
    4277           0 :                                                         break;
    4278           1 :                                                 bsslast = tmp;
    4279           1 :                                         }
    4280             :                                 }
    4281             :                         }
    4282             :                 }
    4283         635 :         } else if (os_strncmp(cmd, "FIRST", 5) == 0)
    4284           2 :                 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
    4285         633 :         else if (os_strncmp(cmd, "LAST", 4) == 0)
    4286           2 :                 bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
    4287         631 :         else if (os_strncmp(cmd, "ID-", 3) == 0) {
    4288           2 :                 i = atoi(cmd + 3);
    4289           2 :                 bss = wpa_bss_get_id(wpa_s, i);
    4290         629 :         } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
    4291           2 :                 i = atoi(cmd + 5);
    4292           2 :                 bss = wpa_bss_get_id(wpa_s, i);
    4293           2 :                 if (bss) {
    4294           2 :                         next = bss->list_id.next;
    4295           2 :                         if (next == &wpa_s->bss_id)
    4296           1 :                                 bss = NULL;
    4297             :                         else
    4298           1 :                                 bss = dl_list_entry(next, struct wpa_bss,
    4299             :                                                     list_id);
    4300             :                 }
    4301             : #ifdef CONFIG_P2P
    4302         627 :         } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
    4303           5 :                 if (hwaddr_aton(cmd + 13, bssid) == 0)
    4304           4 :                         bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
    4305             :                 else
    4306           1 :                         bss = NULL;
    4307             : #endif /* CONFIG_P2P */
    4308         622 :         } else if (hwaddr_aton(cmd, bssid) == 0)
    4309         612 :                 bss = wpa_bss_get_bssid(wpa_s, bssid);
    4310             :         else {
    4311             :                 struct wpa_bss *tmp;
    4312          10 :                 i = atoi(cmd);
    4313          10 :                 bss = NULL;
    4314          10 :                 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
    4315             :                 {
    4316           5 :                         if (i-- == 0) {
    4317           5 :                                 bss = tmp;
    4318           5 :                                 break;
    4319             :                         }
    4320             :                 }
    4321             :         }
    4322             : 
    4323         743 :         if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
    4324         101 :                 mask = strtoul(ctmp + 5, NULL, 0x10);
    4325         101 :                 if (mask == 0)
    4326           1 :                         mask = WPA_BSS_MASK_ALL;
    4327             :         }
    4328             : 
    4329         743 :         if (bss == NULL)
    4330         268 :                 return 0;
    4331             : 
    4332         475 :         if (bsslast == NULL)
    4333         383 :                 bsslast = bss;
    4334             :         do {
    4335         562 :                 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
    4336         562 :                 ret += len;
    4337         562 :                 buf += len;
    4338         562 :                 buflen -= len;
    4339         562 :                 if (bss == bsslast) {
    4340         476 :                         if ((mask & WPA_BSS_MASK_DELIM) && len &&
    4341           1 :                             (bss == dl_list_last(&wpa_s->bss_id,
    4342             :                                                  struct wpa_bss, list_id))) {
    4343             :                                 int res;
    4344             : 
    4345           1 :                                 res = os_snprintf(buf - 5, end - buf + 5,
    4346             :                                                   "####\n");
    4347           1 :                                 if (os_snprintf_error(end - buf + 5, res)) {
    4348           0 :                                         wpa_printf(MSG_DEBUG,
    4349             :                                                    "Could not add end delim");
    4350             :                                 }
    4351             :                         }
    4352         475 :                         break;
    4353             :                 }
    4354          87 :                 next = bss->list_id.next;
    4355          87 :                 if (next == &wpa_s->bss_id)
    4356           0 :                         break;
    4357          87 :                 bss = dl_list_entry(next, struct wpa_bss, list_id);
    4358          87 :         } while (bss && len);
    4359             : 
    4360         475 :         return ret;
    4361             : }
    4362             : 
    4363             : 
    4364          13 : static int wpa_supplicant_ctrl_iface_ap_scan(
    4365             :         struct wpa_supplicant *wpa_s, char *cmd)
    4366             : {
    4367          13 :         int ap_scan = atoi(cmd);
    4368          13 :         return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
    4369             : }
    4370             : 
    4371             : 
    4372          18 : static int wpa_supplicant_ctrl_iface_scan_interval(
    4373             :         struct wpa_supplicant *wpa_s, char *cmd)
    4374             : {
    4375          18 :         int scan_int = atoi(cmd);
    4376          18 :         return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
    4377             : }
    4378             : 
    4379             : 
    4380           3 : static int wpa_supplicant_ctrl_iface_bss_expire_age(
    4381             :         struct wpa_supplicant *wpa_s, char *cmd)
    4382             : {
    4383           3 :         int expire_age = atoi(cmd);
    4384           3 :         return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
    4385             : }
    4386             : 
    4387             : 
    4388           2 : static int wpa_supplicant_ctrl_iface_bss_expire_count(
    4389             :         struct wpa_supplicant *wpa_s, char *cmd)
    4390             : {
    4391           2 :         int expire_count = atoi(cmd);
    4392           2 :         return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
    4393             : }
    4394             : 
    4395             : 
    4396         222 : static void wpa_supplicant_ctrl_iface_bss_flush(
    4397             :         struct wpa_supplicant *wpa_s, char *cmd)
    4398             : {
    4399         222 :         int flush_age = atoi(cmd);
    4400             : 
    4401         222 :         if (flush_age == 0)
    4402         221 :                 wpa_bss_flush(wpa_s);
    4403             :         else
    4404           1 :                 wpa_bss_flush_by_age(wpa_s, flush_age);
    4405         222 : }
    4406             : 
    4407             : 
    4408             : #ifdef CONFIG_TESTING_OPTIONS
    4409           2 : static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
    4410             : {
    4411           2 :         wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
    4412             :         /* MLME-DELETEKEYS.request */
    4413           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
    4414           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
    4415           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
    4416           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
    4417             : #ifdef CONFIG_IEEE80211W
    4418           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
    4419           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
    4420             : #endif /* CONFIG_IEEE80211W */
    4421             : 
    4422           2 :         wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
    4423             :                         0);
    4424             :         /* MLME-SETPROTECTION.request(None) */
    4425           2 :         wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
    4426             :                                    MLME_SETPROTECTION_PROTECT_TYPE_NONE,
    4427             :                                    MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
    4428           2 :         wpa_sm_drop_sa(wpa_s->wpa);
    4429           2 : }
    4430             : #endif /* CONFIG_TESTING_OPTIONS */
    4431             : 
    4432             : 
    4433         155 : static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
    4434             :                                           char *addr)
    4435             : {
    4436             : #ifdef CONFIG_NO_SCAN_PROCESSING
    4437             :         return -1;
    4438             : #else /* CONFIG_NO_SCAN_PROCESSING */
    4439             :         u8 bssid[ETH_ALEN];
    4440             :         struct wpa_bss *bss;
    4441         155 :         struct wpa_ssid *ssid = wpa_s->current_ssid;
    4442             : 
    4443         155 :         if (hwaddr_aton(addr, bssid)) {
    4444           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
    4445             :                            "address '%s'", addr);
    4446           1 :                 return -1;
    4447             :         }
    4448             : 
    4449         154 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
    4450             : 
    4451         154 :         if (!ssid) {
    4452           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
    4453             :                            "configuration known for the target AP");
    4454           1 :                 return -1;
    4455             :         }
    4456             : 
    4457         153 :         bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
    4458         153 :         if (!bss) {
    4459           1 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
    4460             :                            "from BSS table");
    4461           1 :                 return -1;
    4462             :         }
    4463             : 
    4464             :         /*
    4465             :          * TODO: Find best network configuration block from configuration to
    4466             :          * allow roaming to other networks
    4467             :          */
    4468             : 
    4469         152 :         wpa_s->reassociate = 1;
    4470         152 :         wpa_supplicant_connect(wpa_s, bss, ssid);
    4471             : 
    4472         152 :         return 0;
    4473             : #endif /* CONFIG_NO_SCAN_PROCESSING */
    4474             : }
    4475             : 
    4476             : 
    4477             : #ifdef CONFIG_P2P
    4478         338 : static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
    4479             : {
    4480         338 :         unsigned int timeout = atoi(cmd);
    4481         338 :         enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
    4482         338 :         u8 dev_id[ETH_ALEN], *_dev_id = NULL;
    4483         338 :         u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
    4484             :         char *pos;
    4485             :         unsigned int search_delay;
    4486             :         const char *seek[P2P_MAX_QUERY_HASH + 1];
    4487         338 :         u8 seek_count = 0;
    4488             : 
    4489         338 :         if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
    4490           1 :                 wpa_dbg(wpa_s, MSG_INFO,
    4491             :                         "Reject P2P_FIND since interface is disabled");
    4492           1 :                 return -1;
    4493             :         }
    4494         337 :         if (os_strstr(cmd, "type=social"))
    4495         315 :                 type = P2P_FIND_ONLY_SOCIAL;
    4496          22 :         else if (os_strstr(cmd, "type=progressive"))
    4497           1 :                 type = P2P_FIND_PROGRESSIVE;
    4498             : 
    4499         337 :         pos = os_strstr(cmd, "dev_id=");
    4500         337 :         if (pos) {
    4501           5 :                 pos += 7;
    4502           5 :                 if (hwaddr_aton(pos, dev_id))
    4503           1 :                         return -1;
    4504           4 :                 _dev_id = dev_id;
    4505             :         }
    4506             : 
    4507         336 :         pos = os_strstr(cmd, "dev_type=");
    4508         336 :         if (pos) {
    4509           5 :                 pos += 9;
    4510           5 :                 if (wps_dev_type_str2bin(pos, dev_type) < 0)
    4511           1 :                         return -1;
    4512           4 :                 _dev_type = dev_type;
    4513             :         }
    4514             : 
    4515         335 :         pos = os_strstr(cmd, "delay=");
    4516         335 :         if (pos) {
    4517           1 :                 pos += 6;
    4518           1 :                 search_delay = atoi(pos);
    4519             :         } else
    4520         334 :                 search_delay = wpas_p2p_search_delay(wpa_s);
    4521             : 
    4522             :         /* Must be searched for last, because it adds nul termination */
    4523         335 :         pos = os_strstr(cmd, " seek=");
    4524         704 :         while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
    4525             :                 char *term;
    4526             : 
    4527          34 :                 term = os_strchr(pos + 1, ' ');
    4528          34 :                 seek[seek_count++] = pos + 6;
    4529          34 :                 pos = os_strstr(pos + 6, " seek=");
    4530             : 
    4531          34 :                 if (term)
    4532           8 :                         *term = '\0';
    4533             :         }
    4534             : 
    4535         335 :         if (!seek_count)
    4536         309 :                 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
    4537             :                                      _dev_type, _dev_id,
    4538             :                                      search_delay, 0, NULL);
    4539             : 
    4540          26 :         if (seek_count > P2P_MAX_QUERY_HASH) {
    4541           1 :                 seek[0] = NULL;
    4542           1 :                 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
    4543             :                                      _dev_type, _dev_id,
    4544             :                                      search_delay, 1, seek);
    4545             :         }
    4546             : 
    4547          25 :         return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
    4548             :                              _dev_id, search_delay, seek_count, seek);
    4549             : }
    4550             : 
    4551             : 
    4552          18 : static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
    4553             : {
    4554             :         struct p2ps_provision *p2ps_prov;
    4555             :         char *pos;
    4556          18 :         size_t info_len = 0;
    4557          18 :         char *info = NULL;
    4558          18 :         u8 role = P2PS_SETUP_NONE;
    4559             :         long long unsigned val;
    4560             : 
    4561          18 :         pos = os_strstr(cmd, "info=");
    4562          18 :         if (pos) {
    4563          15 :                 pos += 5;
    4564          15 :                 info_len = os_strlen(pos);
    4565             : 
    4566          15 :                 if (info_len) {
    4567          15 :                         info = os_malloc(info_len + 1);
    4568          15 :                         if (info) {
    4569          15 :                                 info_len = utf8_unescape(pos, info_len,
    4570             :                                                          info, info_len + 1);
    4571             :                         } else
    4572           0 :                                 info_len = 0;
    4573             :                 }
    4574             :         }
    4575             : 
    4576          18 :         p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
    4577          18 :         if (p2ps_prov == NULL) {
    4578           0 :                 os_free(info);
    4579           0 :                 return NULL;
    4580             :         }
    4581             : 
    4582          18 :         if (info) {
    4583          15 :                 os_memcpy(p2ps_prov->info, info, info_len);
    4584          15 :                 p2ps_prov->info[info_len] = '\0';
    4585          15 :                 os_free(info);
    4586             :         }
    4587             : 
    4588          18 :         pos = os_strstr(cmd, "status=");
    4589          18 :         if (pos)
    4590           3 :                 p2ps_prov->status = atoi(pos + 7);
    4591             :         else
    4592          15 :                 p2ps_prov->status = -1;
    4593             : 
    4594          18 :         pos = os_strstr(cmd, "adv_id=");
    4595          18 :         if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
    4596             :                 goto invalid_args;
    4597          18 :         p2ps_prov->adv_id = val;
    4598             : 
    4599          18 :         pos = os_strstr(cmd, "method=");
    4600          18 :         if (pos)
    4601          15 :                 p2ps_prov->method = strtol(pos + 7, NULL, 16);
    4602             :         else
    4603           3 :                 p2ps_prov->method = 0;
    4604             : 
    4605          18 :         pos = os_strstr(cmd, "session=");
    4606          18 :         if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
    4607             :                 goto invalid_args;
    4608          18 :         p2ps_prov->session_id = val;
    4609             : 
    4610          18 :         pos = os_strstr(cmd, "adv_mac=");
    4611          18 :         if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
    4612             :                 goto invalid_args;
    4613             : 
    4614          18 :         pos = os_strstr(cmd, "session_mac=");
    4615          18 :         if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
    4616             :                 goto invalid_args;
    4617             : 
    4618             :         /* force conncap with tstCap (no sanity checks) */
    4619          18 :         pos = os_strstr(cmd, "tstCap=");
    4620          18 :         if (pos) {
    4621           0 :                 role = strtol(pos + 7, NULL, 16);
    4622             :         } else {
    4623          18 :                 pos = os_strstr(cmd, "role=");
    4624          18 :                 if (pos) {
    4625           0 :                         role = strtol(pos + 5, NULL, 16);
    4626           0 :                         if (role != P2PS_SETUP_CLIENT &&
    4627             :                             role != P2PS_SETUP_GROUP_OWNER)
    4628           0 :                                 role = P2PS_SETUP_NONE;
    4629             :                 }
    4630             :         }
    4631          18 :         p2ps_prov->role = role;
    4632             : 
    4633          18 :         return p2ps_prov;
    4634             : 
    4635             : invalid_args:
    4636           0 :         os_free(p2ps_prov);
    4637           0 :         return NULL;
    4638             : }
    4639             : 
    4640             : 
    4641           3 : static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
    4642             : {
    4643             :         u8 addr[ETH_ALEN];
    4644             :         struct p2ps_provision *p2ps_prov;
    4645             :         char *pos;
    4646             : 
    4647             :         /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
    4648             : 
    4649           3 :         wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
    4650             : 
    4651           3 :         if (hwaddr_aton(cmd, addr))
    4652           0 :                 return -1;
    4653             : 
    4654           3 :         pos = cmd + 17;
    4655           3 :         if (*pos != ' ')
    4656           0 :                 return -1;
    4657             : 
    4658           3 :         p2ps_prov = p2p_parse_asp_provision_cmd(pos);
    4659           3 :         if (!p2ps_prov)
    4660           0 :                 return -1;
    4661             : 
    4662           3 :         if (p2ps_prov->status < 0) {
    4663           0 :                 os_free(p2ps_prov);
    4664           0 :                 return -1;
    4665             :         }
    4666             : 
    4667           3 :         return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
    4668             :                                   p2ps_prov);
    4669             : }
    4670             : 
    4671             : 
    4672          15 : static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
    4673             : {
    4674             :         u8 addr[ETH_ALEN];
    4675             :         struct p2ps_provision *p2ps_prov;
    4676             :         char *pos;
    4677             : 
    4678             :         /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
    4679             :          *        session=<ses_id> mac=<ses_mac> [info=<infodata>]
    4680             :          */
    4681             : 
    4682          15 :         wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
    4683          15 :         if (hwaddr_aton(cmd, addr))
    4684           0 :                 return -1;
    4685             : 
    4686          15 :         pos = cmd + 17;
    4687          15 :         if (*pos != ' ')
    4688           0 :                 return -1;
    4689             : 
    4690          15 :         p2ps_prov = p2p_parse_asp_provision_cmd(pos);
    4691          15 :         if (!p2ps_prov)
    4692           0 :                 return -1;
    4693             : 
    4694          15 :         return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
    4695             :                                   p2ps_prov);
    4696             : }
    4697             : 
    4698             : 
    4699         284 : static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
    4700             :                             char *buf, size_t buflen)
    4701             : {
    4702             :         u8 addr[ETH_ALEN];
    4703             :         char *pos, *pos2;
    4704         284 :         char *pin = NULL;
    4705             :         enum p2p_wps_method wps_method;
    4706             :         int new_pin;
    4707             :         int ret;
    4708         284 :         int persistent_group, persistent_id = -1;
    4709             :         int join;
    4710             :         int auth;
    4711             :         int automatic;
    4712         284 :         int go_intent = -1;
    4713         284 :         int freq = 0;
    4714             :         int pd;
    4715             :         int ht40, vht;
    4716             : 
    4717             :         /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
    4718             :          * [persistent|persistent=<network id>]
    4719             :          * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
    4720             :          * [ht40] [vht] */
    4721             : 
    4722         284 :         if (hwaddr_aton(cmd, addr))
    4723           1 :                 return -1;
    4724             : 
    4725         283 :         pos = cmd + 17;
    4726         283 :         if (*pos != ' ')
    4727           1 :                 return -1;
    4728         282 :         pos++;
    4729             : 
    4730         282 :         persistent_group = os_strstr(pos, " persistent") != NULL;
    4731         282 :         pos2 = os_strstr(pos, " persistent=");
    4732         282 :         if (pos2) {
    4733             :                 struct wpa_ssid *ssid;
    4734           3 :                 persistent_id = atoi(pos2 + 12);
    4735           3 :                 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
    4736           4 :                 if (ssid == NULL || ssid->disabled != 2 ||
    4737           1 :                     ssid->mode != WPAS_MODE_P2P_GO) {
    4738           2 :                         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
    4739             :                                    "SSID id=%d for persistent P2P group (GO)",
    4740             :                                    persistent_id);
    4741           2 :                         return -1;
    4742             :                 }
    4743             :         }
    4744         280 :         join = os_strstr(pos, " join") != NULL;
    4745         280 :         auth = os_strstr(pos, " auth") != NULL;
    4746         280 :         automatic = os_strstr(pos, " auto") != NULL;
    4747         280 :         pd = os_strstr(pos, " provdisc") != NULL;
    4748         280 :         vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
    4749         280 :         ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
    4750             :                 vht;
    4751             : 
    4752         280 :         pos2 = os_strstr(pos, " go_intent=");
    4753         280 :         if (pos2) {
    4754         103 :                 pos2 += 11;
    4755         103 :                 go_intent = atoi(pos2);
    4756         103 :                 if (go_intent < 0 || go_intent > 15)
    4757           2 :                         return -1;
    4758             :         }
    4759             : 
    4760         278 :         pos2 = os_strstr(pos, " freq=");
    4761         278 :         if (pos2) {
    4762          52 :                 pos2 += 6;
    4763          52 :                 freq = atoi(pos2);
    4764          52 :                 if (freq <= 0)
    4765           1 :                         return -1;
    4766             :         }
    4767             : 
    4768         277 :         if (os_strncmp(pos, "pin", 3) == 0) {
    4769             :                 /* Request random PIN (to be displayed) and enable the PIN */
    4770           3 :                 wps_method = WPS_PIN_DISPLAY;
    4771         274 :         } else if (os_strncmp(pos, "pbc", 3) == 0) {
    4772          66 :                 wps_method = WPS_PBC;
    4773             :         } else {
    4774         208 :                 pin = pos;
    4775         208 :                 pos = os_strchr(pin, ' ');
    4776         208 :                 wps_method = WPS_PIN_KEYPAD;
    4777         208 :                 if (pos) {
    4778         207 :                         *pos++ = '\0';
    4779         207 :                         if (os_strncmp(pos, "display", 7) == 0)
    4780          80 :                                 wps_method = WPS_PIN_DISPLAY;
    4781         127 :                         else if (os_strncmp(pos, "p2ps", 4) == 0)
    4782          10 :                                 wps_method = WPS_P2PS;
    4783             :                 }
    4784         208 :                 if (!wps_pin_str_valid(pin)) {
    4785           1 :                         os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
    4786           1 :                         return 17;
    4787             :                 }
    4788             :         }
    4789             : 
    4790         276 :         new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
    4791             :                                    persistent_group, automatic, join,
    4792             :                                    auth, go_intent, freq, persistent_id, pd,
    4793             :                                    ht40, vht);
    4794         276 :         if (new_pin == -2) {
    4795           0 :                 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
    4796           0 :                 return 25;
    4797             :         }
    4798         276 :         if (new_pin == -3) {
    4799           2 :                 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
    4800           2 :                 return 25;
    4801             :         }
    4802         274 :         if (new_pin < 0)
    4803           1 :                 return -1;
    4804         273 :         if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
    4805           1 :                 ret = os_snprintf(buf, buflen, "%08d", new_pin);
    4806           1 :                 if (os_snprintf_error(buflen, ret))
    4807           0 :                         return -1;
    4808           1 :                 return ret;
    4809             :         }
    4810             : 
    4811         272 :         os_memcpy(buf, "OK\n", 3);
    4812         272 :         return 3;
    4813             : }
    4814             : 
    4815             : 
    4816         346 : static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
    4817             : {
    4818         346 :         unsigned int timeout = atoi(cmd);
    4819         346 :         if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
    4820           2 :                 wpa_dbg(wpa_s, MSG_INFO,
    4821             :                         "Reject P2P_LISTEN since interface is disabled");
    4822           2 :                 return -1;
    4823             :         }
    4824         344 :         return wpas_p2p_listen(wpa_s, timeout);
    4825             : }
    4826             : 
    4827             : 
    4828          16 : static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
    4829             : {
    4830             :         u8 addr[ETH_ALEN];
    4831             :         char *pos;
    4832          16 :         enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
    4833             : 
    4834             :         /* <addr> <config method> [join|auto] */
    4835             : 
    4836          16 :         if (hwaddr_aton(cmd, addr))
    4837           1 :                 return -1;
    4838             : 
    4839          15 :         pos = cmd + 17;
    4840          15 :         if (*pos != ' ')
    4841           1 :                 return -1;
    4842          14 :         pos++;
    4843             : 
    4844          14 :         if (os_strstr(pos, " join") != NULL)
    4845           2 :                 use = WPAS_P2P_PD_FOR_JOIN;
    4846          12 :         else if (os_strstr(pos, " auto") != NULL)
    4847           2 :                 use = WPAS_P2P_PD_AUTO;
    4848             : 
    4849          14 :         return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
    4850             : }
    4851             : 
    4852             : 
    4853           2 : static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
    4854             :                               size_t buflen)
    4855             : {
    4856           2 :         struct wpa_ssid *ssid = wpa_s->current_ssid;
    4857             : 
    4858           3 :         if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
    4859           1 :             ssid->passphrase == NULL)
    4860           1 :                 return -1;
    4861             : 
    4862           1 :         os_strlcpy(buf, ssid->passphrase, buflen);
    4863           1 :         return os_strlen(buf);
    4864             : }
    4865             : 
    4866             : 
    4867          66 : static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
    4868             :                                   char *buf, size_t buflen)
    4869             : {
    4870             :         u64 ref;
    4871             :         int res;
    4872             :         u8 dst_buf[ETH_ALEN], *dst;
    4873             :         struct wpabuf *tlvs;
    4874             :         char *pos;
    4875             :         size_t len;
    4876             : 
    4877          66 :         if (hwaddr_aton(cmd, dst_buf))
    4878           1 :                 return -1;
    4879          65 :         dst = dst_buf;
    4880         104 :         if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
    4881          78 :             dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
    4882          39 :                 dst = NULL;
    4883          65 :         pos = cmd + 17;
    4884          65 :         if (*pos != ' ')
    4885           1 :                 return -1;
    4886          64 :         pos++;
    4887             : 
    4888          64 :         if (os_strncmp(pos, "upnp ", 5) == 0) {
    4889             :                 u8 version;
    4890           4 :                 pos += 5;
    4891           4 :                 if (hexstr2bin(pos, &version, 1) < 0)
    4892           3 :                         return -1;
    4893           3 :                 pos += 2;
    4894           3 :                 if (*pos != ' ')
    4895           1 :                         return -1;
    4896           2 :                 pos++;
    4897           2 :                 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
    4898             : #ifdef CONFIG_WIFI_DISPLAY
    4899          60 :         } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
    4900           1 :                 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
    4901             : #endif /* CONFIG_WIFI_DISPLAY */
    4902          59 :         } else if (os_strncmp(pos, "asp ", 4) == 0) {
    4903             :                 char *svc_str;
    4904          20 :                 char *svc_info = NULL;
    4905             :                 u32 id;
    4906             : 
    4907          20 :                 pos += 4;
    4908          20 :                 if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
    4909           0 :                         return -1;
    4910             : 
    4911          20 :                 pos = os_strchr(pos, ' ');
    4912          20 :                 if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
    4913           0 :                         return -1;
    4914             : 
    4915          20 :                 svc_str = pos + 1;
    4916             : 
    4917          20 :                 pos = os_strchr(svc_str, ' ');
    4918             : 
    4919          20 :                 if (pos)
    4920          20 :                         *pos++ = '\0';
    4921             : 
    4922             :                 /* All remaining data is the svc_info string */
    4923          20 :                 if (pos && pos[0] && pos[0] != ' ') {
    4924          20 :                         len = os_strlen(pos);
    4925             : 
    4926             :                         /* Unescape in place */
    4927          20 :                         len = utf8_unescape(pos, len, pos, len);
    4928          20 :                         if (len > 0xff)
    4929           0 :                                 return -1;
    4930             : 
    4931          20 :                         svc_info = pos;
    4932             :                 }
    4933             : 
    4934          20 :                 ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
    4935             :                                               svc_str, svc_info);
    4936             :         } else {
    4937          39 :                 len = os_strlen(pos);
    4938          39 :                 if (len & 1)
    4939           1 :                         return -1;
    4940          38 :                 len /= 2;
    4941          38 :                 tlvs = wpabuf_alloc(len);
    4942          38 :                 if (tlvs == NULL)
    4943           0 :                         return -1;
    4944          38 :                 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
    4945           1 :                         wpabuf_free(tlvs);
    4946           1 :                         return -1;
    4947             :                 }
    4948             : 
    4949          37 :                 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
    4950          37 :                 wpabuf_free(tlvs);
    4951             :         }
    4952          60 :         if (ref == 0)
    4953           0 :                 return -1;
    4954          60 :         res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
    4955          60 :         if (os_snprintf_error(buflen, res))
    4956           0 :                 return -1;
    4957          60 :         return res;
    4958             : }
    4959             : 
    4960             : 
    4961           9 : static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
    4962             :                                          char *cmd)
    4963             : {
    4964             :         long long unsigned val;
    4965             :         u64 req;
    4966           9 :         if (sscanf(cmd, "%llx", &val) != 1)
    4967           1 :                 return -1;
    4968           8 :         req = val;
    4969           8 :         return wpas_p2p_sd_cancel_request(wpa_s, req);
    4970             : }
    4971             : 
    4972             : 
    4973           9 : static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
    4974             : {
    4975             :         int freq;
    4976             :         u8 dst[ETH_ALEN];
    4977             :         u8 dialog_token;
    4978             :         struct wpabuf *resp_tlvs;
    4979             :         char *pos, *pos2;
    4980             :         size_t len;
    4981             : 
    4982           9 :         pos = os_strchr(cmd, ' ');
    4983           9 :         if (pos == NULL)
    4984           1 :                 return -1;
    4985           8 :         *pos++ = '\0';
    4986           8 :         freq = atoi(cmd);
    4987           8 :         if (freq == 0)
    4988           1 :                 return -1;
    4989             : 
    4990           7 :         if (hwaddr_aton(pos, dst))
    4991           1 :                 return -1;
    4992           6 :         pos += 17;
    4993           6 :         if (*pos != ' ')
    4994           1 :                 return -1;
    4995           5 :         pos++;
    4996             : 
    4997           5 :         pos2 = os_strchr(pos, ' ');
    4998           5 :         if (pos2 == NULL)
    4999           1 :                 return -1;
    5000           4 :         *pos2++ = '\0';
    5001           4 :         dialog_token = atoi(pos);
    5002             : 
    5003           4 :         len = os_strlen(pos2);
    5004           4 :         if (len & 1)
    5005           1 :                 return -1;
    5006           3 :         len /= 2;
    5007           3 :         resp_tlvs = wpabuf_alloc(len);
    5008           3 :         if (resp_tlvs == NULL)
    5009           0 :                 return -1;
    5010           3 :         if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
    5011           1 :                 wpabuf_free(resp_tlvs);
    5012           1 :                 return -1;
    5013             :         }
    5014             : 
    5015           2 :         wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
    5016           2 :         wpabuf_free(resp_tlvs);
    5017           2 :         return 0;
    5018             : }
    5019             : 
    5020             : 
    5021           4 : static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
    5022             :                                        char *cmd)
    5023             : {
    5024           4 :         if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
    5025           1 :                 return -1;
    5026           3 :         wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
    5027           3 :         return 0;
    5028             : }
    5029             : 
    5030             : 
    5031         110 : static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
    5032             :                                         char *cmd)
    5033             : {
    5034             :         char *pos;
    5035             :         size_t len;
    5036             :         struct wpabuf *query, *resp;
    5037             : 
    5038         110 :         pos = os_strchr(cmd, ' ');
    5039         110 :         if (pos == NULL)
    5040           1 :                 return -1;
    5041         109 :         *pos++ = '\0';
    5042             : 
    5043         109 :         len = os_strlen(cmd);
    5044         109 :         if (len & 1)
    5045           1 :                 return -1;
    5046         108 :         len /= 2;
    5047         108 :         query = wpabuf_alloc(len);
    5048         108 :         if (query == NULL)
    5049           0 :                 return -1;
    5050         108 :         if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
    5051           1 :                 wpabuf_free(query);
    5052           1 :                 return -1;
    5053             :         }
    5054             : 
    5055         107 :         len = os_strlen(pos);
    5056         107 :         if (len & 1) {
    5057           1 :                 wpabuf_free(query);
    5058           1 :                 return -1;
    5059             :         }
    5060         106 :         len /= 2;
    5061         106 :         resp = wpabuf_alloc(len);
    5062         106 :         if (resp == NULL) {
    5063           0 :                 wpabuf_free(query);
    5064           0 :                 return -1;
    5065             :         }
    5066         106 :         if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
    5067           1 :                 wpabuf_free(query);
    5068           1 :                 wpabuf_free(resp);
    5069           1 :                 return -1;
    5070             :         }
    5071             : 
    5072         105 :         if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
    5073           0 :                 wpabuf_free(query);
    5074           0 :                 wpabuf_free(resp);
    5075           0 :                 return -1;
    5076             :         }
    5077         105 :         return 0;
    5078             : }
    5079             : 
    5080             : 
    5081         532 : static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
    5082             : {
    5083             :         char *pos;
    5084             :         u8 version;
    5085             : 
    5086         532 :         pos = os_strchr(cmd, ' ');
    5087         532 :         if (pos == NULL)
    5088           1 :                 return -1;
    5089         531 :         *pos++ = '\0';
    5090             : 
    5091         531 :         if (hexstr2bin(cmd, &version, 1) < 0)
    5092           1 :                 return -1;
    5093             : 
    5094         530 :         return wpas_p2p_service_add_upnp(wpa_s, version, pos);
    5095             : }
    5096             : 
    5097             : 
    5098          28 : static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
    5099             :                                     u8 replace, char *cmd)
    5100             : {
    5101             :         char *pos;
    5102             :         char *adv_str;
    5103             :         u32 auto_accept, adv_id, svc_state, config_methods;
    5104          28 :         char *svc_info = NULL;
    5105             : 
    5106          28 :         pos = os_strchr(cmd, ' ');
    5107          28 :         if (pos == NULL)
    5108           0 :                 return -1;
    5109          28 :         *pos++ = '\0';
    5110             : 
    5111             :         /* Auto-Accept value is mandatory, and must be one of the
    5112             :          * single values (0, 1, 2, 4) */
    5113          28 :         auto_accept = atoi(cmd);
    5114          28 :         switch (auto_accept) {
    5115             :         case P2PS_SETUP_NONE: /* No auto-accept */
    5116             :         case P2PS_SETUP_NEW:
    5117             :         case P2PS_SETUP_CLIENT:
    5118             :         case P2PS_SETUP_GROUP_OWNER:
    5119          28 :                 break;
    5120             :         default:
    5121           0 :                 return -1;
    5122             :         }
    5123             : 
    5124             :         /* Advertisement ID is mandatory */
    5125          28 :         cmd = pos;
    5126          28 :         pos = os_strchr(cmd, ' ');
    5127          28 :         if (pos == NULL)
    5128           0 :                 return -1;
    5129          28 :         *pos++ = '\0';
    5130             : 
    5131             :         /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
    5132          28 :         if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
    5133           0 :                 return -1;
    5134             : 
    5135             :         /* Only allow replacements if exist, and adds if not */
    5136          28 :         if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
    5137           2 :                 if (!replace)
    5138           0 :                         return -1;
    5139             :         } else {
    5140          26 :                 if (replace)
    5141           0 :                         return -1;
    5142             :         }
    5143             : 
    5144             :         /* svc_state between 0 - 0xff is mandatory */
    5145          28 :         if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
    5146           0 :                 return -1;
    5147             : 
    5148          28 :         pos = os_strchr(pos, ' ');
    5149          28 :         if (pos == NULL)
    5150           0 :                 return -1;
    5151             : 
    5152             :         /* config_methods is mandatory */
    5153          28 :         pos++;
    5154          28 :         if (sscanf(pos, "%x", &config_methods) != 1)
    5155           0 :                 return -1;
    5156             : 
    5157          28 :         if (!(config_methods &
    5158             :               (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
    5159           0 :                 return -1;
    5160             : 
    5161          28 :         pos = os_strchr(pos, ' ');
    5162          28 :         if (pos == NULL)
    5163           0 :                 return -1;
    5164             : 
    5165          28 :         pos++;
    5166          28 :         adv_str = pos;
    5167             : 
    5168             :         /* Advertisement string is mandatory */
    5169          28 :         if (!pos[0] || pos[0] == ' ')
    5170           0 :                 return -1;
    5171             : 
    5172             :         /* Terminate svc string */
    5173          28 :         pos = os_strchr(pos, ' ');
    5174          28 :         if (pos != NULL)
    5175          28 :                 *pos++ = '\0';
    5176             : 
    5177             :         /* Service and Response Information are optional */
    5178          28 :         if (pos && pos[0]) {
    5179             :                 size_t len;
    5180             : 
    5181             :                 /* Note the bare ' included, which cannot exist legally
    5182             :                  * in unescaped string. */
    5183          28 :                 svc_info = os_strstr(pos, "svc_info='");
    5184             : 
    5185          28 :                 if (svc_info) {
    5186          28 :                         svc_info += 9;
    5187          28 :                         len = os_strlen(svc_info);
    5188          28 :                         utf8_unescape(svc_info, len, svc_info, len);
    5189             :                 }
    5190             :         }
    5191             : 
    5192          56 :         return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
    5193          56 :                                         (u8) svc_state, (u16) config_methods,
    5194             :                                         svc_info);
    5195             : }
    5196             : 
    5197             : 
    5198         670 : static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
    5199             : {
    5200             :         char *pos;
    5201             : 
    5202         670 :         pos = os_strchr(cmd, ' ');
    5203         670 :         if (pos == NULL)
    5204           1 :                 return -1;
    5205         669 :         *pos++ = '\0';
    5206             : 
    5207         669 :         if (os_strcmp(cmd, "bonjour") == 0)
    5208         110 :                 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
    5209         559 :         if (os_strcmp(cmd, "upnp") == 0)
    5210         532 :                 return p2p_ctrl_service_add_upnp(wpa_s, pos);
    5211          27 :         if (os_strcmp(cmd, "asp") == 0)
    5212          26 :                 return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
    5213           1 :         wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
    5214           1 :         return -1;
    5215             : }
    5216             : 
    5217             : 
    5218          40 : static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
    5219             :                                         char *cmd)
    5220             : {
    5221             :         size_t len;
    5222             :         struct wpabuf *query;
    5223             :         int ret;
    5224             : 
    5225          40 :         len = os_strlen(cmd);
    5226          40 :         if (len & 1)
    5227           1 :                 return -1;
    5228          39 :         len /= 2;
    5229          39 :         query = wpabuf_alloc(len);
    5230          39 :         if (query == NULL)
    5231           0 :                 return -1;
    5232          39 :         if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
    5233           1 :                 wpabuf_free(query);
    5234           1 :                 return -1;
    5235             :         }
    5236             : 
    5237          38 :         ret = wpas_p2p_service_del_bonjour(wpa_s, query);
    5238          38 :         wpabuf_free(query);
    5239          38 :         return ret;
    5240             : }
    5241             : 
    5242             : 
    5243          41 : static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
    5244             : {
    5245             :         char *pos;
    5246             :         u8 version;
    5247             : 
    5248          41 :         pos = os_strchr(cmd, ' ');
    5249          41 :         if (pos == NULL)
    5250           1 :                 return -1;
    5251          40 :         *pos++ = '\0';
    5252             : 
    5253          40 :         if (hexstr2bin(cmd, &version, 1) < 0)
    5254           2 :                 return -1;
    5255             : 
    5256          38 :         return wpas_p2p_service_del_upnp(wpa_s, version, pos);
    5257             : }
    5258             : 
    5259             : 
    5260          23 : static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
    5261             : {
    5262             :         u32 adv_id;
    5263             : 
    5264          23 :         if (sscanf(cmd, "%x", &adv_id) != 1)
    5265           0 :                 return -1;
    5266             : 
    5267          23 :         return wpas_p2p_service_del_asp(wpa_s, adv_id);
    5268             : }
    5269             : 
    5270             : 
    5271         106 : static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
    5272             : {
    5273             :         char *pos;
    5274             : 
    5275         106 :         pos = os_strchr(cmd, ' ');
    5276         106 :         if (pos == NULL)
    5277           1 :                 return -1;
    5278         105 :         *pos++ = '\0';
    5279             : 
    5280         105 :         if (os_strcmp(cmd, "bonjour") == 0)
    5281          40 :                 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
    5282          65 :         if (os_strcmp(cmd, "upnp") == 0)
    5283          41 :                 return p2p_ctrl_service_del_upnp(wpa_s, pos);
    5284          24 :         if (os_strcmp(cmd, "asp") == 0)
    5285          23 :                 return p2p_ctrl_service_del_asp(wpa_s, pos);
    5286           1 :         wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
    5287           1 :         return -1;
    5288             : }
    5289             : 
    5290             : 
    5291           2 : static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
    5292             : {
    5293             :         char *pos;
    5294             : 
    5295           2 :         pos = os_strchr(cmd, ' ');
    5296           2 :         if (pos == NULL)
    5297           0 :                 return -1;
    5298           2 :         *pos++ = '\0';
    5299             : 
    5300           2 :         if (os_strcmp(cmd, "asp") == 0)
    5301           2 :                 return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
    5302             : 
    5303           0 :         wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
    5304           0 :         return -1;
    5305             : }
    5306             : 
    5307             : 
    5308           3 : static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
    5309             : {
    5310             :         u8 addr[ETH_ALEN];
    5311             : 
    5312             :         /* <addr> */
    5313             : 
    5314           3 :         if (hwaddr_aton(cmd, addr))
    5315           1 :                 return -1;
    5316             : 
    5317           2 :         return wpas_p2p_reject(wpa_s, addr);
    5318             : }
    5319             : 
    5320             : 
    5321          38 : static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
    5322             : {
    5323             :         char *pos;
    5324             :         int id;
    5325             :         struct wpa_ssid *ssid;
    5326          38 :         u8 *_peer = NULL, peer[ETH_ALEN];
    5327          38 :         int freq = 0, pref_freq = 0;
    5328             :         int ht40, vht;
    5329             : 
    5330          38 :         id = atoi(cmd);
    5331          38 :         pos = os_strstr(cmd, " peer=");
    5332          38 :         if (pos) {
    5333          36 :                 pos += 6;
    5334          36 :                 if (hwaddr_aton(pos, peer))
    5335           1 :                         return -1;
    5336          35 :                 _peer = peer;
    5337             :         }
    5338          37 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    5339          37 :         if (ssid == NULL || ssid->disabled != 2) {
    5340           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
    5341             :                            "for persistent P2P group",
    5342             :                            id);
    5343           2 :                 return -1;
    5344             :         }
    5345             : 
    5346          35 :         pos = os_strstr(cmd, " freq=");
    5347          35 :         if (pos) {
    5348           7 :                 pos += 6;
    5349           7 :                 freq = atoi(pos);
    5350           7 :                 if (freq <= 0)
    5351           1 :                         return -1;
    5352             :         }
    5353             : 
    5354          34 :         pos = os_strstr(cmd, " pref=");
    5355          34 :         if (pos) {
    5356           4 :                 pos += 6;
    5357           4 :                 pref_freq = atoi(pos);
    5358           4 :                 if (pref_freq <= 0)
    5359           1 :                         return -1;
    5360             :         }
    5361             : 
    5362          33 :         vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
    5363          33 :         ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
    5364             :                 vht;
    5365             : 
    5366          33 :         return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
    5367             :                                pref_freq);
    5368             : }
    5369             : 
    5370             : 
    5371          11 : static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
    5372             : {
    5373             :         char *pos;
    5374          11 :         u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
    5375             : 
    5376          11 :         pos = os_strstr(cmd, " peer=");
    5377          11 :         if (!pos)
    5378           1 :                 return -1;
    5379             : 
    5380          10 :         *pos = '\0';
    5381          10 :         pos += 6;
    5382          10 :         if (hwaddr_aton(pos, peer)) {
    5383           1 :                 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
    5384           1 :                 return -1;
    5385             :         }
    5386             : 
    5387           9 :         pos = os_strstr(pos, " go_dev_addr=");
    5388           9 :         if (pos) {
    5389           1 :                 pos += 13;
    5390           1 :                 if (hwaddr_aton(pos, go_dev_addr)) {
    5391           1 :                         wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
    5392             :                                    pos);
    5393           1 :                         return -1;
    5394             :                 }
    5395           0 :                 go_dev = go_dev_addr;
    5396             :         }
    5397             : 
    5398           8 :         return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
    5399             : }
    5400             : 
    5401             : 
    5402          50 : static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
    5403             : {
    5404          50 :         if (os_strncmp(cmd, "persistent=", 11) == 0)
    5405          38 :                 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
    5406          12 :         if (os_strncmp(cmd, "group=", 6) == 0)
    5407          11 :                 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
    5408             : 
    5409           1 :         return -1;
    5410             : }
    5411             : 
    5412             : 
    5413          17 : static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
    5414             :                                          char *cmd, int freq, int ht40,
    5415             :                                          int vht)
    5416             : {
    5417             :         int id;
    5418             :         struct wpa_ssid *ssid;
    5419             : 
    5420          17 :         id = atoi(cmd);
    5421          17 :         ssid = wpa_config_get_network(wpa_s->conf, id);
    5422          17 :         if (ssid == NULL || ssid->disabled != 2) {
    5423           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
    5424             :                            "for persistent P2P group",
    5425             :                            id);
    5426           2 :                 return -1;
    5427             :         }
    5428             : 
    5429          15 :         return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
    5430             :                                              NULL, 0);
    5431             : }
    5432             : 
    5433             : 
    5434          63 : static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
    5435             : {
    5436          63 :         int freq = 0, ht40, vht;
    5437             :         char *pos;
    5438             : 
    5439          63 :         pos = os_strstr(cmd, "freq=");
    5440          63 :         if (pos)
    5441          53 :                 freq = atoi(pos + 5);
    5442             : 
    5443          63 :         vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
    5444          63 :         ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
    5445             :                 vht;
    5446             : 
    5447          63 :         if (os_strncmp(cmd, "persistent=", 11) == 0)
    5448          17 :                 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
    5449             :                                                      ht40, vht);
    5450          90 :         if (os_strcmp(cmd, "persistent") == 0 ||
    5451          44 :             os_strncmp(cmd, "persistent ", 11) == 0)
    5452           2 :                 return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
    5453          44 :         if (os_strncmp(cmd, "freq=", 5) == 0)
    5454          41 :                 return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
    5455           3 :         if (ht40)
    5456           2 :                 return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
    5457             : 
    5458           1 :         wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
    5459             :                    cmd);
    5460           1 :         return -1;
    5461             : }
    5462             : 
    5463             : 
    5464         934 : static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
    5465             :                          char *buf, size_t buflen)
    5466             : {
    5467             :         u8 addr[ETH_ALEN], *addr_ptr;
    5468             :         int next, res;
    5469             :         const struct p2p_peer_info *info;
    5470             :         char *pos, *end;
    5471             :         char devtype[WPS_DEV_TYPE_BUFSIZE];
    5472             :         struct wpa_ssid *ssid;
    5473             :         size_t i;
    5474             : 
    5475         934 :         if (!wpa_s->global->p2p)
    5476           0 :                 return -1;
    5477             : 
    5478         934 :         if (os_strcmp(cmd, "FIRST") == 0) {
    5479           1 :                 addr_ptr = NULL;
    5480           1 :                 next = 0;
    5481         933 :         } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
    5482           2 :                 if (hwaddr_aton(cmd + 5, addr) < 0)
    5483           1 :                         return -1;
    5484           1 :                 addr_ptr = addr;
    5485           1 :                 next = 1;
    5486             :         } else {
    5487         931 :                 if (hwaddr_aton(cmd, addr) < 0)
    5488           1 :                         return -1;
    5489         930 :                 addr_ptr = addr;
    5490         930 :                 next = 0;
    5491             :         }
    5492             : 
    5493         932 :         info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
    5494         932 :         if (info == NULL)
    5495         431 :                 return -1;
    5496             : 
    5497         501 :         pos = buf;
    5498         501 :         end = buf + buflen;
    5499             : 
    5500        5511 :         res = os_snprintf(pos, end - pos, MACSTR "\n"
    5501             :                           "pri_dev_type=%s\n"
    5502             :                           "device_name=%s\n"
    5503             :                           "manufacturer=%s\n"
    5504             :                           "model_name=%s\n"
    5505             :                           "model_number=%s\n"
    5506             :                           "serial_number=%s\n"
    5507             :                           "config_methods=0x%x\n"
    5508             :                           "dev_capab=0x%x\n"
    5509             :                           "group_capab=0x%x\n"
    5510             :                           "level=%d\n",
    5511        3006 :                           MAC2STR(info->p2p_device_addr),
    5512         501 :                           wps_dev_type_bin2str(info->pri_dev_type,
    5513             :                                                devtype, sizeof(devtype)),
    5514         501 :                           info->device_name,
    5515         501 :                           info->manufacturer,
    5516         501 :                           info->model_name,
    5517         501 :                           info->model_number,
    5518         501 :                           info->serial_number,
    5519         501 :                           info->config_methods,
    5520         501 :                           info->dev_capab,
    5521         501 :                           info->group_capab,
    5522             :                           info->level);
    5523         501 :         if (os_snprintf_error(end - pos, res))
    5524           0 :                 return pos - buf;
    5525         501 :         pos += res;
    5526             : 
    5527         509 :         for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
    5528             :         {
    5529             :                 const u8 *t;
    5530           8 :                 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
    5531           8 :                 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
    5532             :                                   wps_dev_type_bin2str(t, devtype,
    5533             :                                                        sizeof(devtype)));
    5534           8 :                 if (os_snprintf_error(end - pos, res))
    5535           0 :                         return pos - buf;
    5536           8 :                 pos += res;
    5537             :         }
    5538             : 
    5539         501 :         ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
    5540         501 :         if (ssid) {
    5541          82 :                 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
    5542          82 :                 if (os_snprintf_error(end - pos, res))
    5543           0 :                         return pos - buf;
    5544          82 :                 pos += res;
    5545             :         }
    5546             : 
    5547         501 :         res = p2p_get_peer_info_txt(info, pos, end - pos);
    5548         501 :         if (res < 0)
    5549           0 :                 return pos - buf;
    5550         501 :         pos += res;
    5551             : 
    5552         501 :         if (info->vendor_elems) {
    5553           4 :                 res = os_snprintf(pos, end - pos, "vendor_elems=");
    5554           4 :                 if (os_snprintf_error(end - pos, res))
    5555           0 :                         return pos - buf;
    5556           4 :                 pos += res;
    5557             : 
    5558           8 :                 pos += wpa_snprintf_hex(pos, end - pos,
    5559           4 :                                         wpabuf_head(info->vendor_elems),
    5560           4 :                                         wpabuf_len(info->vendor_elems));
    5561             : 
    5562           4 :                 res = os_snprintf(pos, end - pos, "\n");
    5563           4 :                 if (os_snprintf_error(end - pos, res))
    5564           0 :                         return pos - buf;
    5565           4 :                 pos += res;
    5566             :         }
    5567             : 
    5568         501 :         return pos - buf;
    5569             : }
    5570             : 
    5571             : 
    5572          16 : static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
    5573             :                                   const char *param)
    5574             : {
    5575             :         unsigned int i;
    5576             : 
    5577          16 :         if (wpa_s->global->p2p == NULL)
    5578           0 :                 return -1;
    5579             : 
    5580          16 :         if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
    5581           0 :                 return -1;
    5582             : 
    5583          32 :         for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
    5584             :                 struct wpa_freq_range *freq;
    5585          16 :                 freq = &wpa_s->global->p2p_disallow_freq.range[i];
    5586          16 :                 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
    5587             :                            freq->min, freq->max);
    5588             :         }
    5589             : 
    5590          16 :         wpas_p2p_update_channel_list(wpa_s);
    5591          16 :         return 0;
    5592             : }
    5593             : 
    5594             : 
    5595         102 : static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
    5596             : {
    5597             :         char *param;
    5598             : 
    5599         102 :         if (wpa_s->global->p2p == NULL)
    5600           0 :                 return -1;
    5601             : 
    5602         102 :         param = os_strchr(cmd, ' ');
    5603         102 :         if (param == NULL)
    5604           1 :                 return -1;
    5605         101 :         *param++ = '\0';
    5606             : 
    5607         101 :         if (os_strcmp(cmd, "discoverability") == 0) {
    5608           2 :                 p2p_set_client_discoverability(wpa_s->global->p2p,
    5609             :                                                atoi(param));
    5610           2 :                 return 0;
    5611             :         }
    5612             : 
    5613          99 :         if (os_strcmp(cmd, "managed") == 0) {
    5614           2 :                 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
    5615           2 :                 return 0;
    5616             :         }
    5617             : 
    5618          97 :         if (os_strcmp(cmd, "listen_channel") == 0) {
    5619           3 :                 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
    5620           3 :                                               atoi(param), 1);
    5621             :         }
    5622             : 
    5623          94 :         if (os_strcmp(cmd, "ssid_postfix") == 0) {
    5624           4 :                 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
    5625             :                                             os_strlen(param));
    5626             :         }
    5627             : 
    5628          90 :         if (os_strcmp(cmd, "noa") == 0) {
    5629             :                 char *pos;
    5630             :                 int count, start, duration;
    5631             :                 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
    5632           9 :                 count = atoi(param);
    5633           9 :                 pos = os_strchr(param, ',');
    5634           9 :                 if (pos == NULL)
    5635           1 :                         return -1;
    5636           8 :                 pos++;
    5637           8 :                 start = atoi(pos);
    5638           8 :                 pos = os_strchr(pos, ',');
    5639           8 :                 if (pos == NULL)
    5640           1 :                         return -1;
    5641           7 :                 pos++;
    5642           7 :                 duration = atoi(pos);
    5643           7 :                 if (count < 0 || count > 255 || start < 0 || duration < 0)
    5644           4 :                         return -1;
    5645           3 :                 if (count == 0 && duration > 0)
    5646           1 :                         return -1;
    5647           2 :                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
    5648             :                            "start=%d duration=%d", count, start, duration);
    5649           2 :                 return wpas_p2p_set_noa(wpa_s, count, start, duration);
    5650             :         }
    5651             : 
    5652          81 :         if (os_strcmp(cmd, "ps") == 0)
    5653           2 :                 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
    5654             : 
    5655          79 :         if (os_strcmp(cmd, "oppps") == 0)
    5656           1 :                 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
    5657             : 
    5658          78 :         if (os_strcmp(cmd, "ctwindow") == 0)
    5659           1 :                 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
    5660             : 
    5661          77 :         if (os_strcmp(cmd, "disabled") == 0) {
    5662          24 :                 wpa_s->global->p2p_disabled = atoi(param);
    5663          24 :                 wpa_printf(MSG_DEBUG, "P2P functionality %s",
    5664          24 :                            wpa_s->global->p2p_disabled ?
    5665             :                            "disabled" : "enabled");
    5666          24 :                 if (wpa_s->global->p2p_disabled) {
    5667          14 :                         wpas_p2p_stop_find(wpa_s);
    5668          14 :                         os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
    5669          14 :                         p2p_flush(wpa_s->global->p2p);
    5670             :                 }
    5671          24 :                 return 0;
    5672             :         }
    5673             : 
    5674          53 :         if (os_strcmp(cmd, "conc_pref") == 0) {
    5675           1 :                 if (os_strcmp(param, "sta") == 0)
    5676           0 :                         wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
    5677           1 :                 else if (os_strcmp(param, "p2p") == 0)
    5678           0 :                         wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
    5679             :                 else {
    5680           1 :                         wpa_printf(MSG_INFO, "Invalid conc_pref value");
    5681           1 :                         return -1;
    5682             :                 }
    5683           0 :                 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
    5684             :                            "%s", param);
    5685           0 :                 return 0;
    5686             :         }
    5687             : 
    5688          52 :         if (os_strcmp(cmd, "force_long_sd") == 0) {
    5689           0 :                 wpa_s->force_long_sd = atoi(param);
    5690           0 :                 return 0;
    5691             :         }
    5692             : 
    5693          52 :         if (os_strcmp(cmd, "peer_filter") == 0) {
    5694             :                 u8 addr[ETH_ALEN];
    5695           3 :                 if (hwaddr_aton(param, addr))
    5696           1 :                         return -1;
    5697           2 :                 p2p_set_peer_filter(wpa_s->global->p2p, addr);
    5698           2 :                 return 0;
    5699             :         }
    5700             : 
    5701          49 :         if (os_strcmp(cmd, "cross_connect") == 0)
    5702           5 :                 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
    5703             : 
    5704          44 :         if (os_strcmp(cmd, "go_apsd") == 0) {
    5705           0 :                 if (os_strcmp(param, "disable") == 0)
    5706           0 :                         wpa_s->set_ap_uapsd = 0;
    5707             :                 else {
    5708           0 :                         wpa_s->set_ap_uapsd = 1;
    5709           0 :                         wpa_s->ap_uapsd = atoi(param);
    5710             :                 }
    5711           0 :                 return 0;
    5712             :         }
    5713             : 
    5714          44 :         if (os_strcmp(cmd, "client_apsd") == 0) {
    5715           3 :                 if (os_strcmp(param, "disable") == 0)
    5716           0 :                         wpa_s->set_sta_uapsd = 0;
    5717             :                 else {
    5718             :                         int be, bk, vi, vo;
    5719             :                         char *pos;
    5720             :                         /* format: BE,BK,VI,VO;max SP Length */
    5721           3 :                         be = atoi(param);
    5722           3 :                         pos = os_strchr(param, ',');
    5723           3 :                         if (pos == NULL)
    5724           1 :                                 return -1;
    5725           2 :                         pos++;
    5726           2 :                         bk = atoi(pos);
    5727           2 :                         pos = os_strchr(pos, ',');
    5728           2 :                         if (pos == NULL)
    5729           1 :                                 return -1;
    5730           1 :                         pos++;
    5731           1 :                         vi = atoi(pos);
    5732           1 :                         pos = os_strchr(pos, ',');
    5733           1 :                         if (pos == NULL)
    5734           1 :                                 return -1;
    5735           0 :                         pos++;
    5736           0 :                         vo = atoi(pos);
    5737             :                         /* ignore max SP Length for now */
    5738             : 
    5739           0 :                         wpa_s->set_sta_uapsd = 1;
    5740           0 :                         wpa_s->sta_uapsd = 0;
    5741           0 :                         if (be)
    5742           0 :                                 wpa_s->sta_uapsd |= BIT(0);
    5743           0 :                         if (bk)
    5744           0 :                                 wpa_s->sta_uapsd |= BIT(1);
    5745           0 :                         if (vi)
    5746           0 :                                 wpa_s->sta_uapsd |= BIT(2);
    5747           0 :                         if (vo)
    5748           0 :                                 wpa_s->sta_uapsd |= BIT(3);
    5749             :                 }
    5750           0 :                 return 0;
    5751             :         }
    5752             : 
    5753          41 :         if (os_strcmp(cmd, "disallow_freq") == 0)
    5754          16 :                 return p2p_ctrl_disallow_freq(wpa_s, param);
    5755             : 
    5756          25 :         if (os_strcmp(cmd, "disc_int") == 0) {
    5757             :                 int min_disc_int, max_disc_int, max_disc_tu;
    5758             :                 char *pos;
    5759             : 
    5760           5 :                 pos = param;
    5761             : 
    5762           5 :                 min_disc_int = atoi(pos);
    5763           5 :                 pos = os_strchr(pos, ' ');
    5764           5 :                 if (pos == NULL)
    5765           1 :                         return -1;
    5766           4 :                 *pos++ = '\0';
    5767             : 
    5768           4 :                 max_disc_int = atoi(pos);
    5769           4 :                 pos = os_strchr(pos, ' ');
    5770           4 :                 if (pos == NULL)
    5771           1 :                         return -1;
    5772           3 :                 *pos++ = '\0';
    5773             : 
    5774           3 :                 max_disc_tu = atoi(pos);
    5775             : 
    5776           3 :                 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
    5777             :                                         max_disc_int, max_disc_tu);
    5778             :         }
    5779             : 
    5780          20 :         if (os_strcmp(cmd, "per_sta_psk") == 0) {
    5781           4 :                 wpa_s->global->p2p_per_sta_psk = !!atoi(param);
    5782           4 :                 return 0;
    5783             :         }
    5784             : 
    5785             : #ifdef CONFIG_WPS_NFC
    5786          16 :         if (os_strcmp(cmd, "nfc_tag") == 0)
    5787          14 :                 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
    5788             : #endif /* CONFIG_WPS_NFC */
    5789             : 
    5790           2 :         if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
    5791           1 :                 wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
    5792           1 :                 return 0;
    5793             :         }
    5794             : 
    5795           1 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
    5796             :                    cmd);
    5797             : 
    5798           1 :         return -1;
    5799             : }
    5800             : 
    5801             : 
    5802        3212 : static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
    5803             : {
    5804        3212 :         os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
    5805        3212 :         wpa_s->force_long_sd = 0;
    5806        3212 :         wpas_p2p_stop_find(wpa_s);
    5807        3212 :         if (wpa_s->global->p2p)
    5808        3212 :                 p2p_flush(wpa_s->global->p2p);
    5809        3212 : }
    5810             : 
    5811             : 
    5812           6 : static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
    5813             : {
    5814             :         char *pos, *pos2;
    5815           6 :         unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
    5816             : 
    5817           6 :         if (cmd[0]) {
    5818           5 :                 pos = os_strchr(cmd, ' ');
    5819           5 :                 if (pos == NULL)
    5820           1 :                         return -1;
    5821           4 :                 *pos++ = '\0';
    5822           4 :                 dur1 = atoi(cmd);
    5823             : 
    5824           4 :                 pos2 = os_strchr(pos, ' ');
    5825           4 :                 if (pos2)
    5826           2 :                         *pos2++ = '\0';
    5827           4 :                 int1 = atoi(pos);
    5828             :         } else
    5829           1 :                 pos2 = NULL;
    5830             : 
    5831           5 :         if (pos2) {
    5832           2 :                 pos = os_strchr(pos2, ' ');
    5833           2 :                 if (pos == NULL)
    5834           1 :                         return -1;
    5835           1 :                 *pos++ = '\0';
    5836           1 :                 dur2 = atoi(pos2);
    5837           1 :                 int2 = atoi(pos);
    5838             :         }
    5839             : 
    5840           4 :         return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
    5841             : }
    5842             : 
    5843             : 
    5844           6 : static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
    5845             : {
    5846             :         char *pos;
    5847           6 :         unsigned int period = 0, interval = 0;
    5848             : 
    5849           6 :         if (cmd[0]) {
    5850           3 :                 pos = os_strchr(cmd, ' ');
    5851           3 :                 if (pos == NULL)
    5852           1 :                         return -1;
    5853           2 :                 *pos++ = '\0';
    5854           2 :                 period = atoi(cmd);
    5855           2 :                 interval = atoi(pos);
    5856             :         }
    5857             : 
    5858           5 :         return wpas_p2p_ext_listen(wpa_s, period, interval);
    5859             : }
    5860             : 
    5861             : 
    5862           7 : static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
    5863             : {
    5864             :         const char *pos;
    5865             :         u8 peer[ETH_ALEN];
    5866           7 :         int iface_addr = 0;
    5867             : 
    5868           7 :         pos = cmd;
    5869           7 :         if (os_strncmp(pos, "iface=", 6) == 0) {
    5870           2 :                 iface_addr = 1;
    5871           2 :                 pos += 6;
    5872             :         }
    5873           7 :         if (hwaddr_aton(pos, peer))
    5874           1 :                 return -1;
    5875             : 
    5876           6 :         wpas_p2p_remove_client(wpa_s, peer, iface_addr);
    5877           6 :         return 0;
    5878             : }
    5879             : 
    5880             : #endif /* CONFIG_P2P */
    5881             : 
    5882             : 
    5883         607 : static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
    5884             : {
    5885             :         struct wpa_freq_range_list ranges;
    5886         607 :         int *freqs = NULL;
    5887             :         struct hostapd_hw_modes *mode;
    5888             :         u16 i;
    5889             : 
    5890         607 :         if (wpa_s->hw.modes == NULL)
    5891           0 :                 return NULL;
    5892             : 
    5893         607 :         os_memset(&ranges, 0, sizeof(ranges));
    5894         607 :         if (freq_range_list_parse(&ranges, val) < 0)
    5895           0 :                 return NULL;
    5896             : 
    5897        2428 :         for (i = 0; i < wpa_s->hw.num_modes; i++) {
    5898             :                 int j;
    5899             : 
    5900        1821 :                 mode = &wpa_s->hw.modes[i];
    5901       33385 :                 for (j = 0; j < mode->num_channels; j++) {
    5902             :                         unsigned int freq;
    5903             : 
    5904       31564 :                         if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
    5905         495 :                                 continue;
    5906             : 
    5907       31069 :                         freq = mode->channels[j].freq;
    5908       31069 :                         if (!freq_range_list_includes(&ranges, freq))
    5909       29655 :                                 continue;
    5910             : 
    5911        1414 :                         int_array_add_unique(&freqs, freq);
    5912             :                 }
    5913             :         }
    5914             : 
    5915         607 :         os_free(ranges.range);
    5916         607 :         return freqs;
    5917             : }
    5918             : 
    5919             : 
    5920             : #ifdef CONFIG_INTERWORKING
    5921             : 
    5922         132 : static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
    5923             : {
    5924         132 :         int auto_sel = 0;
    5925         132 :         int *freqs = NULL;
    5926             : 
    5927         132 :         if (param) {
    5928             :                 char *pos;
    5929             : 
    5930         131 :                 auto_sel = os_strstr(param, "auto") != NULL;
    5931             : 
    5932         131 :                 pos = os_strstr(param, "freq=");
    5933         131 :                 if (pos) {
    5934         130 :                         freqs = freq_range_to_channel_list(wpa_s, pos + 5);
    5935         130 :                         if (freqs == NULL)
    5936           0 :                                 return -1;
    5937             :                 }
    5938             : 
    5939             :         }
    5940             : 
    5941         132 :         return interworking_select(wpa_s, auto_sel, freqs);
    5942             : }
    5943             : 
    5944             : 
    5945          50 : static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
    5946             : {
    5947             :         u8 bssid[ETH_ALEN];
    5948             :         struct wpa_bss *bss;
    5949             : 
    5950          50 :         if (hwaddr_aton(dst, bssid)) {
    5951           1 :                 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
    5952           1 :                 return -1;
    5953             :         }
    5954             : 
    5955          49 :         bss = wpa_bss_get_bssid(wpa_s, bssid);
    5956          49 :         if (bss == NULL) {
    5957           6 :                 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
    5958           6 :                            MAC2STR(bssid));
    5959           1 :                 return -1;
    5960             :         }
    5961             : 
    5962          48 :         if (bss->ssid_len == 0) {
    5963           3 :                 int found = 0;
    5964             : 
    5965          18 :                 wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
    5966          18 :                            " does not have SSID information", MAC2STR(bssid));
    5967             : 
    5968           6 :                 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
    5969             :                                          list) {
    5970          12 :                         if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
    5971           6 :                             bss->ssid_len > 0) {
    5972           3 :                                 found = 1;
    5973           3 :                                 break;
    5974             :                         }
    5975             :                 }
    5976             : 
    5977           3 :                 if (!found)
    5978           0 :                         return -1;
    5979           3 :                 wpa_printf(MSG_DEBUG,
    5980             :                            "Found another matching BSS entry with SSID");
    5981             :         }
    5982             : 
    5983          48 :         return interworking_connect(wpa_s, bss);
    5984             : }
    5985             : 
    5986             : 
    5987          30 : static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
    5988             : {
    5989             :         u8 dst_addr[ETH_ALEN];
    5990             :         int used;
    5991             :         char *pos;
    5992             : #define MAX_ANQP_INFO_ID 100
    5993             :         u16 id[MAX_ANQP_INFO_ID];
    5994          30 :         size_t num_id = 0;
    5995          30 :         u32 subtypes = 0;
    5996             : 
    5997          30 :         used = hwaddr_aton2(dst, dst_addr);
    5998          30 :         if (used < 0)
    5999           2 :                 return -1;
    6000          28 :         pos = dst + used;
    6001          28 :         if (*pos == ' ')
    6002          27 :                 pos++;
    6003          62 :         while (num_id < MAX_ANQP_INFO_ID) {
    6004          34 :                 if (os_strncmp(pos, "hs20:", 5) == 0) {
    6005             : #ifdef CONFIG_HS20
    6006           8 :                         int num = atoi(pos + 5);
    6007           8 :                         if (num <= 0 || num > 31)
    6008           6 :                                 return -1;
    6009           2 :                         subtypes |= BIT(num);
    6010             : #else /* CONFIG_HS20 */
    6011             :                         return -1;
    6012             : #endif /* CONFIG_HS20 */
    6013             :                 } else {
    6014          26 :                         id[num_id] = atoi(pos);
    6015          26 :                         if (id[num_id])
    6016          23 :                                 num_id++;
    6017             :                 }
    6018          28 :                 pos = os_strchr(pos + 1, ',');
    6019          28 :                 if (pos == NULL)
    6020          22 :                         break;
    6021           6 :                 pos++;
    6022             :         }
    6023             : 
    6024          22 :         if (num_id == 0)
    6025           3 :                 return -1;
    6026             : 
    6027          19 :         return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
    6028             : }
    6029             : 
    6030             : 
    6031          20 : static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
    6032             : {
    6033             :         u8 dst_addr[ETH_ALEN];
    6034          20 :         struct wpabuf *advproto, *query = NULL;
    6035          20 :         int used, ret = -1;
    6036             :         char *pos, *end;
    6037             :         size_t len;
    6038             : 
    6039          20 :         used = hwaddr_aton2(cmd, dst_addr);
    6040          20 :         if (used < 0)
    6041           1 :                 return -1;
    6042             : 
    6043          19 :         pos = cmd + used;
    6044          57 :         while (*pos == ' ')
    6045          19 :                 pos++;
    6046             : 
    6047             :         /* Advertisement Protocol ID */
    6048          19 :         end = os_strchr(pos, ' ');
    6049          19 :         if (end)
    6050          14 :                 len = end - pos;
    6051             :         else
    6052           5 :                 len = os_strlen(pos);
    6053          19 :         if (len & 0x01)
    6054           2 :                 return -1;
    6055          17 :         len /= 2;
    6056          17 :         if (len == 0)
    6057           3 :                 return -1;
    6058          14 :         advproto = wpabuf_alloc(len);
    6059          14 :         if (advproto == NULL)
    6060           0 :                 return -1;
    6061          14 :         if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
    6062           2 :                 goto fail;
    6063             : 
    6064          12 :         if (end) {
    6065             :                 /* Optional Query Request */
    6066          12 :                 pos = end + 1;
    6067          29 :                 while (*pos == ' ')
    6068           5 :                         pos++;
    6069             : 
    6070          12 :                 len = os_strlen(pos);
    6071          12 :                 if (len) {
    6072          11 :                         if (len & 0x01)
    6073           2 :                                 goto fail;
    6074           9 :                         len /= 2;
    6075           9 :                         if (len == 0)
    6076           0 :                                 goto fail;
    6077           9 :                         query = wpabuf_alloc(len);
    6078           9 :                         if (query == NULL)
    6079           0 :                                 goto fail;
    6080           9 :                         if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
    6081           1 :                                 goto fail;
    6082             :                 }
    6083             :         }
    6084             : 
    6085           9 :         ret = gas_send_request(wpa_s, dst_addr, advproto, query);
    6086             : 
    6087             : fail:
    6088          14 :         wpabuf_free(advproto);
    6089          14 :         wpabuf_free(query);
    6090             : 
    6091          14 :         return ret;
    6092             : }
    6093             : 
    6094             : 
    6095          14 : static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
    6096             :                             size_t buflen)
    6097             : {
    6098             :         u8 addr[ETH_ALEN];
    6099             :         int dialog_token;
    6100             :         int used;
    6101             :         char *pos;
    6102             :         size_t resp_len, start, requested_len;
    6103             :         struct wpabuf *resp;
    6104             :         int ret;
    6105             : 
    6106          14 :         used = hwaddr_aton2(cmd, addr);
    6107          14 :         if (used < 0)
    6108           1 :                 return -1;
    6109             : 
    6110          13 :         pos = cmd + used;
    6111          39 :         while (*pos == ' ')
    6112          13 :                 pos++;
    6113          13 :         dialog_token = atoi(pos);
    6114             : 
    6115          26 :         if (wpa_s->last_gas_resp &&
    6116          26 :             os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
    6117          13 :             dialog_token == wpa_s->last_gas_dialog_token)
    6118          11 :                 resp = wpa_s->last_gas_resp;
    6119           3 :         else if (wpa_s->prev_gas_resp &&
    6120           2 :                  os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
    6121           1 :                  dialog_token == wpa_s->prev_gas_dialog_token)
    6122           1 :                 resp = wpa_s->prev_gas_resp;
    6123             :         else
    6124           1 :                 return -1;
    6125             : 
    6126          12 :         resp_len = wpabuf_len(resp);
    6127          12 :         start = 0;
    6128          12 :         requested_len = resp_len;
    6129             : 
    6130          12 :         pos = os_strchr(pos, ' ');
    6131          12 :         if (pos) {
    6132           5 :                 start = atoi(pos);
    6133           5 :                 if (start > resp_len)
    6134           1 :                         return os_snprintf(buf, buflen, "FAIL-Invalid range");
    6135           4 :                 pos = os_strchr(pos, ',');
    6136           4 :                 if (pos == NULL)
    6137           1 :                         return -1;
    6138           3 :                 pos++;
    6139           3 :                 requested_len = atoi(pos);
    6140           3 :                 if (start + requested_len > resp_len)
    6141           1 :                         return os_snprintf(buf, buflen, "FAIL-Invalid range");
    6142             :         }
    6143             : 
    6144           9 :         if (requested_len * 2 + 1 > buflen)
    6145           0 :                 return os_snprintf(buf, buflen, "FAIL-Too long response");
    6146             : 
    6147           9 :         ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
    6148             :                                requested_len);
    6149             : 
    6150           9 :         if (start + requested_len == resp_len) {
    6151             :                 /*
    6152             :                  * Free memory by dropping the response after it has been
    6153             :                  * fetched.
    6154             :                  */
    6155           7 :                 if (resp == wpa_s->prev_gas_resp) {
    6156           1 :                         wpabuf_free(wpa_s->prev_gas_resp);
    6157           1 :                         wpa_s->prev_gas_resp = NULL;
    6158             :                 } else {
    6159           6 :                         wpabuf_free(wpa_s->last_gas_resp);
    6160           6 :                         wpa_s->last_gas_resp = NULL;
    6161             :                 }
    6162             :         }
    6163             : 
    6164           9 :         return ret;
    6165             : }
    6166             : #endif /* CONFIG_INTERWORKING */
    6167             : 
    6168             : 
    6169             : #ifdef CONFIG_HS20
    6170             : 
    6171           9 : static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
    6172             : {
    6173             :         u8 dst_addr[ETH_ALEN];
    6174             :         int used;
    6175             :         char *pos;
    6176           9 :         u32 subtypes = 0;
    6177             : 
    6178           9 :         used = hwaddr_aton2(dst, dst_addr);
    6179           9 :         if (used < 0)
    6180           2 :                 return -1;
    6181           7 :         pos = dst + used;
    6182           7 :         if (*pos == ' ')
    6183           6 :                 pos++;
    6184             :         for (;;) {
    6185           8 :                 int num = atoi(pos);
    6186           8 :                 if (num <= 0 || num > 31)
    6187           6 :                         return -1;
    6188           2 :                 subtypes |= BIT(num);
    6189           2 :                 pos = os_strchr(pos + 1, ',');
    6190           2 :                 if (pos == NULL)
    6191           1 :                         break;
    6192           1 :                 pos++;
    6193           1 :         }
    6194             : 
    6195           1 :         if (subtypes == 0)
    6196           0 :                 return -1;
    6197             : 
    6198           1 :         return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
    6199             : }
    6200             : 
    6201             : 
    6202           2 : static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
    6203             :                                     const u8 *addr, const char *realm)
    6204             : {
    6205             :         u8 *buf;
    6206             :         size_t rlen, len;
    6207             :         int ret;
    6208             : 
    6209           2 :         rlen = os_strlen(realm);
    6210           2 :         len = 3 + rlen;
    6211           2 :         buf = os_malloc(len);
    6212           2 :         if (buf == NULL)
    6213           0 :                 return -1;
    6214           2 :         buf[0] = 1; /* NAI Home Realm Count */
    6215           2 :         buf[1] = 0; /* Formatted in accordance with RFC 4282 */
    6216           2 :         buf[2] = rlen;
    6217           2 :         os_memcpy(buf + 3, realm, rlen);
    6218             : 
    6219           2 :         ret = hs20_anqp_send_req(wpa_s, addr,
    6220             :                                  BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
    6221             :                                  buf, len);
    6222             : 
    6223           2 :         os_free(buf);
    6224             : 
    6225           2 :         return ret;
    6226             : }
    6227             : 
    6228             : 
    6229           7 : static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
    6230             :                                         char *dst)
    6231             : {
    6232           7 :         struct wpa_cred *cred = wpa_s->conf->cred;
    6233             :         u8 dst_addr[ETH_ALEN];
    6234             :         int used;
    6235             :         u8 *buf;
    6236             :         size_t len;
    6237             :         int ret;
    6238             : 
    6239           7 :         used = hwaddr_aton2(dst, dst_addr);
    6240           7 :         if (used < 0)
    6241           1 :                 return -1;
    6242             : 
    6243          16 :         while (dst[used] == ' ')
    6244           4 :                 used++;
    6245           6 :         if (os_strncmp(dst + used, "realm=", 6) == 0)
    6246           1 :                 return hs20_nai_home_realm_list(wpa_s, dst_addr,
    6247           1 :                                                 dst + used + 6);
    6248             : 
    6249           5 :         len = os_strlen(dst + used);
    6250             : 
    6251           5 :         if (len == 0 && cred && cred->realm)
    6252           1 :                 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
    6253             : 
    6254           4 :         if (len & 1)
    6255           1 :                 return -1;
    6256           3 :         len /= 2;
    6257           3 :         buf = os_malloc(len);
    6258           3 :         if (buf == NULL)
    6259           0 :                 return -1;
    6260           3 :         if (hexstr2bin(dst + used, buf, len) < 0) {
    6261           1 :                 os_free(buf);
    6262           1 :                 return -1;
    6263             :         }
    6264             : 
    6265           2 :         ret = hs20_anqp_send_req(wpa_s, dst_addr,
    6266             :                                  BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
    6267             :                                  buf, len);
    6268           2 :         os_free(buf);
    6269             : 
    6270           2 :         return ret;
    6271             : }
    6272             : 
    6273             : 
    6274           2 : static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
    6275             : {
    6276             :         u8 dst_addr[ETH_ALEN];
    6277             :         int used;
    6278             :         char *icon;
    6279             : 
    6280           2 :         used = hwaddr_aton2(cmd, dst_addr);
    6281           2 :         if (used < 0)
    6282           1 :                 return -1;
    6283             : 
    6284           3 :         while (cmd[used] == ' ')
    6285           1 :                 used++;
    6286           1 :         icon = &cmd[used];
    6287             : 
    6288           1 :         wpa_s->fetch_osu_icon_in_progress = 0;
    6289           1 :         return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
    6290             :                                   (u8 *) icon, os_strlen(icon));
    6291             : }
    6292             : 
    6293             : #endif /* CONFIG_HS20 */
    6294             : 
    6295             : 
    6296             : #ifdef CONFIG_AUTOSCAN
    6297             : 
    6298          11 : static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
    6299             :                                               char *cmd)
    6300             : {
    6301          11 :         enum wpa_states state = wpa_s->wpa_state;
    6302          11 :         char *new_params = NULL;
    6303             : 
    6304          11 :         if (os_strlen(cmd) > 0) {
    6305           5 :                 new_params = os_strdup(cmd);
    6306           5 :                 if (new_params == NULL)
    6307           0 :                         return -1;
    6308             :         }
    6309             : 
    6310          11 :         os_free(wpa_s->conf->autoscan);
    6311          11 :         wpa_s->conf->autoscan = new_params;
    6312             : 
    6313          11 :         if (wpa_s->conf->autoscan == NULL)
    6314           6 :                 autoscan_deinit(wpa_s);
    6315           5 :         else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
    6316           4 :                 autoscan_init(wpa_s, 1);
    6317           1 :         else if (state == WPA_SCANNING)
    6318           1 :                 wpa_supplicant_reinit_autoscan(wpa_s);
    6319             : 
    6320          11 :         return 0;
    6321             : }
    6322             : 
    6323             : #endif /* CONFIG_AUTOSCAN */
    6324             : 
    6325             : 
    6326             : #ifdef CONFIG_WNM
    6327             : 
    6328          13 : static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
    6329             : {
    6330             :         int enter;
    6331          13 :         int intval = 0;
    6332             :         char *pos;
    6333             :         int ret;
    6334          13 :         struct wpabuf *tfs_req = NULL;
    6335             : 
    6336          13 :         if (os_strncmp(cmd, "enter", 5) == 0)
    6337           6 :                 enter = 1;
    6338           7 :         else if (os_strncmp(cmd, "exit", 4) == 0)
    6339           6 :                 enter = 0;
    6340             :         else
    6341           1 :                 return -1;
    6342             : 
    6343          12 :         pos = os_strstr(cmd, " interval=");
    6344          12 :         if (pos)
    6345           3 :                 intval = atoi(pos + 10);
    6346             : 
    6347          12 :         pos = os_strstr(cmd, " tfs_req=");
    6348          12 :         if (pos) {
    6349             :                 char *end;
    6350             :                 size_t len;
    6351           3 :                 pos += 9;
    6352           3 :                 end = os_strchr(pos, ' ');
    6353           3 :                 if (end)
    6354           2 :                         len = end - pos;
    6355             :                 else
    6356           1 :                         len = os_strlen(pos);
    6357           3 :                 if (len & 1)
    6358           1 :                         return -1;
    6359           2 :                 len /= 2;
    6360           2 :                 tfs_req = wpabuf_alloc(len);
    6361           2 :                 if (tfs_req == NULL)
    6362           0 :                         return -1;
    6363           2 :                 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
    6364           1 :                         wpabuf_free(tfs_req);
    6365           1 :                         return -1;
    6366             :                 }
    6367             :         }
    6368             : 
    6369          10 :         ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
    6370             :                                            WNM_SLEEP_MODE_EXIT, intval,
    6371             :                                            tfs_req);
    6372          10 :         wpabuf_free(tfs_req);
    6373             : 
    6374          10 :         return ret;
    6375             : }
    6376             : 
    6377             : 
    6378           1 : static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
    6379             : {
    6380             :         int query_reason;
    6381             : 
    6382           1 :         query_reason = atoi(cmd);
    6383             : 
    6384           1 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
    6385             :                    query_reason);
    6386             : 
    6387           1 :         return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
    6388             : }
    6389             : 
    6390             : #endif /* CONFIG_WNM */
    6391             : 
    6392             : 
    6393           5 : static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
    6394             :                                       size_t buflen)
    6395             : {
    6396             :         struct wpa_signal_info si;
    6397             :         int ret;
    6398             :         char *pos, *end;
    6399             : 
    6400           5 :         ret = wpa_drv_signal_poll(wpa_s, &si);
    6401           5 :         if (ret)
    6402           0 :                 return -1;
    6403             : 
    6404           5 :         pos = buf;
    6405           5 :         end = buf + buflen;
    6406             : 
    6407          10 :         ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
    6408             :                           "NOISE=%d\nFREQUENCY=%u\n",
    6409           5 :                           si.current_signal, si.current_txrate / 1000,
    6410             :                           si.current_noise, si.frequency);
    6411           5 :         if (os_snprintf_error(end - pos, ret))
    6412           0 :                 return -1;
    6413           5 :         pos += ret;
    6414             : 
    6415           5 :         if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
    6416           4 :                 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
    6417             :                                   channel_width_to_string(si.chanwidth));
    6418           4 :                 if (os_snprintf_error(end - pos, ret))
    6419           0 :                         return -1;
    6420           4 :                 pos += ret;
    6421             :         }
    6422             : 
    6423           5 :         if (si.center_frq1 > 0 && si.center_frq2 > 0) {
    6424           1 :                 ret = os_snprintf(pos, end - pos,
    6425             :                                   "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
    6426             :                                   si.center_frq1, si.center_frq2);
    6427           1 :                 if (os_snprintf_error(end - pos, ret))
    6428           0 :                         return -1;
    6429           1 :                 pos += ret;
    6430             :         }
    6431             : 
    6432           5 :         if (si.avg_signal) {
    6433           4 :                 ret = os_snprintf(pos, end - pos,
    6434             :                                   "AVG_RSSI=%d\n", si.avg_signal);
    6435           4 :                 if (os_snprintf_error(end - pos, ret))
    6436           0 :                         return -1;
    6437           4 :                 pos += ret;
    6438             :         }
    6439             : 
    6440           5 :         return pos - buf;
    6441             : }
    6442             : 
    6443             : 
    6444           1 : static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
    6445             :                                       size_t buflen)
    6446             : {
    6447             :         struct hostap_sta_driver_data sta;
    6448             :         int ret;
    6449             : 
    6450           1 :         ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
    6451           1 :         if (ret)
    6452           0 :                 return -1;
    6453             : 
    6454           1 :         ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
    6455             :                           sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
    6456           1 :         if (os_snprintf_error(buflen, ret))
    6457           0 :                 return -1;
    6458           1 :         return ret;
    6459             : }
    6460             : 
    6461             : 
    6462             : #ifdef ANDROID
    6463             : static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
    6464             :                                      char *buf, size_t buflen)
    6465             : {
    6466             :         int ret;
    6467             : 
    6468             :         ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
    6469             :         if (ret == 0) {
    6470             :                 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
    6471             :                         struct p2p_data *p2p = wpa_s->global->p2p;
    6472             :                         if (p2p) {
    6473             :                                 char country[3];
    6474             :                                 country[0] = cmd[8];
    6475             :                                 country[1] = cmd[9];
    6476             :                                 country[2] = 0x04;
    6477             :                                 p2p_set_country(p2p, country);
    6478             :                         }
    6479             :                 }
    6480             :                 ret = os_snprintf(buf, buflen, "%s\n", "OK");
    6481             :                 if (os_snprintf_error(buflen, ret))
    6482             :                         ret = -1;
    6483             :         }
    6484             :         return ret;
    6485             : }
    6486             : #endif /* ANDROID */
    6487             : 
    6488             : 
    6489           9 : static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
    6490             :                                      char *buf, size_t buflen)
    6491             : {
    6492             :         int ret;
    6493             :         char *pos;
    6494           9 :         u8 *data = NULL;
    6495             :         unsigned int vendor_id, subcmd;
    6496             :         struct wpabuf *reply;
    6497           9 :         size_t data_len = 0;
    6498             : 
    6499             :         /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
    6500           9 :         vendor_id = strtoul(cmd, &pos, 16);
    6501           9 :         if (!isblank(*pos))
    6502           2 :                 return -EINVAL;
    6503             : 
    6504           7 :         subcmd = strtoul(pos, &pos, 10);
    6505             : 
    6506           7 :         if (*pos != '\0') {
    6507           7 :                 if (!isblank(*pos++))
    6508           1 :                         return -EINVAL;
    6509           6 :                 data_len = os_strlen(pos);
    6510             :         }
    6511             : 
    6512           6 :         if (data_len) {
    6513           6 :                 data_len /= 2;
    6514           6 :                 data = os_malloc(data_len);
    6515           6 :                 if (!data)
    6516           0 :                         return -1;
    6517             : 
    6518           6 :                 if (hexstr2bin(pos, data, data_len)) {
    6519           2 :                         wpa_printf(MSG_DEBUG,
    6520             :                                    "Vendor command: wrong parameter format");
    6521           2 :                         os_free(data);
    6522           2 :                         return -EINVAL;
    6523             :                 }
    6524             :         }
    6525             : 
    6526           4 :         reply = wpabuf_alloc((buflen - 1) / 2);
    6527           4 :         if (!reply) {
    6528           0 :                 os_free(data);
    6529           0 :                 return -1;
    6530             :         }
    6531             : 
    6532           4 :         ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
    6533             :                                  reply);
    6534             : 
    6535           4 :         if (ret == 0)
    6536           4 :                 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
    6537             :                                        wpabuf_len(reply));
    6538             : 
    6539           4 :         wpabuf_free(reply);
    6540           4 :         os_free(data);
    6541             : 
    6542           4 :         return ret;
    6543             : }
    6544             : 
    6545             : 
    6546        3171 : static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
    6547             : {
    6548             : #ifdef CONFIG_P2P
    6549        6342 :         struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
    6550        3171 :                 wpa_s->global->p2p_init_wpa_s : wpa_s;
    6551             : #endif /* CONFIG_P2P */
    6552             : 
    6553        3171 :         wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
    6554             : 
    6555             : #ifdef CONFIG_P2P
    6556        3171 :         wpas_p2p_cancel(p2p_wpa_s);
    6557        3171 :         p2p_ctrl_flush(p2p_wpa_s);
    6558        3171 :         wpas_p2p_group_remove(p2p_wpa_s, "*");
    6559        3171 :         wpas_p2p_service_flush(p2p_wpa_s);
    6560        3171 :         p2p_wpa_s->global->p2p_disabled = 0;
    6561        3171 :         p2p_wpa_s->global->p2p_per_sta_psk = 0;
    6562        3171 :         p2p_wpa_s->conf->num_sec_device_types = 0;
    6563        3171 :         p2p_wpa_s->p2p_disable_ip_addr_req = 0;
    6564        3171 :         os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
    6565        3171 :         p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
    6566        3171 :         p2p_wpa_s->global->pending_p2ps_group = 0;
    6567             : #endif /* CONFIG_P2P */
    6568             : 
    6569             : #ifdef CONFIG_WPS_TESTING
    6570        3171 :         wps_version_number = 0x20;
    6571        3171 :         wps_testing_dummy_cred = 0;
    6572        3171 :         wps_corrupt_pkhash = 0;
    6573             : #endif /* CONFIG_WPS_TESTING */
    6574             : #ifdef CONFIG_WPS
    6575        3171 :         wpa_s->wps_fragment_size = 0;
    6576        3171 :         wpas_wps_cancel(wpa_s);
    6577        3171 :         wps_registrar_flush(wpa_s->wps->registrar);
    6578             : #endif /* CONFIG_WPS */
    6579        3171 :         wpa_s->after_wps = 0;
    6580        3171 :         wpa_s->known_wps_freq = 0;
    6581             : 
    6582             : #ifdef CONFIG_TDLS
    6583             : #ifdef CONFIG_TDLS_TESTING
    6584             :         extern unsigned int tdls_testing;
    6585        3171 :         tdls_testing = 0;
    6586             : #endif /* CONFIG_TDLS_TESTING */
    6587        3171 :         wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
    6588        3171 :         wpa_tdls_enable(wpa_s->wpa, 1);
    6589             : #endif /* CONFIG_TDLS */
    6590             : 
    6591        3171 :         eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
    6592        3171 :         wpa_supplicant_stop_countermeasures(wpa_s, NULL);
    6593             : 
    6594        3171 :         wpa_s->no_keep_alive = 0;
    6595             : 
    6596        3171 :         os_free(wpa_s->disallow_aps_bssid);
    6597        3171 :         wpa_s->disallow_aps_bssid = NULL;
    6598        3171 :         wpa_s->disallow_aps_bssid_count = 0;
    6599        3171 :         os_free(wpa_s->disallow_aps_ssid);
    6600        3171 :         wpa_s->disallow_aps_ssid = NULL;
    6601        3171 :         wpa_s->disallow_aps_ssid_count = 0;
    6602             : 
    6603        3171 :         wpa_s->set_sta_uapsd = 0;
    6604        3171 :         wpa_s->sta_uapsd = 0;
    6605             : 
    6606        3171 :         wpa_drv_radio_disable(wpa_s, 0);
    6607        3171 :         wpa_blacklist_clear(wpa_s);
    6608        3171 :         wpa_s->extra_blacklist_count = 0;
    6609        3171 :         wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
    6610        3171 :         wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
    6611        3171 :         wpa_config_flush_blobs(wpa_s->conf);
    6612        3171 :         wpa_s->conf->auto_interworking = 0;
    6613        3171 :         wpa_s->conf->okc = 0;
    6614             : 
    6615        3171 :         wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
    6616        3171 :         rsn_preauth_deinit(wpa_s->wpa);
    6617             : 
    6618        3171 :         wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
    6619        3171 :         wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
    6620        3171 :         wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
    6621        3171 :         eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
    6622             : 
    6623        3171 :         radio_remove_works(wpa_s, NULL, 1);
    6624        3171 :         wpa_s->ext_work_in_progress = 0;
    6625             : 
    6626        3171 :         wpa_s->next_ssid = NULL;
    6627             : 
    6628             : #ifdef CONFIG_INTERWORKING
    6629        3171 :         hs20_cancel_fetch_osu(wpa_s);
    6630             : #endif /* CONFIG_INTERWORKING */
    6631             : 
    6632        3171 :         wpa_s->ext_mgmt_frame_handling = 0;
    6633        3171 :         wpa_s->ext_eapol_frame_io = 0;
    6634             : #ifdef CONFIG_TESTING_OPTIONS
    6635        3171 :         wpa_s->extra_roc_dur = 0;
    6636        3171 :         wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
    6637             : #endif /* CONFIG_TESTING_OPTIONS */
    6638             : 
    6639        3171 :         wpa_s->disconnected = 0;
    6640        3171 :         os_free(wpa_s->next_scan_freqs);
    6641        3171 :         wpa_s->next_scan_freqs = NULL;
    6642             : 
    6643        3171 :         wpa_bss_flush(wpa_s);
    6644        3171 :         if (!dl_list_empty(&wpa_s->bss)) {
    6645           0 :                 wpa_printf(MSG_DEBUG,
    6646             :                            "BSS table not empty after flush: %u entries, current_bss=%p bssid="
    6647             :                            MACSTR " pending_bssid=" MACSTR,
    6648             :                            dl_list_len(&wpa_s->bss), wpa_s->current_bss,
    6649           0 :                            MAC2STR(wpa_s->bssid),
    6650           0 :                            MAC2STR(wpa_s->pending_bssid));
    6651             :         }
    6652        3171 : }
    6653             : 
    6654             : 
    6655           4 : static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
    6656             :                                      char *buf, size_t buflen)
    6657             : {
    6658             :         struct wpa_radio_work *work;
    6659             :         char *pos, *end;
    6660             :         struct os_reltime now, diff;
    6661             : 
    6662           4 :         pos = buf;
    6663           4 :         end = buf + buflen;
    6664             : 
    6665           4 :         os_get_reltime(&now);
    6666             : 
    6667           9 :         dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
    6668             :         {
    6669             :                 int ret;
    6670             : 
    6671           5 :                 os_reltime_sub(&now, &work->time, &diff);
    6672          15 :                 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
    6673           5 :                                   work->type, work->wpa_s->ifname, work->freq,
    6674           5 :                                   work->started, diff.sec, diff.usec);
    6675           5 :                 if (os_snprintf_error(end - pos, ret))
    6676           0 :                         break;
    6677           5 :                 pos += ret;
    6678             :         }
    6679             : 
    6680           4 :         return pos - buf;
    6681             : }
    6682             : 
    6683             : 
    6684           1 : static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
    6685             : {
    6686           1 :         struct wpa_radio_work *work = eloop_ctx;
    6687           1 :         struct wpa_external_work *ework = work->ctx;
    6688             : 
    6689           1 :         wpa_dbg(work->wpa_s, MSG_DEBUG,
    6690             :                 "Timing out external radio work %u (%s)",
    6691             :                 ework->id, work->type);
    6692           1 :         wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
    6693           1 :         work->wpa_s->ext_work_in_progress = 0;
    6694           1 :         radio_work_done(work);
    6695           1 :         os_free(ework);
    6696           1 : }
    6697             : 
    6698             : 
    6699          18 : static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
    6700             : {
    6701          18 :         struct wpa_external_work *ework = work->ctx;
    6702             : 
    6703          18 :         if (deinit) {
    6704           5 :                 if (work->started)
    6705           1 :                         eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
    6706             :                                              work, NULL);
    6707             : 
    6708           5 :                 os_free(ework);
    6709          23 :                 return;
    6710             :         }
    6711             : 
    6712          13 :         wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
    6713             :                 ework->id, ework->type);
    6714          13 :         wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
    6715          13 :         work->wpa_s->ext_work_in_progress = 1;
    6716          13 :         if (!ework->timeout)
    6717          12 :                 ework->timeout = 10;
    6718          13 :         eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
    6719             :                                work, NULL);
    6720             : }
    6721             : 
    6722             : 
    6723          18 : static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
    6724             :                                     char *buf, size_t buflen)
    6725             : {
    6726             :         struct wpa_external_work *ework;
    6727             :         char *pos, *pos2;
    6728             :         size_t type_len;
    6729             :         int ret;
    6730          18 :         unsigned int freq = 0;
    6731             : 
    6732             :         /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
    6733             : 
    6734          18 :         ework = os_zalloc(sizeof(*ework));
    6735          18 :         if (ework == NULL)
    6736           0 :                 return -1;
    6737             : 
    6738          18 :         pos = os_strchr(cmd, ' ');
    6739          18 :         if (pos) {
    6740           2 :                 type_len = pos - cmd;
    6741           2 :                 pos++;
    6742             : 
    6743           2 :                 pos2 = os_strstr(pos, "freq=");
    6744           2 :                 if (pos2)
    6745           1 :                         freq = atoi(pos2 + 5);
    6746             : 
    6747           2 :                 pos2 = os_strstr(pos, "timeout=");
    6748           2 :                 if (pos2)
    6749           1 :                         ework->timeout = atoi(pos2 + 8);
    6750             :         } else {
    6751          16 :                 type_len = os_strlen(cmd);
    6752             :         }
    6753          18 :         if (4 + type_len >= sizeof(ework->type))
    6754           5 :                 type_len = sizeof(ework->type) - 4 - 1;
    6755          18 :         os_strlcpy(ework->type, "ext:", sizeof(ework->type));
    6756          18 :         os_memcpy(ework->type + 4, cmd, type_len);
    6757          18 :         ework->type[4 + type_len] = '\0';
    6758             : 
    6759          18 :         wpa_s->ext_work_id++;
    6760          18 :         if (wpa_s->ext_work_id == 0)
    6761           0 :                 wpa_s->ext_work_id++;
    6762          18 :         ework->id = wpa_s->ext_work_id;
    6763             : 
    6764          18 :         if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
    6765             :                            ework) < 0) {
    6766           0 :                 os_free(ework);
    6767           0 :                 return -1;
    6768             :         }
    6769             : 
    6770          18 :         ret = os_snprintf(buf, buflen, "%u", ework->id);
    6771          18 :         if (os_snprintf_error(buflen, ret))
    6772           0 :                 return -1;
    6773          18 :         return ret;
    6774             : }
    6775             : 
    6776             : 
    6777          12 : static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
    6778             : {
    6779             :         struct wpa_radio_work *work;
    6780          12 :         unsigned int id = atoi(cmd);
    6781             : 
    6782          25 :         dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
    6783             :         {
    6784             :                 struct wpa_external_work *ework;
    6785             : 
    6786          24 :                 if (os_strncmp(work->type, "ext:", 4) != 0)
    6787           7 :                         continue;
    6788          17 :                 ework = work->ctx;
    6789          17 :                 if (id && ework->id != id)
    6790           6 :                         continue;
    6791          11 :                 wpa_dbg(wpa_s, MSG_DEBUG,
    6792             :                         "Completed external radio work %u (%s)",
    6793             :                         ework->id, ework->type);
    6794          11 :                 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
    6795          11 :                 wpa_s->ext_work_in_progress = 0;
    6796          11 :                 radio_work_done(work);
    6797          11 :                 os_free(ework);
    6798          11 :                 return 3; /* "OK\n" */
    6799             :         }
    6800             : 
    6801           1 :         return -1;
    6802             : }
    6803             : 
    6804             : 
    6805          35 : static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
    6806             :                                 char *buf, size_t buflen)
    6807             : {
    6808          35 :         if (os_strcmp(cmd, "show") == 0)
    6809           4 :                 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
    6810          31 :         if (os_strncmp(cmd, "add ", 4) == 0)
    6811          18 :                 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
    6812          13 :         if (os_strncmp(cmd, "done ", 5) == 0)
    6813          12 :                 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
    6814           1 :         return -1;
    6815             : }
    6816             : 
    6817             : 
    6818         212 : void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
    6819             : {
    6820             :         struct wpa_radio_work *work, *tmp;
    6821             : 
    6822         212 :         if (!wpa_s || !wpa_s->radio)
    6823         226 :                 return;
    6824             : 
    6825         204 :         dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
    6826             :                               struct wpa_radio_work, list) {
    6827             :                 struct wpa_external_work *ework;
    6828             : 
    6829           6 :                 if (os_strncmp(work->type, "ext:", 4) != 0)
    6830           5 :                         continue;
    6831           1 :                 ework = work->ctx;
    6832           1 :                 wpa_dbg(wpa_s, MSG_DEBUG,
    6833             :                         "Flushing%s external radio work %u (%s)",
    6834             :                         work->started ? " started" : "", ework->id,
    6835             :                         ework->type);
    6836           1 :                 if (work->started)
    6837           1 :                         eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
    6838             :                                              work, NULL);
    6839           1 :                 radio_work_done(work);
    6840           1 :                 os_free(ework);
    6841             :         }
    6842             : }
    6843             : 
    6844             : 
    6845          44 : static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
    6846             : {
    6847          44 :         struct wpa_supplicant *wpa_s = eloop_ctx;
    6848          44 :         eapol_sm_notify_ctrl_response(wpa_s->eapol);
    6849          44 : }
    6850             : 
    6851             : 
    6852           3 : static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
    6853             :                               unsigned int *scan_id_count, int scan_id[])
    6854             : {
    6855           3 :         const char *pos = value;
    6856             : 
    6857          26 :         while (pos) {
    6858          21 :                 if (*pos == ' ' || *pos == '\0')
    6859             :                         break;
    6860          21 :                 if (*scan_id_count == MAX_SCAN_ID)
    6861           1 :                         return -1;
    6862          20 :                 scan_id[(*scan_id_count)++] = atoi(pos);
    6863          20 :                 pos = os_strchr(pos, ',');
    6864          20 :                 if (pos)
    6865          18 :                         pos++;
    6866             :         }
    6867             : 
    6868           2 :         return 0;
    6869             : }
    6870             : 
    6871             : 
    6872         476 : static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
    6873             :                            char *reply, int reply_size, int *reply_len)
    6874             : {
    6875             :         char *pos;
    6876         476 :         unsigned int manual_scan_passive = 0;
    6877         476 :         unsigned int manual_scan_use_id = 0;
    6878         476 :         unsigned int manual_scan_only_new = 0;
    6879         476 :         unsigned int scan_only = 0;
    6880         476 :         unsigned int scan_id_count = 0;
    6881             :         int scan_id[MAX_SCAN_ID];
    6882             :         void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
    6883             :                                  struct wpa_scan_results *scan_res);
    6884         476 :         int *manual_scan_freqs = NULL;
    6885             : 
    6886         476 :         if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
    6887           1 :                 *reply_len = -1;
    6888           7 :                 return;
    6889             :         }
    6890             : 
    6891         475 :         if (radio_work_pending(wpa_s, "scan")) {
    6892           5 :                 wpa_printf(MSG_DEBUG,
    6893             :                            "Pending scan scheduled - reject new request");
    6894           5 :                 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
    6895           5 :                 return;
    6896             :         }
    6897             : 
    6898         470 :         if (params) {
    6899         458 :                 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
    6900         281 :                         scan_only = 1;
    6901             : 
    6902         458 :                 pos = os_strstr(params, "freq=");
    6903         458 :                 if (pos) {
    6904         447 :                         manual_scan_freqs = freq_range_to_channel_list(wpa_s,
    6905             :                                                                        pos + 5);
    6906         447 :                         if (manual_scan_freqs == NULL) {
    6907           0 :                                 *reply_len = -1;
    6908           0 :                                 goto done;
    6909             :                         }
    6910             :                 }
    6911             : 
    6912         458 :                 pos = os_strstr(params, "passive=");
    6913         458 :                 if (pos)
    6914           4 :                         manual_scan_passive = !!atoi(pos + 8);
    6915             : 
    6916         458 :                 pos = os_strstr(params, "use_id=");
    6917         458 :                 if (pos)
    6918          15 :                         manual_scan_use_id = atoi(pos + 7);
    6919             : 
    6920         458 :                 pos = os_strstr(params, "only_new=1");
    6921         458 :                 if (pos)
    6922         142 :                         manual_scan_only_new = 1;
    6923             : 
    6924         458 :                 pos = os_strstr(params, "scan_id=");
    6925         458 :                 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
    6926             :                                               scan_id) < 0) {
    6927           1 :                         *reply_len = -1;
    6928           1 :                         goto done;
    6929             :                 }
    6930             :         }
    6931             : 
    6932         469 :         if (scan_only)
    6933         281 :                 scan_res_handler = scan_only_handler;
    6934         188 :         else if (wpa_s->scan_res_handler == scan_only_handler)
    6935           0 :                 scan_res_handler = NULL;
    6936             :         else
    6937         188 :                 scan_res_handler = wpa_s->scan_res_handler;
    6938             : 
    6939         938 :         if (!wpa_s->sched_scanning && !wpa_s->scanning &&
    6940         514 :             ((wpa_s->wpa_state <= WPA_SCANNING) ||
    6941          45 :              (wpa_s->wpa_state == WPA_COMPLETED))) {
    6942         469 :                 wpa_s->manual_scan_passive = manual_scan_passive;
    6943         469 :                 wpa_s->manual_scan_use_id = manual_scan_use_id;
    6944         469 :                 wpa_s->manual_scan_only_new = manual_scan_only_new;
    6945         469 :                 wpa_s->scan_id_count = scan_id_count;
    6946         469 :                 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
    6947         469 :                 wpa_s->scan_res_handler = scan_res_handler;
    6948         469 :                 os_free(wpa_s->manual_scan_freqs);
    6949         469 :                 wpa_s->manual_scan_freqs = manual_scan_freqs;
    6950         469 :                 manual_scan_freqs = NULL;
    6951             : 
    6952         469 :                 wpa_s->normal_scans = 0;
    6953         469 :                 wpa_s->scan_req = MANUAL_SCAN_REQ;
    6954         469 :                 wpa_s->after_wps = 0;
    6955         469 :                 wpa_s->known_wps_freq = 0;
    6956         469 :                 wpa_supplicant_req_scan(wpa_s, 0, 0);
    6957         938 :                 if (wpa_s->manual_scan_use_id) {
    6958          15 :                         wpa_s->manual_scan_id++;
    6959          15 :                         wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
    6960             :                                 wpa_s->manual_scan_id);
    6961          15 :                         *reply_len = os_snprintf(reply, reply_size, "%u\n",
    6962             :                                                  wpa_s->manual_scan_id);
    6963             :                 }
    6964           0 :         } else if (wpa_s->sched_scanning) {
    6965           0 :                 wpa_s->manual_scan_passive = manual_scan_passive;
    6966           0 :                 wpa_s->manual_scan_use_id = manual_scan_use_id;
    6967           0 :                 wpa_s->manual_scan_only_new = manual_scan_only_new;
    6968           0 :                 wpa_s->scan_id_count = scan_id_count;
    6969           0 :                 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
    6970           0 :                 wpa_s->scan_res_handler = scan_res_handler;
    6971           0 :                 os_free(wpa_s->manual_scan_freqs);
    6972           0 :                 wpa_s->manual_scan_freqs = manual_scan_freqs;
    6973           0 :                 manual_scan_freqs = NULL;
    6974             : 
    6975           0 :                 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
    6976           0 :                 wpa_supplicant_cancel_sched_scan(wpa_s);
    6977           0 :                 wpa_s->scan_req = MANUAL_SCAN_REQ;
    6978           0 :                 wpa_supplicant_req_scan(wpa_s, 0, 0);
    6979           0 :                 if (wpa_s->manual_scan_use_id) {
    6980           0 :                         wpa_s->manual_scan_id++;
    6981           0 :                         *reply_len = os_snprintf(reply, reply_size, "%u\n",
    6982             :                                                  wpa_s->manual_scan_id);
    6983           0 :                         wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
    6984             :                                 wpa_s->manual_scan_id);
    6985             :                 }
    6986             :         } else {
    6987           0 :                 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
    6988           0 :                 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
    6989             :         }
    6990             : 
    6991             : done:
    6992         470 :         os_free(manual_scan_freqs);
    6993             : }
    6994             : 
    6995             : 
    6996             : #ifdef CONFIG_TESTING_OPTIONS
    6997             : 
    6998          54 : static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
    6999             :                                        unsigned int freq, const u8 *dst,
    7000             :                                        const u8 *src, const u8 *bssid,
    7001             :                                        const u8 *data, size_t data_len,
    7002             :                                        enum offchannel_send_action_result
    7003             :                                        result)
    7004             : {
    7005        1028 :         wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
    7006             :                 " src=" MACSTR " bssid=" MACSTR " result=%s",
    7007         972 :                 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
    7008             :                 result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
    7009             :                 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
    7010           2 :                              "NO_ACK" : "FAILED"));
    7011          54 : }
    7012             : 
    7013             : 
    7014          59 : static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
    7015             : {
    7016             :         char *pos, *param;
    7017             :         size_t len;
    7018             :         u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
    7019             :         int res, used;
    7020          59 :         int freq = 0, no_cck = 0, wait_time = 0;
    7021             : 
    7022             :         /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
    7023             :          *    <action=Action frame payload> */
    7024             : 
    7025          59 :         wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
    7026             : 
    7027          59 :         pos = cmd;
    7028          59 :         used = hwaddr_aton2(pos, da);
    7029          59 :         if (used < 0)
    7030           1 :                 return -1;
    7031          58 :         pos += used;
    7032         174 :         while (*pos == ' ')
    7033          58 :                 pos++;
    7034          58 :         used = hwaddr_aton2(pos, bssid);
    7035          58 :         if (used < 0)
    7036           1 :                 return -1;
    7037          57 :         pos += used;
    7038             : 
    7039          57 :         param = os_strstr(pos, " freq=");
    7040          57 :         if (param) {
    7041          55 :                 param += 6;
    7042          55 :                 freq = atoi(param);
    7043             :         }
    7044             : 
    7045          57 :         param = os_strstr(pos, " no_cck=");
    7046          57 :         if (param) {
    7047          30 :                 param += 8;
    7048          30 :                 no_cck = atoi(param);
    7049             :         }
    7050             : 
    7051          57 :         param = os_strstr(pos, " wait_time=");
    7052          57 :         if (param) {
    7053          40 :                 param += 11;
    7054          40 :                 wait_time = atoi(param);
    7055             :         }
    7056             : 
    7057          57 :         param = os_strstr(pos, " action=");
    7058          57 :         if (param == NULL)
    7059           1 :                 return -1;
    7060          56 :         param += 8;
    7061             : 
    7062          56 :         len = os_strlen(param);
    7063          56 :         if (len & 1)
    7064           1 :                 return -1;
    7065          55 :         len /= 2;
    7066             : 
    7067          55 :         buf = os_malloc(len);
    7068          55 :         if (buf == NULL)
    7069           0 :                 return -1;
    7070             : 
    7071          55 :         if (hexstr2bin(param, buf, len) < 0) {
    7072           1 :                 os_free(buf);
    7073           1 :                 return -1;
    7074             :         }
    7075             : 
    7076          54 :         res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
    7077             :                                      buf, len, wait_time,
    7078             :                                      wpas_ctrl_iface_mgmt_tx_cb, no_cck);
    7079          54 :         os_free(buf);
    7080          54 :         return res;
    7081             : }
    7082             : 
    7083             : 
    7084           1 : static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
    7085             : {
    7086           1 :         wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
    7087           1 :         offchannel_send_action_done(wpa_s);
    7088           1 : }
    7089             : 
    7090             : 
    7091          11 : static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
    7092             : {
    7093             :         char *pos, *param;
    7094             :         union wpa_event_data event;
    7095             :         enum wpa_event_type ev;
    7096             : 
    7097             :         /* <event name> [parameters..] */
    7098             : 
    7099          11 :         wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
    7100             : 
    7101          11 :         pos = cmd;
    7102          11 :         param = os_strchr(pos, ' ');
    7103          11 :         if (param)
    7104           2 :                 *param++ = '\0';
    7105             : 
    7106          11 :         os_memset(&event, 0, sizeof(event));
    7107             : 
    7108          11 :         if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
    7109           4 :                 ev = EVENT_INTERFACE_ENABLED;
    7110           7 :         } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
    7111           2 :                 ev = EVENT_INTERFACE_DISABLED;
    7112           5 :         } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
    7113           4 :                 ev = EVENT_AVOID_FREQUENCIES;
    7114           4 :                 if (param == NULL)
    7115           2 :                         param = "";
    7116           4 :                 if (freq_range_list_parse(&event.freq_range, param) < 0)
    7117           0 :                         return -1;
    7118           4 :                 wpa_supplicant_event(wpa_s, ev, &event);
    7119           4 :                 os_free(event.freq_range.range);
    7120           4 :                 return 0;
    7121             :         } else {
    7122           1 :                 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
    7123             :                         cmd);
    7124           1 :                 return -1;
    7125             :         }
    7126             : 
    7127           6 :         wpa_supplicant_event(wpa_s, ev, &event);
    7128             : 
    7129           6 :         return 0;
    7130             : }
    7131             : 
    7132             : 
    7133          47 : static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
    7134             : {
    7135             :         char *pos;
    7136             :         u8 src[ETH_ALEN], *buf;
    7137             :         int used;
    7138             :         size_t len;
    7139             : 
    7140          47 :         wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
    7141             : 
    7142          47 :         pos = cmd;
    7143          47 :         used = hwaddr_aton2(pos, src);
    7144          47 :         if (used < 0)
    7145           1 :                 return -1;
    7146          46 :         pos += used;
    7147         138 :         while (*pos == ' ')
    7148          46 :                 pos++;
    7149             : 
    7150          46 :         len = os_strlen(pos);
    7151          46 :         if (len & 1)
    7152           1 :                 return -1;
    7153          45 :         len /= 2;
    7154             : 
    7155          45 :         buf = os_malloc(len);
    7156          45 :         if (buf == NULL)
    7157           0 :                 return -1;
    7158             : 
    7159          45 :         if (hexstr2bin(pos, buf, len) < 0) {
    7160           1 :                 os_free(buf);
    7161           1 :                 return -1;
    7162             :         }
    7163             : 
    7164          44 :         wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
    7165          44 :         os_free(buf);
    7166             : 
    7167          44 :         return 0;
    7168             : }
    7169             : 
    7170             : 
    7171        2125 : static u16 ipv4_hdr_checksum(const void *buf, size_t len)
    7172             : {
    7173             :         size_t i;
    7174        2125 :         u32 sum = 0;
    7175        2125 :         const u16 *pos = buf;
    7176             : 
    7177       23375 :         for (i = 0; i < len / 2; i++)
    7178       21250 :                 sum += *pos++;
    7179             : 
    7180        6375 :         while (sum >> 16)
    7181        2125 :                 sum = (sum & 0xffff) + (sum >> 16);
    7182             : 
    7183        2125 :         return sum ^ 0xffff;
    7184             : }
    7185             : 
    7186             : 
    7187             : #define HWSIM_PACKETLEN 1500
    7188             : #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
    7189             : 
    7190        2116 : void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
    7191             : {
    7192        2116 :         struct wpa_supplicant *wpa_s = ctx;
    7193             :         const struct ether_header *eth;
    7194             :         const struct iphdr *ip;
    7195             :         const u8 *pos;
    7196             :         unsigned int i;
    7197             : 
    7198        2116 :         if (len != HWSIM_PACKETLEN)
    7199           0 :                 return;
    7200             : 
    7201        2116 :         eth = (const struct ether_header *) buf;
    7202        2116 :         ip = (const struct iphdr *) (eth + 1);
    7203        2116 :         pos = (const u8 *) (ip + 1);
    7204             : 
    7205        4232 :         if (ip->ihl != 5 || ip->version != 4 ||
    7206        2116 :             ntohs(ip->tot_len) != HWSIM_IP_LEN)
    7207           0 :                 return;
    7208             : 
    7209     3104172 :         for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
    7210     3102056 :                 if (*pos != (u8) i)
    7211           0 :                         return;
    7212     3102056 :                 pos++;
    7213             :         }
    7214             : 
    7215       25392 :         wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
    7216       25392 :                 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
    7217             : }
    7218             : 
    7219             : 
    7220        2046 : static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
    7221             :                                             char *cmd)
    7222             : {
    7223        2046 :         int enabled = atoi(cmd);
    7224             : 
    7225        2046 :         if (!enabled) {
    7226        1023 :                 if (wpa_s->l2_test) {
    7227        1022 :                         l2_packet_deinit(wpa_s->l2_test);
    7228        1022 :                         wpa_s->l2_test = NULL;
    7229        1022 :                         wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
    7230             :                 }
    7231        1023 :                 return 0;
    7232             :         }
    7233             : 
    7234        1023 :         if (wpa_s->l2_test)
    7235           1 :                 return 0;
    7236             : 
    7237        1022 :         wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
    7238             :                                         ETHERTYPE_IP, wpas_data_test_rx,
    7239             :                                         wpa_s, 1);
    7240        1022 :         if (wpa_s->l2_test == NULL)
    7241           0 :                 return -1;
    7242             : 
    7243        1022 :         wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
    7244             : 
    7245        1022 :         return 0;
    7246             : }
    7247             : 
    7248             : 
    7249        2130 : static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
    7250             : {
    7251             :         u8 dst[ETH_ALEN], src[ETH_ALEN];
    7252             :         char *pos;
    7253             :         int used;
    7254             :         long int val;
    7255             :         u8 tos;
    7256             :         u8 buf[HWSIM_PACKETLEN];
    7257             :         struct ether_header *eth;
    7258             :         struct iphdr *ip;
    7259             :         u8 *dpos;
    7260             :         unsigned int i;
    7261             : 
    7262        2130 :         if (wpa_s->l2_test == NULL)
    7263           1 :                 return -1;
    7264             : 
    7265             :         /* format: <dst> <src> <tos> */
    7266             : 
    7267        2129 :         pos = cmd;
    7268        2129 :         used = hwaddr_aton2(pos, dst);
    7269        2129 :         if (used < 0)
    7270           1 :                 return -1;
    7271        2128 :         pos += used;
    7272        6384 :         while (*pos == ' ')
    7273        2128 :                 pos++;
    7274        2128 :         used = hwaddr_aton2(pos, src);
    7275        2128 :         if (used < 0)
    7276           1 :                 return -1;
    7277        2127 :         pos += used;
    7278             : 
    7279        2127 :         val = strtol(pos, NULL, 0);
    7280        2127 :         if (val < 0 || val > 0xff)
    7281           2 :                 return -1;
    7282        2125 :         tos = val;
    7283             : 
    7284        2125 :         eth = (struct ether_header *) buf;
    7285        2125 :         os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
    7286        2125 :         os_memcpy(eth->ether_shost, src, ETH_ALEN);
    7287        2125 :         eth->ether_type = htons(ETHERTYPE_IP);
    7288        2125 :         ip = (struct iphdr *) (eth + 1);
    7289        2125 :         os_memset(ip, 0, sizeof(*ip));
    7290        2125 :         ip->ihl = 5;
    7291        2125 :         ip->version = 4;
    7292        2125 :         ip->ttl = 64;
    7293        2125 :         ip->tos = tos;
    7294        2125 :         ip->tot_len = htons(HWSIM_IP_LEN);
    7295        2125 :         ip->protocol = 1;
    7296        2125 :         ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
    7297        2125 :         ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
    7298        2125 :         ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
    7299        2125 :         dpos = (u8 *) (ip + 1);
    7300     3117375 :         for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
    7301     3115250 :                 *dpos++ = i;
    7302             : 
    7303        2125 :         if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
    7304             :                            HWSIM_PACKETLEN) < 0)
    7305           0 :                 return -1;
    7306             : 
    7307        2125 :         wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
    7308             :                 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
    7309             : 
    7310        2125 :         return 0;
    7311             : }
    7312             : 
    7313             : 
    7314          98 : static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
    7315             :                                            char *cmd)
    7316             : {
    7317             :         u8 *buf;
    7318             :         struct ether_header *eth;
    7319          98 :         struct l2_packet_data *l2 = NULL;
    7320             :         size_t len;
    7321             :         u16 ethertype;
    7322          98 :         int res = -1;
    7323             : 
    7324          98 :         len = os_strlen(cmd);
    7325          98 :         if (len & 1 || len < ETH_HLEN * 2)
    7326           3 :                 return -1;
    7327          95 :         len /= 2;
    7328             : 
    7329          95 :         buf = os_malloc(len);
    7330          95 :         if (buf == NULL)
    7331           0 :                 return -1;
    7332             : 
    7333          95 :         if (hexstr2bin(cmd, buf, len) < 0)
    7334           1 :                 goto done;
    7335             : 
    7336          94 :         eth = (struct ether_header *) buf;
    7337          94 :         ethertype = ntohs(eth->ether_type);
    7338             : 
    7339          94 :         l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
    7340             :                             wpas_data_test_rx, wpa_s, 1);
    7341          94 :         if (l2 == NULL)
    7342           0 :                 goto done;
    7343             : 
    7344          94 :         res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
    7345          94 :         wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
    7346             : done:
    7347          95 :         if (l2)
    7348          94 :                 l2_packet_deinit(l2);
    7349          95 :         os_free(buf);
    7350             : 
    7351          95 :         return res < 0 ? -1 : 0;
    7352             : }
    7353             : 
    7354             : 
    7355         230 : static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
    7356             : {
    7357             : #ifdef WPA_TRACE_BFD
    7358             :         extern char wpa_trace_fail_func[256];
    7359             :         extern unsigned int wpa_trace_fail_after;
    7360             :         char *pos;
    7361             : 
    7362         230 :         wpa_trace_fail_after = atoi(cmd);
    7363         230 :         pos = os_strchr(cmd, ':');
    7364         230 :         if (pos) {
    7365         230 :                 pos++;
    7366         230 :                 os_strlcpy(wpa_trace_fail_func, pos,
    7367             :                            sizeof(wpa_trace_fail_func));
    7368             :         } else {
    7369           0 :                 wpa_trace_fail_after = 0;
    7370             :         }
    7371         230 :         return 0;
    7372             : #else /* WPA_TRACE_BFD */
    7373             :         return -1;
    7374             : #endif /* WPA_TRACE_BFD */
    7375             : }
    7376             : 
    7377             : 
    7378          88 : static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
    7379             :                                     char *buf, size_t buflen)
    7380             : {
    7381             : #ifdef WPA_TRACE_BFD
    7382             :         extern char wpa_trace_fail_func[256];
    7383             :         extern unsigned int wpa_trace_fail_after;
    7384             : 
    7385          88 :         return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
    7386             :                            wpa_trace_fail_func);
    7387             : #else /* WPA_TRACE_BFD */
    7388             :         return -1;
    7389             : #endif /* WPA_TRACE_BFD */
    7390             : }
    7391             : 
    7392             : #endif /* CONFIG_TESTING_OPTIONS */
    7393             : 
    7394             : 
    7395          20 : static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
    7396             : {
    7397             :         unsigned int i;
    7398             :         char buf[30];
    7399             : 
    7400          20 :         wpa_printf(MSG_DEBUG, "Update vendor elements");
    7401             : 
    7402         300 :         for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
    7403         280 :                 if (wpa_s->vendor_elem[i]) {
    7404             :                         int res;
    7405             : 
    7406          17 :                         res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
    7407          17 :                         if (!os_snprintf_error(sizeof(buf), res)) {
    7408          17 :                                 wpa_hexdump_buf(MSG_DEBUG, buf,
    7409          17 :                                                 wpa_s->vendor_elem[i]);
    7410             :                         }
    7411             :                 }
    7412             :         }
    7413             : 
    7414             : #ifdef CONFIG_P2P
    7415          40 :         if (wpa_s->parent == wpa_s &&
    7416          40 :             wpa_s->global->p2p &&
    7417          20 :             !wpa_s->global->p2p_disabled)
    7418          20 :                 p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
    7419             : #endif /* CONFIG_P2P */
    7420          20 : }
    7421             : 
    7422             : 
    7423             : static struct wpa_supplicant *
    7424          46 : wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
    7425             :                             enum wpa_vendor_elem_frame frame)
    7426             : {
    7427          46 :         switch (frame) {
    7428             : #ifdef CONFIG_P2P
    7429             :         case VENDOR_ELEM_PROBE_REQ_P2P:
    7430             :         case VENDOR_ELEM_PROBE_RESP_P2P:
    7431             :         case VENDOR_ELEM_PROBE_RESP_P2P_GO:
    7432             :         case VENDOR_ELEM_BEACON_P2P_GO:
    7433             :         case VENDOR_ELEM_P2P_PD_REQ:
    7434             :         case VENDOR_ELEM_P2P_PD_RESP:
    7435             :         case VENDOR_ELEM_P2P_GO_NEG_REQ:
    7436             :         case VENDOR_ELEM_P2P_GO_NEG_RESP:
    7437             :         case VENDOR_ELEM_P2P_GO_NEG_CONF:
    7438             :         case VENDOR_ELEM_P2P_INV_REQ:
    7439             :         case VENDOR_ELEM_P2P_INV_RESP:
    7440             :         case VENDOR_ELEM_P2P_ASSOC_REQ:
    7441          42 :                 return wpa_s->parent;
    7442             : #endif /* CONFIG_P2P */
    7443             :         default:
    7444           4 :                 return wpa_s;
    7445             :         }
    7446             : }
    7447             : 
    7448             : 
    7449          16 : static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
    7450             : {
    7451          16 :         char *pos = cmd;
    7452             :         int frame;
    7453             :         size_t len;
    7454             :         struct wpabuf *buf;
    7455             :         struct ieee802_11_elems elems;
    7456             : 
    7457          16 :         frame = atoi(pos);
    7458          16 :         if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
    7459           2 :                 return -1;
    7460          14 :         wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
    7461             : 
    7462          14 :         pos = os_strchr(pos, ' ');
    7463          14 :         if (pos == NULL)
    7464           1 :                 return -1;
    7465          13 :         pos++;
    7466             : 
    7467          13 :         len = os_strlen(pos);
    7468          13 :         if (len == 0)
    7469           1 :                 return 0;
    7470          12 :         if (len & 1)
    7471           1 :                 return -1;
    7472          11 :         len /= 2;
    7473             : 
    7474          11 :         buf = wpabuf_alloc(len);
    7475          11 :         if (buf == NULL)
    7476           0 :                 return -1;
    7477             : 
    7478          11 :         if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
    7479           1 :                 wpabuf_free(buf);
    7480           1 :                 return -1;
    7481             :         }
    7482             : 
    7483          10 :         if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
    7484             :             ParseFailed) {
    7485           1 :                 wpabuf_free(buf);
    7486           1 :                 return -1;
    7487             :         }
    7488             : 
    7489           9 :         if (wpa_s->vendor_elem[frame] == NULL) {
    7490           8 :                 wpa_s->vendor_elem[frame] = buf;
    7491           8 :                 wpas_ctrl_vendor_elem_update(wpa_s);
    7492           8 :                 return 0;
    7493             :         }
    7494             : 
    7495           1 :         if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
    7496           0 :                 wpabuf_free(buf);
    7497           0 :                 return -1;
    7498             :         }
    7499             : 
    7500           1 :         wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
    7501           1 :         wpabuf_free(buf);
    7502           1 :         wpas_ctrl_vendor_elem_update(wpa_s);
    7503             : 
    7504           1 :         return 0;
    7505             : }
    7506             : 
    7507             : 
    7508           9 : static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
    7509             :                                      char *buf, size_t buflen)
    7510             : {
    7511           9 :         int frame = atoi(cmd);
    7512             : 
    7513           9 :         if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
    7514           2 :                 return -1;
    7515           7 :         wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
    7516             : 
    7517           7 :         if (wpa_s->vendor_elem[frame] == NULL)
    7518           2 :                 return 0;
    7519             : 
    7520          10 :         return wpa_snprintf_hex(buf, buflen,
    7521           5 :                                 wpabuf_head_u8(wpa_s->vendor_elem[frame]),
    7522           5 :                                 wpabuf_len(wpa_s->vendor_elem[frame]));
    7523             : }
    7524             : 
    7525             : 
    7526          29 : static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
    7527             : {
    7528          29 :         char *pos = cmd;
    7529             :         int frame;
    7530             :         size_t len;
    7531             :         u8 *buf;
    7532             :         struct ieee802_11_elems elems;
    7533             :         u8 *ie, *end;
    7534             : 
    7535          29 :         frame = atoi(pos);
    7536          29 :         if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
    7537           4 :                 return -1;
    7538          25 :         wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
    7539             : 
    7540          25 :         pos = os_strchr(pos, ' ');
    7541          25 :         if (pos == NULL)
    7542           3 :                 return -1;
    7543          22 :         pos++;
    7544             : 
    7545          22 :         if (*pos == '*') {
    7546           7 :                 wpabuf_free(wpa_s->vendor_elem[frame]);
    7547           7 :                 wpa_s->vendor_elem[frame] = NULL;
    7548           7 :                 wpas_ctrl_vendor_elem_update(wpa_s);
    7549           7 :                 return 0;
    7550             :         }
    7551             : 
    7552          15 :         if (wpa_s->vendor_elem[frame] == NULL)
    7553           4 :                 return -1;
    7554             : 
    7555          11 :         len = os_strlen(pos);
    7556          11 :         if (len == 0)
    7557           1 :                 return 0;
    7558          10 :         if (len & 1)
    7559           1 :                 return -1;
    7560           9 :         len /= 2;
    7561             : 
    7562           9 :         buf = os_malloc(len);
    7563           9 :         if (buf == NULL)
    7564           0 :                 return -1;
    7565             : 
    7566           9 :         if (hexstr2bin(pos, buf, len) < 0) {
    7567           1 :                 os_free(buf);
    7568           1 :                 return -1;
    7569             :         }
    7570             : 
    7571           8 :         if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
    7572           2 :                 os_free(buf);
    7573           2 :                 return -1;
    7574             :         }
    7575             : 
    7576           6 :         ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
    7577           6 :         end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
    7578             : 
    7579          20 :         for (; ie + 1 < end; ie += 2 + ie[1]) {
    7580           8 :                 if (ie + len > end)
    7581           0 :                         break;
    7582           8 :                 if (os_memcmp(ie, buf, len) != 0)
    7583           4 :                         continue;
    7584             : 
    7585           4 :                 if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
    7586           2 :                         wpabuf_free(wpa_s->vendor_elem[frame]);
    7587           2 :                         wpa_s->vendor_elem[frame] = NULL;
    7588             :                 } else {
    7589           2 :                         os_memmove(ie, ie + len,
    7590             :                                    end - (ie + len));
    7591           2 :                         wpa_s->vendor_elem[frame]->used -= len;
    7592             :                 }
    7593           4 :                 os_free(buf);
    7594           4 :                 wpas_ctrl_vendor_elem_update(wpa_s);
    7595           4 :                 return 0;
    7596             :         }
    7597             : 
    7598           2 :         os_free(buf);
    7599             : 
    7600           2 :         return -1;
    7601             : }
    7602             : 
    7603             : 
    7604           2 : static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
    7605             : {
    7606           2 :         struct wpa_supplicant *wpa_s = ctx;
    7607             : 
    7608           2 :         if (neighbor_rep) {
    7609           0 :                 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
    7610             :                              "length=%u",
    7611           0 :                              (unsigned int) wpabuf_len(neighbor_rep));
    7612           0 :                 wpabuf_free(neighbor_rep);
    7613             :         } else {
    7614           2 :                 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
    7615             :         }
    7616           2 : }
    7617             : 
    7618             : 
    7619           4 : static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
    7620             :                                             char *cmd)
    7621             : {
    7622             :         struct wpa_ssid ssid;
    7623           4 :         struct wpa_ssid *ssid_p = NULL;
    7624           4 :         int ret = 0;
    7625             : 
    7626           4 :         if (os_strncmp(cmd, " ssid=", 6) == 0) {
    7627           2 :                 ssid.ssid_len = os_strlen(cmd + 6);
    7628           2 :                 if (ssid.ssid_len > 32)
    7629           0 :                         return -1;
    7630           2 :                 ssid.ssid = (u8 *) (cmd + 6);
    7631           2 :                 ssid_p = &ssid;
    7632             :         }
    7633             : 
    7634           4 :         ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
    7635             :                                                  wpas_ctrl_neighbor_rep_cb,
    7636             :                                                  wpa_s);
    7637             : 
    7638           4 :         return ret;
    7639             : }
    7640             : 
    7641             : 
    7642          19 : static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
    7643             : {
    7644          19 :         eapol_sm_erp_flush(wpa_s->eapol);
    7645          19 :         return 0;
    7646             : }
    7647             : 
    7648             : 
    7649          16 : static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
    7650             :                                          char *cmd)
    7651             : {
    7652          16 :         char *token, *context = NULL;
    7653          16 :         unsigned int enable = ~0, type = 0;
    7654             :         u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
    7655          16 :         u8 *addr = NULL, *mask = NULL;
    7656             : 
    7657          68 :         while ((token = str_token(cmd, " ", &context))) {
    7658          39 :                 if (os_strcasecmp(token, "scan") == 0) {
    7659           1 :                         type |= MAC_ADDR_RAND_SCAN;
    7660          38 :                 } else if (os_strcasecmp(token, "sched") == 0) {
    7661           1 :                         type |= MAC_ADDR_RAND_SCHED_SCAN;
    7662          37 :                 } else if (os_strcasecmp(token, "pno") == 0) {
    7663           2 :                         type |= MAC_ADDR_RAND_PNO;
    7664          35 :                 } else if (os_strcasecmp(token, "all") == 0) {
    7665          10 :                         type = wpa_s->mac_addr_rand_supported;
    7666          25 :                 } else if (os_strncasecmp(token, "enable=", 7) == 0) {
    7667          12 :                         enable = atoi(token + 7);
    7668          13 :                 } else if (os_strncasecmp(token, "addr=", 5) == 0) {
    7669           6 :                         addr = _addr;
    7670           6 :                         if (hwaddr_aton(token + 5, addr)) {
    7671           1 :                                 wpa_printf(MSG_INFO,
    7672             :                                            "CTRL: Invalid MAC address: %s",
    7673             :                                            token);
    7674           1 :                                 return -1;
    7675             :                         }
    7676           7 :                 } else if (os_strncasecmp(token, "mask=", 5) == 0) {
    7677           6 :                         mask = _mask;
    7678           6 :                         if (hwaddr_aton(token + 5, mask)) {
    7679           1 :                                 wpa_printf(MSG_INFO,
    7680             :                                            "CTRL: Invalid MAC address mask: %s",
    7681             :                                            token);
    7682           1 :                                 return -1;
    7683             :                         }
    7684             :                 } else {
    7685           1 :                         wpa_printf(MSG_INFO,
    7686             :                                    "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
    7687             :                                    token);
    7688           1 :                         return -1;
    7689             :                 }
    7690             :         }
    7691             : 
    7692          13 :         if (!type) {
    7693           2 :                 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
    7694           2 :                 return -1;
    7695             :         }
    7696             : 
    7697          11 :         if ((wpa_s->mac_addr_rand_supported & type) != type) {
    7698           1 :                 wpa_printf(MSG_INFO,
    7699             :                            "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
    7700             :                            type, wpa_s->mac_addr_rand_supported);
    7701           1 :                 return -1;
    7702             :         }
    7703             : 
    7704          10 :         if (enable > 1) {
    7705           2 :                 wpa_printf(MSG_INFO,
    7706             :                            "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
    7707           2 :                 return -1;
    7708             :         }
    7709             : 
    7710           8 :         if (!enable) {
    7711           1 :                 wpas_mac_addr_rand_scan_clear(wpa_s, type);
    7712           1 :                 if (wpa_s->pno) {
    7713           0 :                         if (type & MAC_ADDR_RAND_PNO) {
    7714           0 :                                 wpas_stop_pno(wpa_s);
    7715           0 :                                 wpas_start_pno(wpa_s);
    7716             :                         }
    7717           1 :                 } else if (wpa_s->sched_scanning &&
    7718           0 :                            (type & MAC_ADDR_RAND_SCHED_SCAN)) {
    7719             :                         /* simulate timeout to restart the sched scan */
    7720           0 :                         wpa_s->sched_scan_timed_out = 1;
    7721           0 :                         wpa_s->prev_sched_ssid = NULL;
    7722           0 :                         wpa_supplicant_cancel_sched_scan(wpa_s);
    7723             :                 }
    7724           1 :                 return 0;
    7725             :         }
    7726             : 
    7727           7 :         if ((addr && !mask) || (!addr && mask)) {
    7728           2 :                 wpa_printf(MSG_INFO,
    7729             :                            "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
    7730           2 :                 return -1;
    7731             :         }
    7732             : 
    7733           5 :         if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
    7734           2 :                 wpa_printf(MSG_INFO,
    7735             :                            "CTRL: MAC_RAND_SCAN cannot allow multicast address");
    7736           2 :                 return -1;
    7737             :         }
    7738             : 
    7739           3 :         if (type & MAC_ADDR_RAND_SCAN) {
    7740           3 :                 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
    7741             :                                             addr, mask);
    7742             :         }
    7743             : 
    7744           3 :         if (type & MAC_ADDR_RAND_SCHED_SCAN) {
    7745           0 :                 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
    7746             :                                             addr, mask);
    7747             : 
    7748           0 :                 if (wpa_s->sched_scanning && !wpa_s->pno) {
    7749             :                         /* simulate timeout to restart the sched scan */
    7750           0 :                         wpa_s->sched_scan_timed_out = 1;
    7751           0 :                         wpa_s->prev_sched_ssid = NULL;
    7752           0 :                         wpa_supplicant_cancel_sched_scan(wpa_s);
    7753             :                 }
    7754             :         }
    7755             : 
    7756           3 :         if (type & MAC_ADDR_RAND_PNO) {
    7757           0 :                 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
    7758             :                                             addr, mask);
    7759           0 :                 if (wpa_s->pno) {
    7760           0 :                         wpas_stop_pno(wpa_s);
    7761           0 :                         wpas_start_pno(wpa_s);
    7762             :                 }
    7763             :         }
    7764             : 
    7765           3 :         return 0;
    7766             : }
    7767             : 
    7768             : 
    7769       67309 : char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
    7770             :                                          char *buf, size_t *resp_len)
    7771             : {
    7772             :         char *reply;
    7773       67309 :         const int reply_size = 4096;
    7774             :         int reply_len;
    7775             : 
    7776      134569 :         if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
    7777       67260 :             os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
    7778       15278 :                 if (wpa_debug_show_keys)
    7779        7639 :                         wpa_dbg(wpa_s, MSG_DEBUG,
    7780             :                                 "Control interface command '%s'", buf);
    7781             :                 else
    7782           0 :                         wpa_dbg(wpa_s, MSG_DEBUG,
    7783             :                                 "Control interface command '%s [REMOVED]'",
    7784             :                                 os_strncmp(buf, WPA_CTRL_RSP,
    7785             :                                            os_strlen(WPA_CTRL_RSP)) == 0 ?
    7786             :                                 WPA_CTRL_RSP : "SET_NETWORK");
    7787      119303 :         } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
    7788       59633 :                    os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
    7789          77 :                 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
    7790             :                                       (const u8 *) buf, os_strlen(buf));
    7791             :         } else {
    7792       59593 :                 int level = MSG_DEBUG;
    7793       59593 :                 if (os_strcmp(buf, "PING") == 0)
    7794        6308 :                         level = MSG_EXCESSIVE;
    7795       59593 :                 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
    7796             :         }
    7797             : 
    7798       67309 :         reply = os_malloc(reply_size);
    7799       67309 :         if (reply == NULL) {
    7800           0 :                 *resp_len = 1;
    7801           0 :                 return NULL;
    7802             :         }
    7803             : 
    7804       67309 :         os_memcpy(reply, "OK\n", 3);
    7805       67309 :         reply_len = 3;
    7806             : 
    7807       67309 :         if (os_strcmp(buf, "PING") == 0) {
    7808        6308 :                 os_memcpy(reply, "PONG\n", 5);
    7809        6308 :                 reply_len = 5;
    7810       61001 :         } else if (os_strcmp(buf, "IFNAME") == 0) {
    7811           1 :                 reply_len = os_strlen(wpa_s->ifname);
    7812           1 :                 os_memcpy(reply, wpa_s->ifname, reply_len);
    7813       61000 :         } else if (os_strncmp(buf, "RELOG", 5) == 0) {
    7814           1 :                 if (wpa_debug_reopen_file() < 0)
    7815           0 :                         reply_len = -1;
    7816       60999 :         } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
    7817        6270 :                 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
    7818       54729 :         } else if (os_strcmp(buf, "MIB") == 0) {
    7819          11 :                 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
    7820          11 :                 if (reply_len >= 0) {
    7821          11 :                         reply_len += eapol_sm_get_mib(wpa_s->eapol,
    7822             :                                                       reply + reply_len,
    7823          11 :                                                       reply_size - reply_len);
    7824             :                 }
    7825       54718 :         } else if (os_strncmp(buf, "STATUS", 6) == 0) {
    7826        6574 :                 reply_len = wpa_supplicant_ctrl_iface_status(
    7827             :                         wpa_s, buf + 6, reply, reply_size);
    7828       48144 :         } else if (os_strcmp(buf, "PMKSA") == 0) {
    7829         149 :                 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
    7830             :                                                     reply_size);
    7831       47995 :         } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
    7832           7 :                 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
    7833       47988 :         } else if (os_strncmp(buf, "SET ", 4) == 0) {
    7834       19677 :                 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
    7835          36 :                         reply_len = -1;
    7836       28311 :         } else if (os_strncmp(buf, "GET ", 4) == 0) {
    7837          16 :                 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
    7838             :                                                           reply, reply_size);
    7839       28295 :         } else if (os_strcmp(buf, "LOGON") == 0) {
    7840           1 :                 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
    7841       28294 :         } else if (os_strcmp(buf, "LOGOFF") == 0) {
    7842           1 :                 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
    7843       28293 :         } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
    7844          17 :                 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
    7845           1 :                         reply_len = -1;
    7846             :                 else
    7847          16 :                         wpas_request_connection(wpa_s);
    7848       28276 :         } else if (os_strcmp(buf, "REATTACH") == 0) {
    7849           5 :                 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
    7850           2 :                     !wpa_s->current_ssid)
    7851           2 :                         reply_len = -1;
    7852             :                 else {
    7853           1 :                         wpa_s->reattach = 1;
    7854           1 :                         wpas_request_connection(wpa_s);
    7855             :                 }
    7856       28273 :         } else if (os_strcmp(buf, "RECONNECT") == 0) {
    7857          31 :                 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
    7858           1 :                         reply_len = -1;
    7859          30 :                 else if (wpa_s->disconnected)
    7860          30 :                         wpas_request_connection(wpa_s);
    7861             : #ifdef IEEE8021X_EAPOL
    7862       28242 :         } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
    7863          16 :                 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
    7864           6 :                         reply_len = -1;
    7865             : #endif /* IEEE8021X_EAPOL */
    7866             : #ifdef CONFIG_PEERKEY
    7867       28226 :         } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
    7868           6 :                 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
    7869           2 :                         reply_len = -1;
    7870             : #endif /* CONFIG_PEERKEY */
    7871             : #ifdef CONFIG_IEEE80211R
    7872       28220 :         } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
    7873         115 :                 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
    7874           1 :                         reply_len = -1;
    7875             : #endif /* CONFIG_IEEE80211R */
    7876             : #ifdef CONFIG_WPS
    7877       28105 :         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
    7878          14 :                 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
    7879          14 :                 if (res == -2) {
    7880           1 :                         os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
    7881           1 :                         reply_len = 17;
    7882          13 :                 } else if (res)
    7883           0 :                         reply_len = -1;
    7884       28091 :         } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
    7885          29 :                 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
    7886          29 :                 if (res == -2) {
    7887           1 :                         os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
    7888           1 :                         reply_len = 17;
    7889          28 :                 } else if (res)
    7890           2 :                         reply_len = -1;
    7891       28062 :         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
    7892         197 :                 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
    7893             :                                                               reply,
    7894             :                                                               reply_size);
    7895       27865 :         } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
    7896          17 :                 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
    7897             :                         wpa_s, buf + 14, reply, reply_size);
    7898       27848 :         } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
    7899          14 :                 if (wpas_wps_cancel(wpa_s))
    7900           1 :                         reply_len = -1;
    7901             : #ifdef CONFIG_WPS_NFC
    7902       27834 :         } else if (os_strcmp(buf, "WPS_NFC") == 0) {
    7903           3 :                 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
    7904           0 :                         reply_len = -1;
    7905       27831 :         } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
    7906           1 :                 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
    7907           1 :                         reply_len = -1;
    7908       27830 :         } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
    7909           3 :                 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
    7910             :                         wpa_s, buf + 21, reply, reply_size);
    7911       27827 :         } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
    7912          14 :                 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
    7913             :                         wpa_s, buf + 14, reply, reply_size);
    7914       27813 :         } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
    7915          37 :                 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
    7916             :                                                                buf + 17))
    7917          22 :                         reply_len = -1;
    7918       27776 :         } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
    7919          28 :                 reply_len = wpas_ctrl_nfc_get_handover_req(
    7920             :                         wpa_s, buf + 21, reply, reply_size);
    7921       27748 :         } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
    7922          32 :                 reply_len = wpas_ctrl_nfc_get_handover_sel(
    7923             :                         wpa_s, buf + 21, reply, reply_size);
    7924       27716 :         } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
    7925          40 :                 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
    7926           9 :                         reply_len = -1;
    7927             : #endif /* CONFIG_WPS_NFC */
    7928       27676 :         } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
    7929          45 :                 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
    7930           5 :                         reply_len = -1;
    7931             : #ifdef CONFIG_AP
    7932       27631 :         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
    7933          16 :                 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
    7934             :                         wpa_s, buf + 11, reply, reply_size);
    7935             : #endif /* CONFIG_AP */
    7936             : #ifdef CONFIG_WPS_ER
    7937       27615 :         } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
    7938           1 :                 if (wpas_wps_er_start(wpa_s, NULL))
    7939           0 :                         reply_len = -1;
    7940       27614 :         } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
    7941          10 :                 if (wpas_wps_er_start(wpa_s, buf + 13))
    7942           0 :                         reply_len = -1;
    7943       27604 :         } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
    7944          18 :                 wpas_wps_er_stop(wpa_s);
    7945       27586 :         } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
    7946           5 :                 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
    7947           1 :                         reply_len = -1;
    7948       27581 :         } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
    7949           5 :                 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
    7950           5 :                 if (ret == -2) {
    7951           1 :                         os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
    7952           1 :                         reply_len = 17;
    7953           4 :                 } else if (ret == -3) {
    7954           1 :                         os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
    7955           1 :                         reply_len = 18;
    7956           3 :                 } else if (ret == -4) {
    7957           1 :                         os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
    7958           1 :                         reply_len = 20;
    7959           2 :                 } else if (ret)
    7960           1 :                         reply_len = -1;
    7961       27576 :         } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
    7962           2 :                 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
    7963           1 :                         reply_len = -1;
    7964       27574 :         } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
    7965           9 :                 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
    7966             :                                                                 buf + 18))
    7967           1 :                         reply_len = -1;
    7968       27565 :         } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
    7969           6 :                 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
    7970           5 :                         reply_len = -1;
    7971             : #ifdef CONFIG_WPS_NFC
    7972       27559 :         } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
    7973           5 :                 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
    7974             :                         wpa_s, buf + 24, reply, reply_size);
    7975             : #endif /* CONFIG_WPS_NFC */
    7976             : #endif /* CONFIG_WPS_ER */
    7977             : #endif /* CONFIG_WPS */
    7978             : #ifdef CONFIG_IBSS_RSN
    7979       27554 :         } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
    7980           2 :                 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
    7981           1 :                         reply_len = -1;
    7982             : #endif /* CONFIG_IBSS_RSN */
    7983             : #ifdef CONFIG_MESH
    7984       27552 :         } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
    7985           2 :                 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
    7986             :                         wpa_s, buf + 19, reply, reply_size);
    7987       27550 :         } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
    7988           2 :                 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
    7989             :                         wpa_s, "", reply, reply_size);
    7990       27548 :         } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
    7991          32 :                 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
    7992           3 :                         reply_len = -1;
    7993       27516 :         } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
    7994          17 :                 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
    7995             :                                                                 buf + 18))
    7996           7 :                         reply_len = -1;
    7997             : #endif /* CONFIG_MESH */
    7998             : #ifdef CONFIG_P2P
    7999       27499 :         } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
    8000         318 :                 if (p2p_ctrl_find(wpa_s, buf + 8))
    8001           2 :                         reply_len = -1;
    8002       27181 :         } else if (os_strcmp(buf, "P2P_FIND") == 0) {
    8003          20 :                 if (p2p_ctrl_find(wpa_s, ""))
    8004           1 :                         reply_len = -1;
    8005       27161 :         } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
    8006         122 :                 wpas_p2p_stop_find(wpa_s);
    8007       27039 :         } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
    8008          15 :                 if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
    8009           0 :                         reply_len = -1;
    8010       27024 :         } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
    8011           3 :                 if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
    8012           0 :                         reply_len = -1;
    8013       27021 :         } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
    8014         284 :                 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
    8015             :                                              reply_size);
    8016       26737 :         } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
    8017           2 :                 if (p2p_ctrl_listen(wpa_s, buf + 11))
    8018           1 :                         reply_len = -1;
    8019       26735 :         } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
    8020         344 :                 if (p2p_ctrl_listen(wpa_s, ""))
    8021           1 :                         reply_len = -1;
    8022       26391 :         } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
    8023         232 :                 if (wpas_p2p_group_remove(wpa_s, buf + 17))
    8024          16 :                         reply_len = -1;
    8025       26159 :         } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
    8026          35 :                 if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
    8027           0 :                         reply_len = -1;
    8028       26124 :         } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
    8029          63 :                 if (p2p_ctrl_group_add(wpa_s, buf + 14))
    8030           3 :                         reply_len = -1;
    8031       26061 :         } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
    8032          16 :                 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
    8033           6 :                         reply_len = -1;
    8034       26045 :         } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
    8035           2 :                 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
    8036       26043 :         } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
    8037          66 :                 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
    8038             :                                                    reply_size);
    8039       25977 :         } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
    8040           9 :                 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
    8041           2 :                         reply_len = -1;
    8042       25968 :         } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
    8043           9 :                 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
    8044           7 :                         reply_len = -1;
    8045       25959 :         } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
    8046           1 :                 wpas_p2p_sd_service_update(wpa_s);
    8047       25958 :         } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
    8048           4 :                 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
    8049           1 :                         reply_len = -1;
    8050       25954 :         } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
    8051           1 :                 wpas_p2p_service_flush(wpa_s);
    8052       25953 :         } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
    8053         670 :                 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
    8054           9 :                         reply_len = -1;
    8055       25283 :         } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
    8056         106 :                 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
    8057          45 :                         reply_len = -1;
    8058       25177 :         } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
    8059           2 :                 if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
    8060           1 :                         reply_len = -1;
    8061       25175 :         } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
    8062           3 :                 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
    8063           1 :                         reply_len = -1;
    8064       25172 :         } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
    8065          50 :                 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
    8066          10 :                         reply_len = -1;
    8067       25122 :         } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
    8068         934 :                 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
    8069             :                                               reply_size);
    8070       24188 :         } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
    8071         102 :                 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
    8072          26 :                         reply_len = -1;
    8073       24086 :         } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
    8074          41 :                 p2p_ctrl_flush(wpa_s);
    8075       24045 :         } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
    8076           3 :                 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
    8077           2 :                         reply_len = -1;
    8078       24042 :         } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
    8079           4 :                 if (wpas_p2p_cancel(wpa_s))
    8080           2 :                         reply_len = -1;
    8081       24038 :         } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
    8082           5 :                 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
    8083           2 :                         reply_len = -1;
    8084       24033 :         } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
    8085           1 :                 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
    8086           0 :                         reply_len = -1;
    8087       24032 :         } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
    8088           3 :                 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
    8089           1 :                         reply_len = -1;
    8090       24029 :         } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
    8091           3 :                 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
    8092           0 :                         reply_len = -1;
    8093       24026 :         } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
    8094           7 :                 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
    8095           1 :                         reply_len = -1;
    8096             : #endif /* CONFIG_P2P */
    8097             : #ifdef CONFIG_WIFI_DISPLAY
    8098       24019 :         } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
    8099          37 :                 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
    8100           8 :                         reply_len = -1;
    8101       23982 :         } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
    8102          16 :                 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
    8103             :                                                      reply, reply_size);
    8104             : #endif /* CONFIG_WIFI_DISPLAY */
    8105             : #ifdef CONFIG_INTERWORKING
    8106       23966 :         } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
    8107           7 :                 if (interworking_fetch_anqp(wpa_s) < 0)
    8108           0 :                         reply_len = -1;
    8109       23959 :         } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
    8110           2 :                 interworking_stop_fetch_anqp(wpa_s);
    8111       23957 :         } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
    8112           1 :                 if (ctrl_interworking_select(wpa_s, NULL) < 0)
    8113           0 :                         reply_len = -1;
    8114       23956 :         } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
    8115         131 :                 if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
    8116           0 :                         reply_len = -1;
    8117       23825 :         } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
    8118          50 :                 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
    8119           3 :                         reply_len = -1;
    8120       23775 :         } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
    8121          30 :                 if (get_anqp(wpa_s, buf + 9) < 0)
    8122          11 :                         reply_len = -1;
    8123       23745 :         } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
    8124          20 :                 if (gas_request(wpa_s, buf + 12) < 0)
    8125          12 :                         reply_len = -1;
    8126       23725 :         } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
    8127          14 :                 reply_len = gas_response_get(wpa_s, buf + 17, reply,
    8128             :                                              reply_size);
    8129             : #endif /* CONFIG_INTERWORKING */
    8130             : #ifdef CONFIG_HS20
    8131       23711 :         } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
    8132           9 :                 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
    8133           8 :                         reply_len = -1;
    8134       23702 :         } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
    8135           7 :                 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
    8136           3 :                         reply_len = -1;
    8137       23695 :         } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
    8138           2 :                 if (hs20_icon_request(wpa_s, buf + 18) < 0)
    8139           1 :                         reply_len = -1;
    8140       23693 :         } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
    8141           9 :                 if (hs20_fetch_osu(wpa_s) < 0)
    8142           6 :                         reply_len = -1;
    8143       23684 :         } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
    8144           2 :                 hs20_cancel_fetch_osu(wpa_s);
    8145             : #endif /* CONFIG_HS20 */
    8146       23682 :         } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
    8147             :         {
    8148          49 :                 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
    8149             :                             wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
    8150           5 :                         reply_len = -1;
    8151             :                 else {
    8152             :                         /*
    8153             :                          * Notify response from timeout to allow the control
    8154             :                          * interface response to be sent first.
    8155             :                          */
    8156          44 :                         eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
    8157             :                                                wpa_s, NULL);
    8158             :                 }
    8159       23633 :         } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
    8160           1 :                 if (wpa_supplicant_reload_configuration(wpa_s))
    8161           0 :                         reply_len = -1;
    8162       23632 :         } else if (os_strcmp(buf, "TERMINATE") == 0) {
    8163           0 :                 wpa_supplicant_terminate_proc(wpa_s->global);
    8164       23632 :         } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
    8165           5 :                 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
    8166           3 :                         reply_len = -1;
    8167       23627 :         } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
    8168          12 :                 reply_len = wpa_supplicant_ctrl_iface_blacklist(
    8169             :                         wpa_s, buf + 9, reply, reply_size);
    8170       23615 :         } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
    8171          21 :                 reply_len = wpa_supplicant_ctrl_iface_log_level(
    8172             :                         wpa_s, buf + 9, reply, reply_size);
    8173       23594 :         } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
    8174           1 :                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
    8175             :                         wpa_s, buf + 14, reply, reply_size);
    8176       23593 :         } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
    8177          24 :                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
    8178             :                         wpa_s, NULL, reply, reply_size);
    8179       23569 :         } else if (os_strcmp(buf, "DISCONNECT") == 0) {
    8180             : #ifdef CONFIG_SME
    8181         239 :                 wpa_s->sme.prev_bssid_set = 0;
    8182             : #endif /* CONFIG_SME */
    8183         239 :                 wpa_s->reassociate = 0;
    8184         239 :                 wpa_s->disconnected = 1;
    8185         239 :                 wpa_supplicant_cancel_sched_scan(wpa_s);
    8186         239 :                 wpa_supplicant_cancel_scan(wpa_s);
    8187         239 :                 wpa_supplicant_deauthenticate(wpa_s,
    8188             :                                               WLAN_REASON_DEAUTH_LEAVING);
    8189       23330 :         } else if (os_strcmp(buf, "SCAN") == 0) {
    8190          18 :                 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
    8191       23312 :         } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
    8192         458 :                 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
    8193       22854 :         } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
    8194          31 :                 reply_len = wpa_supplicant_ctrl_iface_scan_results(
    8195             :                         wpa_s, reply, reply_size);
    8196       22823 :         } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
    8197        1386 :                 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
    8198           2 :                         reply_len = -1;
    8199       21437 :         } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
    8200          28 :                 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
    8201           2 :                         reply_len = -1;
    8202       21409 :         } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
    8203           6 :                 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
    8204           2 :                         reply_len = -1;
    8205       21403 :         } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
    8206        2401 :                 reply_len = wpa_supplicant_ctrl_iface_add_network(
    8207             :                         wpa_s, reply, reply_size);
    8208       19002 :         } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
    8209         683 :                 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
    8210           1 :                         reply_len = -1;
    8211       18319 :         } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
    8212        7590 :                 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
    8213          36 :                         reply_len = -1;
    8214       10729 :         } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
    8215          56 :                 reply_len = wpa_supplicant_ctrl_iface_get_network(
    8216             :                         wpa_s, buf + 12, reply, reply_size);
    8217       10673 :         } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
    8218          10 :                 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12))
    8219           6 :                         reply_len = -1;
    8220       10663 :         } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
    8221           8 :                 reply_len = wpa_supplicant_ctrl_iface_list_creds(
    8222             :                         wpa_s, reply, reply_size);
    8223       10655 :         } else if (os_strcmp(buf, "ADD_CRED") == 0) {
    8224         223 :                 reply_len = wpa_supplicant_ctrl_iface_add_cred(
    8225             :                         wpa_s, reply, reply_size);
    8226       10432 :         } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
    8227         147 :                 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
    8228           1 :                         reply_len = -1;
    8229       10285 :         } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
    8230         746 :                 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
    8231          16 :                         reply_len = -1;
    8232        9539 :         } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
    8233          39 :                 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
    8234             :                                                                reply,
    8235             :                                                                reply_size);
    8236             : #ifndef CONFIG_NO_CONFIG_WRITE
    8237        9500 :         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
    8238           4 :                 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
    8239           2 :                         reply_len = -1;
    8240             : #endif /* CONFIG_NO_CONFIG_WRITE */
    8241        9496 :         } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
    8242          84 :                 reply_len = wpa_supplicant_ctrl_iface_get_capability(
    8243             :                         wpa_s, buf + 15, reply, reply_size);
    8244        9412 :         } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
    8245          13 :                 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
    8246           2 :                         reply_len = -1;
    8247        9399 :         } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
    8248          18 :                 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
    8249           1 :                         reply_len = -1;
    8250        9381 :         } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
    8251           1 :                 reply_len = wpa_supplicant_global_iface_list(
    8252             :                         wpa_s->global, reply, reply_size);
    8253        9380 :         } else if (os_strcmp(buf, "INTERFACES") == 0) {
    8254           1 :                 reply_len = wpa_supplicant_global_iface_interfaces(
    8255             :                         wpa_s->global, reply, reply_size);
    8256        9379 :         } else if (os_strncmp(buf, "BSS ", 4) == 0) {
    8257         744 :                 reply_len = wpa_supplicant_ctrl_iface_bss(
    8258             :                         wpa_s, buf + 4, reply, reply_size);
    8259             : #ifdef CONFIG_AP
    8260        8635 :         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
    8261           1 :                 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
    8262        8634 :         } else if (os_strncmp(buf, "STA ", 4) == 0) {
    8263           1 :                 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
    8264             :                                               reply_size);
    8265        8633 :         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
    8266           2 :                 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
    8267             :                                                    reply_size);
    8268        8631 :         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
    8269          22 :                 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
    8270           2 :                         reply_len = -1;
    8271        8609 :         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
    8272          22 :                 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
    8273           2 :                         reply_len = -1;
    8274        8587 :         } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
    8275           2 :                 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
    8276           1 :                         reply_len = -1;
    8277             : #endif /* CONFIG_AP */
    8278        8585 :         } else if (os_strcmp(buf, "SUSPEND") == 0) {
    8279           1 :                 wpas_notify_suspend(wpa_s->global);
    8280        8584 :         } else if (os_strcmp(buf, "RESUME") == 0) {
    8281           1 :                 wpas_notify_resume(wpa_s->global);
    8282             : #ifdef CONFIG_TESTING_OPTIONS
    8283        8583 :         } else if (os_strcmp(buf, "DROP_SA") == 0) {
    8284           2 :                 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
    8285             : #endif /* CONFIG_TESTING_OPTIONS */
    8286        8581 :         } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
    8287         155 :                 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
    8288           3 :                         reply_len = -1;
    8289        8426 :         } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
    8290           2 :                 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
    8291        8424 :         } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
    8292           3 :                 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
    8293           1 :                         reply_len = -1;
    8294        8421 :         } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
    8295           2 :                 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
    8296             :                                                                buf + 17))
    8297           1 :                         reply_len = -1;
    8298        8419 :         } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
    8299         222 :                 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
    8300             : #ifdef CONFIG_TDLS
    8301        8197 :         } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
    8302           3 :                 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
    8303           2 :                         reply_len = -1;
    8304        8194 :         } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
    8305          29 :                 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
    8306           1 :                         reply_len = -1;
    8307        8165 :         } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
    8308          13 :                 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
    8309           1 :                         reply_len = -1;
    8310        8152 :         } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
    8311           8 :                 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
    8312             :                                                                buf + 17))
    8313           7 :                         reply_len = -1;
    8314        8144 :         } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
    8315           4 :                 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
    8316             :                                                                       buf + 24))
    8317           3 :                         reply_len = -1;
    8318             : #endif /* CONFIG_TDLS */
    8319        8140 :         } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
    8320          13 :                 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
    8321        8127 :         } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
    8322          16 :                 if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
    8323           9 :                         reply_len = -1;
    8324        8111 :         } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
    8325           3 :                 if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
    8326           2 :                         reply_len = -1;
    8327        8108 :         } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
    8328           5 :                 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
    8329             :                                                        reply_size);
    8330        8103 :         } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
    8331           1 :                 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
    8332             :                                                        reply_size);
    8333             : #ifdef CONFIG_AUTOSCAN
    8334        8102 :         } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
    8335          11 :                 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
    8336           0 :                         reply_len = -1;
    8337             : #endif /* CONFIG_AUTOSCAN */
    8338             : #ifdef ANDROID
    8339             :         } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
    8340             :                 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
    8341             :                                                       reply_size);
    8342             : #endif /* ANDROID */
    8343        8091 :         } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
    8344           9 :                 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
    8345             :                                                       reply_size);
    8346        8082 :         } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
    8347          58 :                 pmksa_cache_clear_current(wpa_s->wpa);
    8348          58 :                 eapol_sm_request_reauth(wpa_s->eapol);
    8349             : #ifdef CONFIG_WNM
    8350        8024 :         } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
    8351          13 :                 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
    8352           3 :                         reply_len = -1;
    8353        8011 :         } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
    8354           1 :                 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
    8355           0 :                                 reply_len = -1;
    8356             : #endif /* CONFIG_WNM */
    8357        8010 :         } else if (os_strcmp(buf, "FLUSH") == 0) {
    8358        3171 :                 wpa_supplicant_ctrl_iface_flush(wpa_s);
    8359        4839 :         } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
    8360          35 :                 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
    8361             :                                                  reply_size);
    8362             : #ifdef CONFIG_TESTING_OPTIONS
    8363        4804 :         } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
    8364          59 :                 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
    8365           5 :                         reply_len = -1;
    8366        4745 :         } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
    8367           1 :                 wpas_ctrl_iface_mgmt_tx_done(wpa_s);
    8368        4744 :         } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
    8369          11 :                 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
    8370           1 :                         reply_len = -1;
    8371        4733 :         } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
    8372          47 :                 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
    8373           3 :                         reply_len = -1;
    8374        4686 :         } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
    8375        2046 :                 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
    8376           0 :                         reply_len = -1;
    8377        2640 :         } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
    8378        2130 :                 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
    8379           5 :                         reply_len = -1;
    8380         510 :         } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
    8381          98 :                 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
    8382           4 :                         reply_len = -1;
    8383         412 :         } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
    8384         230 :                 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
    8385           0 :                         reply_len = -1;
    8386         182 :         } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
    8387          88 :                 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
    8388             : #endif /* CONFIG_TESTING_OPTIONS */
    8389          94 :         } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
    8390          16 :                 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
    8391           6 :                         reply_len = -1;
    8392          78 :         } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
    8393           9 :                 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
    8394             :                                                       reply_size);
    8395          69 :         } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
    8396          29 :                 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
    8397          17 :                         reply_len = -1;
    8398          40 :         } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
    8399           4 :                 if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
    8400           2 :                         reply_len = -1;
    8401          36 :         } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
    8402          19 :                 wpas_ctrl_iface_erp_flush(wpa_s);
    8403          17 :         } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
    8404          16 :                 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
    8405          12 :                         reply_len = -1;
    8406             :         } else {
    8407           1 :                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
    8408           1 :                 reply_len = 16;
    8409             :         }
    8410             : 
    8411       67309 :         if (reply_len < 0) {
    8412         984 :                 os_memcpy(reply, "FAIL\n", 5);
    8413         984 :                 reply_len = 5;
    8414             :         }
    8415             : 
    8416       67309 :         *resp_len = reply_len;
    8417       67309 :         return reply;
    8418             : }
    8419             : 
    8420             : 
    8421          86 : static int wpa_supplicant_global_iface_add(struct wpa_global *global,
    8422             :                                            char *cmd)
    8423             : {
    8424             :         struct wpa_interface iface;
    8425             :         char *pos;
    8426             : 
    8427             :         /*
    8428             :          * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
    8429             :          * TAB<bridge_ifname>
    8430             :          */
    8431          86 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
    8432             : 
    8433          86 :         os_memset(&iface, 0, sizeof(iface));
    8434             : 
    8435             :         do {
    8436          86 :                 iface.ifname = pos = cmd;
    8437          86 :                 pos = os_strchr(pos, '\t');
    8438          86 :                 if (pos)
    8439          84 :                         *pos++ = '\0';
    8440          86 :                 if (iface.ifname[0] == '\0')
    8441           1 :                         return -1;
    8442          85 :                 if (pos == NULL)
    8443           1 :                         break;
    8444             : 
    8445          84 :                 iface.confname = pos;
    8446          84 :                 pos = os_strchr(pos, '\t');
    8447          84 :                 if (pos)
    8448          83 :                         *pos++ = '\0';
    8449          84 :                 if (iface.confname[0] == '\0')
    8450          75 :                         iface.confname = NULL;
    8451          84 :                 if (pos == NULL)
    8452           1 :                         break;
    8453             : 
    8454          83 :                 iface.driver = pos;
    8455          83 :                 pos = os_strchr(pos, '\t');
    8456          83 :                 if (pos)
    8457          82 :                         *pos++ = '\0';
    8458          83 :                 if (iface.driver[0] == '\0')
    8459           1 :                         iface.driver = NULL;
    8460          83 :                 if (pos == NULL)
    8461           1 :                         break;
    8462             : 
    8463          82 :                 iface.ctrl_interface = pos;
    8464          82 :                 pos = os_strchr(pos, '\t');
    8465          82 :                 if (pos)
    8466          30 :                         *pos++ = '\0';
    8467          82 :                 if (iface.ctrl_interface[0] == '\0')
    8468           1 :                         iface.ctrl_interface = NULL;
    8469          82 :                 if (pos == NULL)
    8470          52 :                         break;
    8471             : 
    8472          30 :                 iface.driver_param = pos;
    8473          30 :                 pos = os_strchr(pos, '\t');
    8474          30 :                 if (pos)
    8475           6 :                         *pos++ = '\0';
    8476          30 :                 if (iface.driver_param[0] == '\0')
    8477           4 :                         iface.driver_param = NULL;
    8478          30 :                 if (pos == NULL)
    8479          24 :                         break;
    8480             : 
    8481           6 :                 iface.bridge_ifname = pos;
    8482           6 :                 pos = os_strchr(pos, '\t');
    8483           6 :                 if (pos)
    8484           1 :                         *pos++ = '\0';
    8485           6 :                 if (iface.bridge_ifname[0] == '\0')
    8486           1 :                         iface.bridge_ifname = NULL;
    8487           6 :                 if (pos == NULL)
    8488           5 :                         break;
    8489             :         } while (0);
    8490             : 
    8491          85 :         if (wpa_supplicant_get_iface(global, iface.ifname))
    8492           0 :                 return -1;
    8493             : 
    8494          85 :         return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
    8495             : }
    8496             : 
    8497             : 
    8498          76 : static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
    8499             :                                               char *cmd)
    8500             : {
    8501             :         struct wpa_supplicant *wpa_s;
    8502             : 
    8503          76 :         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
    8504             : 
    8505          76 :         wpa_s = wpa_supplicant_get_iface(global, cmd);
    8506          76 :         if (wpa_s == NULL)
    8507           1 :                 return -1;
    8508          75 :         return wpa_supplicant_remove_iface(global, wpa_s, 0);
    8509             : }
    8510             : 
    8511             : 
    8512           2 : static void wpa_free_iface_info(struct wpa_interface_info *iface)
    8513             : {
    8514             :         struct wpa_interface_info *prev;
    8515             : 
    8516           4 :         while (iface) {
    8517           0 :                 prev = iface;
    8518           0 :                 iface = iface->next;
    8519             : 
    8520           0 :                 os_free(prev->ifname);
    8521           0 :                 os_free(prev->desc);
    8522           0 :                 os_free(prev);
    8523             :         }
    8524           2 : }
    8525             : 
    8526             : 
    8527           2 : static int wpa_supplicant_global_iface_list(struct wpa_global *global,
    8528             :                                             char *buf, int len)
    8529             : {
    8530             :         int i, res;
    8531           2 :         struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
    8532             :         char *pos, *end;
    8533             : 
    8534           8 :         for (i = 0; wpa_drivers[i]; i++) {
    8535           6 :                 struct wpa_driver_ops *drv = wpa_drivers[i];
    8536           6 :                 if (drv->get_interfaces == NULL)
    8537           6 :                         continue;
    8538           0 :                 tmp = drv->get_interfaces(global->drv_priv[i]);
    8539           0 :                 if (tmp == NULL)
    8540           0 :                         continue;
    8541             : 
    8542           0 :                 if (last == NULL)
    8543           0 :                         iface = last = tmp;
    8544             :                 else
    8545           0 :                         last->next = tmp;
    8546           0 :                 while (last->next)
    8547           0 :                         last = last->next;
    8548             :         }
    8549             : 
    8550           2 :         pos = buf;
    8551           2 :         end = buf + len;
    8552           2 :         for (tmp = iface; tmp; tmp = tmp->next) {
    8553           0 :                 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
    8554             :                                   tmp->drv_name, tmp->ifname,
    8555           0 :                                   tmp->desc ? tmp->desc : "");
    8556           0 :                 if (os_snprintf_error(end - pos, res)) {
    8557           0 :                         *pos = '\0';
    8558           0 :                         break;
    8559             :                 }
    8560           0 :                 pos += res;
    8561             :         }
    8562             : 
    8563           2 :         wpa_free_iface_info(iface);
    8564             : 
    8565           2 :         return pos - buf;
    8566             : }
    8567             : 
    8568             : 
    8569        1052 : static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
    8570             :                                                   char *buf, int len)
    8571             : {
    8572             :         int res;
    8573             :         char *pos, *end;
    8574             :         struct wpa_supplicant *wpa_s;
    8575             : 
    8576        1052 :         wpa_s = global->ifaces;
    8577        1052 :         pos = buf;
    8578        1052 :         end = buf + len;
    8579             : 
    8580        2183 :         while (wpa_s) {
    8581          79 :                 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
    8582          79 :                 if (os_snprintf_error(end - pos, res)) {
    8583           0 :                         *pos = '\0';
    8584           0 :                         break;
    8585             :                 }
    8586          79 :                 pos += res;
    8587          79 :                 wpa_s = wpa_s->next;
    8588             :         }
    8589        1052 :         return pos - buf;
    8590             : }
    8591             : 
    8592             : 
    8593           3 : static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
    8594             :                                             const char *ifname,
    8595             :                                             char *cmd, size_t *resp_len)
    8596             : {
    8597             :         struct wpa_supplicant *wpa_s;
    8598             : 
    8599           4 :         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
    8600           3 :                 if (os_strcmp(ifname, wpa_s->ifname) == 0)
    8601           2 :                         break;
    8602             :         }
    8603             : 
    8604           3 :         if (wpa_s == NULL) {
    8605           1 :                 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
    8606           1 :                 if (resp)
    8607           1 :                         *resp_len = os_strlen(resp);
    8608             :                 else
    8609           0 :                         *resp_len = 1;
    8610           1 :                 return resp;
    8611             :         }
    8612             : 
    8613           2 :         return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
    8614             : }
    8615             : 
    8616             : 
    8617       11054 : static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
    8618             :                                                char *buf, size_t *resp_len)
    8619             : {
    8620             : #ifdef CONFIG_P2P
    8621             :         static const char * cmd[] = {
    8622             :                 "LIST_NETWORKS",
    8623             :                 "P2P_FIND",
    8624             :                 "P2P_STOP_FIND",
    8625             :                 "P2P_LISTEN",
    8626             :                 "P2P_GROUP_ADD",
    8627             :                 "P2P_GET_PASSPHRASE",
    8628             :                 "P2P_SERVICE_UPDATE",
    8629             :                 "P2P_SERVICE_FLUSH",
    8630             :                 "P2P_FLUSH",
    8631             :                 "P2P_CANCEL",
    8632             :                 "P2P_PRESENCE_REQ",
    8633             :                 "P2P_EXT_LISTEN",
    8634             :                 NULL
    8635             :         };
    8636             :         static const char * prefix[] = {
    8637             : #ifdef ANDROID
    8638             :                 "DRIVER ",
    8639             : #endif /* ANDROID */
    8640             :                 "GET_NETWORK ",
    8641             :                 "REMOVE_NETWORK ",
    8642             :                 "P2P_FIND ",
    8643             :                 "P2P_CONNECT ",
    8644             :                 "P2P_LISTEN ",
    8645             :                 "P2P_GROUP_REMOVE ",
    8646             :                 "P2P_GROUP_ADD ",
    8647             :                 "P2P_PROV_DISC ",
    8648             :                 "P2P_SERV_DISC_REQ ",
    8649             :                 "P2P_SERV_DISC_CANCEL_REQ ",
    8650             :                 "P2P_SERV_DISC_RESP ",
    8651             :                 "P2P_SERV_DISC_EXTERNAL ",
    8652             :                 "P2P_SERVICE_ADD ",
    8653             :                 "P2P_SERVICE_DEL ",
    8654             :                 "P2P_SERVICE_REP ",
    8655             :                 "P2P_REJECT ",
    8656             :                 "P2P_INVITE ",
    8657             :                 "P2P_PEER ",
    8658             :                 "P2P_SET ",
    8659             :                 "P2P_UNAUTHORIZE ",
    8660             :                 "P2P_PRESENCE_REQ ",
    8661             :                 "P2P_EXT_LISTEN ",
    8662             :                 "P2P_REMOVE_CLIENT ",
    8663             :                 "WPS_NFC_TOKEN ",
    8664             :                 "WPS_NFC_TAG_READ ",
    8665             :                 "NFC_GET_HANDOVER_SEL ",
    8666             :                 "NFC_GET_HANDOVER_REQ ",
    8667             :                 "NFC_REPORT_HANDOVER ",
    8668             :                 "P2P_ASP_PROVISION ",
    8669             :                 "P2P_ASP_PROVISION_RESP ",
    8670             :                 NULL
    8671             :         };
    8672       11054 :         int found = 0;
    8673             :         int i;
    8674             : 
    8675       11054 :         if (global->p2p_init_wpa_s == NULL)
    8676        2062 :                 return NULL;
    8677             : 
    8678      112663 :         for (i = 0; !found && cmd[i]; i++) {
    8679      103671 :                 if (os_strcmp(buf, cmd[i]) == 0)
    8680         517 :                         found = 1;
    8681             :         }
    8682             : 
    8683      227534 :         for (i = 0; !found && prefix[i]; i++) {
    8684      218542 :                 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
    8685        1964 :                         found = 1;
    8686             :         }
    8687             : 
    8688        8992 :         if (found)
    8689        2481 :                 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
    8690             :                                                          buf, resp_len);
    8691             : #endif /* CONFIG_P2P */
    8692        6511 :         return NULL;
    8693             : }
    8694             : 
    8695             : 
    8696        8573 : static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
    8697             :                                                char *buf, size_t *resp_len)
    8698             : {
    8699             : #ifdef CONFIG_WIFI_DISPLAY
    8700        8573 :         if (global->p2p_init_wpa_s == NULL)
    8701        2062 :                 return NULL;
    8702       13021 :         if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
    8703        6510 :             os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
    8704           2 :                 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
    8705             :                                                          buf, resp_len);
    8706             : #endif /* CONFIG_WIFI_DISPLAY */
    8707        6509 :         return NULL;
    8708             : }
    8709             : 
    8710             : 
    8711       11054 : static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
    8712             :                                            char *buf, size_t *resp_len)
    8713             : {
    8714             :         char *ret;
    8715             : 
    8716       11054 :         ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
    8717       11054 :         if (ret)
    8718        2481 :                 return ret;
    8719             : 
    8720        8573 :         ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
    8721        8573 :         if (ret)
    8722           2 :                 return ret;
    8723             : 
    8724        8571 :         return NULL;
    8725             : }
    8726             : 
    8727             : 
    8728           4 : static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
    8729             : {
    8730             :         char *value;
    8731             : 
    8732           4 :         value = os_strchr(cmd, ' ');
    8733           4 :         if (value == NULL)
    8734           1 :                 return -1;
    8735           3 :         *value++ = '\0';
    8736             : 
    8737           3 :         wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
    8738             : 
    8739             : #ifdef CONFIG_WIFI_DISPLAY
    8740           3 :         if (os_strcasecmp(cmd, "wifi_display") == 0) {
    8741           2 :                 wifi_display_enable(global, !!atoi(value));
    8742           2 :                 return 0;
    8743             :         }
    8744             : #endif /* CONFIG_WIFI_DISPLAY */
    8745             : 
    8746             :         /* Restore cmd to its original value to allow redirection */
    8747           1 :         value[-1] = ' ';
    8748             : 
    8749           1 :         return -1;
    8750             : }
    8751             : 
    8752             : 
    8753             : #ifndef CONFIG_NO_CONFIG_WRITE
    8754           4 : static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
    8755             : {
    8756           4 :         int ret = 0, saved = 0;
    8757             :         struct wpa_supplicant *wpa_s;
    8758             : 
    8759           8 :         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
    8760           4 :                 if (!wpa_s->conf->update_config) {
    8761           2 :                         wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
    8762           2 :                         continue;
    8763             :                 }
    8764             : 
    8765           2 :                 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
    8766           1 :                         wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
    8767           1 :                         ret = 1;
    8768             :                 } else {
    8769           1 :                         wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
    8770           1 :                         saved++;
    8771             :                 }
    8772             :         }
    8773             : 
    8774           4 :         if (!saved && !ret) {
    8775           2 :                 wpa_dbg(wpa_s, MSG_DEBUG,
    8776             :                         "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
    8777           2 :                 ret = 1;
    8778             :         }
    8779             : 
    8780           4 :         return ret;
    8781             : }
    8782             : #endif /* CONFIG_NO_CONFIG_WRITE */
    8783             : 
    8784             : 
    8785           7 : static int wpas_global_ctrl_iface_status(struct wpa_global *global,
    8786             :                                          char *buf, size_t buflen)
    8787             : {
    8788             :         char *pos, *end;
    8789             :         int ret;
    8790             :         struct wpa_supplicant *wpa_s;
    8791             : 
    8792           7 :         pos = buf;
    8793           7 :         end = buf + buflen;
    8794             : 
    8795             : #ifdef CONFIG_P2P
    8796           7 :         if (global->p2p && !global->p2p_disabled) {
    8797          42 :                 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
    8798             :                                   "\n"
    8799             :                                   "p2p_state=%s\n",
    8800          36 :                                   MAC2STR(global->p2p_dev_addr),
    8801             :                                   p2p_get_state_txt(global->p2p));
    8802           6 :                 if (os_snprintf_error(end - pos, ret))
    8803           0 :                         return pos - buf;
    8804           6 :                 pos += ret;
    8805           1 :         } else if (global->p2p) {
    8806           1 :                 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
    8807           1 :                 if (os_snprintf_error(end - pos, ret))
    8808           0 :                         return pos - buf;
    8809           1 :                 pos += ret;
    8810             :         }
    8811             : #endif /* CONFIG_P2P */
    8812             : 
    8813             : #ifdef CONFIG_WIFI_DISPLAY
    8814           7 :         ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
    8815           7 :                           !!global->wifi_display);
    8816           7 :         if (os_snprintf_error(end - pos, ret))
    8817           0 :                 return pos - buf;
    8818           7 :         pos += ret;
    8819             : #endif /* CONFIG_WIFI_DISPLAY */
    8820             : 
    8821          14 :         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
    8822          49 :                 ret = os_snprintf(pos, end - pos, "ifname=%s\n"
    8823             :                                   "address=" MACSTR "\n",
    8824          49 :                                   wpa_s->ifname, MAC2STR(wpa_s->own_addr));
    8825           7 :                 if (os_snprintf_error(end - pos, ret))
    8826           0 :                         return pos - buf;
    8827           7 :                 pos += ret;
    8828             :         }
    8829             : 
    8830           7 :         return pos - buf;
    8831             : }
    8832             : 
    8833             : 
    8834       11057 : char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
    8835             :                                                 char *buf, size_t *resp_len)
    8836             : {
    8837             :         char *reply;
    8838       11057 :         const int reply_size = 2048;
    8839             :         int reply_len;
    8840       11057 :         int level = MSG_DEBUG;
    8841             : 
    8842       11057 :         if (os_strncmp(buf, "IFNAME=", 7) == 0) {
    8843           3 :                 char *pos = os_strchr(buf + 7, ' ');
    8844           3 :                 if (pos) {
    8845           3 :                         *pos++ = '\0';
    8846           3 :                         return wpas_global_ctrl_iface_ifname(global,
    8847             :                                                              buf + 7, pos,
    8848             :                                                              resp_len);
    8849             :                 }
    8850             :         }
    8851             : 
    8852       11054 :         reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
    8853       11054 :         if (reply)
    8854        2483 :                 return reply;
    8855             : 
    8856        8571 :         if (os_strcmp(buf, "PING") == 0)
    8857        3152 :                 level = MSG_EXCESSIVE;
    8858        8571 :         wpa_hexdump_ascii(level, "RX global ctrl_iface",
    8859             :                           (const u8 *) buf, os_strlen(buf));
    8860             : 
    8861        8571 :         reply = os_malloc(reply_size);
    8862        8571 :         if (reply == NULL) {
    8863           0 :                 *resp_len = 1;
    8864           0 :                 return NULL;
    8865             :         }
    8866             : 
    8867        8571 :         os_memcpy(reply, "OK\n", 3);
    8868        8571 :         reply_len = 3;
    8869             : 
    8870        8571 :         if (os_strcmp(buf, "PING") == 0) {
    8871        3152 :                 os_memcpy(reply, "PONG\n", 5);
    8872        3152 :                 reply_len = 5;
    8873        5419 :         } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
    8874          86 :                 if (wpa_supplicant_global_iface_add(global, buf + 14))
    8875          11 :                         reply_len = -1;
    8876        5333 :         } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
    8877          76 :                 if (wpa_supplicant_global_iface_remove(global, buf + 17))
    8878           1 :                         reply_len = -1;
    8879        5257 :         } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
    8880           1 :                 reply_len = wpa_supplicant_global_iface_list(
    8881             :                         global, reply, reply_size);
    8882        5256 :         } else if (os_strcmp(buf, "INTERFACES") == 0) {
    8883        1051 :                 reply_len = wpa_supplicant_global_iface_interfaces(
    8884             :                         global, reply, reply_size);
    8885        4205 :         } else if (os_strcmp(buf, "TERMINATE") == 0) {
    8886           0 :                 wpa_supplicant_terminate_proc(global);
    8887        4205 :         } else if (os_strcmp(buf, "SUSPEND") == 0) {
    8888           1 :                 wpas_notify_suspend(global);
    8889        4204 :         } else if (os_strcmp(buf, "RESUME") == 0) {
    8890           1 :                 wpas_notify_resume(global);
    8891        4203 :         } else if (os_strncmp(buf, "SET ", 4) == 0) {
    8892           4 :                 if (wpas_global_ctrl_iface_set(global, buf + 4)) {
    8893             : #ifdef CONFIG_P2P
    8894           2 :                         if (global->p2p_init_wpa_s) {
    8895           2 :                                 os_free(reply);
    8896             :                                 /* Check if P2P redirection would work for this
    8897             :                                  * command. */
    8898           2 :                                 return wpa_supplicant_ctrl_iface_process(
    8899             :                                         global->p2p_init_wpa_s,
    8900             :                                         buf, resp_len);
    8901             :                         }
    8902             : #endif /* CONFIG_P2P */
    8903           0 :                         reply_len = -1;
    8904             :                 }
    8905             : #ifndef CONFIG_NO_CONFIG_WRITE
    8906        4199 :         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
    8907           4 :                 if (wpas_global_ctrl_iface_save_config(global))
    8908           3 :                         reply_len = -1;
    8909             : #endif /* CONFIG_NO_CONFIG_WRITE */
    8910        4195 :         } else if (os_strcmp(buf, "STATUS") == 0) {
    8911           7 :                 reply_len = wpas_global_ctrl_iface_status(global, reply,
    8912             :                                                           reply_size);
    8913             : #ifdef CONFIG_MODULE_TESTS
    8914        4188 :         } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
    8915             :                 int wpas_module_tests(void);
    8916           1 :                 if (wpas_module_tests() < 0)
    8917           0 :                         reply_len = -1;
    8918             : #endif /* CONFIG_MODULE_TESTS */
    8919        4187 :         } else if (os_strncmp(buf, "RELOG", 5) == 0) {
    8920        4186 :                 if (wpa_debug_reopen_file() < 0)
    8921           0 :                         reply_len = -1;
    8922             :         } else {
    8923           1 :                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
    8924           1 :                 reply_len = 16;
    8925             :         }
    8926             : 
    8927        8569 :         if (reply_len < 0) {
    8928          15 :                 os_memcpy(reply, "FAIL\n", 5);
    8929          15 :                 reply_len = 5;
    8930             :         }
    8931             : 
    8932        8569 :         *resp_len = reply_len;
    8933        8569 :         return reply;
    8934             : }

Generated by: LCOV version 1.10